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