magnusja / libaums

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

Issue in kotlin version #246

Closed brixzen closed 4 years ago

brixzen commented 4 years ago

Thanks magnusja for great library..!!! i have problem with kotlin version. but it work normally in java version 0.6.0, the problem started in 0.7.0 version.

Problem

unsupported PeripheralQualifier or PeripheralDeviceType, The library have issue in kotlin version, they request device.init() twice time. first request is oke, peripheralDeviceType = 0 second request get deviceType = 13, so library can't read correctly. if i downgrade to 0.6.0 version then this case will oke, no problem anymore.

Stacktrace of Excpetion

I/UsbMassStorageDevice: found usb device: UsbDevice[mName=/dev/bus/usb/001/003,mVendorId=4184,mProductId=9697,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=Western Digital,mProductName=My Passport 25E1,mVersion=10.21,mSerialNumber=57583531413239354E383550,mConfigurations=[
    UsbConfiguration[mId=1,mName=null,mAttributes=128,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]]]]
    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]]
    found usb endpoint: UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=512,mInterval=0]
    found usb endpoint: UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=512,mInterval=0]
I/UsbMassStorageDevice: found usb device: UsbDevice[mName=/dev/bus/usb/001/003,mVendorId=4184,mProductId=9697,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=Western Digital,mProductName=My Passport 25E1,mVersion=10.21,mSerialNumber=57583531413239354E383550,mConfigurations=[
    UsbConfiguration[mId=1,mName=null,mAttributes=128,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]]]]
    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]]
    found usb endpoint: UsbEndpoint[mAddress=129,mAttributes=2,mMaxPacketSize=512,mInterval=0]
    found usb endpoint: UsbEndpoint[mAddress=2,mAttributes=2,mMaxPacketSize=512,mInterval=0]
D/UsbMassStorageDevice: setup device
I/UsbMassStorageDevice: MAX LUN 1
D/ScsiBlockDevice: inquiry response: ScsiInquiryResponse [peripheralQualifier=0, peripheralDeviceType=0, removableMedia=false, spcVersion=6, responseDataFormat=2]
I/ScsiBlockDevice: Block size: 512
    Last block address: -388003841
I/FAT: fat is mirrored, fat count: 2
D/ClusterChain: Init a cluster chain, reading from FAT
D/ClusterChain: Finished init of a cluster chain
D/FatDirectory: volume label: UsbStorage
D/Fat32FileSystem: Fat32BootSector{bytesPerSector=512, sectorsPerCluster=64, reservedSectors=48, fatCount=2, totalNumberOfSectors=3906961380, sectorsPerFat=476808, rootDirStartCluster=2, fsInfoStartSector=1, fatMirrored=true, validFat=0, volumeLabel=''}
D/ScsiBlockDevice: inquiry response: ScsiInquiryResponse [peripheralQualifier=0, peripheralDeviceType=13, removableMedia=false, spcVersion=6, responseDataFormat=2]
E/ActivitySourceSelector: java.io.IOException: unsupported PeripheralQualifier or PeripheralDeviceType

Code where problem occurs

The problem in file UsbMassStorageDevice.kt
line 132 i think.
this.partitions = (0..maxLun[0])
                .map { lun ->
                    BlockDeviceDriverFactory.createBlockDevice(usbCommunication, lun = lun.toByte())
                }
                .mapNotNull { blockDevice ->
                    try {
                        blockDevice.init()
                    } catch (e: UnitNotReady) {
                        if (maxLun[0] == 0.toByte()) {
                            throw e
                        }
                        // else:  seems to support multiple logical units (e.g. card reader)
                        // so some LUNs may not be inserted. Silently fail in this case and
                        // continue with next LUN
                        return@mapNotNull null
                    }

                    val partitionTable = PartitionTableFactory.createPartitionTable(blockDevice)

                    initPartitions(partitionTable, blockDevice)
                }
                .flatten()
magnusja commented 4 years ago

That is very interesting. I have to test this myself, I have no idea why this would suddenly give a different result :/

magnusja commented 4 years ago

Quick test works for me. Can you provide some code on how your are calling init twice?

brixzen commented 4 years ago

Thanks for response, here is the code

