summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author William Escande <wescande@google.com> 2025-03-11 17:10:23 -0700
committer William Escande <wescande@google.com> 2025-03-11 17:46:12 -0700
commitfb610bad48bab1bbfea676a93fa5ea9ab30070a4 (patch)
treeb07cc67f3230ef21a86b77216c3cae3f2433a86e
parentfdbf19f4c09baffc00d00cbf3cbcdec8264c751c (diff)
SystemServer: Improve test checks
Tests are now using: * inOrder to validate the order of event * Intent matcher to better validate what has been broadcasted Bug: 402332571 Flag: TEST_ONLY Test: atest ServiceBluetoothTests Change-Id: I91750faa6dd8159ba7afa5ab92e83100578a45e6
-rw-r--r--service/src/com/android/server/bluetooth/BluetoothManagerService.java68
-rw-r--r--service/tests/Android.bp1
-rw-r--r--service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java150
3 files changed, 126 insertions, 93 deletions
diff --git a/service/src/com/android/server/bluetooth/BluetoothManagerService.java b/service/src/com/android/server/bluetooth/BluetoothManagerService.java
index 08a949d81a..3f1017f88d 100644
--- a/service/src/com/android/server/bluetooth/BluetoothManagerService.java
+++ b/service/src/com/android/server/bluetooth/BluetoothManagerService.java
@@ -78,7 +78,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.sysprop.BluetoothProperties;
-import android.util.proto.ProtoOutputStream;
import androidx.annotation.RequiresApi;
@@ -95,7 +94,6 @@ import kotlin.Unit;
import kotlin.time.TimeSource;
import java.io.FileDescriptor;
-import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -1228,10 +1226,10 @@ class BluetoothManagerService {
}
if (Flags.setComponentAvailableFix()) {
- mHandler
- .obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED,
- componentName.getPackageName())
- .sendToTarget();
+ mHandler.obtainMessage(
+ MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED,
+ componentName.getPackageName())
+ .sendToTarget();
} else {
mHandler.sendEmptyMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
}
@@ -2254,33 +2252,34 @@ class BluetoothManagerService {
}
/**
- * In case of a Bluetooth crash, mark it's enabled components as non longer available to
- * trigger the PACKAGE_CHANGED intent. This should not be needed in a normal shutdown as the
- * Bluetooth clean its components on its own
+ * In case of a Bluetooth crash, mark it's enabled components as non longer available to trigger
+ * the PACKAGE_CHANGED intent. This should not be needed in a normal shutdown as the Bluetooth
+ * clean its components on its own
*/
private void disableBluetoothComponents(String packageName) {
PackageManager pm = mContext.getPackageManager();
PackageInfo packageInfo = null;
try {
- packageInfo = pm.getPackageInfo(
- packageName,
- PackageManager.GET_SERVICES |
- PackageManager.GET_ACTIVITIES |
- PackageManager.GET_RECEIVERS |
- PackageManager.GET_PROVIDERS);
+ packageInfo =
+ pm.getPackageInfo(
+ packageName,
+ PackageManager.GET_SERVICES
+ | PackageManager.GET_ACTIVITIES
+ | PackageManager.GET_RECEIVERS
+ | PackageManager.GET_PROVIDERS);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Package not found: " + packageName, e);
return;
}
// Refer to updateOppLauncherComponentState()
- List<String> baseBluetoothOppActivities = List.of(
- "com.android.bluetooth.opp.BluetoothOppLauncherActivity",
- "com.android.bluetooth.opp.BluetoothOppBtEnableActivity",
- "com.android.bluetooth.opp.BluetoothOppBtEnablingActivity",
- "com.android.bluetooth.opp.BluetoothOppBtErrorActivity"
- );
+ List<String> baseBluetoothOppActivities =
+ List.of(
+ "com.android.bluetooth.opp.BluetoothOppLauncherActivity",
+ "com.android.bluetooth.opp.BluetoothOppBtEnableActivity",
+ "com.android.bluetooth.opp.BluetoothOppBtEnablingActivity",
+ "com.android.bluetooth.opp.BluetoothOppBtErrorActivity");
disableComponents(pm, packageInfo.activities, packageName, baseBluetoothOppActivities);
disableComponents(pm, packageInfo.services, packageName, null);
@@ -2295,17 +2294,20 @@ class BluetoothManagerService {
}
Arrays.stream(components)
- .filter(componentInfo -> !componentInfo.enabled)
- .map(componentInfo -> new ComponentName(packageName, componentInfo.name))
- .filter(componentName ->
- (componentsToKeep == null ||
- !componentsToKeep.contains(componentName.getClassName())))
- .forEach(componentName -> {
- pm.setComponentEnabledSetting(
- componentName,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- Log.i(TAG, "Disabled component: " + componentName.flattenToString());
- });
+ .filter(componentInfo -> !componentInfo.enabled)
+ .map(componentInfo -> new ComponentName(packageName, componentInfo.name))
+ .filter(
+ componentName ->
+ (componentsToKeep == null
+ || !componentsToKeep.contains(
+ componentName.getClassName())))
+ .forEach(
+ componentName -> {
+ pm.setComponentEnabledSetting(
+ componentName,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ Log.i(TAG, "Disabled component: " + componentName.flattenToString());
+ });
}
}
diff --git a/service/tests/Android.bp b/service/tests/Android.bp
index 217bd36f70..8bdefcc8ac 100644
--- a/service/tests/Android.bp
+++ b/service/tests/Android.bp
@@ -26,6 +26,7 @@ android_test {
],
static_libs: [
+ "androidx.test.espresso.intents",
"androidx.test.rules",
"flag-junit",
"frameworks-base-testutils",
diff --git a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java
index 480af98329..c6105ec731 100644
--- a/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java
+++ b/service/tests/src/com/android/server/bluetooth/BluetoothManagerServiceTest.java
@@ -22,6 +22,9 @@ 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 androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
+import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
+
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;
@@ -41,13 +44,16 @@ import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.verify;
import android.annotation.SuppressLint;
+import android.app.AppOpsManager;
import android.app.PropertyInvalidatedCache;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothManager;
@@ -55,7 +61,6 @@ import android.bluetooth.IBluetoothManagerCallback;
import android.bluetooth.IBluetoothStateChangeCallback;
import android.content.ComponentName;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
@@ -63,21 +68,25 @@ import android.os.Message;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.test.TestLooper;
+import android.permission.PermissionManager;
import android.platform.test.flag.junit.FlagsParameterization;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import androidx.test.platform.app.InstrumentationRegistry;
+import org.hamcrest.Matcher;
+import org.hamcrest.core.AllOf;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
+import org.mockito.hamcrest.MockitoHamcrest;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
@@ -103,24 +112,26 @@ public class BluetoothManagerServiceTest {
private static final int STATE_BLE_TURNING_ON = 14; // can't find the symbol because hidden api
private static final int STATE_BLE_TURNING_OFF = 16; // can't find the symbol because hidden api
- BluetoothManagerService mManagerService;
-
- @Spy
- private final Context mContext =
- new ContextWrapper(InstrumentationRegistry.getInstrumentation().getTargetContext());
+ private final Context mTargetContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
- @Spy BluetoothServerProxy mBluetoothServerProxy;
+ @Mock BluetoothServerProxy mBluetoothServerProxy;
+ @Mock Context mContext;
@Mock UserManager mUserManager;
@Mock UserHandle mUserHandle;
-
@Mock IBinder mBinder;
@Mock IBluetoothManagerCallback mManagerCallback;
@Mock IBluetoothStateChangeCallback mStateChangeCallback;
-
@Mock IBluetooth mAdapterService;
@Mock AdapterBinder mAdapterBinder;
+ @Mock AppOpsManager mAppOpsManager;
+ @Mock PermissionManager mPermissionManager;
+
+ private int mPersistedState = BluetoothManagerService.BLUETOOTH_OFF;
- TestLooper mLooper;
+ private InOrder mInOrder;
+ private TestLooper mLooper;
+ private BluetoothManagerService mManagerService;
private static class ServerQuery
extends PropertyInvalidatedCache.QueryHandler<IBluetoothManager, Integer> {
@@ -146,6 +157,7 @@ public class BluetoothManagerServiceTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mInOrder = inOrder(mContext, mManagerCallback, mAdapterBinder);
PropertyInvalidatedCache<IBluetoothManager, Integer> testCache =
new PropertyInvalidatedCache<>(
@@ -163,24 +175,37 @@ public class BluetoothManagerServiceTest {
doReturn("00:11:22:33:44:55")
.when(mBluetoothServerProxy)
.settingsSecureGetString(any(), eq(Settings.Secure.BLUETOOTH_ADDRESS));
- // Set persisted state to BLUETOOTH_OFF to not generate unwanted behavior when starting test
- doReturn(BluetoothManagerService.BLUETOOTH_OFF)
+ doAnswer(
+ inv -> {
+ return mPersistedState;
+ })
.when(mBluetoothServerProxy)
.getBluetoothPersistedState(any(), anyInt());
doAnswer(
inv -> {
- doReturn(inv.getArguments()[1])
- .when(mBluetoothServerProxy)
- .getBluetoothPersistedState(any(), anyInt());
+ mPersistedState = inv.getArgument(1);
return null;
})
.when(mBluetoothServerProxy)
.setBluetoothPersistedState(any(), anyInt());
- // Test is not allowed to send broadcast as Bluetooth. doNothing Prevent SecurityException
- doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any(), any());
+ doAnswer(
+ inv -> {
+ IBinder.DeathRecipient recipient = inv.getArgument(0);
+ recipient.binderDied();
+ return null;
+ })
+ .when(mBinder)
+ .linkToDeath(any(), anyInt());
+
+ doReturn(BluetoothManagerServiceTest.class.getSimpleName()).when(mContext).getPackageName();
+ doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+ doReturn(mTargetContext.getContentResolver()).when(mContext).getContentResolver();
+ doReturn(mTargetContext.getPackageManager()).when(mContext).getPackageManager();
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
+ doReturn(mPermissionManager).when(mContext).getSystemService(PermissionManager.class);
doReturn(mBinder).when(mManagerCallback).asBinder();
@@ -285,6 +310,7 @@ public class BluetoothManagerServiceTest {
mManagerService.enableBle("enable_bindFailure_removesTimeout", mBinder);
syncHandler(MESSAGE_ENABLE);
verify(mContext).unbindService(any());
+ mInOrder.verify(mContext).unbindService(any());
// TODO(b/280518177): Failed to start should be noted / reported in metrics
// Maybe show a popup or a crash notification
@@ -312,7 +338,7 @@ public class BluetoothManagerServiceTest {
ArgumentCaptor<BluetoothManagerService.BluetoothServiceConnection> captor =
ArgumentCaptor.forClass(BluetoothManagerService.BluetoothServiceConnection.class);
- verify(mContext)
+ mInOrder.verify(mContext)
.bindServiceAsUser(
any(Intent.class), captor.capture(), anyInt(), any(UserHandle.class));
assertThat(captor.getAllValues()).hasSize(1);
@@ -324,11 +350,10 @@ public class BluetoothManagerServiceTest {
return serviceConnection;
}
- private static IBluetoothCallback captureBluetoothCallback(AdapterBinder adapterBinder)
- throws Exception {
+ private IBluetoothCallback captureBluetoothCallback() throws Exception {
ArgumentCaptor<IBluetoothCallback> captor =
ArgumentCaptor.forClass(IBluetoothCallback.class);
- verify(adapterBinder).registerCallback(captor.capture(), any());
+ mInOrder.verify(mAdapterBinder).registerCallback(captor.capture(), any());
assertThat(captor.getAllValues()).hasSize(1);
return captor.getValue();
}
@@ -337,11 +362,10 @@ public class BluetoothManagerServiceTest {
// Binding of IBluetooth
acceptBluetoothBinding();
- // TODO(b/280518177): This callback is too early, bt is not ON nor BLE_ON
- verify(mManagerCallback).onBluetoothServiceUp(any());
-
- IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder);
- verify(mAdapterBinder).offToBleOn(anyBoolean(), any());
+ IBluetoothCallback btCallback = captureBluetoothCallback();
+ mInOrder.verify(mAdapterBinder).offToBleOn(anyBoolean(), any());
+ verifyBleStateIntentSent(STATE_OFF, STATE_BLE_TURNING_ON);
+ mInOrder.verify(mManagerCallback).onBluetoothServiceUp(any());
assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON);
@@ -349,30 +373,30 @@ public class BluetoothManagerServiceTest {
// trigger the stateChangeCallback from native
btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON);
syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE);
+ verifyBleStateIntentSent(STATE_BLE_TURNING_ON, STATE_BLE_ON);
return btCallback;
}
private IBluetoothCallback transition_offToOn() throws Exception {
IBluetoothCallback btCallback = transition_offToBleOn();
- verify(mAdapterBinder).bleOnToOn(any());
+ mInOrder.verify(mAdapterBinder).bleOnToOn(any());
// AdapterService go to turning_on and start all profile on its own
btCallback.onBluetoothStateChange(STATE_BLE_ON, STATE_TURNING_ON);
syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE);
+ verifyBleStateIntentSent(STATE_BLE_ON, STATE_TURNING_ON);
+ verifyStateIntentSent(STATE_OFF, STATE_TURNING_ON);
// When all the profile are started, adapterService consider it is ON
btCallback.onBluetoothStateChange(STATE_TURNING_ON, STATE_ON);
syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE);
-
- // Check that we sent 6 intent, 4 for BLE: BLE_TURNING_ON + BLE_ON + TURNING_ON + ON
- // and 2 for classic: TURNING_ON + ON
- // TODO(b/280518177): assert the intent are the correct one
- verify(mContext, times(6)).sendBroadcastAsUser(any(), any(), any(), any());
+ verifyBleStateIntentSent(STATE_TURNING_ON, STATE_ON);
+ verifyStateIntentSent(STATE_TURNING_ON, STATE_ON);
return btCallback;
}
private void transition_onToBleOn(IBluetoothCallback btCallback) throws Exception {
- verify(mAdapterBinder).onToBleOn(any());
+ mInOrder.verify(mAdapterBinder).onToBleOn(any());
btCallback.onBluetoothStateChange(STATE_TURNING_OFF, STATE_BLE_ON);
syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE);
@@ -380,7 +404,7 @@ public class BluetoothManagerServiceTest {
private void transition_onToOff(IBluetoothCallback btCallback) throws Exception {
transition_onToBleOn(btCallback);
- verify(mAdapterBinder).bleOnToOff(any());
+ mInOrder.verify(mAdapterBinder).bleOnToOff(any());
// When all the profile are started, adapterService consider it is ON
btCallback.onBluetoothStateChange(STATE_BLE_TURNING_OFF, STATE_OFF);
@@ -393,7 +417,7 @@ public class BluetoothManagerServiceTest {
syncHandler(MESSAGE_ENABLE);
acceptBluetoothBinding();
- IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder);
+ IBluetoothCallback btCallback = captureBluetoothCallback();
assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON);
// receive enable when Bluetooth is in BLE_TURNING_ON
@@ -403,7 +427,7 @@ public class BluetoothManagerServiceTest {
btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON);
syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE);
- verify(mAdapterBinder).bleOnToOn(any());
+ mInOrder.verify(mAdapterBinder).bleOnToOn(any());
}
@Test
@@ -417,13 +441,13 @@ public class BluetoothManagerServiceTest {
syncHandler(MESSAGE_ENABLE);
acceptBluetoothBinding();
- IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder);
+ IBluetoothCallback btCallback = captureBluetoothCallback();
assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_TURNING_ON);
btCallback.onBluetoothStateChange(STATE_BLE_TURNING_ON, STATE_BLE_ON);
syncHandler(MESSAGE_BLUETOOTH_STATE_CHANGE);
- verify(mAdapterBinder).bleOnToOn(any());
+ mInOrder.verify(mAdapterBinder).bleOnToOn(any());
}
@Test
@@ -433,12 +457,8 @@ public class BluetoothManagerServiceTest {
transition_offToBleOn();
- // Check that we sent 2 intent, one for BLE_TURNING_ON, one for BLE_ON
- // TODO(b/280518177): assert the intent are the correct one
- verify(mContext, times(2)).sendBroadcastAsUser(any(), any(), any(), any());
-
// Check that there was no transition to STATE_ON
- verify(mAdapterBinder, times(0)).bleOnToOn(any());
+ mInOrder.verify(mAdapterBinder, never()).bleOnToOn(any());
assertThat(mManagerService.getState()).isEqualTo(STATE_BLE_ON);
}
@@ -460,8 +480,8 @@ public class BluetoothManagerServiceTest {
BluetoothManagerService.BluetoothServiceConnection serviceConnection =
acceptBluetoothBinding();
- IBluetoothCallback btCallback = captureBluetoothCallback(mAdapterBinder);
- verify(mAdapterBinder).offToBleOn(anyBoolean(), any());
+ IBluetoothCallback btCallback = captureBluetoothCallback();
+ mInOrder.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);
@@ -484,9 +504,7 @@ public class BluetoothManagerServiceTest {
@Test
public void disableAirplane_whenNothing_startBluetooth() throws Exception {
- doReturn(BluetoothManagerService.BLUETOOTH_ON_BLUETOOTH)
- .when(mBluetoothServerProxy)
- .getBluetoothPersistedState(any(), anyInt());
+ mPersistedState = BluetoothManagerService.BLUETOOTH_ON_BLUETOOTH;
mManagerService.enable("disableAirplane_whenNothing_startBluetooth");
discardMessage(MESSAGE_ENABLE);
@@ -496,16 +514,7 @@ public class BluetoothManagerServiceTest {
@Test
public void disableAirplane_whenFactoryReset_doesNotStartBluetooth() throws Exception {
- doAnswer(
- invocation -> {
- IBinder.DeathRecipient recipient = invocation.getArgument(0);
- recipient.binderDied();
- return null;
- })
- .when(mBinder)
- .linkToDeath(any(), anyInt());
-
- mManagerService.enable("test_offToOn");
+ mManagerService.enable("disableAirplane_whenFactoryReset_doesNotStartBluetooth");
syncHandler(MESSAGE_ENABLE);
IBluetoothCallback btCallback = transition_offToOn();
assertThat(mManagerService.getState()).isEqualTo(STATE_ON);
@@ -522,4 +531,25 @@ public class BluetoothManagerServiceTest {
mManagerService.onAirplaneModeChanged(false);
assertThat(mLooper.nextMessage()).isNull(); // Must not create a MESSAGE_ENABLE
}
+
+ @SafeVarargs
+ private void verifyIntentSent(Matcher<Intent>... matchers) {
+ mInOrder.verify(mContext)
+ .sendBroadcastAsUser(
+ MockitoHamcrest.argThat(AllOf.allOf(matchers)), any(), any(), any());
+ }
+
+ private void verifyBleStateIntentSent(int from, int to) {
+ verifyIntentSent(
+ hasAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED),
+ hasExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, from),
+ hasExtra(BluetoothAdapter.EXTRA_STATE, to));
+ }
+
+ private void verifyStateIntentSent(int from, int to) {
+ verifyIntentSent(
+ hasAction(BluetoothAdapter.ACTION_STATE_CHANGED),
+ hasExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, from),
+ hasExtra(BluetoothAdapter.EXTRA_STATE, to));
+ }
}