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.Matchers.anyInt; 21 import static org.mockito.Mockito.doReturn; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.timeout; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.app.AlarmManager; 28 import android.bluetooth.BluetoothAdapter; 29 import android.bluetooth.IBluetoothCallback; 30 import android.content.Context; 31 import android.content.pm.ApplicationInfo; 32 import android.content.pm.PackageManager; 33 import android.content.res.Resources; 34 import android.media.AudioManager; 35 import android.os.Binder; 36 import android.os.Looper; 37 import android.os.PowerManager; 38 import android.os.Process; 39 import android.os.SystemProperties; 40 import android.os.UserManager; 41 import android.support.test.InstrumentationRegistry; 42 import android.support.test.filters.MediumTest; 43 import android.support.test.runner.AndroidJUnit4; 44 import android.test.mock.MockContentResolver; 45 46 import com.android.bluetooth.R; 47 48 import org.junit.After; 49 import org.junit.Assert; 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 56 @MediumTest 57 @RunWith(AndroidJUnit4.class) 58 public class AdapterServiceTest { 59 private AdapterService mAdapterService; 60 61 private @Mock Context mMockContext; 62 private @Mock ApplicationInfo mMockApplicationInfo; 63 private @Mock AlarmManager mMockAlarmManager; 64 private @Mock Resources mMockResources; 65 private @Mock UserManager mMockUserManager; 66 private @Mock ProfileService mMockGattService; 67 private @Mock ProfileService mMockService; 68 private @Mock ProfileService mMockService2; 69 private @Mock IBluetoothCallback mIBluetoothCallback; 70 private @Mock Binder mBinder; 71 private @Mock AudioManager mAudioManager; 72 73 private static final int CONTEXT_SWITCH_MS = 100; 74 private static final int ONE_SECOND_MS = 1000; 75 private static final int NATIVE_INIT_MS = 8000; 76 77 private PowerManager mPowerManager; 78 private PackageManager mMockPackageManager; 79 private MockContentResolver mMockContentResolver; 80 81 @Before setUp()82 public void setUp() throws PackageManager.NameNotFoundException { 83 if (Looper.myLooper() == null) { 84 Looper.prepare(); 85 } 86 Assert.assertNotNull(Looper.myLooper()); 87 88 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 89 @Override 90 public void run() { 91 mAdapterService = new AdapterService(); 92 } 93 }); 94 mMockPackageManager = mock(PackageManager.class); 95 mMockContentResolver = new MockContentResolver(mMockContext); 96 MockitoAnnotations.initMocks(this); 97 mPowerManager = (PowerManager) InstrumentationRegistry.getTargetContext() 98 .getSystemService(Context.POWER_SERVICE); 99 100 when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo); 101 when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); 102 when(mMockContext.getApplicationContext()).thenReturn(mMockContext); 103 when(mMockContext.getResources()).thenReturn(mMockResources); 104 when(mMockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID); 105 when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); 106 when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager); 107 when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager); 108 when(mMockContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mMockAlarmManager); 109 when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager); 110 111 when(mMockResources.getBoolean(R.bool.profile_supported_gatt)).thenReturn(true); 112 when(mMockResources.getBoolean(R.bool.profile_supported_pbap)).thenReturn(true); 113 when(mMockResources.getBoolean(R.bool.profile_supported_pan)).thenReturn(true); 114 115 when(mIBluetoothCallback.asBinder()).thenReturn(mBinder); 116 117 doReturn(Process.BLUETOOTH_UID).when(mMockPackageManager) 118 .getPackageUidAsUser(any(), anyInt(), anyInt()); 119 120 when(mMockGattService.getName()).thenReturn("GattService"); 121 when(mMockService.getName()).thenReturn("Service1"); 122 when(mMockService2.getName()).thenReturn("Service2"); 123 124 // Attach a context to the service for permission checks. 125 mAdapterService.attach(mMockContext, null, null, null, null, null); 126 127 mAdapterService.onCreate(); 128 mAdapterService.registerCallback(mIBluetoothCallback); 129 130 Config.init(mMockContext); 131 } 132 133 @After tearDown()134 public void tearDown() { 135 mAdapterService.unregisterCallback(mIBluetoothCallback); 136 mAdapterService.cleanup(); 137 Config.init(InstrumentationRegistry.getTargetContext()); 138 } 139 verifyStateChange(int prevState, int currState, int callNumber, int timeoutMs)140 private void verifyStateChange(int prevState, int currState, int callNumber, int timeoutMs) { 141 try { 142 verify(mIBluetoothCallback, timeout(timeoutMs) 143 .times(callNumber)).onBluetoothStateChange(prevState, currState); 144 } catch (Exception e) { 145 // the mocked onBluetoothStateChange doesn't throw exceptions 146 } 147 } 148 doEnable(int invocationNumber, boolean onlyGatt)149 private void doEnable(int invocationNumber, boolean onlyGatt) { 150 Assert.assertFalse(mAdapterService.isEnabled()); 151 152 final int startServiceCalls = 2 * (onlyGatt ? 1 : 3); // Start and stop GATT + 2 153 154 mAdapterService.enable(); 155 156 verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON, 157 invocationNumber + 1, CONTEXT_SWITCH_MS); 158 159 // Start GATT 160 verify(mMockContext, timeout(CONTEXT_SWITCH_MS).times( 161 startServiceCalls * invocationNumber + 1)).startService(any()); 162 mAdapterService.addProfile(mMockGattService); 163 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_ON); 164 165 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, BluetoothAdapter.STATE_BLE_ON, 166 invocationNumber + 1, NATIVE_INIT_MS); 167 168 mAdapterService.onLeServiceUp(); 169 170 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_TURNING_ON, 171 invocationNumber + 1, CONTEXT_SWITCH_MS); 172 173 if (!onlyGatt) { 174 // Start Mock PBAP and PAN services 175 verify(mMockContext, timeout(ONE_SECOND_MS).times( 176 startServiceCalls * invocationNumber + 3)).startService(any()); 177 mAdapterService.addProfile(mMockService); 178 mAdapterService.addProfile(mMockService2); 179 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_ON); 180 mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_ON); 181 } 182 183 verifyStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_ON, 184 invocationNumber + 1, CONTEXT_SWITCH_MS); 185 186 final int scanMode = mAdapterService.getScanMode(); 187 Assert.assertTrue(scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE 188 || scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE); 189 Assert.assertTrue(mAdapterService.isEnabled()); 190 } 191 doDisable(int invocationNumber, boolean onlyGatt)192 private void doDisable(int invocationNumber, boolean onlyGatt) { 193 Assert.assertTrue(mAdapterService.isEnabled()); 194 195 final int startServiceCalls = 2 * (onlyGatt ? 1 : 3); // Start and stop GATT + 2 196 197 mAdapterService.disable(); 198 199 verifyStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF, 200 invocationNumber + 1, CONTEXT_SWITCH_MS); 201 202 if (!onlyGatt) { 203 // Stop PBAP and PAN 204 verify(mMockContext, timeout(ONE_SECOND_MS).times( 205 startServiceCalls * invocationNumber + 5)).startService(any()); 206 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 207 mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_OFF); 208 } 209 210 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_BLE_ON, 211 invocationNumber + 1, CONTEXT_SWITCH_MS); 212 213 mAdapterService.onBrEdrDown(); 214 215 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_BLE_TURNING_OFF, 216 invocationNumber + 1, CONTEXT_SWITCH_MS); 217 218 // Stop GATT 219 verify(mMockContext, timeout(ONE_SECOND_MS).times( 220 startServiceCalls * invocationNumber + startServiceCalls)).startService(any()); 221 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_OFF); 222 223 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 224 invocationNumber + 1, CONTEXT_SWITCH_MS); 225 226 Assert.assertFalse(mAdapterService.isEnabled()); 227 } 228 229 /** 230 * Test: Turn Bluetooth on. 231 * Check whether the AdapterService gets started. 232 */ 233 @Test testEnable()234 public void testEnable() { 235 doEnable(0, false); 236 } 237 238 /** 239 * Test: Turn Bluetooth on/off. 240 * Check whether the AdapterService gets started and stopped. 241 */ 242 @Test testEnableDisable()243 public void testEnableDisable() { 244 doEnable(0, false); 245 doDisable(0, false); 246 } 247 248 /** 249 * Test: Turn Bluetooth on/off with only GATT supported. 250 * Check whether the AdapterService gets started and stopped. 251 */ 252 @Test testEnableDisableOnlyGatt()253 public void testEnableDisableOnlyGatt() { 254 Context mockContext = mock(Context.class); 255 Resources mockResources = mock(Resources.class); 256 257 when(mockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo); 258 when(mockContext.getContentResolver()).thenReturn(mMockContentResolver); 259 when(mockContext.getApplicationContext()).thenReturn(mockContext); 260 when(mockContext.getResources()).thenReturn(mockResources); 261 when(mockContext.getUserId()).thenReturn(Process.BLUETOOTH_UID); 262 when(mockContext.getPackageManager()).thenReturn(mMockPackageManager); 263 when(mockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager); 264 when(mockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mPowerManager); 265 when(mockContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mMockAlarmManager); 266 267 when(mockResources.getBoolean(R.bool.profile_supported_gatt)).thenReturn(true); 268 269 Config.init(mockContext); 270 doEnable(0, true); 271 doDisable(0, true); 272 } 273 274 /** 275 * Test: Don't start GATT 276 * Check whether the AdapterService quits gracefully 277 */ 278 @Test testGattStartTimeout()279 public void testGattStartTimeout() { 280 Assert.assertFalse(mAdapterService.isEnabled()); 281 282 mAdapterService.enable(); 283 284 verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON, 1, 285 CONTEXT_SWITCH_MS); 286 287 // Start GATT 288 verify(mMockContext, timeout(CONTEXT_SWITCH_MS).times(1)).startService(any()); 289 mAdapterService.addProfile(mMockGattService); 290 291 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, 292 BluetoothAdapter.STATE_BLE_TURNING_OFF, 1, 293 AdapterState.BLE_START_TIMEOUT_DELAY + CONTEXT_SWITCH_MS); 294 295 // Stop GATT 296 verify(mMockContext, timeout(AdapterState.BLE_STOP_TIMEOUT_DELAY + CONTEXT_SWITCH_MS) 297 .times(2)).startService(any()); 298 299 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 1, 300 CONTEXT_SWITCH_MS); 301 302 Assert.assertFalse(mAdapterService.isEnabled()); 303 } 304 305 /** 306 * Test: Don't stop GATT 307 * Check whether the AdapterService quits gracefully 308 */ 309 @Test testGattStopTimeout()310 public void testGattStopTimeout() { 311 doEnable(0, false); 312 Assert.assertTrue(mAdapterService.isEnabled()); 313 314 mAdapterService.disable(); 315 316 verifyStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF, 1, 317 CONTEXT_SWITCH_MS); 318 319 // Stop PBAP and PAN 320 verify(mMockContext, timeout(ONE_SECOND_MS).times(5)).startService(any()); 321 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 322 mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_OFF); 323 324 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_BLE_ON, 1, 325 CONTEXT_SWITCH_MS); 326 327 mAdapterService.onBrEdrDown(); 328 329 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_BLE_TURNING_OFF, 1, 330 CONTEXT_SWITCH_MS); 331 332 // Stop GATT 333 verify(mMockContext, timeout(ONE_SECOND_MS).times(6)).startService(any()); 334 335 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 1, 336 AdapterState.BLE_STOP_TIMEOUT_DELAY + CONTEXT_SWITCH_MS); 337 338 Assert.assertFalse(mAdapterService.isEnabled()); 339 } 340 341 /** 342 * Test: Don't start a classic profile 343 * Check whether the AdapterService quits gracefully 344 */ 345 @Test testProfileStartTimeout()346 public void testProfileStartTimeout() { 347 Assert.assertFalse(mAdapterService.isEnabled()); 348 349 mAdapterService.enable(); 350 351 verifyStateChange(BluetoothAdapter.STATE_OFF, BluetoothAdapter.STATE_BLE_TURNING_ON, 1, 352 CONTEXT_SWITCH_MS); 353 354 // Start GATT 355 verify(mMockContext, timeout(CONTEXT_SWITCH_MS).times(1)).startService(any()); 356 mAdapterService.addProfile(mMockGattService); 357 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_ON); 358 359 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON, BluetoothAdapter.STATE_BLE_ON, 1, 360 NATIVE_INIT_MS); 361 362 mAdapterService.onLeServiceUp(); 363 364 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_TURNING_ON, 1, 365 CONTEXT_SWITCH_MS); 366 367 // Register Mock PBAP and PAN services, only start one 368 verify(mMockContext, timeout(ONE_SECOND_MS).times(3)).startService(any()); 369 mAdapterService.addProfile(mMockService); 370 mAdapterService.addProfile(mMockService2); 371 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_ON); 372 373 verifyStateChange(BluetoothAdapter.STATE_TURNING_ON, BluetoothAdapter.STATE_TURNING_OFF, 1, 374 AdapterState.BREDR_START_TIMEOUT_DELAY + CONTEXT_SWITCH_MS); 375 376 // Stop PBAP and PAN 377 verify(mMockContext, timeout(ONE_SECOND_MS).times(5)).startService(any()); 378 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 379 380 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_BLE_ON, 1, 381 CONTEXT_SWITCH_MS); 382 } 383 384 /** 385 * Test: Don't stop a classic profile 386 * Check whether the AdapterService quits gracefully 387 */ 388 @Test testProfileStopTimeout()389 public void testProfileStopTimeout() { 390 doEnable(0, false); 391 392 Assert.assertTrue(mAdapterService.isEnabled()); 393 394 mAdapterService.disable(); 395 396 verifyStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF, 1, 397 CONTEXT_SWITCH_MS); 398 399 // Stop PBAP and PAN 400 verify(mMockContext, timeout(ONE_SECOND_MS).times(5)).startService(any()); 401 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 402 403 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, 404 BluetoothAdapter.STATE_BLE_TURNING_OFF, 1, 405 AdapterState.BREDR_STOP_TIMEOUT_DELAY + CONTEXT_SWITCH_MS); 406 407 // Stop GATT 408 verify(mMockContext, timeout(ONE_SECOND_MS).times(6)).startService(any()); 409 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_OFF); 410 411 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 1, 412 AdapterState.BLE_STOP_TIMEOUT_DELAY + CONTEXT_SWITCH_MS); 413 414 Assert.assertFalse(mAdapterService.isEnabled()); 415 } 416 417 /** 418 * Test: Toggle snoop logging setting 419 * Check whether the AdapterService restarts fully 420 */ 421 @Test testSnoopLoggingChange()422 public void testSnoopLoggingChange() { 423 String snoopSetting = 424 SystemProperties.get(AdapterService.BLUETOOTH_BTSNOOP_ENABLE_PROPERTY, ""); 425 SystemProperties.set(AdapterService.BLUETOOTH_BTSNOOP_ENABLE_PROPERTY, "false"); 426 doEnable(0, false); 427 428 Assert.assertTrue(mAdapterService.isEnabled()); 429 430 Assert.assertFalse( 431 SystemProperties.getBoolean(AdapterService.BLUETOOTH_BTSNOOP_ENABLE_PROPERTY, 432 true)); 433 434 SystemProperties.set(AdapterService.BLUETOOTH_BTSNOOP_ENABLE_PROPERTY, "true"); 435 436 mAdapterService.disable(); 437 438 verifyStateChange(BluetoothAdapter.STATE_ON, BluetoothAdapter.STATE_TURNING_OFF, 1, 439 CONTEXT_SWITCH_MS); 440 441 // Stop PBAP and PAN 442 verify(mMockContext, timeout(ONE_SECOND_MS).times(5)).startService(any()); 443 mAdapterService.onProfileServiceStateChanged(mMockService, BluetoothAdapter.STATE_OFF); 444 mAdapterService.onProfileServiceStateChanged(mMockService2, BluetoothAdapter.STATE_OFF); 445 446 verifyStateChange(BluetoothAdapter.STATE_TURNING_OFF, BluetoothAdapter.STATE_BLE_ON, 1, 447 CONTEXT_SWITCH_MS); 448 449 // Don't call onBrEdrDown(). The Adapter should turn itself off. 450 451 verifyStateChange(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_BLE_TURNING_OFF, 1, 452 CONTEXT_SWITCH_MS); 453 454 // Stop GATT 455 verify(mMockContext, timeout(ONE_SECOND_MS).times(6)).startService(any()); 456 mAdapterService.onProfileServiceStateChanged(mMockGattService, BluetoothAdapter.STATE_OFF); 457 458 verifyStateChange(BluetoothAdapter.STATE_BLE_TURNING_OFF, BluetoothAdapter.STATE_OFF, 1, 459 CONTEXT_SWITCH_MS); 460 461 Assert.assertFalse(mAdapterService.isEnabled()); 462 463 // Restore earlier setting 464 SystemProperties.set(AdapterService.BLUETOOTH_BTSNOOP_ENABLE_PROPERTY, snoopSetting); 465 } 466 } 467