1 /*
2  * Copyright (C) 2015 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 org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 
25 import android.platform.test.annotations.Presubmit;
26 
27 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
28 import com.android.ddmlib.Log;
29 import com.android.tradefed.device.DeviceNotAvailableException;
30 import com.android.tradefed.device.ITestDevice;
31 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
32 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
33 import com.android.tradefed.util.AbiUtils;
34 import com.android.tradefed.util.RunUtil;
35 
36 import org.junit.After;
37 import org.junit.Assume;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 import java.io.File;
43 import java.io.FileNotFoundException;
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 /**
48  * Set of tests that verify behavior of external storage devices.
49  */
50 @Presubmit
51 @RunWith(DeviceJUnit4ClassRunner.class)
52 public class ExternalStorageHostTest extends BaseHostJUnit4Test {
53     private static final String TAG = "ExternalStorageHostTest";
54 
55     private static class Config {
56         public final String apk;
57         public final String pkg;
58         public final String clazz;
59 
Config(String apk, String pkg, String clazz)60         public Config(String apk, String pkg, String clazz) {
61             this.apk = apk;
62             this.pkg = pkg;
63             this.clazz = clazz;
64         }
65     }
66 
67     private static final String COMMON_CLASS =
68             "com.android.cts.externalstorageapp.CommonExternalStorageTest";
69 
70     private static final String NONE_APK = "CtsExternalStorageApp.apk";
71     private static final String NONE_PKG = "com.android.cts.externalstorageapp";
72     private static final String NONE_CLASS = NONE_PKG + ".ExternalStorageTest";
73     private static final String READ_APK = "CtsReadExternalStorageApp.apk";
74     private static final String READ_PKG = "com.android.cts.readexternalstorageapp";
75     private static final String READ_CLASS = READ_PKG + ".ReadExternalStorageTest";
76     private static final String WRITE_APK = "CtsWriteExternalStorageApp.apk";
77     private static final String WRITE_PKG = "com.android.cts.writeexternalstorageapp";
78     private static final String WRITE_CLASS = WRITE_PKG + ".WriteExternalStorageTest";
79     private static final String WRITE_APK_2 = "CtsWriteExternalStorageApp2.apk";
80     private static final String WRITE_PKG_2 = "com.android.cts.writeexternalstorageapp2";
81     private static final String MULTIUSER_APK = "CtsMultiUserStorageApp.apk";
82     private static final String MULTIUSER_PKG = "com.android.cts.multiuserstorageapp";
83     private static final String MULTIUSER_CLASS = MULTIUSER_PKG + ".MultiUserStorageTest";
84 
85     private static final String MEDIA_CLAZZ = "com.android.cts.mediastorageapp.MediaStorageTest";
86 
87     private static final Config MEDIA = new Config("CtsMediaStorageApp.apk",
88             "com.android.cts.mediastorageapp", MEDIA_CLAZZ);
89     private static final Config MEDIA_28 = new Config("CtsMediaStorageApp28.apk",
90             "com.android.cts.mediastorageapp28", MEDIA_CLAZZ);
91     private static final Config MEDIA_29 = new Config("CtsMediaStorageApp29.apk",
92             "com.android.cts.mediastorageapp29", MEDIA_CLAZZ);
93     private static final Config MEDIA_31 = new Config("CtsMediaStorageApp31.apk",
94             "com.android.cts.mediastorageapp31", MEDIA_CLAZZ);
95 
96     private static final String PERM_ACCESS_MEDIA_LOCATION =
97             "android.permission.ACCESS_MEDIA_LOCATION";
98     private static final String PERM_READ_EXTERNAL_STORAGE =
99             "android.permission.READ_EXTERNAL_STORAGE";
100     private static final String PERM_READ_MEDIA_IMAGES =
101             "android.permission.READ_MEDIA_IMAGES";
102     private static final String PERM_READ_MEDIA_AUDIO =
103             "android.permission.READ_MEDIA_AUDIO";
104     private static final String PERM_READ_MEDIA_VIDEO =
105             "android.permission.READ_MEDIA_VIDEO";
106     private static final String PERM_READ_MEDIA_VISUAL_USER_SELECTED =
107             "android.permission.READ_MEDIA_VISUAL_USER_SELECTED";
108     private static final String PERM_WRITE_EXTERNAL_STORAGE =
109             "android.permission.WRITE_EXTERNAL_STORAGE";
110 
111     private static final String APP_OPS_MANAGE_EXTERNAL_STORAGE = "android:manage_external_storage";
112     private static final String APP_OPS_MANAGE_MEDIA = "android:manage_media";
113 
114     /** Copied from PackageManager*/
115     private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
116     private static final String FEATURE_EMBEDDED = "android.hardware.type.embedded";
117     private static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
118     private static final String FEATURE_WATCH = "android.hardware.type.watch";
119 
120     private int[] mUsers;
121     private boolean mAdbWasRoot;
122 
getTestAppFile(String fileName)123     private File getTestAppFile(String fileName) throws FileNotFoundException {
124         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
125         return buildHelper.getTestFile(fileName);
126     }
127 
128     @Before
setUp()129     public void setUp() throws Exception {
130         mUsers = Utils.prepareMultipleUsers(getDevice());
131         assertNotNull(getAbi());
132         assertNotNull(getBuild());
133 
134         ITestDevice device = getDevice();
135         mAdbWasRoot = device.isAdbRoot();
136         if (mAdbWasRoot) {
137             // This test assumes that the test is not run with root privileges. But this test runs
138             // as a part of appsecurity test suite which contains a lot of other tests. Some of
139             // which may enable adb root, make sure that this test is run without root access.
140             device.disableAdbRoot();
141             assertFalse("adb root is enabled", device.isAdbRoot());
142         }
143     }
144 
145     @Before
146     @After
cleanUp()147     public void cleanUp() throws DeviceNotAvailableException {
148         getDevice().uninstallPackage(NONE_PKG);
149         getDevice().uninstallPackage(READ_PKG);
150         getDevice().uninstallPackage(WRITE_PKG);
151         getDevice().uninstallPackage(MULTIUSER_PKG);
152 
153         wipePrimaryExternalStorage();
154     }
155 
156     @After
tearDown()157     public void tearDown() throws DeviceNotAvailableException {
158         ITestDevice device = getDevice();
159         if (mAdbWasRoot) {
160             device.enableAdbRoot();
161         } else {
162             device.disableAdbRoot();
163         }
164     }
165 
166     @Test
testExternalStorageRename()167     public void testExternalStorageRename() throws Exception {
168         try {
169             wipePrimaryExternalStorage();
170 
171             getDevice().uninstallPackage(WRITE_PKG);
172             installPackage(WRITE_APK);
173 
174             // Make sure user initialization is complete before testing
175             waitForBroadcastIdle();
176 
177             for (int user : mUsers) {
178                 runDeviceTests(WRITE_PKG, WRITE_CLASS, "testExternalStorageRename", user);
179             }
180         } finally {
181             getDevice().uninstallPackage(WRITE_PKG);
182         }
183     }
184 
185     /**
186      * Verify that app with no external storage permissions works correctly.
187      */
188     @Test
testExternalStorageNone29()189     public void testExternalStorageNone29() throws Exception {
190         try {
191             wipePrimaryExternalStorage();
192 
193             getDevice().uninstallPackage(NONE_PKG);
194             String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
195             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
196 
197             for (int user : mUsers) {
198                 runDeviceTests(NONE_PKG, COMMON_CLASS, user);
199                 runDeviceTests(NONE_PKG, NONE_CLASS, user);
200             }
201         } finally {
202             getDevice().uninstallPackage(NONE_PKG);
203         }
204     }
205 
206     /**
207      * Verify that app with
208      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} works
209      * correctly.
210      */
211     @Test
testExternalStorageRead29()212     public void testExternalStorageRead29() throws Exception {
213         try {
214             wipePrimaryExternalStorage();
215 
216             getDevice().uninstallPackage(READ_PKG);
217             String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
218             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
219 
220             for (int user : mUsers) {
221                 runDeviceTests(READ_PKG, COMMON_CLASS, user);
222                 runDeviceTests(READ_PKG, READ_CLASS, user);
223             }
224         } finally {
225             getDevice().uninstallPackage(READ_PKG);
226         }
227     }
228 
229     /**
230      * Verify that app with
231      * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} works
232      * correctly.
233      */
234     @Test
testExternalStorageWrite()235     public void testExternalStorageWrite() throws Exception {
236         try {
237             wipePrimaryExternalStorage();
238 
239             getDevice().uninstallPackage(WRITE_PKG);
240             String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
241             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
242 
243             for (int user : mUsers) {
244                 runDeviceTests(WRITE_PKG, COMMON_CLASS, user);
245                 runDeviceTests(WRITE_PKG, WRITE_CLASS, user);
246             }
247         } finally {
248             getDevice().uninstallPackage(WRITE_PKG);
249         }
250     }
251 
252     /**
253      * Verify that apps can't leave gifts in package specific external storage
254      * directories belonging to other apps. Apps can only create files in their
255      * external storage directories.
256      */
257     @Test
testExternalStorageNoGifts()258     public void testExternalStorageNoGifts() throws Exception {
259         try {
260             wipePrimaryExternalStorage();
261 
262             getDevice().uninstallPackage(NONE_PKG);
263             getDevice().uninstallPackage(READ_PKG);
264             getDevice().uninstallPackage(WRITE_PKG);
265             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
266 
267             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
268             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
269             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
270             for (int user : mUsers) {
271                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testStageNonGifts", user);
272                 runDeviceTests(READ_PKG, READ_PKG + ".ReadGiftTest", "testStageNonGifts", user);
273                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testStageNonGifts", user);
274 
275                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testNoGifts", user);
276                 runDeviceTests(READ_PKG, READ_PKG + ".ReadGiftTest", "testNoGifts", user);
277                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testNoGifts", user);
278             }
279         } finally {
280             getDevice().uninstallPackage(NONE_PKG);
281             getDevice().uninstallPackage(READ_PKG);
282             getDevice().uninstallPackage(WRITE_PKG);
283         }
284     }
285 
286     /**
287      * Verify that app with REQUEST_INSTALL_PACKAGES can leave gifts in obb
288      * directories belonging to other apps, and those apps can read.
289      */
290     @Test
testCanAccessOtherObbDirs()291     public void testCanAccessOtherObbDirs() throws Exception {
292         try {
293             wipePrimaryExternalStorage();
294 
295             getDevice().uninstallPackage(WRITE_PKG_2);
296             getDevice().uninstallPackage(NONE_PKG);
297             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
298 
299             // We purposefully delay the installation of the reading apps to
300             // verify that the daemon correctly invalidates any caches.
301             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK_2), false, options));
302             for (int user : mUsers) {
303                 updateAppOp(WRITE_PKG_2, user, "android:request_install_packages", true);
304                 updatePermissions(WRITE_PKG_2, user, new String[] {
305                         PERM_READ_MEDIA_IMAGES,
306                         PERM_READ_MEDIA_VIDEO,
307                         PERM_READ_MEDIA_AUDIO,
308                         PERM_READ_EXTERNAL_STORAGE,
309                         PERM_WRITE_EXTERNAL_STORAGE,
310                 }, true);
311             }
312 
313             for (int user : mUsers) {
314                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest", "testObbGifts", user);
315             }
316 
317             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
318             for (int user : mUsers) {
319                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testObbGifts", user);
320             }
321 
322             for (int user : mUsers) {
323                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
324                         "testAccessObbGifts", user);
325                 updateAppOp(WRITE_PKG_2, user, "android:request_install_packages", false);
326                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
327                         "testCantAccessObbGifts", user);
328             }
329         } finally {
330             getDevice().uninstallPackage(WRITE_PKG_2);
331             getDevice().uninstallPackage(NONE_PKG);
332         }
333     }
334 
335     @Test
testExternalStorageUnsharedObb()336     public void testExternalStorageUnsharedObb() throws Exception {
337         final int numUsers = mUsers.length;
338         Assume.assumeTrue(numUsers > 1);
339 
340         try {
341             wipePrimaryExternalStorage();
342 
343             getDevice().uninstallPackage(NONE_PKG);
344             getDevice().uninstallPackage(WRITE_PKG);
345             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
346 
347             // We purposefully delay the installation of the reading apps to
348             // verify that the daemon correctly invalidates any caches.
349             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
350             updateAppOp(WRITE_PKG, mUsers[0], "android:request_install_packages", true);
351             runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testObbGifts", mUsers[0]);
352 
353             // Create a file in one user and verify that file is not accessible to other users.
354             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
355             for (int i = 1; i < numUsers; ++i) {
356                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testNoObbGifts", mUsers[i]);
357                 updateAppOp(WRITE_PKG, mUsers[i], "android:request_install_packages", true);
358                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testObbGifts", mUsers[i]);
359             }
360 
361             // Delete a file in one user and verify that it doesn't affect files accessible to
362             // other users.
363             runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testRemoveObbGifts", mUsers[0]);
364             for (int i = 1; i < numUsers; ++i) {
365                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testObbGifts", mUsers[i]);
366             }
367 
368         } finally {
369             getDevice().uninstallPackage(NONE_PKG);
370             getDevice().uninstallPackage(WRITE_PKG);
371         }
372     }
373 
374     /**
375      * Test multi-user emulated storage environment, ensuring that each user has
376      * isolated storage.
377      */
378     @Test
testMultiUserStorageIsolated()379     public void testMultiUserStorageIsolated() throws Exception {
380         try {
381             if (mUsers.length == 1) {
382                 Log.d(TAG, "Single user device; skipping isolated storage tests");
383                 return;
384             }
385 
386             final int owner = mUsers[0];
387             final int secondary = mUsers[1];
388 
389             // Install our test app
390             getDevice().uninstallPackage(MULTIUSER_PKG);
391             String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
392             final String installResult = getDevice()
393                     .installPackage(getTestAppFile(MULTIUSER_APK), false, options);
394             assertNull("Failed to install: " + installResult, installResult);
395 
396             // Clear data from previous tests
397             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testCleanIsolatedStorage", owner);
398             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testCleanIsolatedStorage", secondary);
399 
400             // Have both users try writing into isolated storage
401             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testWriteIsolatedStorage", owner);
402             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testWriteIsolatedStorage", secondary);
403 
404             // Verify they both have isolated view of storage
405             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", owner);
406             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", secondary);
407 
408             // Verify they can't poke at each other
409             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", owner);
410             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", secondary);
411 
412             // Verify they can't access other users' content using media provider
413             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testMediaProviderUserIsolation", owner);
414             runDeviceTests(
415                     MULTIUSER_PKG, MULTIUSER_CLASS, "testMediaProviderUserIsolation", secondary);
416         } finally {
417             getDevice().uninstallPackage(MULTIUSER_PKG);
418         }
419     }
420 
421     /**
422      * Test that apps with read permissions see the appropriate permissions.
423      */
424     @Test
testMultiViewMoveConsistency()425     public void testMultiViewMoveConsistency() throws Exception {
426         try {
427             wipePrimaryExternalStorage();
428 
429             getDevice().uninstallPackage(NONE_PKG);
430             getDevice().uninstallPackage(READ_PKG);
431             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
432 
433             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
434 
435             for (int user : mUsers) {
436                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testFolderSetup", user);
437             }
438             for (int user : mUsers) {
439                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testRWAccess", user);
440             }
441 
442             // for fuse file system
443             RunUtil.getDefault().sleep(10000);
444             for (int user : mUsers) {
445                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testRWAccess", user);
446             }
447         } finally {
448             getDevice().uninstallPackage(NONE_PKG);
449             getDevice().uninstallPackage(READ_PKG);
450         }
451     }
452 
453     /** Verify that app without READ_EXTERNAL can play default URIs in external storage. */
454     @Test
testExternalStorageReadDefaultUris()455     public void testExternalStorageReadDefaultUris() throws Exception {
456         Throwable existingException = null;
457         try {
458             wipePrimaryExternalStorage();
459 
460             getDevice().uninstallPackage(NONE_PKG);
461             getDevice().uninstallPackage(WRITE_PKG);
462             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
463 
464             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
465             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
466 
467             for (int user : mUsers) {
468                 updateAppOp(WRITE_PKG, user, "android:write_settings", true);
469                 runDeviceTests(
470                         WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testChangeDefaultUris", user);
471 
472                 runDeviceTests(
473                         NONE_PKG, NONE_PKG + ".ReadDefaultUris", "testPlayDefaultUris", user);
474             }
475         } catch (Throwable t) {
476             Log.e(TAG, "Test exception: " + t);
477             // Don't rethrow if there is already an exception.
478             if (existingException == null) {
479                 existingException = t;
480                 throw t;
481             }
482         } finally {
483             try {
484                 // Make sure the provider and uris are reset on failure.
485                 for (int user : mUsers) {
486                     runDeviceTests(
487                             WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testResetDefaultUris",
488                             user);
489                 }
490                 getDevice().uninstallPackage(NONE_PKG);
491                 getDevice().uninstallPackage(WRITE_PKG);
492             } catch (Throwable t) {
493                 Log.e(TAG, "Cleanup exception: " + t);
494                 // Don't rethrow if there is already an exception.
495                 if (existingException == null) {
496                     existingException = t;
497                     throw t;
498                 }
499             }
500         }
501     }
502 
503     /**
504      * For security reasons, the shell user cannot access the shared storage of
505      * secondary users. Instead, developers should use the {@code content} shell
506      * tool to read/write files in those locations.
507      */
508     @Test
testSecondaryUsersInaccessible()509     public void testSecondaryUsersInaccessible() throws Exception {
510         List<String> mounts = new ArrayList<>();
511         for (String line : getDevice().executeShellCommand("cat /proc/mounts").split("\n")) {
512             String[] split = line.split(" ");
513             if (split[1].startsWith("/storage/") || split[1].startsWith("/mnt/")) {
514                 mounts.add(split[1]);
515             }
516         }
517 
518         for (int user : mUsers) {
519             String probe = "/sdcard/../" + user;
520             if (user == Utils.USER_SYSTEM) {
521                 // Primary user should always be visible. Skip checking raw
522                 // mount points, since we'd get false-positives for physical
523                 // devices that aren't multi-user aware.
524                 assertTrue(probe, access(probe));
525             } else {
526                 // Secondary user should never be visible.
527                 assertFalse(probe, access(probe));
528                 for (String mount : mounts) {
529                     probe = mount + "/" + user;
530                     assertFalse(probe, access(probe));
531                 }
532             }
533         }
534     }
535 
536     @Test
testMediaLegacy28()537     public void testMediaLegacy28() throws Exception {
538         doMediaLegacy(MEDIA_28);
539     }
540     @Test
testMediaLegacy29()541     public void testMediaLegacy29() throws Exception {
542         doMediaLegacy(MEDIA_29);
543     }
544 
doMediaLegacy(Config config)545     private void doMediaLegacy(Config config) throws Exception {
546         installPackage(config.apk);
547         installPackage(MEDIA_29.apk);
548         // Make sure user initialization is complete before updating permission
549         waitForBroadcastIdle();
550         for (int user : mUsers) {
551             updatePermissions(config.pkg, user, new String[] {
552                     PERM_READ_MEDIA_IMAGES,
553                     PERM_READ_MEDIA_VIDEO,
554                     PERM_READ_MEDIA_AUDIO,
555                     PERM_READ_EXTERNAL_STORAGE,
556                     PERM_WRITE_EXTERNAL_STORAGE,
557             }, true);
558             updatePermissions(MEDIA_29.pkg, user, new String[] {
559                     PERM_READ_EXTERNAL_STORAGE,
560                     PERM_WRITE_EXTERNAL_STORAGE,
561             }, true);
562 
563             // Create the files needed for the test from MEDIA_29 pkg since shell
564             // can't access secondary user's storage.
565             runDeviceTests(MEDIA_29.pkg, MEDIA_29.clazz, "testStageFiles", user);
566             runDeviceTests(config.pkg, config.clazz, "testLegacy", user);
567             runDeviceTests(MEDIA_29.pkg, MEDIA_29.clazz, "testClearFiles", user);
568         }
569     }
570 
571     /**
572      * b/197302116. The apps can't be granted prefix UriPermissions to the uri, when the query
573      * result of the uri is 1.
574      */
575     @Test
testOwningOneFileNotGrantPrefixUriPermission()576     public void testOwningOneFileNotGrantPrefixUriPermission() throws Exception {
577         installPackage(MEDIA.apk);
578 
579         int user = getDevice().getCurrentUser();
580 
581         // revoke permissions
582         updatePermissions(MEDIA.pkg, user, new String[] {
583                 PERM_READ_MEDIA_IMAGES,
584                 PERM_READ_MEDIA_VIDEO,
585                 PERM_READ_MEDIA_AUDIO,
586                 PERM_READ_EXTERNAL_STORAGE,
587                 PERM_WRITE_EXTERNAL_STORAGE,
588         }, false);
589 
590 
591         // revoke the app ops permission
592         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_EXTERNAL_STORAGE, false);
593 
594         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
595                 "testOwningOneFileNotGrantPrefixUriPermission", user);
596     }
597 
598     /**
599      * If the app grants read UriPermission to the uri without id (E.g.
600      * MediaStore.Audio.Media.EXTERNAL_CONTENT_URI), the query result of the uri should be the same
601      * without granting permission.
602      */
603     @Test
testReadUriPermissionOnUriWithoutId_sameQueryResult()604     public void testReadUriPermissionOnUriWithoutId_sameQueryResult() throws Exception {
605         installPackage(MEDIA.apk);
606 
607         int user = getDevice().getCurrentUser();
608 
609         // revoke permissions
610         updatePermissions(MEDIA.pkg, user, new String[] {
611                 PERM_READ_MEDIA_IMAGES,
612                 PERM_READ_MEDIA_VIDEO,
613                 PERM_READ_MEDIA_AUDIO,
614                 PERM_READ_EXTERNAL_STORAGE,
615                 PERM_WRITE_EXTERNAL_STORAGE,
616         }, false);
617 
618 
619         // revoke the app ops permission
620         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_EXTERNAL_STORAGE, false);
621 
622         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
623                 "testReadUriPermissionOnUriWithoutId_sameQueryResult", user);
624     }
625 
626     @Test
testGrantUriPermission()627     public void testGrantUriPermission() throws Exception {
628         doGrantUriPermission(MEDIA, "testGrantUriPermission", new String[]{});
629         doGrantUriPermission(MEDIA, "testGrantUriPermission",
630                 new String[]{PERM_READ_MEDIA_IMAGES, PERM_READ_MEDIA_VIDEO,
631                     PERM_READ_MEDIA_AUDIO, PERM_READ_EXTERNAL_STORAGE});
632         doGrantUriPermission(MEDIA, "testGrantUriPermission",
633                 new String[]{PERM_READ_EXTERNAL_STORAGE, PERM_READ_MEDIA_IMAGES,
634                     PERM_READ_MEDIA_VIDEO, PERM_READ_MEDIA_AUDIO, PERM_WRITE_EXTERNAL_STORAGE});
635     }
636 
637     @Test
testGrantUriPermission29()638     public void testGrantUriPermission29() throws Exception {
639         doGrantUriPermission(MEDIA_29, "testGrantUriPermission", new String[]{});
640         doGrantUriPermission(MEDIA_29, "testGrantUriPermission",
641                 new String[]{PERM_READ_EXTERNAL_STORAGE});
642         doGrantUriPermission(MEDIA_29, "testGrantUriPermission",
643                 new String[]{PERM_READ_EXTERNAL_STORAGE, PERM_WRITE_EXTERNAL_STORAGE});
644     }
645 
doGrantUriPermission(Config config, String method, String[] grantPermissions)646     private void doGrantUriPermission(Config config, String method, String[] grantPermissions)
647             throws Exception {
648         uninstallPackage(config.apk);
649         installPackage(config.apk);
650         for (int user : mUsers) {
651             // Over revoke all permissions and grant necessary permissions later.
652             updatePermissions(config.pkg, user, new String[] {
653                     PERM_READ_MEDIA_IMAGES,
654                     PERM_READ_MEDIA_VIDEO,
655                     PERM_READ_MEDIA_AUDIO,
656                     PERM_READ_EXTERNAL_STORAGE,
657                     PERM_WRITE_EXTERNAL_STORAGE,
658             }, false);
659             updatePermissions(config.pkg, user, grantPermissions, true);
660             runDeviceTests(config.pkg, config.clazz, method, user);
661         }
662     }
663 
664     @Test
testMediaNone()665     public void testMediaNone() throws Exception {
666         doMediaNone(MEDIA);
667     }
668     @Test
testMediaNone28()669     public void testMediaNone28() throws Exception {
670         doMediaNone(MEDIA_28);
671     }
672     @Test
testMediaNone29()673     public void testMediaNone29() throws Exception {
674         doMediaNone(MEDIA_29);
675     }
676 
doMediaNone(Config config)677     private void doMediaNone(Config config) throws Exception {
678         installPackage(config.apk);
679         for (int user : mUsers) {
680             updatePermissions(config.pkg, user, new String[] {
681                     PERM_READ_MEDIA_IMAGES,
682                     PERM_READ_MEDIA_VIDEO,
683                     PERM_READ_MEDIA_AUDIO,
684                     PERM_READ_EXTERNAL_STORAGE,
685                     PERM_WRITE_EXTERNAL_STORAGE,
686             }, false);
687 
688             runDeviceTests(config.pkg, config.clazz, "testMediaNone", user);
689         }
690     }
691 
692     @Test
testMediaRead()693     public void testMediaRead() throws Exception {
694         doMediaRead(MEDIA);
695     }
696     @Test
testMediaRead28()697     public void testMediaRead28() throws Exception {
698         doMediaRead(MEDIA_28);
699     }
700     @Test
testMediaRead29()701     public void testMediaRead29() throws Exception {
702         doMediaRead(MEDIA_29);
703     }
704 
doMediaRead(Config config)705     private void doMediaRead(Config config) throws Exception {
706         installPackage(config.apk);
707         for (int user : mUsers) {
708             updatePermissions(config.pkg, user, new String[] {
709                     PERM_READ_MEDIA_IMAGES,
710                     PERM_READ_MEDIA_VIDEO,
711                     PERM_READ_MEDIA_AUDIO,
712                     PERM_READ_EXTERNAL_STORAGE,
713             }, true);
714             updatePermissions(config.pkg, user, new String[] {
715                     PERM_WRITE_EXTERNAL_STORAGE,
716             }, false);
717 
718             runDeviceTests(config.pkg, config.clazz, "testMediaRead", user);
719         }
720     }
721 
722     @Test
testMediaWrite()723     public void testMediaWrite() throws Exception {
724         doMediaWrite(MEDIA);
725     }
726     @Test
testMediaWrite28()727     public void testMediaWrite28() throws Exception {
728         doMediaWrite(MEDIA_28);
729     }
730     @Test
testMediaWrite29()731     public void testMediaWrite29() throws Exception {
732         doMediaWrite(MEDIA_29);
733     }
734 
doMediaWrite(Config config)735     private void doMediaWrite(Config config) throws Exception {
736         installPackage(config.apk);
737         for (int user : mUsers) {
738             updatePermissions(config.pkg, user, new String[] {
739                     PERM_READ_MEDIA_IMAGES,
740                     PERM_READ_MEDIA_VIDEO,
741                     PERM_READ_MEDIA_AUDIO,
742                     PERM_READ_EXTERNAL_STORAGE,
743                     PERM_WRITE_EXTERNAL_STORAGE,
744             }, true);
745 
746             runDeviceTests(config.pkg, config.clazz, "testMediaWrite", user);
747         }
748     }
749 
750     @Test
testMediaEscalation_RequestWriteFilePathSupport()751     public void testMediaEscalation_RequestWriteFilePathSupport() throws Exception {
752         // Not adding tests for MEDIA_28 and MEDIA_29 as they need W_E_S for write access via file
753         // path for shared files, and will always have access as they have W_E_S.
754         installPackage(MEDIA.apk);
755 
756         int user = getDevice().getCurrentUser();
757         // revoke all permissions
758         updatePermissions(MEDIA.pkg, user, new String[] {
759                 PERM_ACCESS_MEDIA_LOCATION,
760                 PERM_READ_MEDIA_IMAGES,
761                 PERM_READ_MEDIA_VIDEO,
762                 PERM_READ_MEDIA_AUDIO,
763                 PERM_READ_EXTERNAL_STORAGE,
764                 PERM_WRITE_EXTERNAL_STORAGE,
765         }, false);
766 
767         // revoke the app ops permission
768         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_MEDIA, false);
769         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_EXTERNAL_STORAGE, false);
770 
771         runDeviceTests(MEDIA.pkg, MEDIA.clazz, "testMediaEscalation_RequestWriteFilePathSupport",
772                 user);
773     }
774 
775     @Test
testMediaEscalation()776     public void testMediaEscalation() throws Exception {
777         doMediaEscalation(MEDIA);
778     }
779     @Test
testMediaEscalation28()780     public void testMediaEscalation28() throws Exception {
781         doMediaEscalation(MEDIA_28);
782     }
783     @Test
testMediaEscalation29()784     public void testMediaEscalation29() throws Exception {
785         doMediaEscalation(MEDIA_29);
786     }
787 
doMediaEscalation(Config config)788     private void doMediaEscalation(Config config) throws Exception {
789         installPackage(config.apk);
790 
791         // TODO: extend test to exercise secondary users
792         int user = getDevice().getCurrentUser();
793         updatePermissions(config.pkg, user, new String[] {
794                 PERM_READ_MEDIA_IMAGES,
795                 PERM_READ_MEDIA_VIDEO,
796                 PERM_READ_MEDIA_AUDIO,
797                 PERM_READ_EXTERNAL_STORAGE,
798         }, true);
799         updatePermissions(config.pkg, user, new String[] {
800                 PERM_WRITE_EXTERNAL_STORAGE,
801         }, false);
802 
803         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Open", user);
804         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Update", user);
805         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Delete", user);
806 
807         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_RequestWrite", user);
808         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_RequestTrash", user);
809         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_RequestFavorite", user);
810         runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_RequestDelete", user);
811     }
812 
813     @Test
testExternalStorageClearing()814     public void testExternalStorageClearing() throws Exception {
815         String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
816 
817         try {
818             getDevice().uninstallPackage(WRITE_PKG);
819             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
820             for (int user : mUsers) {
821                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testClearingWrite", user);
822             }
823 
824             // Uninstall and reinstall means all storage should be cleared
825             getDevice().uninstallPackage(WRITE_PKG);
826             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
827             for (int user : mUsers) {
828                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testClearingRead", user);
829             }
830         } finally {
831             getDevice().uninstallPackage(WRITE_PKG);
832         }
833     }
834 
835     @Test
testIsExternalStorageLegacy()836     public void testIsExternalStorageLegacy() throws Exception {
837         String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
838 
839         try {
840             getDevice().uninstallPackage(WRITE_PKG);
841             getDevice().uninstallPackage(WRITE_PKG_2);
842             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
843             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK_2), false, options));
844             for (int user : mUsers) {
845                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest",
846                         "testIsExternalStorageLegacy", user);
847                 updatePermissions(WRITE_PKG, user, new String[] {
848                         PERM_READ_EXTERNAL_STORAGE,
849                         PERM_WRITE_EXTERNAL_STORAGE,
850                 }, false);
851                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest",
852                         "testIsExternalStorageLegacy", user);
853 
854                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
855                         "testNotIsExternalStorageLegacy", user);
856             }
857         } finally {
858             getDevice().uninstallPackage(WRITE_PKG);
859             getDevice().uninstallPackage(WRITE_PKG_2);
860         }
861     }
862 
863     /**
864      * Check the behavior when the app calls MediaStore#createTrashRequest,
865      * MediaStore#createDeleteRequest or MediaStore#createWriteRequest, the user
866      * click the deny button on confirmation dialog.
867      *
868      * @throws Exception
869      */
870     @Test
testCreateRequest_userDenied()871     public void testCreateRequest_userDenied() throws Exception {
872         installPackage(MEDIA.apk);
873 
874         int user = getDevice().getCurrentUser();
875 
876         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
877                 "testMediaEscalationWithDenied_RequestWrite", user);
878         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
879                 "testMediaEscalationWithDenied_RequestDelete", user);
880         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
881                 "testMediaEscalationWithDenied_RequestTrash", user);
882         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
883                 "testMediaEscalationWithDenied_RequestUnTrash", user);
884     }
885 
886     /**
887      * If the app is NOT granted {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
888      * and {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
889      * when it calls MediaStore#createTrashRequest,
890      * MediaStore#createDeleteRequest, or MediaStore#createWriteRequest,
891      * the system will show the user confirmation dialog.
892      *
893      * @throws Exception
894      */
895     @Test
testCreateRequest_noRESAndMES_showConfirmDialog()896     public void testCreateRequest_noRESAndMES_showConfirmDialog() throws Exception {
897         installPackage(MEDIA.apk);
898 
899         int user = getDevice().getCurrentUser();
900 
901         // grant permissions
902         updatePermissions(MEDIA.pkg, user, new String[] {
903                 PERM_ACCESS_MEDIA_LOCATION,
904         }, true);
905         // revoke permissions
906         updatePermissions(MEDIA.pkg, user, new String[] {
907                 PERM_READ_MEDIA_IMAGES,
908                 PERM_READ_MEDIA_VIDEO,
909                 PERM_READ_MEDIA_AUDIO,
910                 PERM_READ_EXTERNAL_STORAGE,
911                 PERM_WRITE_EXTERNAL_STORAGE,
912         }, false);
913 
914 
915         // revoke the app ops permission
916         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_EXTERNAL_STORAGE, false);
917 
918         // grant the app ops permission
919         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_MEDIA, true);
920 
921         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
922                 "testMediaEscalation_RequestWrite_showConfirmDialog", user);
923     }
924 
925     /**
926      * If the app is NOT granted {@link android.Manifest.permission#MANAGE_MEDIA},
927      * when it calls MediaStore#createTrashRequest,
928      * MediaStore#createDeleteRequest, or MediaStore#createWriteRequest,
929      * the system will show the user confirmation dialog.
930      *
931      * @throws Exception
932      */
933     @Test
testCreateRequest_noMANAGEMEDIA_showConfirmDialog()934     public void testCreateRequest_noMANAGEMEDIA_showConfirmDialog() throws Exception {
935         installPackage(MEDIA.apk);
936 
937         int user = getDevice().getCurrentUser();
938         // grant permissions
939         updatePermissions(MEDIA.pkg, user, new String[] {
940                 PERM_READ_MEDIA_IMAGES,
941                 PERM_READ_MEDIA_VIDEO,
942                 PERM_READ_MEDIA_AUDIO,
943                 PERM_READ_EXTERNAL_STORAGE,
944                 PERM_ACCESS_MEDIA_LOCATION,
945         }, true);
946 
947         // revoke the app ops permission
948         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_MEDIA, false);
949 
950         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
951                 "testMediaEscalation_RequestWrite_showConfirmDialog", user);
952         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
953                 "testMediaEscalation_RequestTrash_showConfirmDialog", user);
954         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
955                 "testMediaEscalation_RequestDelete_showConfirmDialog", user);
956     }
957 
958     /**
959      * If the app is granted {@link android.Manifest.permission#MANAGE_MEDIA},
960      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}, without
961      * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION},
962      * when it calls MediaStore#createTrashRequest or
963      * MediaStore#createDeleteRequest, The system will NOT show the user
964      * confirmation dialog. When it calls MediaStore#createWriteRequest, the
965      * system will show the user confirmation dialog.
966      *
967      * @throws Exception
968      */
969     @Test
testCreateRequest_withNoAML_showConfirmDialog()970     public void testCreateRequest_withNoAML_showConfirmDialog() throws Exception {
971         installPackage(MEDIA.apk);
972 
973         int user = getDevice().getCurrentUser();
974         // grant permissions
975         updatePermissions(MEDIA.pkg, user, new String[] {
976                 PERM_READ_MEDIA_IMAGES,
977                 PERM_READ_MEDIA_VIDEO,
978                 PERM_READ_MEDIA_AUDIO,
979                 PERM_READ_EXTERNAL_STORAGE,
980         }, true);
981         // revoke permission
982         updatePermissions(MEDIA.pkg, user, new String[] {
983                 PERM_ACCESS_MEDIA_LOCATION,
984         }, false);
985 
986         // grant the app ops permission
987         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_MEDIA, true);
988 
989         // show confirm dialog in requestWrite
990         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
991                 "testMediaEscalation_RequestWrite_showConfirmDialog", user);
992 
993         // not show confirm dialog in requestTrash and requestDelete
994         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
995                 "testMediaEscalation_RequestTrash_notShowConfirmDialog", user);
996         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
997                 "testMediaEscalation_RequestDelete_notShowConfirmDialog", user);
998     }
999 
1000     /**
1001      * If the app is granted {@link android.Manifest.permission#MANAGE_MEDIA}, {@link
1002      * android.Manifest.permission#READ_EXTERNAL_STORAGE}, without {@link
1003      * android.Manifest.permission#ACCESS_MEDIA_LOCATION}, when it calls
1004      * MediaStore#createTrashRequest or MediaStore#createDeleteRequest, The system will NOT show the
1005      * user confirmation dialog. When it calls MediaStore#createWriteRequest, the system will show
1006      * the user confirmation dialog. This tests pre-SDK level 33 behavior.
1007      *
1008      * @throws Exception
1009      */
1010     @Test
testCreateRequest_withNoAML_showConfirmDialog31()1011     public void testCreateRequest_withNoAML_showConfirmDialog31() throws Exception {
1012         installPackage(MEDIA_31.apk);
1013 
1014         int user = getDevice().getCurrentUser();
1015         // grant permissions
1016         updatePermissions(MEDIA_31.pkg, user, new String[] {
1017                 PERM_READ_MEDIA_IMAGES,
1018                 PERM_READ_MEDIA_VIDEO,
1019                 PERM_READ_MEDIA_AUDIO,
1020                 PERM_READ_EXTERNAL_STORAGE,
1021         }, true);
1022         // revoke permission
1023         updatePermissions(MEDIA_31.pkg, user, new String[] {
1024                 PERM_ACCESS_MEDIA_LOCATION,
1025         }, false);
1026 
1027         // grant the app ops permission
1028         updateAppOp(MEDIA_31.pkg, user, APP_OPS_MANAGE_MEDIA, true);
1029 
1030         // show confirm dialog in requestWrite
1031         runDeviceTests(MEDIA_31.pkg, MEDIA_31.clazz,
1032                 "testMediaEscalation_RequestWrite_showConfirmDialog", user);
1033 
1034         // not show confirm dialog in requestTrash and requestDelete
1035         runDeviceTests(MEDIA_31.pkg, MEDIA_31.clazz,
1036                 "testMediaEscalation_RequestTrash_notShowConfirmDialog", user);
1037         runDeviceTests(MEDIA_31.pkg, MEDIA_31.clazz,
1038                 "testMediaEscalation_RequestDelete_notShowConfirmDialog", user);
1039     }
1040 
1041     /**
1042      * If the app is granted {@link android.Manifest.permission#MANAGE_MEDIA},
1043      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}, and
1044      * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION},
1045      * when it calls MediaStore#createWriteRequest, MediaStore#createTrashRequest or
1046      * MediaStore#createDeleteRequest, the system will NOT show the user confirmation dialog.
1047      *
1048      * @throws Exception
1049      */
1050     @Test
testCreateRequest_withPermission_notShowConfirmDialog()1051     public void testCreateRequest_withPermission_notShowConfirmDialog() throws Exception {
1052         installPackage(MEDIA.apk);
1053 
1054         int user = getDevice().getCurrentUser();
1055         // grant permissions
1056         updatePermissions(MEDIA.pkg, user, new String[] {
1057                 PERM_READ_MEDIA_IMAGES,
1058                 PERM_READ_MEDIA_VIDEO,
1059                 PERM_READ_MEDIA_AUDIO,
1060                 PERM_READ_EXTERNAL_STORAGE,
1061                 PERM_ACCESS_MEDIA_LOCATION,
1062                 PERM_READ_MEDIA_VISUAL_USER_SELECTED,
1063         }, true);
1064 
1065         // revoke the app ops permission
1066         updateAppOp(MEDIA.pkg, user, APP_OPS_MANAGE_MEDIA, true);
1067 
1068         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
1069                 "testMediaEscalation_RequestWrite_notShowConfirmDialog", user);
1070         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
1071                 "testMediaEscalation_RequestTrash_notShowConfirmDialog", user);
1072         runDeviceTests(MEDIA.pkg, MEDIA.clazz,
1073                 "testMediaEscalation_RequestDelete_notShowConfirmDialog", user);
1074     }
1075 
1076     /**
1077      * Bypasses the calling test case if ANY of the given features is available in the device.
1078      */
bypassTestForFeatures(String... features)1079     private void bypassTestForFeatures(String... features) throws DeviceNotAvailableException {
1080         final String featureList = getDevice().executeShellCommand("pm list features");
1081         for (String feature : features) {
1082             Assume.assumeFalse(featureList.contains(feature));
1083         }
1084     }
1085 
1086     @Test
testSystemGalleryExists()1087     public void testSystemGalleryExists() throws Exception {
1088         // Watches, TVs and IoT devices are not obligated to have a system gallery
1089         bypassTestForFeatures(FEATURE_AUTOMOTIVE, FEATURE_EMBEDDED, FEATURE_LEANBACK_ONLY,
1090                 FEATURE_WATCH);
1091 
1092         for (int user : mUsers) {
1093             final String[] roleHolders = getDevice().executeShellCommand(
1094                     "cmd role get-role-holders --user " + user
1095                             + " android.app.role.SYSTEM_GALLERY").trim().split(";");
1096             assertEquals("Expected 1 SYSTEM_GALLERY for user " + user, 1, roleHolders.length);
1097         }
1098     }
1099 
access(String path)1100     private boolean access(String path) throws DeviceNotAvailableException {
1101         final long nonce = System.nanoTime();
1102         return getDevice().executeShellCommand("ls -la " + path + " && echo " + nonce)
1103                 .contains(Long.toString(nonce));
1104     }
1105 
updatePermissions(String packageName, int userId, String[] permissions, boolean grant)1106     private void updatePermissions(String packageName, int userId, String[] permissions,
1107             boolean grant) throws Exception {
1108         final String verb = grant ? "grant" : "revoke";
1109         for (String permission : permissions) {
1110             getDevice().executeShellCommand(
1111                     "cmd package " + verb + " --user " + userId + " --uid " + packageName + " "
1112                             + permission);
1113         }
1114     }
1115 
1116     /** Wait until all broadcast queues are idle. */
waitForBroadcastIdle()1117     private void waitForBroadcastIdle() throws Exception{
1118         getDevice().executeShellCommand("am wait-for-broadcast-idle");
1119     }
1120 
updateAppOp(String packageName, int userId, String appOp, boolean allow)1121     private void updateAppOp(String packageName, int userId, String appOp, boolean allow)
1122             throws Exception {
1123         updateAppOp(packageName, false, userId, appOp, allow);
1124     }
1125 
updateAppOp(String packageName, boolean targetsUid, int userId, String appOp, boolean allow)1126     private void updateAppOp(String packageName, boolean targetsUid, int userId,
1127             String appOp, boolean allow)
1128             throws Exception {
1129         final String verb = allow ? "allow" : "default";
1130         getDevice().executeShellCommand(
1131                 "cmd appops set --user " + userId + (targetsUid ? " --uid " : " ") + packageName
1132                         + " " + appOp + " " + verb);
1133     }
1134 
wipePrimaryExternalStorage()1135     private void wipePrimaryExternalStorage() throws DeviceNotAvailableException {
1136         // Can't delete everything under /sdcard as that's going to remove the mounts.
1137         getDevice().executeShellCommand("find /sdcard -type f -delete");
1138         getDevice().executeShellCommand("rm -rf /sdcard/DCIM/*");
1139         getDevice().executeShellCommand("rm -rf /sdcard/MUST_*");
1140     }
1141 
runDeviceTests(String packageName, String testClassName, int userId)1142     private void runDeviceTests(String packageName, String testClassName, int userId)
1143             throws DeviceNotAvailableException {
1144         runDeviceTests(getDevice(), packageName, testClassName, null, userId, null);
1145     }
1146 
runDeviceTests(String packageName, String testClassName, String testMethodName, int userId)1147     private void runDeviceTests(String packageName, String testClassName, String testMethodName,
1148             int userId) throws DeviceNotAvailableException {
1149         runDeviceTests(getDevice(), packageName, testClassName, testMethodName, userId, null);
1150     }
1151 }
1152