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