magnusja / libaums

Open source library to access USB Mass Storage devices on Android without rooting your device
Apache License 2.0
1.25k stars 269 forks source link

Can't init usb device with "virtual CD-Rom" #365

Open thebino opened 1 year ago

thebino commented 1 year ago

Problem

When initializing a device with multiple endpoints where the first behaves like a CD-Rom drive, the initialisation fails.

See attached files for more details on the device. device_dump.txt device_info.txt

Expected behavior

Initialise at least the non virtual CD-Rom drive

Actual behavior

Crash due initialisation

Stacktrace of Excpetion

I  USB Device detached
I  ⏹️ stop communication
I  USB Device attached '￿￿￿￿￿￿￿￿￿￿￿￿' on port '/dev/bus/usb/001/002'
V  request USB permission for device '￿￿￿￿￿￿￿￿￿￿￿￿' on port '/dev/bus/usb/001/002'
W  USB Permission denied!
W  USB Permission denied!
V  Has permission for attached device /dev/bus/usb/001/002
I  ▶️️ start communication
I  found usb device: /dev/bus/usb/001/002=UsbDevice[mName=/dev/bus/usb/001/002,mVendorId=3141,mProductId=12801,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=null,mProductName=￿￿￿￿￿￿￿￿￿￿￿￿,mVersion=1.00,mSerialNumberReader=android.hardware.usb.IUsbSerialReader$Stub$Proxy@ac570ec, mHasAudioPlayback=false, mHasAudioCapture=false, mHasMidi=false, mHasVideoCapture=false, mHasVideoPlayback=false, mConfigurations=[
    UsbConfiguration[mId=1,mName=null,mAttributes=192,mMaxPower=250,mInterfaces=[
    UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=8,mSubclass=6,mProtocol=80,mEndpoints=[
    UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=512,mInterval=0]
    UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=512,mInterval=0]]]]
I  Found usb interface: UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=8,mSubclass=6,mProtocol=80,mEndpoints=[
    UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=512,mInterval=0]
    UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=512,mInterval=0]]
I  Found usb endpoint: UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=512,mInterval=0]
I  Found usb endpoint: UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=512,mInterval=0]
I  Found 1 usb mass storage devices.
I  Initialize device[0]
D  setup device
I  MAX LUN 1
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
W  Could not read from device, result == -1 errno 0 null, retrying...
E  Could not init devise!
    java.io.IOException: MAX_RECOVERY_ATTEMPTS Exceeded while trying to transfer command to device, please reattach device and try again
        at me.jahnen.libaums.core.driver.scsi.ScsiBlockDevice.transferCommand(ScsiBlockDevice.kt:181)
        at me.jahnen.libaums.core.driver.scsi.ScsiBlockDevice.initAttempt(ScsiBlockDevice.kt:100)
        at me.jahnen.libaums.core.driver.scsi.ScsiBlockDevice.init(ScsiBlockDevice.kt:83)
        at me.jahnen.libaums.core.UsbMassStorageDevice.setupDevice(UsbMassStorageDevice.kt:138)
        at me.jahnen.libaums.core.UsbMassStorageDevice.init(UsbMassStorageDevice.kt:100)
        at pro.stuermer.bookii.usb.ConnectionService.connect(ConnectionService.kt:56)
        at pro.stuermer.bookii.usb.repository.ConnectionRepositoryImpl.initConnection(ConnectionRepositoryImpl.kt:37)
        at pro.stuermer.bookii.devices.domain.InitConnectionUseCase.invoke(InitConnectionUseCase.kt:10)
        at pro.stuermer.bookii.MainViewModel.startCommunication(MainViewModel.kt:16)
        at pro.stuermer.bookii.MainActivity.scanForAlreadyAttachedDevices(MainActivity.kt:133)
        at pro.stuermer.bookii.MainActivity.onResume(MainActivity.kt:63)
        at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1569)
        at android.app.Activity.performResume(Activity.java:8484)
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4769)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4812)
        at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:54)
        at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7878)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:952)
I  USB Device detached
I  ⏹️ stop communication

Code where problem occurs

val massStorageDevice = device.getMassStorageDevices(context = context.applicationContext)
massStorageDevice.init()
magnusja commented 1 year ago

Puh I never tested CD roms tbh

I dont think it is compatible. They probably use a different protocol.

thebino commented 1 year ago

@magnusja It is not a real CD-drive. The USB device contains two interfaces, see attached device_dump.txt and device_info.txt for more details.

magnusja commented 1 year ago

So it seems that the interface does not respond properly to a scsi inquiry. I guess one option would to not throw an exception in that case.

magnusja commented 1 year ago

