Issue #49 fixed: updating SD no longer forces the bond info on the phone to be removed

This commit is contained in:
Aleksander Nowakowski 2017-03-15 15:35:01 +01:00
parent 4678d3e51e
commit 98bed1ab90
5 changed files with 27 additions and 17 deletions

View File

@ -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();

View File

@ -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

View File

@ -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 <code>true</code>.</p>
*
* <p>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
* <p>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: <code>#define DFU_APP_DATA_RESERVED 0x0000</code>) 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)}).</p>
*

View File

@ -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();

View File

@ -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);