1 /*
2  * Copyright (C) 2020 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.appsecurity.cts;
18 
19 import static android.appsecurity.cts.Utils.waitForBootCompleted;
20 
21 import static org.hamcrest.CoreMatchers.is;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.fail;
24 import static org.junit.Assume.assumeThat;
25 import static org.junit.Assume.assumeTrue;
26 
27 import com.android.tradefed.device.DeviceNotAvailableException;
28 import com.android.tradefed.device.ITestDevice;
29 import com.android.tradefed.log.LogUtil;
30 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
31 
32 import org.junit.After;
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 
37 import java.util.HashMap;
38 import java.util.Map;
39 
40 /**
41  * Set of tests that verify app data isolation works.
42  */
43 @RunWith(DeviceJUnit4ClassRunner.class)
44 public class AppDataIsolationTests extends BaseAppSecurityTest {
45 
46     private static final String APPA_APK = "CtsAppDataIsolationAppA.apk";
47     private static final String APP_SHARED_A_APK = "CtsAppDataIsolationAppSharedA.apk";
48     private static final String APP_DIRECT_BOOT_A_APK = "CtsAppDataIsolationAppDirectBootA.apk";
49     private static final String APP_API29_A_APK = "CtsAppDataIsolationAppApi29A.apk";
50     private static final String APPA_PKG = "com.android.cts.appdataisolation.appa";
51     private static final String APPA_CLASS =
52             "com.android.cts.appdataisolation.appa.AppATests";
53     private static final String APPA_METHOD_CREATE_CE_DE_DATA = "testCreateCeDeAppData";
54     private static final String APPA_METHOD_CHECK_CE_DATA_EXISTS = "testAppACeDataExists";
55     private static final String APPA_METHOD_CHECK_CE_DATA_DOES_NOT_EXIST =
56             "testAppACeDataDoesNotExist";
57     private static final String APPA_METHOD_CHECK_DE_DATA_EXISTS = "testAppADeDataExists";
58     private static final String APPA_METHOD_CHECK_DE_DATA_DOES_NOT_EXIST =
59             "testAppADeDataDoesNotExist";
60     private static final String APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE =
61             "testAppACurProfileDataAccessible";
62     private static final String APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE =
63             "testAppARefProfileDataAccessible";
64     private static final String APPA_METHOD_UNLOCK_DEVICE_AND_VERIFY_CE_DE_EXTERNAL_EXIST =
65             "testAppAUnlockDeviceAndVerifyCeDeExternalDataExist";
66     private static final String APPA_METHOD_CANNOT_ACCESS_APPB_DIR = "testCannotAccessAppBDataDir";
67 
68     private static final String APPA_METHOD_TEST_UNLOCK_DEVICE =
69             "testUnlockDevice";
70 
71     private static final String APPB_APK = "CtsAppDataIsolationAppB.apk";
72     private static final String APP_SHARED_B_APK = "CtsAppDataIsolationAppSharedB.apk";
73     private static final String APPB_PKG = "com.android.cts.appdataisolation.appb";
74     private static final String APPB_CLASS =
75             "com.android.cts.appdataisolation.appb.AppBTests";
76     private static final String APPB_METHOD_CAN_NOT_ACCESS_APPA_DIR = "testCanNotAccessAppADataDir";
77     private static final String APPB_METHOD_CAN_ACCESS_APPA_DIR = "testCanAccessAppADataDir";
78 
79     private static final String FBE_MODE_NATIVE = "native";
80     private static final String FBE_MODE_EMULATED = "emulated";
81 
82     private static final String APPA_METHOD_CREATE_EXTERNAL_DIRS = "testCreateExternalDirs";
83     private static final String APPA_METHOD_TEST_ISOLATED_PROCESS = "testIsolatedProcess";
84     private static final String APPA_METHOD_TEST_APP_ZYGOTE_ISOLATED_PROCESS =
85             "testAppZygoteIsolatedProcess";
86     private static final String APPB_METHOD_CAN_NOT_ACCESS_APPA_EXTERNAL_DIRS =
87             "testCanNotAccessAppAExternalDirs";
88     private static final String APPB_METHOD_CAN_ACCESS_APPA_EXTERNAL_DIRS =
89             "testCanAccessAppAExternalDirs";
90     private static final String APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_NOT_EXIST =
91             "testAppAExternalDirsDoNotExist";
92     private static final String APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST =
93             "testAppAExternalDirsDoExist";
94     private static final String APPA_METHOD_CHECK_EXTERNAL_DIRS_UNAVAILABLE =
95             "testAppAExternalDirsUnavailable";
96     private static final String APPA_METHOD_TEST_OTHER_USER_DIRS_NOT_PRESENT =
97             "testOtherUserDirsNotPresent";
98     private static final String APPA_METHOD_TEST_OTHER_USER_DIRS_NOT_ACCESSIBLE =
99             "testOtherUserDirsNotAccessible";
100 
101     private int mOtherUser = -1;
102 
103     @Before
setUp()104     public void setUp() throws Exception {
105         Utils.prepareSingleUser(getDevice());
106         getDevice().uninstallPackage(APPA_PKG);
107         getDevice().uninstallPackage(APPB_PKG);
108     }
109 
110     @After
tearDown()111     public void tearDown() throws Exception {
112         if (mOtherUser != -1) {
113             getDevice().removeUser(mOtherUser);
114         }
115         getDevice().uninstallPackage(APPA_PKG);
116         getDevice().uninstallPackage(APPB_PKG);
117     }
118 
119     @Test
testAppAbleToAccessItsDataAfterForceStop()120     public void testAppAbleToAccessItsDataAfterForceStop() throws Exception {
121         // Install AppA and verify no data stored
122         new InstallMultiple().addFile(APPA_APK).run();
123         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_DOES_NOT_EXIST);
124         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_DOES_NOT_EXIST);
125         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_NOT_EXIST);
126 
127         // Create data in CE, DE and external storage
128         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_CE_DE_DATA);
129         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_EXTERNAL_DIRS);
130 
131         // Verify CE, DE and external storage contains data, cur profile is accessible and ref
132         // profile is not accessible
133         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_EXISTS);
134         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
135         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
136         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
137         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
138 
139         // Force stop and verify CE, DE and external storage contains data, cur profile is
140         // accessible and ref profile is not accessible, to confirm it's binding back the same data
141         // directory, not binding to a wrong one / create a new one.
142         forceStopPackage(APPA_PKG);
143         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_EXISTS);
144         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
145         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
146         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
147         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
148     }
149 
150     @Test
testAppAbleToAccessItsDataAfterReboot()151     public void testAppAbleToAccessItsDataAfterReboot() throws Exception {
152         // Install AppA and verify no data stored
153         new InstallMultiple().addFile(APPA_APK).run();
154         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_DOES_NOT_EXIST);
155         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_DOES_NOT_EXIST);
156         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_NOT_EXIST);
157 
158         // Create data in CE, DE and external storage
159         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_CE_DE_DATA);
160         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_EXTERNAL_DIRS);
161 
162         // Verify CE, DE and external storage contains data, cur profile is accessible and ref
163         // profile is not accessible
164         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_EXISTS);
165         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
166         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
167         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
168         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
169 
170         // Reboot and verify CE, DE and external storage contains data, cur profile is accessible
171         // and ref profile is not accessible
172         reboot();
173         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_EXISTS);
174         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
175         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
176         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
177         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
178     }
179 
180     @Test
testDirectBootModeWorks()181     public void testDirectBootModeWorks() throws Exception {
182         if (!"file".equals(getDevice().getProperty("ro.crypto.type"))) {
183             LogUtil.CLog.d("Device is NOT encrypted with file-based encryption. skipping test");
184             return;
185         }
186         assumeTrue("Screen lock is not supported so skip direct boot test",
187                 hasDeviceFeature("android.software.secure_lock_screen"));
188         // Install AppA and verify no data stored
189         new InstallMultiple().addFile(APP_DIRECT_BOOT_A_APK).run();
190         new InstallMultiple().addFile(APPB_APK).run();
191         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_DOES_NOT_EXIST);
192         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_DOES_NOT_EXIST);
193         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_NOT_EXIST);
194 
195         // Create data in CE, DE and external storage
196         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_CE_DE_DATA);
197         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_EXTERNAL_DIRS);
198 
199         // Verify CE, DE and external storage contains data, cur profile is accessible and ref
200         // profile is not accessible
201         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_EXISTS);
202         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
203         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
204         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
205         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
206 
207         try {
208             // Setup screenlock
209             getDevice().executeShellCommand("settings put global require_password_to_decrypt 0");
210             getDevice().executeShellCommand("locksettings set-disabled false");
211             String response = getDevice().executeShellCommand("locksettings set-pin 12345");
212             if (!response.contains("12345")) {
213                 // This seems to fail occasionally. Try again once, then give up.
214                 Thread.sleep(500);
215                 response = getDevice().executeShellCommand("locksettings set-pin 12345");
216                 assumeTrue("Test requires setting a pin, which failed: " + response,
217                         response.contains("12345"));
218             }
219 
220             // Give enough time for vold to update keys
221             Thread.sleep(15000);
222 
223             // Follow DirectBootHostTest, reboot system into known state with keys ejected
224             if (isFbeModeEmulated()) {
225                 final String res = getDevice().executeShellCommand("sm set-emulate-fbe true");
226                 if (res != null && res.contains("Emulation not supported")) {
227                     LogUtil.CLog.i("FBE emulation is not supported, skipping test");
228                     return;
229                 }
230                 getDevice().waitForDeviceNotAvailable(30000);
231                 getDevice().waitForDeviceOnline(120000);
232             } else {
233                 getDevice().rebootUntilOnline();
234             }
235             waitForBootCompleted(getDevice());
236 
237             // Verify DE data is still readable and writeable, while CE and external data are not
238             // accessible
239             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
240             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_DOES_NOT_EXIST);
241             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_UNAVAILABLE);
242             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
243             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
244             // Verify cannot access other apps data
245             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CANNOT_ACCESS_APPB_DIR);
246 
247             // Unlock device and verify CE, DE and external data still exist, without killing the
248             // process, as test process usually will be killed after the test
249             runDeviceTests(APPA_PKG, APPA_CLASS,
250                     APPA_METHOD_UNLOCK_DEVICE_AND_VERIFY_CE_DE_EXTERNAL_EXIST);
251 
252             // Restart test app and verify CE, DE and external storage contains data, cur profile is
253             // accessible and ref profile is not accessible
254             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_EXISTS);
255             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_EXISTS);
256             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_EXIST);
257             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CUR_PROFILE_ACCESSIBLE);
258             runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_REF_PROFILE_ACCESSIBLE);
259         } finally {
260             try {
261                 // Always try to unlock first, then clear screenlock setting
262                 try {
263                     runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_TEST_UNLOCK_DEVICE);
264                 } catch (Exception e) {}
265                 getDevice().executeShellCommand("locksettings clear --old 12345");
266                 getDevice().executeShellCommand("locksettings set-disabled true");
267                 getDevice().executeShellCommand(
268                         "settings delete global require_password_to_decrypt");
269             } finally {
270                 // Get ourselves back into a known-good state
271                 if (isFbeModeEmulated()) {
272                     getDevice().executeShellCommand("sm set-emulate-fbe false");
273                     getDevice().waitForDeviceNotAvailable(30000);
274                     getDevice().waitForDeviceOnline();
275                 } else {
276                     getDevice().rebootUntilOnline();
277                 }
278                 getDevice().waitForDeviceAvailable();
279             }
280         }
281     }
282 
283     @Test
testAppNotAbleToAccessItsDataAfterReinstall()284     public void testAppNotAbleToAccessItsDataAfterReinstall() throws Exception {
285         // Install AppA create CE DE data
286         new InstallMultiple().addFile(APPA_APK).run();
287         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_CE_DE_DATA);
288         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_EXTERNAL_DIRS);
289 
290         // Reinstall AppA
291         getDevice().uninstallPackage(APPA_PKG);
292         new InstallMultiple().addFile(APPA_APK).run();
293 
294         // Verify CE, DE and external data are removed
295         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_CE_DATA_DOES_NOT_EXIST);
296         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_DE_DATA_DOES_NOT_EXIST);
297         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CHECK_EXTERNAL_DIRS_DO_NOT_EXIST);
298     }
299 
300     @Test
testNormalProcessCannotAccessOtherAppDataDir()301     public void testNormalProcessCannotAccessOtherAppDataDir() throws Exception {
302         new InstallMultiple().addFile(APPA_APK).run();
303         new InstallMultiple().addFile(APPB_APK).run();
304 
305         runDeviceTests(APPB_PKG, APPB_CLASS, APPB_METHOD_CAN_NOT_ACCESS_APPA_DIR);
306     }
307 
308     @Test
testSharedAppAbleToAccessOtherAppDataDir()309     public void testSharedAppAbleToAccessOtherAppDataDir() throws Exception {
310         new InstallMultiple().addFile(APP_SHARED_A_APK).run();
311         new InstallMultiple().addFile(APP_SHARED_B_APK).run();
312 
313         runDeviceTests(APPB_PKG, APPB_CLASS, APPB_METHOD_CAN_ACCESS_APPA_DIR);
314     }
315 
316     @Test
testNormalProcessCannotAccessOtherAppExternalDataDir()317     public void testNormalProcessCannotAccessOtherAppExternalDataDir() throws Exception {
318         assumeThatFuseDataIsolationIsEnabled(getDevice());
319 
320         new InstallMultiple().addFile(APPA_APK).run();
321         new InstallMultiple().addFile(APPB_APK).run();
322 
323         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_EXTERNAL_DIRS);
324         runDeviceTests(APPB_PKG, APPB_CLASS, APPB_METHOD_CAN_NOT_ACCESS_APPA_EXTERNAL_DIRS);
325     }
326 
327     @Test
testSharedAppAbleToAccessOtherAppExternalDataDir()328     public void testSharedAppAbleToAccessOtherAppExternalDataDir() throws Exception {
329         new InstallMultiple().addFile(APP_SHARED_A_APK).run();
330         new InstallMultiple().addFile(APP_SHARED_B_APK).run();
331 
332         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_CREATE_EXTERNAL_DIRS);
333         runDeviceTests(APPB_PKG, APPB_CLASS, APPB_METHOD_CAN_ACCESS_APPA_EXTERNAL_DIRS);
334     }
335 
336     @Test
testIsolatedProcess()337     public void testIsolatedProcess() throws Exception {
338         new InstallMultiple().addFile(APPA_APK).run();
339         new InstallMultiple().addFile(APPB_APK).run();
340         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_TEST_ISOLATED_PROCESS);
341     }
342 
343     @Test
testAppZygoteIsolatedProcess()344     public void testAppZygoteIsolatedProcess() throws Exception {
345         new InstallMultiple().addFile(APPA_APK).run();
346         new InstallMultiple().addFile(APPB_APK).run();
347         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_TEST_APP_ZYGOTE_ISOLATED_PROCESS);
348     }
349 
350     @Test
testAppUnableToAccessOtherUserAppDataDir()351     public void testAppUnableToAccessOtherUserAppDataDir() throws Exception {
352         assumeCanCreateUser();
353         mOtherUser = getDevice().createUser("other_user");
354 
355         // For targetSdk > 29, directories related to other users are not visible at all.
356         new InstallMultiple().addFile(APPA_APK).run();
357         new InstallMultiple().addFile(APPB_APK).run();
358         getDevice().startUser(mOtherUser, true /* wait */);
359         installExistingAppAsUser(APPB_PKG, mOtherUser);
360 
361         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_TEST_OTHER_USER_DIRS_NOT_PRESENT,
362                 makeOtherUserIdArgs(mOtherUser));
363     }
364 
365     @Test
testAppUnableToAccessOtherUserAppDataDirApi29()366     public void testAppUnableToAccessOtherUserAppDataDirApi29() throws Exception {
367         assumeCanCreateUser();
368         mOtherUser = getDevice().createUser("other_user");
369 
370         // For targetSdk <= 29, directories related to other users are visible but we cannot
371         // access anything within them.
372         new InstallMultiple().addFile(APP_API29_A_APK).run();
373         new InstallMultiple().addFile(APPB_APK).run();
374         getDevice().startUser(mOtherUser, true /* wait */);
375         installExistingAppAsUser(APPB_PKG, mOtherUser);
376 
377         runDeviceTests(APPA_PKG, APPA_CLASS, APPA_METHOD_TEST_OTHER_USER_DIRS_NOT_ACCESSIBLE,
378                 makeOtherUserIdArgs(mOtherUser));
379     }
380 
assumeCanCreateUser()381     private void assumeCanCreateUser() throws DeviceNotAvailableException {
382         assumeTrue("Test requires multi-user support", mSupportsMultiUser);
383         // If we're already at the user limit, e.g. when running the test in a secondary user,
384         // then we can't create another one.
385         int currentUserCount = getDevice().listUsers().size();
386         assumeTrue("Test requires creating another user",
387                 getDevice().getMaxNumberOfUsersSupported() > currentUserCount);
388     }
389 
runDeviceTests(String pkgName, String testClassName, String testMethodName, Map<String, String> instrumentationArgs)390     private void runDeviceTests(String pkgName, String testClassName, String testMethodName,
391             Map<String, String> instrumentationArgs) throws DeviceNotAvailableException {
392         runDeviceTests(getDevice(), null, pkgName, testClassName, testMethodName, null,
393                 10 * 60 * 1000L, 10 * 60 * 1000L, 0L, true, false, instrumentationArgs);
394     }
395 
makeOtherUserIdArgs(int otherUser)396     private Map<String, String> makeOtherUserIdArgs(int otherUser) {
397         Map<String, String> args = new HashMap<>();
398         args.put("other_user_id", Integer.toString(otherUser));
399         return args;
400     }
401 
forceStopPackage(String packageName)402     private void forceStopPackage(String packageName) throws Exception {
403         getDevice().executeShellCommand("am force-stop " + packageName);
404     }
405 
reboot()406     private void reboot() throws Exception {
407         getDevice().reboot();
408         waitForBootCompleted(getDevice());
409     }
410 
installExistingAppAsUser(String packageName, int userId)411     private void installExistingAppAsUser(String packageName, int userId) throws Exception {
412         final String installString =
413                 "Package " + packageName + " installed for user: " + userId + "\n";
414         assertEquals(installString, getDevice().executeShellCommand(
415                 "cmd package install-existing --full"
416                         + " --user " + Integer.toString(userId)
417                         + " " + packageName));
418     }
419 
assumeThatFuseDataIsolationIsEnabled(ITestDevice device)420     private static void assumeThatFuseDataIsolationIsEnabled(ITestDevice device)
421             throws DeviceNotAvailableException {
422         assumeThat(device.executeShellCommand(
423                 "getprop persist.sys.vold_app_data_isolation_enabled").trim(),
424                 is("true"));
425     }
426 
isFbeModeEmulated()427     private boolean isFbeModeEmulated() throws Exception {
428         String mode = getDevice().executeShellCommand("sm get-fbe-mode").trim();
429         if (mode.equals(FBE_MODE_EMULATED)) {
430             return true;
431         } else if (mode.equals(FBE_MODE_NATIVE)) {
432             return false;
433         }
434         fail("Unknown FBE mode: " + mode);
435         return false;
436     }
437 }
438