Loading service/src/com/android/server/bluetooth/BluetoothManagerService.java +19 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.bluetooth.BluetoothAdapter.STATE_OFF; import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_OFF; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_ON; import static android.bluetooth.BluetoothAdapter.nameForState; import static android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE; import static android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST; import static android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH; Loading Loading @@ -216,6 +217,11 @@ class BluetoothManagerService { new IBluetoothCallback.Stub() { @Override public void onBluetoothStateChange(int prevState, int newState) { Log.d( TAG, "IBluetoothCallback.onBluetoothStateChange:" + (" prevState=" + nameForState(prevState)) + (" newState=" + nameForState(newState))); mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState) .sendToTarget(); } Loading @@ -226,6 +232,7 @@ class BluetoothManagerService { if (name.isEmpty()) { throw new IllegalArgumentException("Invalid Empty name"); } Log.d(TAG, "IBluetoothCallback.onAdapterNameChange: " + name); mHandler.post(() -> storeName(name)); } Loading @@ -235,6 +242,7 @@ class BluetoothManagerService { if (!BluetoothAdapter.checkBluetoothAddress(address)) { throw new IllegalArgumentException("Invalid address"); } Log.d(TAG, "IBluetoothCallback.onAdapterAddressChange: " + logAddress(address)); mHandler.post(() -> storeAddress(address)); } }; Loading Loading @@ -353,7 +361,7 @@ class BluetoothManagerService { Log.d( TAG, ("delayModeChangedIfNeeded(" + modechanged + "):") + (" state=" + BluetoothAdapter.nameForState(state)) + (" state=" + nameForState(state)) + (" Airplane.isOnOverrode=" + AirplaneModeListener.isOnOverrode()) + (" Airplane.isOn=" + AirplaneModeListener.isOn()) + (" isSatelliteModeOn()=" + isSatelliteModeOn()) Loading Loading @@ -458,7 +466,7 @@ class BluetoothManagerService { Log.d( TAG, ("handleAirplaneModeChanged(" + isAirplaneModeOn + "):") + (" currentState=" + BluetoothAdapter.nameForState(currentState))); + (" currentState=" + nameForState(currentState))); if (isAirplaneModeOn) { forceToOffFromModeChange(currentState, ENABLE_DISABLE_REASON_AIRPLANE_MODE); Loading Loading @@ -1596,8 +1604,12 @@ class BluetoothManagerService { Log.d( TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE:" + (" prevState=" + BluetoothAdapter.nameForState(prevState)) + (" newState=" + BluetoothAdapter.nameForState(newState))); + (" prevState=" + nameForState(prevState)) + (" newState=" + nameForState(newState))); if (mAdapter == null) { Log.e(TAG, "State change received after bluetooth has crashed"); break; } bluetoothStateChangeHandler(prevState, newState); // handle error state transition case from TURNING_ON to OFF // unbind and rebind bluetooth service and enable bluetooth Loading Loading @@ -1955,8 +1967,8 @@ class BluetoothManagerService { TAG, "broadcastIntentStateChange:" + (" action=" + action.substring(action.lastIndexOf('.') + 1)) + (" prevState=" + BluetoothAdapter.nameForState(prevState)) + (" newState=" + BluetoothAdapter.nameForState(newState))); + (" prevState=" + nameForState(prevState)) + (" newState=" + nameForState(newState))); // Send broadcast message to everyone else Intent intent = new Intent(action); intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); Loading Loading @@ -2304,9 +2316,7 @@ class BluetoothManagerService { final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd)); proto.write(BluetoothManagerServiceDumpProto.ENABLED, isEnabled()); proto.write(BluetoothManagerServiceDumpProto.STATE, mState.get()); proto.write( BluetoothManagerServiceDumpProto.STATE_NAME, BluetoothAdapter.nameForState(mState.get())); proto.write(BluetoothManagerServiceDumpProto.STATE_NAME, nameForState(mState.get())); proto.write(BluetoothManagerServiceDumpProto.ADDRESS, logAddress(mAddress)); proto.write(BluetoothManagerServiceDumpProto.NAME, mName); if (mEnable) { Loading service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java +46 −7 Original line number Diff line number Diff line Loading @@ -22,9 +22,11 @@ import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_ON; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_SERVICE_CONNECTED; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_STATE_CHANGE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_DISABLE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_ENABLE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_RESTART_BLUETOOTH_SERVICE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_TIMEOUT_BIND; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -173,6 +175,7 @@ public class BluetoothManagerServiceTest { any(ServiceConnection.class), anyInt(), any(UserHandle.class)); doNothing().when(mContext).unbindService(any()); BluetoothServerProxy.setInstanceForTesting(mBluetoothServerProxy); Loading Loading @@ -244,7 +247,6 @@ public class BluetoothManagerServiceTest { any(ServiceConnection.class), anyInt(), any(UserHandle.class)); doNothing().when(mContext).unbindService(any()); mManagerService.enableBle("enable_bindFailure_removesTimeout", mBinder); syncHandler(MESSAGE_ENABLE); verify(mContext).unbindService(any()); Loading @@ -269,18 +271,22 @@ public class BluetoothManagerServiceTest { // * if user ask to enable again, it will start a second bind but the first still run } private void acceptBluetoothBinding(IBinder binder, String name, int n) { ComponentName compName = new ComponentName("", "com.android.bluetooth." + name); private BluetoothManagerService.BluetoothServiceConnection acceptBluetoothBinding() { ComponentName compName = new ComponentName("", "com.android.bluetooth.btservice.AdapterService"); ArgumentCaptor<BluetoothManagerService.BluetoothServiceConnection> captor = ArgumentCaptor.forClass(BluetoothManagerService.BluetoothServiceConnection.class); verify(mContext, times(n)) verify(mContext) .bindServiceAsUser( any(Intent.class), captor.capture(), anyInt(), any(UserHandle.class)); assertThat(captor.getAllValues().size()).isEqualTo(n); assertThat(captor.getAllValues().size()).isEqualTo(1); captor.getAllValues().get(n - 1).onServiceConnected(compName, binder); BluetoothManagerService.BluetoothServiceConnection serviceConnection = captor.getAllValues().get(0); serviceConnection.onServiceConnected(compName, mBinder); syncHandler(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); return serviceConnection; } private static IBluetoothCallback captureBluetoothCallback(AdapterBinder adapterBinder) Loading @@ -294,7 +300,7 @@ public class BluetoothManagerServiceTest { IBluetoothCallback transition_offToBleOn() throws Exception { // Binding of IBluetooth acceptBluetoothBinding(mBinder, "btservice.AdapterService", 1); acceptBluetoothBinding(); // TODO(b/280518177): This callback is too early, bt is not ON nor BLE_ON verify(mManagerCallback).onBluetoothServiceUp(any()); Loading Loading @@ -361,4 +367,37 @@ public class BluetoothManagerServiceTest { assertThat(mManagerService.getState()).isEqualTo(STATE_ON); } @Test public void crash_whileTransitionState_canRecover() throws Exception { mManagerService.enableBle("crash_whileTransitionState_canRecover", mBinder); syncHandler(MESSAGE_ENABLE); BluetoothManagerService.BluetoothServiceConnection serviceConnection = acceptBluetoothBinding(); IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder); verify(mAdapterBinder).offToBleOn(anyBoolean(), any()); btCallback.onBluetoothStateChange(STATE_OFF, STATE_BLE_TURNING_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON); serviceConnection.onServiceDisconnected( new ComponentName("", "com.android.bluetooth.btservice.AdapterService")); syncHandler(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); // Send a late bluetoothStateChange (since it can happen concurrently) btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); // Bluetooth is still OFF and doesn't crash assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); mLooper.moveTimeForward(120_000); Message msg = mLooper.nextMessage(); assertThat(msg).isNotNull(); assertThat(msg.what).isEqualTo(MESSAGE_RESTART_BLUETOOTH_SERVICE); // Discard the msg without executing it } } Loading
service/src/com/android/server/bluetooth/BluetoothManagerService.java +19 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.bluetooth.BluetoothAdapter.STATE_OFF; import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_OFF; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_ON; import static android.bluetooth.BluetoothAdapter.nameForState; import static android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE; import static android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST; import static android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH; Loading Loading @@ -216,6 +217,11 @@ class BluetoothManagerService { new IBluetoothCallback.Stub() { @Override public void onBluetoothStateChange(int prevState, int newState) { Log.d( TAG, "IBluetoothCallback.onBluetoothStateChange:" + (" prevState=" + nameForState(prevState)) + (" newState=" + nameForState(newState))); mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState) .sendToTarget(); } Loading @@ -226,6 +232,7 @@ class BluetoothManagerService { if (name.isEmpty()) { throw new IllegalArgumentException("Invalid Empty name"); } Log.d(TAG, "IBluetoothCallback.onAdapterNameChange: " + name); mHandler.post(() -> storeName(name)); } Loading @@ -235,6 +242,7 @@ class BluetoothManagerService { if (!BluetoothAdapter.checkBluetoothAddress(address)) { throw new IllegalArgumentException("Invalid address"); } Log.d(TAG, "IBluetoothCallback.onAdapterAddressChange: " + logAddress(address)); mHandler.post(() -> storeAddress(address)); } }; Loading Loading @@ -353,7 +361,7 @@ class BluetoothManagerService { Log.d( TAG, ("delayModeChangedIfNeeded(" + modechanged + "):") + (" state=" + BluetoothAdapter.nameForState(state)) + (" state=" + nameForState(state)) + (" Airplane.isOnOverrode=" + AirplaneModeListener.isOnOverrode()) + (" Airplane.isOn=" + AirplaneModeListener.isOn()) + (" isSatelliteModeOn()=" + isSatelliteModeOn()) Loading Loading @@ -458,7 +466,7 @@ class BluetoothManagerService { Log.d( TAG, ("handleAirplaneModeChanged(" + isAirplaneModeOn + "):") + (" currentState=" + BluetoothAdapter.nameForState(currentState))); + (" currentState=" + nameForState(currentState))); if (isAirplaneModeOn) { forceToOffFromModeChange(currentState, ENABLE_DISABLE_REASON_AIRPLANE_MODE); Loading Loading @@ -1596,8 +1604,12 @@ class BluetoothManagerService { Log.d( TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE:" + (" prevState=" + BluetoothAdapter.nameForState(prevState)) + (" newState=" + BluetoothAdapter.nameForState(newState))); + (" prevState=" + nameForState(prevState)) + (" newState=" + nameForState(newState))); if (mAdapter == null) { Log.e(TAG, "State change received after bluetooth has crashed"); break; } bluetoothStateChangeHandler(prevState, newState); // handle error state transition case from TURNING_ON to OFF // unbind and rebind bluetooth service and enable bluetooth Loading Loading @@ -1955,8 +1967,8 @@ class BluetoothManagerService { TAG, "broadcastIntentStateChange:" + (" action=" + action.substring(action.lastIndexOf('.') + 1)) + (" prevState=" + BluetoothAdapter.nameForState(prevState)) + (" newState=" + BluetoothAdapter.nameForState(newState))); + (" prevState=" + nameForState(prevState)) + (" newState=" + nameForState(newState))); // Send broadcast message to everyone else Intent intent = new Intent(action); intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState); Loading Loading @@ -2304,9 +2316,7 @@ class BluetoothManagerService { final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd)); proto.write(BluetoothManagerServiceDumpProto.ENABLED, isEnabled()); proto.write(BluetoothManagerServiceDumpProto.STATE, mState.get()); proto.write( BluetoothManagerServiceDumpProto.STATE_NAME, BluetoothAdapter.nameForState(mState.get())); proto.write(BluetoothManagerServiceDumpProto.STATE_NAME, nameForState(mState.get())); proto.write(BluetoothManagerServiceDumpProto.ADDRESS, logAddress(mAddress)); proto.write(BluetoothManagerServiceDumpProto.NAME, mName); if (mEnable) { Loading
service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java +46 −7 Original line number Diff line number Diff line Loading @@ -22,9 +22,11 @@ import static android.bluetooth.BluetoothAdapter.STATE_ON; import static android.bluetooth.BluetoothAdapter.STATE_TURNING_ON; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_SERVICE_CONNECTED; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_BLUETOOTH_STATE_CHANGE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_DISABLE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_ENABLE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_RESTART_BLUETOOTH_SERVICE; import static com.android.server.bluetooth.BluetoothManagerService.MESSAGE_TIMEOUT_BIND; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -173,6 +175,7 @@ public class BluetoothManagerServiceTest { any(ServiceConnection.class), anyInt(), any(UserHandle.class)); doNothing().when(mContext).unbindService(any()); BluetoothServerProxy.setInstanceForTesting(mBluetoothServerProxy); Loading Loading @@ -244,7 +247,6 @@ public class BluetoothManagerServiceTest { any(ServiceConnection.class), anyInt(), any(UserHandle.class)); doNothing().when(mContext).unbindService(any()); mManagerService.enableBle("enable_bindFailure_removesTimeout", mBinder); syncHandler(MESSAGE_ENABLE); verify(mContext).unbindService(any()); Loading @@ -269,18 +271,22 @@ public class BluetoothManagerServiceTest { // * if user ask to enable again, it will start a second bind but the first still run } private void acceptBluetoothBinding(IBinder binder, String name, int n) { ComponentName compName = new ComponentName("", "com.android.bluetooth." + name); private BluetoothManagerService.BluetoothServiceConnection acceptBluetoothBinding() { ComponentName compName = new ComponentName("", "com.android.bluetooth.btservice.AdapterService"); ArgumentCaptor<BluetoothManagerService.BluetoothServiceConnection> captor = ArgumentCaptor.forClass(BluetoothManagerService.BluetoothServiceConnection.class); verify(mContext, times(n)) verify(mContext) .bindServiceAsUser( any(Intent.class), captor.capture(), anyInt(), any(UserHandle.class)); assertThat(captor.getAllValues().size()).isEqualTo(n); assertThat(captor.getAllValues().size()).isEqualTo(1); captor.getAllValues().get(n - 1).onServiceConnected(compName, binder); BluetoothManagerService.BluetoothServiceConnection serviceConnection = captor.getAllValues().get(0); serviceConnection.onServiceConnected(compName, mBinder); syncHandler(MESSAGE_BLUETOOTH_SERVICE_CONNECTED); return serviceConnection; } private static IBluetoothCallback captureBluetoothCallback(AdapterBinder adapterBinder) Loading @@ -294,7 +300,7 @@ public class BluetoothManagerServiceTest { IBluetoothCallback transition_offToBleOn() throws Exception { // Binding of IBluetooth acceptBluetoothBinding(mBinder, "btservice.AdapterService", 1); acceptBluetoothBinding(); // TODO(b/280518177): This callback is too early, bt is not ON nor BLE_ON verify(mManagerCallback).onBluetoothServiceUp(any()); Loading Loading @@ -361,4 +367,37 @@ public class BluetoothManagerServiceTest { assertThat(mManagerService.getState()).isEqualTo(STATE_ON); } @Test public void crash_whileTransitionState_canRecover() throws Exception { mManagerService.enableBle("crash_whileTransitionState_canRecover", mBinder); syncHandler(MESSAGE_ENABLE); BluetoothManagerService.BluetoothServiceConnection serviceConnection = acceptBluetoothBinding(); IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder); verify(mAdapterBinder).offToBleOn(anyBoolean(), any()); btCallback.onBluetoothStateChange(STATE_OFF, STATE_BLE_TURNING_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON); serviceConnection.onServiceDisconnected( new ComponentName("", "com.android.bluetooth.btservice.AdapterService")); syncHandler(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED); assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); // Send a late bluetoothStateChange (since it can happen concurrently) btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON); syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE); // Bluetooth is still OFF and doesn't crash assertThat(mManagerService.getState()).isEqualTo(STATE_OFF); mLooper.moveTimeForward(120_000); Message msg = mLooper.nextMessage(); assertThat(msg).isNotNull(); assertThat(msg.what).isEqualTo(MESSAGE_RESTART_BLUETOOTH_SERVICE); // Discard the msg without executing it } }