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