`UsbMassStorageDevice[] devices = UsbMassStorageDevice.getMassStorageDevices(this); LogUtils.debug(TAG, "Jumlah dev " + devices.length);

    for (UsbMassStorageDevice device : devices) {
        try {
            device.init();
            usbDevice = device;
        } catch (IOException e) {
            if (devices.length >= 2) {
                continue;
            } else {
                LogUtils.error(TAG, e.toString());
                showMessageLong("init device failed, with message " + e.getMessage());
                finish();
                break;
            }
        }
        LogUtils.debug(TAG, "check partition size");
        if (device.getPartitions().size() <= 0) {
            showMessageLong("usb don't have any partition");
            finish();
            break;
        }
        LogUtils.debug(TAG, "Use only first partition in USB");
        currentFs = device.getPartitions().get(0).getFileSystem();
        rootUsb = currentFs.getRootDirectory();
        LogUtils.debug(TAG, "Capacity: " + currentFs.getCapacity());
    }

    if (devices.length >= 2 && usbDevice == null) {
        showMessageLong("Failed init all USB device");
        finish();
        return;
    }`
magnusja commented 4 years ago

Where are you calling init twice in that snippet?

brixzen commented 4 years ago

I not calling init twice :| but library always call init twice, in java version 0.6.0 not call init twice, using same code.

magnusja commented 4 years ago

You mean blockDevice.init()?

brixzen commented 4 years ago

You mean blockDevice.init()?

yes blockDevice.init(), i don't know why this method called twice, it happen only kotlin version and not all android device, only happen in some of device like Xiaomi Redmi note 7, Xiaomi mi4c, Tanix TX6, Mi box S.

brixzen commented 4 years ago

I also test using latest 0.7.5 with libusb native, issue still same :| what the meaning of this debug? Block size: 512 this is mean that read MBR?

` D/a: inquiry response: ScsiInquiryResponse [peripheralQualifier=0, peripheralDeviceType=0, removableMedia=false, spcVersion=6, responseDataFormat=2]

I/a: Block size: 512 Last block address: -388003841

I/b: fat is mirrored, fat count: 2

D/a: Init a cluster chain, reading from FAT

D/a: Finished init of a cluster chain

D/f: volume label: UsbStorage

D/d: Fat32BootSector{bytesPerSector=512, sectorsPerCluster=64, reservedSectors=48, fatCount=2, totalNumberOfSectors=3906961380, sectorsPerFat=476808, rootDirStartCluster=2, fsInfoStartSector=1, fatMirrored=true, validFat=0, volumeLabel=''}

D/a: inquiry response: ScsiInquiryResponse [peripheralQualifier=0, peripheralDeviceType=13, removableMedia=false, spcVersion=6, responseDataFormat=2]

`

brixzen commented 4 years ago

Dear magnusja, i found some info, not working when format is FAT32L, will work normally in FAT-32 format.

Screen Shot 2020-02-26 at 00 33 22
magnusja commented 4 years ago

Hey @brixzen

okay so I get what you mean now. A new feature in v0.7.0 is that it supports multiple LUNs. That means for a card reader with lets say three different kind of cards (e.g. micro and usual SD) libaums would iterate over every slot and try to initialise it. Are you using an SD card reader or just an ordinary pen drive?

blockSize is the size of one block on the device. Not on file system level but very low level what your USB drive uses to address blocks of memory.

FAT32L is not supported that is true, but does this solve our problem with the init method?

brixzen commented 4 years ago

Hey @brixzen

okay so I get what you mean now. A new feature in v0.7.0 is that it supports multiple LUNs. That means for a card reader with lets say three different kind of cards (e.g. micro and usual SD) libaums would iterate over every slot and try to initialise it. Are you using an SD card reader or just an ordinary pen drive?

blockSize is the size of one block on the device. Not on file system level but very low level what your USB drive uses to address blocks of memory.

FAT32L is not supported that is true, but does this solve our problem with the init method?

Hi @magnusja

Okay thanks for explain, noted in 0.6.0 version support FAT32L, in kotlin version not support, yes this solve my problem, thanks for response..

magnusja commented 4 years ago

Hey @brixzen okay so I get what you mean now. A new feature in v0.7.0 is that it supports multiple LUNs. That means for a card reader with lets say three different kind of cards (e.g. micro and usual SD) libaums would iterate over every slot and try to initialise it. Are you using an SD card reader or just an ordinary pen drive? blockSize is the size of one block on the device. Not on file system level but very low level what your USB drive uses to address blocks of memory. FAT32L is not supported that is true, but does this solve our problem with the init method?

Hi @magnusja

Okay thanks for explain, noted in 0.6.0 version support FAT32L, in kotlin version not support, yes this solve my problem, thanks for response..

FAT32L is not supported in 0.6.0 as well, I think we have a misunderstanding here.

brixzen commented 4 years ago

but it's works using 0.6.0, hhhmmmmm.. ok ok noted, FAT32L not support..

magnusja commented 4 years ago

Yeah I guess the reason that it works on v0.6.0 has nothing to do with the FAT32L, it is probably something else.