Reputation: 1015
Currently I start the pairing procedure (well it starts automatically to be honest) when i try to do a GATT operation and it fails to successfully complete that operation. Once the pairing procedure is finished and i get bonded with the remote device i continue to do my GATT operations in which everything works just fine.
What i have noticed is that while pairing:
1) if i disconnect from the remote device without closing the GATT client then it still pairs successfully and i go into the BluetoothDevice.BOND_BONDED
state and my app continues to work just fine.
2) if i disconnect and i also close the GATT client then once i go into the BluetoothDevice.BOND_BONDED
state then my app crashes
Why does my app crashes when i close the GATT client of the remote device while in the pairing procedure? is that normal or am i doing something wrong?
This is my BroadcastReceiver implementation for getting the bonding state of the remote device
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
if(state == BluetoothDevice.BOND_BONDING){
DebugWrapper.debugMsg("On Bonding...", TAG);
mIsBonding = true;
onBonding();
} else if(state == BluetoothDevice.BOND_BONDED){
DebugWrapper.debugMsg("On Bonded", TAG);
mIsBonded = true;
mActivity.unregisterReceiver(mReceiver);
/*
* finish what we started
*/
if(mBluetoothGatt != null){
if(mOperationState == OperationState.READ_CHARACTERISTIC){
readCharacteristic(mCurrentCharacteristic);
} else if(mOperationState == OperationState.WRITE_CHARACTERISTIC){
writeCharacteristic(mCurrentCharacteristic);
} else if(mOperationState == OperationState.READ_DESCRIPTOR){
readDescriptor(mCurrentDescriptor);
} else if(mOperationState == OperationState.WRITE_DESCRIPTOR){
writeDescriptor(mCurrentDescriptor);
}
mOperationState = OperationState.NONE;
}
onBonded();
} else if(state == BluetoothDevice.BOND_NONE){
DebugWrapper.debugMsg("Not Bonded", TAG);
notBonded();
}
}
}
};
Update LogCat files (Links to Pastebin.com as the files where too big to be added here)
From this logCat you can see the steps i am following
Upvotes: 3
Views: 1695
Reputation: 40407
You appear to have found a bug in bluedroid, Android's bluetooth stack.
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000008
backtrace:
#00 pc 0007c86e /system/lib/hw/bluetooth.default.so (GKI_getnext+9)
#01 pc 000bd9e3 /system/lib/hw/bluetooth.default.so (gatt_sec_check_complete+10)
#02 pc 000bdde9 /system/lib/hw/bluetooth.default.so (gatt_enc_cmpl_cback+104)
This is a native null pointer exception in gki/common/gki_buffer.c of Android's "bluedroid" BT stack.
It happens to be a confusing one, as at first glance the problematic function appears to be GKI_getnext(), but in reality, it is actually the first instruction of the immediately following function, GKI_queue_is_empty()
BOOLEAN GKI_queue_is_empty(BUFFER_Q *p_q)
{
return ((BOOLEAN) (p_q->count == 0));
}
If we look at the actual decompilation,
<GKI_queue_is_empty>:
ldrh r0, [r0, #8]
rsbs r0, r0, #1
it cc
movcc r0, #0
bx lr
We see that we are trying to reference the count
member of the BUFFER_Q
structure pointed to by r0, however what is happening is that we were called with a NULL buffer, so we add 8 to NULL, and try to load a register from the illegal address 00000008
causing a SIGSEGV.
Going up a level, this is called from gatt_sec_check_complete() - indeed, if we look in stack/gatt/gatt_auth.c we find the first thing it does is check if queue is empty.
void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB *p_clcb, UINT8 sec_act)
{
if (GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb))
gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
But the problem is that the queue isn't empty, rather it is null.
So either there is a bug in bluedroid where it doesn't realize that something can be NULL, or else your program is peforming an invalid series of operations which sets the bluedroid stack up for this failure.
Assigning blame however turns out to be simple, because we can look at the security model. The process which is crashing runs as user bluetooth
which is a semi-privileged account, not the user id of your application. Therefore, as a matter of basic principle, nothing your unprivileged app does should be able to crash it, and we can categorize this as a bug in the platform bluetooth stack, rather than your application.
Upvotes: 3