Not sure if there is way to recognize before if the device responds to the scisi command protocol

magnusja commented 1 year ago

Does the device really have two interfaces? I can only see one.

thebino commented 1 year ago

The device_dump.txt lists two interfaces when using dumping the USB Device from android itself.

The device_info.txt has it listed as two different disks (disk5 the MTP storage I'm interested in, and disk6 which is just the fake CD-Rom with the application/driver for windows)

magnusja commented 1 year ago

I would suggest that you change the initialization of the device so that you catch the exception, ignore it and then continue to initialize the second LUN.

magnusja commented 1 year ago

The device_dump.txt lists two interfaces when using dumping the USB Device from android itself.

This is what I see.

ConnectionService  I  ▶️️ start communication
ConnectionService  V  ├── manufacturerName = null
ConnectionService  V  ├── productId = 12801
ConnectionService  V  ├── productName = ￿￿￿￿￿￿￿￿￿￿￿￿
ConnectionService  V  ├── serialNumber = ￿￿￿￿￿￿￿￿￿￿￿￿
ConnectionService  V  ├── vendorId = 3141
ConnectionService  V  ├── version = 1.00
ConnectionService  V  ├── deviceClass = 0
ConnectionService  V  ├── deviceId = 1006
ConnectionService  V  ├── deviceName = /dev/bus/usb/001/006
ConnectionService  V  ├── deviceProtocol = 0
ConnectionService  V  ├── deviceSubclass = 0
ConnectionService  V  └─ interface
ConnectionService  V      ├─ name = null
ConnectionService  V      ├─ interfaceProtocol = 80
ConnectionService  V      ├─ interfaceClass = 8
ConnectionService  V      ├─ interfaceSubclass = 6
ConnectionService  V      ├─ endpoint
ConnectionService  V      │   ├─ address = 129
ConnectionService  V      │   ├─ attributes = 2
ConnectionService  V      │   ├─ direction = 128
ConnectionService  V      │   ├─ endpointNumber = 1
ConnectionService  V      │   ├─ interval = 0
ConnectionService  V      │   ├─ maxPacketSize = 512
ConnectionService  V      │   └─ type = 2
ConnectionService  V      └─ endpoint
ConnectionService  V          ├─ address = 2
ConnectionService  V          ├─ attributes = 2
ConnectionService  V          ├─ direction = 0
ConnectionService  V          ├─ endpointNumber = 2
ConnectionService  V          ├─ interval = 0
ConnectionService  V          ├─ maxPacketSize = 512
ConnectionService  V          └─ type = 2
MainAct...eceiver  I  USB Device detached
ConnectionService  I  ⏹️ stop communication

One interface, two endpoints. What am I missing?

The device_info.txt has it listed as two different disks (disk5 the MTP storage I'm interested in, and disk6 which is just the fake CD-Rom with the application/driver for windows)

MTP is not supported! That is a whole nother protocol. This lib only supports the SCSI block command set. I am happy to take contributions though.

magnusja commented 1 year ago

Are you sure it is an MTP device?

I would have hoped that an MTP device would not advertise itself as a device which supports scsi.

https://github.com/magnusja/libaums/blob/e5a31e98b3241cee4086848f49a5a370938bdb71/libaums/src/main/java/me/jahnen/libaums/core/UsbMassStorageDevice.kt#L181-L190

thebino commented 1 year ago

I meant "Mass Storage Device" not MTP.

And yes, 1 interface, 2 endpoints

magnusja commented 1 year ago

I see. Then try what I suggested. Ignore the exception on first LUN and try the second. Maybe we are in luck. But the device not responding to the SCSI inquiry is odd. Maybe the CDRom thingy only supports an older version of that inquiry, I am unsure.

thebino commented 1 year ago

Hasn't changed anything. See attached logcat logcat.txt

magnusja commented 1 year ago

This doesnt look like you did what I suggested. Did you catch the exception in you application code? That wont work. Please fork and catch the exception in libaums to ignore and continue initialization of second LUN.

thebino commented 1 year ago

It's catching the exception for the init() which doesn't help since it is only a single device.

I can try to fork it and debug libaums directly

for (device in devices) {
    Timber.d("try to init device ${device.usbDevice.deviceName}")
    Timber.v("\t${device.usbDevice}")
    try {
        Timber.d("\twith ${device.partitions.size} partitions")
    } catch (u: UninitializedPropertyAccessException) {
        // no-op: partitions aren't initialized yet
    }

    try {
        // before interacting with a device you need to call init()!
        device.init()
    } catch (io: IOException) {
        Timber.e(io, "catch IOException while initializing device!")
    }
}