From 98bed1ab903ba8f08e78ae2eb0e68d0fec2f5c86 Mon Sep 17 00:00:00 2001
From: Aleksander Nowakowski
Date: Wed, 15 Mar 2017 15:35:01 +0100
Subject: [PATCH] Issue #49 fixed: updating SD no longer forces the bond info
on the phone to be removed
---
.../android/dfu/BaseCustomDfuImpl.java | 2 +-
.../nordicsemi/android/dfu/BaseDfuImpl.java | 29 ++++++++++++-------
.../android/dfu/DfuBaseService.java | 4 +--
.../dfu/ExperimentalButtonlessDfuImpl.java | 7 +++--
.../nordicsemi/android/dfu/LegacyDfuImpl.java | 2 +-
5 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/BaseCustomDfuImpl.java b/dfu/src/main/java/no/nordicsemi/android/dfu/BaseCustomDfuImpl.java
index 9c57036..6f999b7 100644
--- a/dfu/src/main/java/no/nordicsemi/android/dfu/BaseCustomDfuImpl.java
+++ b/dfu/src/main/java/no/nordicsemi/android/dfu/BaseCustomDfuImpl.java
@@ -425,7 +425,7 @@ import no.nordicsemi.android.dfu.internal.scanner.BootloaderScannerFactory;
boolean alreadyWaited = false;
if (mGatt.getDevice().getBondState() == BluetoothDevice.BOND_BONDED) {
final boolean restoreBond = intent.getBooleanExtra(DfuBaseService.EXTRA_RESTORE_BOND, false);
- if (restoreBond || !keepBond || (mFileType & DfuBaseService.TYPE_SOFT_DEVICE) > 0) {
+ if (restoreBond || !keepBond) {
// The bond information was lost.
removeBond();
diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/BaseDfuImpl.java b/dfu/src/main/java/no/nordicsemi/android/dfu/BaseDfuImpl.java
index 9e111c8..a5abeba 100644
--- a/dfu/src/main/java/no/nordicsemi/android/dfu/BaseDfuImpl.java
+++ b/dfu/src/main/java/no/nordicsemi/android/dfu/BaseDfuImpl.java
@@ -272,7 +272,16 @@ import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
// not work by default on iOS with buttonless update on SDKs < 8 on bonded devices. The bootloader must be modified to
// always send the indication when connected.
- // This has been fixed on Android 6. Now the Android enables Service Changed indications automatically after bonding.
+ // The requirement of enabling Service Changed indications manually has been fixed on Android 6.
+ // Now the Android enables Service Changed indications automatically after bonding.
+ //
+ // However, be aware, that in SDK 8 (and perhaps some never) the Service Changed CCCD state is saved on DISCONNECT event on the nRF.
+ // That means, that if a user has connected to a new device, bonded and enabled SC indications (manually on automatically) the
+ // setting will not be preserved in flash if DFU is started immediately. Jumping to DFU mode causes reset, not a DISCONNECT, so the
+ // CCCD value will be lost and SC indication will not be sent from the bootloader.
+ // If the device has disconnected at least once after SC CCCD value was written everything will work.
+ // Also, the Secure DFU does not support sharing bond information between App and Bootloader (instead it uses address+1 trick, so no bonding),
+ // so this issue does no apply there.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && gatt.getDevice().getBondState() == BluetoothDevice.BOND_BONDED) {
final BluetoothGattService genericAttributeService = gatt.getService(GENERIC_ATTRIBUTE_SERVICE_UUID);
if (genericAttributeService != null) {
@@ -288,28 +297,28 @@ import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
/*
* NOTE: The DFU Bootloader from SDK 8.0 (v0.6 and 0.5) has the following issue:
*
- * When the central device (phone) connects to a bonded device (or connects and bonds) which supports the Service Changed characteristic,
+ * When a central device (phone) connects to a bonded device (or connects and bonds) which supports the Service Changed characteristic,
* but does not have the Service Changed indications enabled, the phone must enable them, disconnect and reconnect before starting the
* DFU operation. This is because the current version of the Soft Device saves the ATT table on the DISCONNECTED event.
- * Sending the "jump to Bootloader" command (0x01-04) will cause the disconnect followed be a reset. The Soft Device does not
+ * Sending the "jump to Bootloader" command (0x01-04) will cause the disconnect followed be a reset. The SoftDevice does not
* have time to store the ATT table on Flash memory before the reset.
*
* This applies only if:
* - the device was bonded before an upgrade,
- * - the Application or the Bootloader is upgraded (upgrade of the Soft Device will erase the bond information anyway),
- * - Application:
+ * - In case of an Application update:
+ * - For Legacy DFU:
* if the DFU Bootloader has been modified and compiled to preserve the LTK and the ATT table after application upgrade (at least 2 pages)
- * See: \Nordic\nrf51\components\libraries\bootloader_dfu\dfu_types.h, line 56(?):
- * #define DFU_APP_DATA_RESERVED 0x0000 -> 0x0800+ //< Size of Application Data that must be preserved between application updates...
- * - Bootloader:
- * The Application memory should not be removed when the Bootloader is upgraded, so the Bootloader configuration does not matter.
+ * See: http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/bledfu_memory_banks.html?cp=4_0_3_4_3_1_3_2 -> Preserving application data
+ * - For Secure DFU:
+ * the default number of pages to be preserved is set to 3. That includes the LTK and ATT table
+ * See: http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v12.0.0/lib_bootloader_dfu_banks.html#lib_bootloader_dfu_appdata -> Preserving application data
*
* If the bond information is not to be preserved between the old and new applications, we may skip this disconnect/reconnect process.
* The DFU Bootloader will send the SD indication anyway when we will just continue here, as the information whether it should send it or not it is not being
* read from the application's ATT table, but rather passed as an argument of the "reboot to bootloader" method.
*/
final boolean keepBond = intent.getBooleanExtra(DfuBaseService.EXTRA_KEEP_BOND, false);
- if (keepBond && (mFileType & DfuBaseService.TYPE_SOFT_DEVICE) == 0) {
+ if (keepBond) {
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_VERBOSE, "Restarting service...");
// Disconnect
diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/DfuBaseService.java b/dfu/src/main/java/no/nordicsemi/android/dfu/DfuBaseService.java
index 8981ba5..0cd6879 100644
--- a/dfu/src/main/java/no/nordicsemi/android/dfu/DfuBaseService.java
+++ b/dfu/src/main/java/no/nordicsemi/android/dfu/DfuBaseService.java
@@ -129,9 +129,9 @@ public abstract class DfuBaseService extends IntentService implements DfuProgres
* If an application is being updated on a bonded device with the DFU Bootloader that has been configured to preserve the bond information for the new application,
* set it to true
.
*
- * By default the DFU Bootloader clears the whole application's memory. It may be however configured in the \Nordic\nrf51\components\libraries\bootloader_dfu\dfu_types.h
+ *
By default the Legacy DFU Bootloader clears the whole application's memory. It may be however configured in the \Nordic\nrf51\components\libraries\bootloader_dfu\dfu_types.h
* file (sdk 11, line 76: #define DFU_APP_DATA_RESERVED 0x0000
) to preserve some pages. The BLE_APP_HRM_DFU sample app stores the LTK and System Attributes in the first
- * two pages, so in order to preserve the bond information this value should be changed to 0x0800 or more.
+ * two pages, so in order to preserve the bond information this value should be changed to 0x0800 or more. For Secure DFU this value is by default set to 3 pages.
* When those data are preserved, the new Application will notify the app with the Service Changed indication when launched for the first time. Otherwise this
* service will remove the bond information from the phone and force to refresh the device cache (see {@link #refreshDeviceCache(android.bluetooth.BluetoothGatt, boolean)}).
*
diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/ExperimentalButtonlessDfuImpl.java b/dfu/src/main/java/no/nordicsemi/android/dfu/ExperimentalButtonlessDfuImpl.java
index 68088ba..2ecbca9 100644
--- a/dfu/src/main/java/no/nordicsemi/android/dfu/ExperimentalButtonlessDfuImpl.java
+++ b/dfu/src/main/java/no/nordicsemi/android/dfu/ExperimentalButtonlessDfuImpl.java
@@ -142,7 +142,7 @@ public class ExperimentalButtonlessDfuImpl extends BaseDfuImpl {
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_INFO, "Disconnected by the remote device");
- finalize(intent, true);
+ finalize(intent, false); // Secure DFU by default preserves 3 pages of App Data, those include Att table and bond information
} catch (final UnknownResponseException e) {
final int error = DfuBaseService.ERROR_INVALID_RESPONSE;
loge(e.getMessage());
@@ -157,7 +157,8 @@ public class ExperimentalButtonlessDfuImpl extends BaseDfuImpl {
}
/**
- * Closes the BLE connection to the device and removes bonding, if a proper flags were set in the {@link DfuServiceInitiator}.
+ * Closes the BLE connection to the device and removes bonding information if a proper flag was NOT set
+ * in the {@link DfuServiceInitiator#setKeepBond(boolean)}.
* This method will scan for a bootloader advertising with the address equal to the current or incremented by 1 and restart the service.
* @param intent the intent used to start the DFU service. It contains all user flags in the bundle.
* @param forceRefresh true, if cache should be cleared even for a bonded device. Usually the Service Changed indication should be used for this purpose.
@@ -181,7 +182,7 @@ public class ExperimentalButtonlessDfuImpl extends BaseDfuImpl {
*/
if (mGatt.getDevice().getBondState() == BluetoothDevice.BOND_BONDED) {
final boolean restoreBond = intent.getBooleanExtra(DfuBaseService.EXTRA_RESTORE_BOND, false);
- if (restoreBond || !keepBond || (mFileType & DfuBaseService.TYPE_SOFT_DEVICE) > 0) {
+ if (restoreBond || !keepBond) {
// The bond information was lost.
removeBond();
diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/LegacyDfuImpl.java b/dfu/src/main/java/no/nordicsemi/android/dfu/LegacyDfuImpl.java
index 155d31f..f7eec91 100644
--- a/dfu/src/main/java/no/nordicsemi/android/dfu/LegacyDfuImpl.java
+++ b/dfu/src/main/java/no/nordicsemi/android/dfu/LegacyDfuImpl.java
@@ -288,7 +288,7 @@ import no.nordicsemi.android.error.LegacyDfuError;
* [Vol. 3, Part G, 2.5.2 - Attribute Caching]
* Note: Clients without a trusted relationship must perform service discovery on each connection if the server supports the Services Changed characteristic.
*
- * However, as up to Android 5 the system does NOT respect this requirement and servers are cached for every device, even if Service Changed is enabled -> Android BUG?
+ * However, as up to Android 7 the system does NOT respect this requirement and servers are cached for every device, even if Service Changed is enabled -> Android BUG?
* For bonded devices Android performs service re-discovery when SC indication is received.
*/
final BluetoothGattService gas = gatt.getService(GENERIC_ATTRIBUTE_SERVICE_UUID);