1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.btservice; 18 19 import static org.mockito.ArgumentMatchers.any; 20 import static org.mockito.Mockito.*; 21 22 import android.app.AlarmManager; 23 import android.app.admin.DevicePolicyManager; 24 import android.bluetooth.BluetoothAdapter; 25 import android.bluetooth.BluetoothDevice; 26 import android.bluetooth.IBluetoothCallback; 27 import android.content.Context; 28 import android.content.pm.ApplicationInfo; 29 import android.content.pm.PackageManager; 30 import android.content.res.Resources; 31 import android.media.AudioManager; 32 import android.os.Binder; 33 import android.os.Looper; 34 import android.os.PowerManager; 35 import android.os.Process; 36 import android.os.SystemProperties; 37 import android.os.UserManager; 38 import android.test.mock.MockContentResolver; 39 import android.util.Log; 40 41 import androidx.test.InstrumentationRegistry; 42 import androidx.test.filters.MediumTest; 43 import androidx.test.runner.AndroidJUnit4; 44 45 import com.android.bluetooth.R; 46 import com.android.bluetooth.TestUtils; 47 import com.android.bluetooth.Utils; 48 49 import libcore.util.HexEncoding; 50 51 import org.junit.After; 52 import org.junit.Assert; 53 import org.junit.Before; 54 import org.junit.BeforeClass; 55 import org.junit.Ignore; 56 import org.junit.Test; 57 import org.junit.runner.RunWith; 58 import org.mockito.Mock; 59 import org.mockito.MockitoAnnotations; 60 61 import java.security.InvalidKeyException; 62 import java.security.NoSuchAlgorithmException; 63 import java.util.Arrays; 64 import java.util.HashMap; 65 66 import javax.crypto.Mac; 67 import javax.crypto.spec.SecretKeySpec; 68 69 @MediumTest 70 @RunWith(AndroidJUnit4.class) 71 public class AdapterServiceTest { 72 private static final String TAG = AdapterServiceTest.class.getSimpleName(); 73 74 private AdapterService mAdapterService; 75 private AdapterService.AdapterServiceBinder mServiceBinder; 76 77 private @Mock Context mMockContext; 78 private @Mock ApplicationInfo mMockApplicationInfo; 79 private @Mock AlarmManager mMockAlarmManager; 80 private @Mock Resources mMockResources; 81 private @Mock UserManager mMockUserManager; 82 private @Mock DevicePolicyManager mMockDevicePolicyManager; 83 private @Mock ProfileService mMockGattService; 84 private @Mock ProfileService mMockService; 85 private @Mock ProfileService mMockService2; 86 private @Mock IBluetoothCallback mIBluetoothCallback; 87 private @Mock Binder mBinder; 88 private @Mock AudioManager mAudioManager; 89 private @Mock android.app.Application mApplication; 90 91 private static final int CONTEXT_SWITCH_MS = 100; 92 private static final int GATT_START_TIME_MS = 500; 93 private static final int ONE_SECOND_MS = 1000; 94 private static final int NATIVE_INIT_MS = 8000; 95 private static final int NATIVE_DISABLE_MS = 1000; 96 97 private PowerManager mPowerManager; 98 private PackageManager mMockPackageManager; 99 private MockContentResolver mMockContentResolver; 100 private HashMap<String, HashMap<String, String>> mAdapterConfig; 101 102 @BeforeClass setupClass()103 public static void setupClass() { 104 // Bring native layer up and down to make sure config files are properly loaded 105 if (Looper.myLooper() == null) { 106 Looper.prepare(); 107 } 108 Assert.assertNotNull(Looper.myLooper()); 109 AdapterService adapterService = new AdapterService(); 110 adapterService.initNative(false /* is_restricted */, false /* is_niap_mode */, 111 0 /* config_compare_result */); 112 adapterService.cleanupNative(); 113 HashMap<String, HashMap<String, String>> adapterConfig = TestUtils.readAdapterConfig(); 114 Assert.assertNotNull(adapterConfig); 115 Assert.assertNotNull("metrics salt is null: " + adapterConfig.toString(), 116 getMetricsSalt(adapterConfig)); 117 } 118 119 @Before setUp()120 public void setUp() throws PackageManager.NameNotFoundException { 121 if (Looper.myLooper() == null) { 122 Looper.prepare(); 123 } 124 Assert.assertNotNull(Looper.myLooper()); 125 126 InstrumentationRegistry.getInstrumentation().runOnMainSync( 127 () -> mAdapterService = new AdapterService()); 128 mServiceBinder = new AdapterService.AdapterServiceBinder(mAdapterService); 129 mMockPackageManager = mock(PackageManager.class); 130 mMockContentResolver = new MockContentResolver(mMockContext); 131 MockitoAnnotations.initMocks(this); 132 mPowerManager = (PowerManager) InstrumentationRegistry.getTargetContext() 133 .getSystemService(Context.POWER_SERVICE); 134 135 when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo); 136 when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); 137 when(mMockContext.getApplicationContext()).thenReturn(mMockContext); 138 when(mMockContext.getResources()).thenReturn(mMockResources); 139 when(mMockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID); 140 when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); 141 when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager); 142 when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn( 143 mMockDevicePolicyManager); 144 when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager); 145 when(mMockContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mMockAlarmManager); 146 when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager); 147 doAnswer(invocation -> { 148 Object[] args = invocation.getArguments(); 149 return InstrumentationRegistry.getTargetContext().getDatabasePath((String) args[0]); 150 }).when(mMockContext).getDatabasePath(anyString()); 151 152 when(mMockResources.getBoolean(R.bool.profile_supported_gatt)).thenReturn(true); 153 when(mMockResources.getBoolean(R.bool.profile_supported_pbap)).thenReturn(true); 154 when(mMockResources.getBoolean(R.bool.profile_supported_pan)).thenReturn(true); 155 156 when(mMockDevicePolicyManager.isCommonCriteriaModeEnabled(any())).thenReturn(false); 157 158 when(mIBluetoothCallback.asBinder()).thenReturn(mBinder); 159 160 doReturn(Process.BLUETOOTH_UID).when(mMockPackageManager) 161 .getPackageUidAsUser(any(), anyInt(), anyInt()); 162 163 when(mMockGattService.getName()).thenReturn("GattService"); 164 when(mMockService.getName()).thenReturn("Service1"); 165 when(mMockService2.getName()).thenReturn("Service2"); 166 167 // Attach a context to the service for permission checks. 168 mAdapterService.attach(mMockContext, null, null, null, mApplication, null); 169 170 mAdapterService.onCreate(); 171 mServiceBinder.registerCallback(mIBluetoothCallback); 172 173 Config.init(mMockContext); 174 175 mAdapterConfig = TestUtils.readAdapterConfig(); 176 Assert.assertNotNull(mAdapterConfig); 177 } 178 179 @After tearDown()180 public void tearDown() { 181 mServiceBinder.unregisterCallback(mIBluetoothCallback); 182 mAdapterService.cleanup(); 183 Config.init(InstrumentationRegistry.getTargetContext()); 184 } 185 verifyStateChange(int prevState, int currState, int callNumber, int timeoutMs)186 private void verifyStateChange(int prevState, int currState, int callNumber, int timeoutMs) { 187 try { 188 verify(mIBluetoothCallback, timeout(timeoutMs) 189 .times(callNumber)).onBluetoothStateChange(prevState, currState); 190 } catch (Exception e) { 191 // the mocked onBluetoothStateChange doesn't throw exceptions 192 } 193 } 194 doEnable(int invocationNumber, boolean onlyGatt)195 private void doEnable(int invocationNumber, boolean onlyGatt) { 196 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 197 198 final int startServiceCalls = 2 * (onlyGatt ? 1 : 3); // Start and stop GATT + 2 199 200 mAdapterService.enable(false); 201 202 verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON, 203 invocationNumber + 1, CONTEXT_SWITCH_MS); 204 205 // Start GATT 206 verify(mMockContext, timeout(GATT_START_TIME_MS).times( 207 startServiceCalls * invocationNumber + 1)).startService(any()); 208 mAdapterService.addProfile(mMockGattService); 209 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_ON); 210 211 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, BluetoothAdapter.STATE_BLE_ON, 212 invocationNumber + 1, NATIVE_INIT_MS); 213 214 mServiceBinder.onLeServiceUp(); 215 216 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_TURNING_ON, 217 invocationNumber + 1, CONTEXT_SWITCH_MS); 218 219 if (!onlyGatt) { 220 // Start Mock PBAP and PAN services 221 verify(mMockContext, timeout(ONE_SECOND_MS).times( 222 startServiceCalls * invocationNumber + 3)).startService(any()); 223 mAdapterService.addProfile(mMockService); 224 mAdapterService.addProfile(mMockService2); 225 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_ON); 226 mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_ON); 227 } 228 229 verifyStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_ON, 230 invocationNumber + 1, CONTEXT_SWITCH_MS); 231 232 verify(mMockContext, timeout(CONTEXT_SWITCH_MS).times(2 * invocationNumber + 2)) 233 .sendBroadcast(any(), eq(android.Manifest.permission.BLUETOOTH)); 234 final int scanMode = mServiceBinder.getScanMode(); 235 Assert.assertTrue(scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE 236 || scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE); 237 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 238 } 239 doDisable(int invocationNumber, boolean onlyGatt)240 private void doDisable(int invocationNumber, boolean onlyGatt) { 241 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 242 243 final int startServiceCalls = 2 * (onlyGatt ? 1 : 3); // Start and stop GATT + 2 244 245 mAdapterService.disable(); 246 247 verifyStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF, 248 invocationNumber + 1, CONTEXT_SWITCH_MS); 249 250 if (!onlyGatt) { 251 // Stop PBAP and PAN 252 verify(mMockContext, timeout(ONE_SECOND_MS).times( 253 startServiceCalls * invocationNumber + 5)).startService(any()); 254 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 255 mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_OFF); 256 } 257 258 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_BLE_ON, 259 invocationNumber + 1, CONTEXT_SWITCH_MS); 260 261 mServiceBinder.onBrEdrDown(); 262 263 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_BLE_TURNING_OFF, 264 invocationNumber + 1, CONTEXT_SWITCH_MS); 265 266 // Stop GATT 267 verify(mMockContext, timeout(ONE_SECOND_MS).times( 268 startServiceCalls * invocationNumber + startServiceCalls)).startService(any()); 269 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_OFF); 270 271 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 272 invocationNumber + 1, NATIVE_DISABLE_MS); 273 274 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 275 } 276 277 /** 278 * Test: Turn Bluetooth on. 279 * Check whether the AdapterService gets started. 280 */ 281 @Test testEnable()282 public void testEnable() { 283 doEnable(0, false); 284 } 285 286 /** 287 * Test: Turn Bluetooth on/off. 288 * Check whether the AdapterService gets started and stopped. 289 */ 290 @Test testEnableDisable()291 public void testEnableDisable() { 292 doEnable(0, false); 293 doDisable(0, false); 294 } 295 296 /** 297 * Test: Turn Bluetooth on/off with only GATT supported. 298 * Check whether the AdapterService gets started and stopped. 299 */ 300 @Test testEnableDisableOnlyGatt()301 public void testEnableDisableOnlyGatt() { 302 Context mockContext = mock(Context.class); 303 Resources mockResources = mock(Resources.class); 304 305 when(mockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo); 306 when(mockContext.getContentResolver()).thenReturn(mMockContentResolver); 307 when(mockContext.getApplicationContext()).thenReturn(mockContext); 308 when(mockContext.getResources()).thenReturn(mockResources); 309 when(mockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID); 310 when(mockContext.getPackageManager()).thenReturn(mMockPackageManager); 311 when(mockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager); 312 when(mockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager); 313 when(mockContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mMockAlarmManager); 314 315 when(mockResources.getBoolean(R.bool.profile_supported_gatt)).thenReturn(true); 316 317 Config.init(mockContext); 318 doEnable(0, true); 319 doDisable(0, true); 320 } 321 322 /** 323 * Test: Don't start GATT 324 * Check whether the AdapterService quits gracefully 325 */ 326 @Test testGattStartTimeout()327 public void testGattStartTimeout() { 328 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 329 330 mAdapterService.enable(false); 331 332 verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON, 1, 333 CONTEXT_SWITCH_MS); 334 335 // Start GATT 336 verify(mMockContext, timeout(GATT_START_TIME_MS).times(1)).startService(any()); 337 mAdapterService.addProfile(mMockGattService); 338 339 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, 340 BluetoothAdapter.STATE_BLE_TURNING_OFF, 1, 341 AdapterState.BLE_START_TIMEOUT_DELAY + CONTEXT_SWITCH_MS); 342 343 // Stop GATT 344 verify(mMockContext, timeout(AdapterState.BLE_STOP_TIMEOUT_DELAY + CONTEXT_SWITCH_MS) 345 .times(2)).startService(any()); 346 347 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 1, 348 NATIVE_DISABLE_MS); 349 350 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 351 } 352 353 /** 354 * Test: Don't stop GATT 355 * Check whether the AdapterService quits gracefully 356 */ 357 @Test testGattStopTimeout()358 public void testGattStopTimeout() { 359 doEnable(0, false); 360 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 361 362 mAdapterService.disable(); 363 364 verifyStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF, 1, 365 CONTEXT_SWITCH_MS); 366 367 // Stop PBAP and PAN 368 verify(mMockContext, timeout(ONE_SECOND_MS).times(5)).startService(any()); 369 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 370 mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_OFF); 371 372 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_BLE_ON, 1, 373 CONTEXT_SWITCH_MS); 374 375 mServiceBinder.onBrEdrDown(); 376 377 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_BLE_TURNING_OFF, 1, 378 CONTEXT_SWITCH_MS); 379 380 // Stop GATT 381 verify(mMockContext, timeout(ONE_SECOND_MS).times(6)).startService(any()); 382 383 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 1, 384 AdapterState.BLE_STOP_TIMEOUT_DELAY + NATIVE_DISABLE_MS); 385 386 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 387 } 388 389 /** 390 * Test: Don't start a classic profile 391 * Check whether the AdapterService quits gracefully 392 */ 393 @Test testProfileStartTimeout()394 public void testProfileStartTimeout() { 395 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 396 397 mAdapterService.enable(false); 398 399 verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON, 1, 400 CONTEXT_SWITCH_MS); 401 402 // Start GATT 403 verify(mMockContext, timeout(GATT_START_TIME_MS).times(1)).startService(any()); 404 mAdapterService.addProfile(mMockGattService); 405 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_ON); 406 407 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, BluetoothAdapter.STATE_BLE_ON, 1, 408 NATIVE_INIT_MS); 409 410 mServiceBinder.onLeServiceUp(); 411 412 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_TURNING_ON, 1, 413 CONTEXT_SWITCH_MS); 414 415 // Register Mock PBAP and PAN services, only start one 416 verify(mMockContext, timeout(ONE_SECOND_MS).times(3)).startService(any()); 417 mAdapterService.addProfile(mMockService); 418 mAdapterService.addProfile(mMockService2); 419 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_ON); 420 421 verifyStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_TURNING_OFF, 1, 422 AdapterState.BREDR_START_TIMEOUT_DELAY + CONTEXT_SWITCH_MS); 423 424 // Stop PBAP and PAN 425 verify(mMockContext, timeout(ONE_SECOND_MS).times(5)).startService(any()); 426 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 427 428 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_BLE_ON, 1, 429 CONTEXT_SWITCH_MS); 430 } 431 432 /** 433 * Test: Don't stop a classic profile 434 * Check whether the AdapterService quits gracefully 435 */ 436 @Test testProfileStopTimeout()437 public void testProfileStopTimeout() { 438 doEnable(0, false); 439 440 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 441 442 mAdapterService.disable(); 443 444 verifyStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF, 1, 445 CONTEXT_SWITCH_MS); 446 447 // Stop PBAP and PAN 448 verify(mMockContext, timeout(ONE_SECOND_MS).times(5)).startService(any()); 449 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 450 451 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, 452 BluetoothAdapter.STATE_BLE_TURNING_OFF, 1, 453 AdapterState.BREDR_STOP_TIMEOUT_DELAY + CONTEXT_SWITCH_MS); 454 455 // Stop GATT 456 verify(mMockContext, timeout(ONE_SECOND_MS).times(6)).startService(any()); 457 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_OFF); 458 459 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 1, 460 AdapterState.BLE_STOP_TIMEOUT_DELAY + NATIVE_DISABLE_MS); 461 462 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 463 } 464 465 /** 466 * Test: Toggle snoop logging setting 467 * Check whether the AdapterService restarts fully 468 */ 469 @Test testSnoopLoggingChange()470 public void testSnoopLoggingChange() { 471 String snoopSetting = 472 SystemProperties.get(AdapterService.BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY, ""); 473 SystemProperties.set(AdapterService.BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY, "false"); 474 doEnable(0, false); 475 476 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 477 478 Assert.assertFalse( 479 SystemProperties.get(AdapterService.BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY, 480 "true").equals("true")); 481 482 SystemProperties.set(AdapterService.BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY, "true"); 483 484 mAdapterService.disable(); 485 486 verifyStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF, 1, 487 CONTEXT_SWITCH_MS); 488 489 // Stop PBAP and PAN 490 verify(mMockContext, timeout(ONE_SECOND_MS).times(5)).startService(any()); 491 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 492 mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_OFF); 493 494 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_BLE_ON, 1, 495 CONTEXT_SWITCH_MS); 496 497 // Don't call onBrEdrDown(). The Adapter should turn itself off. 498 499 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_BLE_TURNING_OFF, 1, 500 CONTEXT_SWITCH_MS); 501 502 // Stop GATT 503 verify(mMockContext, timeout(ONE_SECOND_MS).times(6)).startService(any()); 504 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_OFF); 505 506 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 1, 507 NATIVE_DISABLE_MS); 508 509 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 510 511 // Restore earlier setting 512 SystemProperties.set(AdapterService.BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY, snoopSetting); 513 } 514 515 516 /** 517 * Test: Obfuscate a null Bluetooth 518 * Check if returned value from {@link AdapterService#obfuscateAddress(BluetoothDevice)} is 519 * an empty array when device address is null 520 */ 521 @Test testObfuscateBluetoothAddress_NullAddress()522 public void testObfuscateBluetoothAddress_NullAddress() { 523 Assert.assertArrayEquals(mAdapterService.obfuscateAddress(null), new byte[0]); 524 } 525 526 /** 527 * Test: Obfuscate Bluetooth address when Bluetooth is disabled 528 * Check whether the returned value meets expectation 529 */ 530 @Test testObfuscateBluetoothAddress_BluetoothDisabled()531 public void testObfuscateBluetoothAddress_BluetoothDisabled() { 532 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 533 byte[] metricsSalt = getMetricsSalt(mAdapterConfig); 534 Assert.assertNotNull(metricsSalt); 535 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 536 byte[] obfuscatedAddress = mAdapterService.obfuscateAddress(device); 537 Assert.assertTrue(obfuscatedAddress.length > 0); 538 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress)); 539 Assert.assertArrayEquals(obfuscateInJava(metricsSalt, device), obfuscatedAddress); 540 } 541 542 /** 543 * Test: Obfuscate Bluetooth address when Bluetooth is enabled 544 * Check whether the returned value meets expectation 545 */ 546 @Test testObfuscateBluetoothAddress_BluetoothEnabled()547 public void testObfuscateBluetoothAddress_BluetoothEnabled() { 548 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 549 doEnable(0, false); 550 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 551 byte[] metricsSalt = getMetricsSalt(mAdapterConfig); 552 Assert.assertNotNull(metricsSalt); 553 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 554 byte[] obfuscatedAddress = mAdapterService.obfuscateAddress(device); 555 Assert.assertTrue(obfuscatedAddress.length > 0); 556 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress)); 557 Assert.assertArrayEquals(obfuscateInJava(metricsSalt, device), obfuscatedAddress); 558 } 559 560 /** 561 * Test: Check if obfuscated Bluetooth address stays the same after toggling Bluetooth 562 */ 563 @Test testObfuscateBluetoothAddress_PersistentBetweenToggle()564 public void testObfuscateBluetoothAddress_PersistentBetweenToggle() { 565 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 566 byte[] metricsSalt = getMetricsSalt(mAdapterConfig); 567 Assert.assertNotNull(metricsSalt); 568 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 569 byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device); 570 Assert.assertTrue(obfuscatedAddress1.length > 0); 571 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1)); 572 Assert.assertArrayEquals(obfuscateInJava(metricsSalt, device), 573 obfuscatedAddress1); 574 // Enable 575 doEnable(0, false); 576 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 577 byte[] obfuscatedAddress3 = mAdapterService.obfuscateAddress(device); 578 Assert.assertTrue(obfuscatedAddress3.length > 0); 579 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress3)); 580 Assert.assertArrayEquals(obfuscatedAddress3, 581 obfuscatedAddress1); 582 // Disable 583 doDisable(0, false); 584 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 585 byte[] obfuscatedAddress4 = mAdapterService.obfuscateAddress(device); 586 Assert.assertTrue(obfuscatedAddress4.length > 0); 587 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress4)); 588 Assert.assertArrayEquals(obfuscatedAddress4, 589 obfuscatedAddress1); 590 } 591 592 /** 593 * Test: Check if obfuscated Bluetooth address stays the same after re-initializing 594 * {@link AdapterService} 595 */ 596 @Test testObfuscateBluetoothAddress_PersistentBetweenAdapterServiceInitialization()597 public void testObfuscateBluetoothAddress_PersistentBetweenAdapterServiceInitialization() throws 598 PackageManager.NameNotFoundException { 599 byte[] metricsSalt = getMetricsSalt(mAdapterConfig); 600 Assert.assertNotNull(metricsSalt); 601 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 602 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 603 byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device); 604 Assert.assertTrue(obfuscatedAddress1.length > 0); 605 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1)); 606 Assert.assertArrayEquals(obfuscateInJava(metricsSalt, device), 607 obfuscatedAddress1); 608 tearDown(); 609 setUp(); 610 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 611 byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device); 612 Assert.assertTrue(obfuscatedAddress2.length > 0); 613 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2)); 614 Assert.assertArrayEquals(obfuscatedAddress2, 615 obfuscatedAddress1); 616 } 617 618 /** 619 * Test: Verify that obfuscated Bluetooth address changes after factory reset 620 * 621 * There are 4 types of factory reset that we are talking about: 622 * 1. Factory reset all user data from Settings -> Will restart phone 623 * 2. Factory reset WiFi and Bluetooth from Settings -> Will only restart WiFi and BT 624 * 3. Call BluetoothAdapter.factoryReset() -> Will disable Bluetooth and reset config in 625 * memory and disk 626 * 4. Call AdapterService.factoryReset() -> Will only reset config in memory 627 * 628 * We can only use No. 4 here 629 */ 630 @Ignore("AdapterService.factoryReset() does not reload config into memory and hence old salt" 631 + " is still used until next time Bluetooth library is initialized. However Bluetooth" 632 + " cannot be used until Bluetooth process restart any way. Thus it is almost" 633 + " guaranteed that user has to re-enable Bluetooth and hence re-generate new salt" 634 + " after factory reset") 635 @Test testObfuscateBluetoothAddress_FactoryReset()636 public void testObfuscateBluetoothAddress_FactoryReset() { 637 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 638 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 639 byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device); 640 Assert.assertTrue(obfuscatedAddress1.length > 0); 641 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1)); 642 mServiceBinder.factoryReset(); 643 byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device); 644 Assert.assertTrue(obfuscatedAddress2.length > 0); 645 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2)); 646 Assert.assertFalse(Arrays.equals(obfuscatedAddress2, 647 obfuscatedAddress1)); 648 doEnable(0, false); 649 byte[] obfuscatedAddress3 = mAdapterService.obfuscateAddress(device); 650 Assert.assertTrue(obfuscatedAddress3.length > 0); 651 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress3)); 652 Assert.assertArrayEquals(obfuscatedAddress3, 653 obfuscatedAddress2); 654 mServiceBinder.factoryReset(); 655 byte[] obfuscatedAddress4 = mAdapterService.obfuscateAddress(device); 656 Assert.assertTrue(obfuscatedAddress4.length > 0); 657 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress4)); 658 Assert.assertFalse(Arrays.equals(obfuscatedAddress4, 659 obfuscatedAddress3)); 660 } 661 662 /** 663 * Test: Verify that obfuscated Bluetooth address changes after factory reset and reloading 664 * native layer 665 */ 666 @Test testObfuscateBluetoothAddress_FactoryResetAndReloadNativeLayer()667 public void testObfuscateBluetoothAddress_FactoryResetAndReloadNativeLayer() throws 668 PackageManager.NameNotFoundException { 669 byte[] metricsSalt1 = getMetricsSalt(mAdapterConfig); 670 Assert.assertNotNull(metricsSalt1); 671 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 672 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 673 byte[] obfuscatedAddress1 = mAdapterService.obfuscateAddress(device); 674 Assert.assertTrue(obfuscatedAddress1.length > 0); 675 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress1)); 676 Assert.assertArrayEquals(obfuscateInJava(metricsSalt1, device), 677 obfuscatedAddress1); 678 mServiceBinder.factoryReset(); 679 tearDown(); 680 setUp(); 681 // Cannot verify metrics salt since it is not written to disk until native cleanup 682 byte[] obfuscatedAddress2 = mAdapterService.obfuscateAddress(device); 683 Assert.assertTrue(obfuscatedAddress2.length > 0); 684 Assert.assertFalse(isByteArrayAllZero(obfuscatedAddress2)); 685 Assert.assertFalse(Arrays.equals(obfuscatedAddress2, 686 obfuscatedAddress1)); 687 } 688 getMetricsSalt(HashMap<String, HashMap<String, String>> adapterConfig)689 private static byte[] getMetricsSalt(HashMap<String, HashMap<String, String>> adapterConfig) { 690 HashMap<String, String> metricsSection = adapterConfig.get("Metrics"); 691 if (metricsSection == null) { 692 Log.e(TAG, "Metrics section is null: " + adapterConfig.toString()); 693 return null; 694 } 695 String saltString = metricsSection.get("Salt256Bit"); 696 if (saltString == null) { 697 Log.e(TAG, "Salt256Bit is null: " + metricsSection.toString()); 698 return null; 699 } 700 byte[] metricsSalt = HexEncoding.decode(saltString, false /* allowSingleChar */); 701 if (metricsSalt.length != 32) { 702 Log.e(TAG, "Salt length is not 32 bit, but is " + metricsSalt.length); 703 return null; 704 } 705 return metricsSalt; 706 } 707 obfuscateInJava(byte[] key, BluetoothDevice device)708 private static byte[] obfuscateInJava(byte[] key, BluetoothDevice device) { 709 String algorithm = "HmacSHA256"; 710 try { 711 Mac hmac256 = Mac.getInstance(algorithm); 712 hmac256.init(new SecretKeySpec(key, algorithm)); 713 return hmac256.doFinal(Utils.getByteAddress(device)); 714 } catch (NoSuchAlgorithmException | IllegalStateException | InvalidKeyException exp) { 715 exp.printStackTrace(); 716 return null; 717 } 718 } 719 isByteArrayAllZero(byte[] byteArray)720 private static boolean isByteArrayAllZero(byte[] byteArray) { 721 for (byte i : byteArray) { 722 if (i != 0) { 723 return false; 724 } 725 } 726 return true; 727 } 728 729 /** 730 * Test: Get id for null address 731 * Check if returned value from {@link AdapterService#getMetricId(BluetoothDevice)} is 732 * 0 when device address is null 733 */ 734 @Test testGetMetricId_NullAddress()735 public void testGetMetricId_NullAddress() { 736 Assert.assertEquals(mAdapterService.getMetricId(null), 0); 737 } 738 739 /** 740 * Test: Get id when Bluetooth is disabled 741 * Check whether the returned value meets expectation 742 */ 743 @Test testGetMetricId_BluetoothDisabled()744 public void testGetMetricId_BluetoothDisabled() { 745 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 746 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 747 int id = mAdapterService.getMetricId(device); 748 Assert.assertTrue(id > 0); 749 } 750 751 /** 752 * Test: Get id when Bluetooth is enabled 753 * Check whether the returned value meets expectation 754 */ 755 @Test testGetMetricId_BluetoothEnabled()756 public void testGetMetricId_BluetoothEnabled() { 757 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 758 doEnable(0, false); 759 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 760 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 761 int id = mAdapterService.getMetricId(device); 762 Assert.assertTrue(id > 0); 763 } 764 765 /** 766 * Test: Check if id gotten stays the same after toggling Bluetooth 767 */ 768 @Test testGetMetricId_PersistentBetweenToggle()769 public void testGetMetricId_PersistentBetweenToggle() { 770 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 771 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 772 int id1 = mAdapterService.getMetricId(device); 773 Assert.assertTrue(id1 > 0); 774 775 // Enable 776 doEnable(0, false); 777 Assert.assertTrue(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 778 int id2 = mAdapterService.getMetricId(device); 779 Assert.assertEquals(id2, id1); 780 781 // Disable 782 doDisable(0, false); 783 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 784 int id3 = mAdapterService.getMetricId(device); 785 Assert.assertEquals(id3, id1); 786 } 787 788 /** 789 * Test: Check if id gotten stays the same after re-initializing 790 * {@link AdapterService} 791 */ 792 @Test testgetMetricId_PersistentBetweenAdapterServiceInitialization()793 public void testgetMetricId_PersistentBetweenAdapterServiceInitialization() throws 794 PackageManager.NameNotFoundException { 795 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 796 BluetoothDevice device = TestUtils.getTestDevice(BluetoothAdapter.getDefaultAdapter(), 0); 797 int id1 = mAdapterService.getMetricId(device); 798 Assert.assertTrue(id1 > 0); 799 tearDown(); 800 setUp(); 801 Assert.assertFalse(mAdapterService.getState() == BluetoothAdapter.STATE_ON); 802 int id2 = mAdapterService.getMetricId(device); 803 Assert.assertEquals(id2, id1); 804 } 805 } 806