Fix race with BT disable in BLE_ON_STATE

This will restart the BT stack when it detects a transition
into OFF state while the user enable flag (mEnable) is set.

Bug: 29363429
Change-Id: I9839119b34c4694ad92e96240c6989008b2f8d52
This commit is contained in:
Calvin On
2016-06-15 17:58:23 -07:00
committed by Andre Eisenbach
parent 6bc33b07f4
commit a0b91d77d6
2 changed files with 45 additions and 32 deletions

View File

@ -897,28 +897,10 @@ public final class BluetoothAdapter {
*/
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean enable() {
int state = BluetoothAdapter.STATE_OFF;
if (isEnabled() == true) {
if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
return true;
}
// Use service interface to get the exact state
try {
mServiceLock.readLock().lock();
if (mService != null) {
state = mService.getState();
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
} finally {
mServiceLock.readLock().unlock();
}
if (state == BluetoothAdapter.STATE_BLE_ON) {
Log.e(TAG, "BT is in BLE_ON State");
notifyUserAction(true);
return true;
}
try {
return mManagerService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}

View File

@ -1153,8 +1153,27 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
mEnable = true;
// Use service interface to get the exact state
try {
mBluetoothLock.readLock().lock();
if (mBluetooth != null) {
int state = mBluetooth.getState();
if (state == BluetoothAdapter.STATE_BLE_ON) {
Slog.w(TAG, "BT is in BLE_ON State");
mBluetooth.onLeServiceUp();
break;
}
}
} catch (RemoteException e) {
Slog.e(TAG, "", e);
} finally {
mBluetoothLock.readLock().unlock();
}
mQuietEnable = (msg.arg1 == 1);
if (mBluetooth == null) {
handleEnable(msg.arg1 == 1);
handleEnable(mQuietEnable);
} else {
//
// We need to wait until transitioned to STATE_OFF and
@ -1172,7 +1191,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// on the order of (2 * SERVICE_RESTART_TIME_MS).
//
waitForOnOff(false, true);
mQuietEnable = (msg.arg1 == 1);
Message restartMsg = mHandler.obtainMessage(
MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg,
@ -1335,17 +1353,30 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// handle error state transition case from TURNING_ON to OFF
// unbind and rebind bluetooth service and enable bluetooth
if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
(newState == BluetoothAdapter.STATE_OFF) &&
(mBluetooth != null) && mEnable) {
(newState == BluetoothAdapter.STATE_OFF) &&
(mBluetooth != null) && mEnable) {
recoverBluetoothServiceFromError();
}
if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
(newState == BluetoothAdapter.STATE_BLE_ON) &&
(mBluetooth != null) && mEnable) {
(newState == BluetoothAdapter.STATE_BLE_ON) &&
(mBluetooth != null) && mEnable) {
recoverBluetoothServiceFromError();
}
// If we tried to enable BT while BT was in the process of shutting down,
// wait for the BT process to fully tear down and then force a restart
// here. This is a bit of a hack (b/29363429).
if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) &&
(newState == BluetoothAdapter.STATE_OFF)) {
if (mEnable) {
Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
waitForOnOff(false, true);
Message restartMsg = mHandler.obtainMessage(
MESSAGE_RESTART_BLUETOOTH_SERVICE);
mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
}
}
if (newState == BluetoothAdapter.STATE_ON ||
newState == BluetoothAdapter.STATE_BLE_ON) {
newState == BluetoothAdapter.STATE_BLE_ON) {
// bluetooth is working, reset the counter
if (mErrorRecoveryRetryCounter != 0) {
Slog.w(TAG, "bluetooth is recovered from error");
@ -1388,7 +1419,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// Send BT state broadcast to update
// the BT icon correctly
if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
(mState == BluetoothAdapter.STATE_ON)) {
(mState == BluetoothAdapter.STATE_ON)) {
bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
BluetoothAdapter.STATE_TURNING_OFF);
mState = BluetoothAdapter.STATE_TURNING_OFF;
@ -1621,8 +1652,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
boolean isStandardBroadcast = true;
if (prevState != newState) {
//Notify all proxy objects first of adapter state change
if (newState == BluetoothAdapter.STATE_BLE_ON
|| newState == BluetoothAdapter.STATE_OFF) {
if (newState == BluetoothAdapter.STATE_BLE_ON ||
newState == BluetoothAdapter.STATE_OFF) {
boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
&& newState == BluetoothAdapter.STATE_BLE_ON);
@ -1667,13 +1698,13 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
sendBluetoothStateCallback(isUp);
sendBleStateChanged(prevState, newState);
} else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
|| newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
} else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON ||
newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
sendBleStateChanged(prevState, newState);
isStandardBroadcast = false;
} else if (newState == BluetoothAdapter.STATE_TURNING_ON
|| newState == BluetoothAdapter.STATE_TURNING_OFF) {
} else if (newState == BluetoothAdapter.STATE_TURNING_ON ||
newState == BluetoothAdapter.STATE_TURNING_OFF) {
sendBleStateChanged(prevState, newState);
}