• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 android.security.cts.TestBluetoothDiscoverable;
18 
19 import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
20 import static android.provider.SettingsSlicesContract.AUTHORITY;
21 
22 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
23 
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assume.assumeNoException;
26 import static org.junit.Assume.assumeTrue;
27 
28 import android.app.Instrumentation;
29 import android.app.KeyguardManager;
30 import android.app.UiAutomation;
31 import android.bluetooth.BluetoothAdapter;
32 import android.content.BroadcastReceiver;
33 import android.content.ComponentName;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.IntentFilter;
37 import android.content.res.Resources;
38 import android.net.Uri;
39 import android.os.PowerManager;
40 import android.provider.Settings;
41 
42 import androidx.test.runner.AndroidJUnit4;
43 import androidx.test.uiautomator.By;
44 import androidx.test.uiautomator.UiDevice;
45 import androidx.test.uiautomator.Until;
46 
47 import org.junit.After;
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 
52 import java.util.concurrent.Semaphore;
53 import java.util.concurrent.TimeUnit;
54 
55 @RunWith(AndroidJUnit4.class)
56 public class DeviceTest {
57     private static Context sContext;
58     private BluetoothAdapter mBtAdapter;
59     private BroadcastReceiver mBroadcastReceiver;
60     private Instrumentation mInstrumentation;
61     private Resources mResources;
62     private Semaphore mBroadcastReceived;
63     private String mErrorMessage;
64     private UiAutomation mUiAutomation;
65     private UiDevice mDevice;
66     private boolean mBtState;
67     private int mStatusCode;
68 
69     @Before
setUp()70     public void setUp() {
71         try {
72             mInstrumentation = getInstrumentation();
73             sContext = mInstrumentation.getTargetContext();
74             mBroadcastReceived = new Semaphore(0);
75             mBtState = false;
76             mResources = sContext.getResources();
77             mBtAdapter = BluetoothAdapter.getDefaultAdapter();
78             mStatusCode = mResources.getInteger(R.integer.assumptionFailure);
79             mErrorMessage = "";
80 
81             // Register BroadcastReceiver to receive status from PocActivity
82             mBroadcastReceiver = new BroadcastReceiver() {
83                 @Override
84                 public void onReceive(Context context, Intent intent) {
85                     try {
86                         if (intent.getAction()
87                                 .equals(mResources.getString(R.string.broadcastAction))) {
88                             mStatusCode =
89                                     intent.getIntExtra(mResources.getString(R.string.resultKey),
90                                             mResources.getInteger(R.integer.assumptionFailure));
91                             mErrorMessage = intent
92                                     .getStringExtra(mResources.getString(R.string.messageKey));
93                             mBroadcastReceived.release();
94                         }
95                     } catch (Exception ignored) {
96                         // Ignore exceptions here
97                     }
98                 }
99             };
100             IntentFilter filter = new IntentFilter();
101             filter.addAction(sContext.getString(R.string.broadcastAction));
102             sContext.registerReceiver(mBroadcastReceiver, filter);
103 
104             // Save the state of bluetooth adapter to reset after the test
105             mBtState = mBtAdapter.isEnabled();
106 
107             // Disable bluetooth if already enabled in 'SCAN_MODE_CONNECTABLE_DISCOVERABLE' mode
108             if (mBtAdapter.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
109                 switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
110             }
111 
112             // Enable bluetooth if in disabled state
113             switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_ENABLE);
114 
115             // 'MODIFY_PHONE_STATE' permission is required to launch target Settings app activity
116             mUiAutomation = mInstrumentation.getUiAutomation();
117             mUiAutomation
118                     .adoptShellPermissionIdentity(android.Manifest.permission.MODIFY_PHONE_STATE);
119         } catch (Exception e) {
120             assumeNoException(e);
121         }
122     }
123 
124     @After
tearDown()125     public void tearDown() {
126         try {
127             mUiAutomation.dropShellPermissionIdentity();
128             // Disable bluetooth if it was OFF before the test
129             if (!mBtState) {
130                 switchBluetoothMode(BluetoothAdapter.ACTION_REQUEST_DISABLE);
131             }
132             sContext.unregisterReceiver(mBroadcastReceiver);
133         } catch (Exception e) {
134             // Ignore exceptions here
135         }
136     }
137 
138     @Test
testConnectedDeviceDashboardFragment()139     public void testConnectedDeviceDashboardFragment() {
140         try {
141             // Check if device is unlocked
142             PowerManager powerManager = sContext.getSystemService(PowerManager.class);
143             KeyguardManager keyguardManager = sContext.getSystemService(KeyguardManager.class);
144             assumeTrue(sContext.getString(R.string.msgDeviceLocked),
145                     powerManager.isInteractive() && !keyguardManager.isKeyguardLocked());
146 
147             // Check if bluetooth is enabled. The test requires bluetooth to be enabled
148             assumeTrue(mBtAdapter.isEnabled());
149 
150             // Check if bluetooth mode is not set to SCAN_MODE_CONNECTABLE_DISCOVERABLE
151             assumeTrue(mBtAdapter.getScanMode() != SCAN_MODE_CONNECTABLE_DISCOVERABLE);
152 
153             // Launch bluetooth settings which is supposed to set scan mode to
154             // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is present
155             String settingsPkg = getSettingsPkgName();
156             Intent intent = new Intent();
157             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
158             intent.setData(Uri.parse(
159                     sContext.getString(R.string.sliceConnectedDevicesDashboardUri, settingsPkg)));
160             intent.setClassName(settingsPkg,
161                     sContext.getString(R.string.sliceDeepLinkSpringBoardClassName, settingsPkg));
162             sContext.startActivity(intent);
163 
164             // Wait until target activity from settings package is launched
165             mDevice = UiDevice.getInstance(mInstrumentation);
166             assumeTrue(mDevice.wait(Until.hasObject(By.pkg(settingsPkg)),
167                     mResources.getInteger(R.integer.timeoutMs)));
168 
169             // Test fails if bluetooth is made discoverable through PoC
170             boolean isBtDiscoverable =
171                     (mBtAdapter.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE);
172             assertFalse(sContext.getString(R.string.msgFailConnectedDeviceDashboardFragment),
173                     isBtDiscoverable);
174         } catch (Exception e) {
175             assumeNoException(e);
176         }
177     }
178 
179     @Test
testBluetoothDashboardFragment()180     public void testBluetoothDashboardFragment() {
181         try {
182             // Check if device is unlocked
183             PowerManager powerManager = sContext.getSystemService(PowerManager.class);
184             KeyguardManager keyguardManager = sContext.getSystemService(KeyguardManager.class);
185             assumeTrue(sContext.getString(R.string.msgDeviceLocked),
186                     powerManager.isInteractive() && !keyguardManager.isKeyguardLocked());
187 
188             // Check if bluetooth is enabled. The test requires bluetooth to be enabled
189             assumeTrue(mBtAdapter.isEnabled());
190 
191             // Check if bluetooth mode is not set to SCAN_MODE_CONNECTABLE_DISCOVERABLE
192             assumeTrue(mBtAdapter.getScanMode() != SCAN_MODE_CONNECTABLE_DISCOVERABLE);
193 
194             // Launch bluetooth settings which is supposed to set scan mode to
195             // SCAN_MODE_CONNECTABLE_DISCOVERABLE if vulnerability is present
196             String settingsPkg = getSettingsPkgName();
197             Intent intent = new Intent();
198             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
199             intent.setData(Uri.parse(sContext.getString(R.string.sliceBluetoothDashboardUri,
200                     settingsPkg, AUTHORITY)));
201             sContext.startActivity(intent);
202 
203             // Wait until target activity from settings package is launched
204             mDevice = UiDevice.getInstance(mInstrumentation);
205             assumeTrue(mDevice.wait(Until.hasObject(By.pkg(settingsPkg)),
206                     mResources.getInteger(R.integer.timeoutMs)));
207 
208             // Test fails if bluetooth is made discoverable through PoC
209             boolean isBtDiscoverable =
210                     (mBtAdapter.getScanMode() == SCAN_MODE_CONNECTABLE_DISCOVERABLE);
211             assertFalse(sContext.getString(R.string.msgFailBluetoothDashboardFragment),
212                     isBtDiscoverable);
213         } catch (Exception e) {
214             assumeNoException(e);
215         }
216     }
217 
218 
getSettingsPkgName()219     public static String getSettingsPkgName() {
220         // Retrieve settings package name dynamically
221         Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
222         ComponentName settingsComponent =
223                 settingsIntent.resolveActivity(sContext.getPackageManager());
224         String pkgName = settingsComponent != null ? settingsComponent.getPackageName()
225                 : sContext.getString(R.string.defaultSettingsPkg);
226         return pkgName;
227     }
228 
switchBluetoothMode(String action)229     private void switchBluetoothMode(String action) throws Exception {
230         // Start PocActivity to switch bluetooth mode
231         Intent intent = new Intent(sContext, PocActivity.class);
232         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
233         intent.putExtra(sContext.getString(R.string.btAction), action);
234         sContext.startActivity(intent);
235 
236         // Wait until bluetooth mode switch is completed successfully
237         assumeTrue(mBroadcastReceived.tryAcquire(mResources.getInteger(R.integer.timeoutMs),
238                 TimeUnit.MILLISECONDS));
239         assumeTrue(mErrorMessage,
240                 mStatusCode != mResources.getInteger(R.integer.assumptionFailure));
241     }
242 }
243