NordicSemiconductor / Android-DFU-Library

Device Firmware Update library and Android app
http://www.nordicsemi.com/dfu
BSD 3-Clause "New" or "Revised" License
768 stars 272 forks source link

different speed dfu #208

Closed gksrb4 closed 4 years ago

gksrb4 commented 4 years ago

device: nRF51822 sdk13.3.0 In galaxy note 4, Dfu takes 40~50 sec. but, In galaxy note 10, It takes almost 3 min. It is obviously slow.

I have used following code.

final DfuServiceInitiator starter = new DfuServiceInitiator(deviceAddress)
                .setDeviceName(deviceName)
                .setKeepBond(false)
                .setForceDfu(false)
                .setPacketsReceiptNotificationsEnabled(false)
                .setPacketsReceiptNotificationsValue(DfuServiceInitiator.DEFAULT_PRN_VALUE)
                .setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true);
starter.setZip(fileStreamUri, filePath);
starter.start(this, DfuService.class);

Does I miss something?

philips77 commented 4 years ago

Hi, Can you provide logs? FYI: I'll release an update to DFU Library on both Android and iOS today, and it may improve the speed on newer phones. If you'll find there "XXX bytes were lost" on the DFU performed from Note 10, the update should help. If not, I need more information.

gksrb4 commented 4 years ago

Hi, I'm waiting to release next version! but, It's still not released officially. I saw usage implementation 'no.nordicsemi.android:dfu:1.9.1' so I tried. but, this version doesn't work even in starting dfu. So. I share 1.9.0 version dfu log.

... 2019-11-29 13:29:46.667 W/DfuImpl: 1040 bytes were lost! ...

2019-11-29 13:32:27.039 I/DfuImpl: Transfer of 78824 bytes has taken 162752 ms --> almost 3 minutes!

dfu log.txt

gksrb4 commented 4 years ago

1.9.1 version crash log

    --------- beginning of crash
2019-11-29 13:47:59.177 E/AndroidRuntime: FATAL EXCEPTION: IntentService[DfuBaseService]
    Process: my-package-name, PID: 10230
    java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/gson/Gson;
        at no.nordicsemi.android.dfu.internal.ArchiveInputStream.parseZip(ArchiveInputStream.java:329)
        at no.nordicsemi.android.dfu.internal.ArchiveInputStream.<init>(ArchiveInputStream.java:139)
        at no.nordicsemi.android.dfu.DfuBaseService.openInputStream(DfuBaseService.java:1439)
        at no.nordicsemi.android.dfu.DfuBaseService.onHandleIntent(DfuBaseService.java:1158)
        at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:76)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:216)
        at android.os.HandlerThread.run(HandlerThread.java:65)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.gson.Gson" on path: DexPathList[[zip file "/data/app/my-package-name-b-mP7oEYzNmnSqGusx_dvg==/base.apk"],nativeLibraryDirectories=[/data/app/my-package-name-b-mP7oEYzNmnSqGusx_dvg==/lib/arm64, /system/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at no.nordicsemi.android.dfu.internal.ArchiveInputStream.parseZip(ArchiveInputStream.java:329) 
        at no.nordicsemi.android.dfu.internal.ArchiveInputStream.<init>(ArchiveInputStream.java:139) 
        at no.nordicsemi.android.dfu.DfuBaseService.openInputStream(DfuBaseService.java:1439) 
        at no.nordicsemi.android.dfu.DfuBaseService.onHandleIntent(DfuBaseService.java:1158) 
        at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:76) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:216) 
        at android.os.HandlerThread.run(HandlerThread.java:65) 
philips77 commented 4 years ago

This looks like R8 configuration or missing dependency to gson. Try adding the library as a module, not from jcenter. Clone it and follow the instructions in Readme.

gksrb4 commented 4 years ago

adding

implementation 'no.nordicsemi.android:dfu:1.9.1'
implementation 'com.google.code.gson:gson:2.8.6'

and -keep class no.nordicsemi.android.dfu.** { *; } to proguard rule. so, It doesn't occur the crash. but It's still slow.

2019-12-02 09:32:39.306 W/DfuImpl: 1280 bytes were lost!
..
2019-12-02 09:35:30.279 I/DfuImpl: Transfer of 78824 bytes has taken 172737 ms

dfu log 2.txt

philips77 commented 4 years ago

So here's why it's slow. As you are using the latest version, which contains a fix for the issue we found when doing DFU on devices with DFU bootloader from recent SDKs, the library waits 400 ms before sending bytes of the first data object. You have excluded all debug messages from the log, but it can be seen in the timings here:

