• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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