2019-12-02 09:32:37.142 I/DfuImpl: Creating Data object (Op Code = 1, Type = 2, Size = 4096) (1/20)
2019-12-02 09:32:37.586 I/DfuImpl: Uploading firmware...

The Uploading firmware... message is sent 400+ ms after the first message is printed. For comparison, creating the second object took 37 ms:

2019-12-02 09:32:38.427 I/DfuImpl: Creating Data object (Op Code = 1, Type = 2, Size = 4096) (2/20)
2019-12-02 09:32:38.464 I/DfuImpl: Uploading firmware..

During our tests we found that those 400 ms delay is required and enough. Without it, the error you get on the 3rd object was coming immediately during sending the first one and no matter how many retries the lib did, some packets were lost, the CRC didn't match and DFU was stopped with an error. With the initial delay it seems to be stable. However, from time to time we also observe that bytes get lost in a later stage. At that time we try to minimize the risk of failure, so the library sets the PRN (Packet Receipt Notifications) to 1:

2019-12-02 09:32:39.305 I/DfuImpl: Checksum received (Offset = 6912, CRC = 044F3C7B)
2019-12-02 09:32:39.306 W/DfuImpl: 1280 bytes were lost!
2019-12-02 09:32:39.324 I/DfuImpl: Sending the number of packets before notifications (Op Code = 2, Value = 1) <- here
2019-12-02 09:32:39.375 I/DfuImpl: CRC does not match! Expected 28531180 but found 044F3C7B. Retrying...(2/3)

so that each packet sent is ack by the DFU target. This means that instead of sending packets as fast as possible, most probably many packets per connection interval, the library now switches to "safe" mode, where it sends one packet in one connection interval, then waits for a PRN in the next interval, etc, so effectively sends 1 packet per 2 connection intervals. You may observe, that sending the 1st took 809 ms:

2019-12-02 09:32:37.586 I/DfuImpl: Uploading firmware...
2019-12-02 09:32:38.030 I/DfuImpl: Sending Calculate Checksum command (Op Code = 3)
2019-12-02 09:32:38.395 I/DfuImpl: Checksum received (Offset = 4096, CRC = 587F0D7E)

but after setting PRN to 1 each next packet took ~9 seconds:

2019-12-02 09:32:39.445 I/DfuImpl: Uploading firmware...
2019-12-02 09:32:48.718 I/DfuImpl: Sending Calculate Checksum command (Op Code = 3)
2019-12-02 09:32:48.755 I/DfuImpl: Checksum received (Offset = 8192, CRC = E273DD66)

What you may do, is to import the DFU library as a module (check how) and modify this part: https://github.com/NordicSemiconductor/Android-DFU-Library/blob/58bd4c2aec66b85e779d8be7d6e05ca8a47cb1ed/dfu/src/main/java/no/nordicsemi/android/dfu/SecureDfuImpl.java#L596-L599 so it does this 400 ms delay for every packet, not only for the first one. 400 ms delay is better than 9 sec. You may also try other values for the delay.

gksrb4 commented 4 years ago

Hi, thanks to analyze the log! I have understood meaning of the log.

However, from time to time we also observe that bytes get lost in a later stage.

--> Why this happen in galaxy 10 note only not galaxy note 4? As I understood, this is a ultimate reason for different speed.

What you may do, is to import the DFU library as a module (check how) and modify this part:

delete condition and only mService.waitFor(initialDelay); like this?

philips77 commented 4 years ago

Why this happen in galaxy 10 note only not galaxy note 4? As I understood, this is a ultimate reason for different speed.

Yes, I think it's that the newest phones can send data faster than the target can handle. The connection parameters on the peripheral should not allow such situation, but thy do so we have to "slow down" is a bit on the phone side. I don't know what could be some other reason.

like this?

Yes, that should be ok. Please, let me know if it improved the speed and no bytes were lost after that.

gksrb4 commented 4 years ago

I have tired to add module. but the some trouble occur.

ERROR: Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve project :dfu.

What I did was.

delete //implementation 'no.nordicsemi.android:dfu:1.9.1' in dependency. replace implementation project(':dfu') and clone and copy to my project dir as DFULibrary.

In settings.gradle add

include ':dfu'
project(':dfu').projectDir = file('../DFULibrary/dfu')
philips77 commented 4 years ago

In the settings.gradle you have to provide the correct path to the dfu folder. By default it is cloned to Android-DFU-Library folder, so if you have it there, replace the DFULibrary with the correct path.

include ':dfu'
project(':dfu').projectDir = file('../Android-DFU-Library/dfu')
gksrb4 commented 4 years ago

I already tried this name. however, It was not working. so I changed directory name Android-DFU-Library to DFULibrary.

philips77 commented 4 years ago

Just make sure the path is correct.