• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.assertFalse;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertNull;
22 import static org.junit.Assert.assertTrue;
23 
24 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
25 import com.android.ddmlib.Log;
26 import com.android.tradefed.device.DeviceNotAvailableException;
27 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
28 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
29 import com.android.tradefed.util.AbiUtils;
30 
31 import org.junit.After;
32 import org.junit.Assume;
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 
37 import java.io.File;
38 import java.io.FileNotFoundException;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42 
43 /**
44  * Set of tests that verify behavior of external storage devices.
45  */
46 @RunWith(DeviceJUnit4ClassRunner.class)
47 public class ExternalStorageHostTest extends BaseHostJUnit4Test {
48     private static final String TAG = "ExternalStorageHostTest";
49 
50     private static class Config {
51         public final String apk;
52         public final String pkg;
53         public final String clazz;
54 
Config(String apk, String pkg, String clazz)55         public Config(String apk, String pkg, String clazz) {
56             this.apk = apk;
57             this.pkg = pkg;
58             this.clazz = clazz;
59         }
60     }
61 
62     private static final String COMMON_CLASS =
63             "com.android.cts.externalstorageapp.CommonExternalStorageTest";
64 
65     private static final String NONE_APK = "CtsExternalStorageApp.apk";
66     private static final String NONE_PKG = "com.android.cts.externalstorageapp";
67     private static final String NONE_CLASS = NONE_PKG + ".ExternalStorageTest";
68     private static final String READ_APK = "CtsReadExternalStorageApp.apk";
69     private static final String READ_PKG = "com.android.cts.readexternalstorageapp";
70     private static final String READ_CLASS = READ_PKG + ".ReadExternalStorageTest";
71     private static final String WRITE_APK = "CtsWriteExternalStorageApp.apk";
72     private static final String WRITE_PKG = "com.android.cts.writeexternalstorageapp";
73     private static final String WRITE_CLASS = WRITE_PKG + ".WriteExternalStorageTest";
74     private static final String WRITE_APK_2 = "CtsWriteExternalStorageApp2.apk";
75     private static final String WRITE_PKG_2 = "com.android.cts.writeexternalstorageapp2";
76     private static final String MULTIUSER_APK = "CtsMultiUserStorageApp.apk";
77     private static final String MULTIUSER_PKG = "com.android.cts.multiuserstorageapp";
78     private static final String MULTIUSER_CLASS = MULTIUSER_PKG + ".MultiUserStorageTest";
79 
80     private static final String MEDIA_CLAZZ = "com.android.cts.mediastorageapp.MediaStorageTest";
81 
82     private static final Config MEDIA = new Config("CtsMediaStorageApp.apk",
83             "com.android.cts.mediastorageapp", MEDIA_CLAZZ);
84     private static final Config MEDIA_28 = new Config("CtsMediaStorageApp28.apk",
85             "com.android.cts.mediastorageapp28", MEDIA_CLAZZ);
86     private static final Config MEDIA_FULL = new Config("CtsMediaStorageAppFull.apk",
87             "com.android.cts.mediastorageappfull", MEDIA_CLAZZ);
88 
89     private static final String PERM_READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
90     private static final String PERM_WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
91 
92     private int[] mUsers;
93 
getTestAppFile(String fileName)94     private File getTestAppFile(String fileName) throws FileNotFoundException {
95         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
96         return buildHelper.getTestFile(fileName);
97     }
98 
99     @Before
setUp()100     public void setUp() throws Exception {
101         mUsers = Utils.prepareMultipleUsers(getDevice());
102         assertNotNull(getAbi());
103         assertNotNull(getBuild());
104     }
105 
106     @Before
107     @After
cleanUp()108     public void cleanUp() throws DeviceNotAvailableException {
109         getDevice().uninstallPackage(NONE_PKG);
110         getDevice().uninstallPackage(READ_PKG);
111         getDevice().uninstallPackage(WRITE_PKG);
112         getDevice().uninstallPackage(MULTIUSER_PKG);
113 
114         wipePrimaryExternalStorage();
115     }
116 
117     @Test
testExternalStorageRename()118     public void testExternalStorageRename() throws Exception {
119         try {
120             wipePrimaryExternalStorage();
121 
122             getDevice().uninstallPackage(WRITE_PKG);
123             installPackage(WRITE_APK);
124 
125             for (int user : mUsers) {
126                 runDeviceTests(WRITE_PKG, WRITE_CLASS, "testExternalStorageRename", user);
127             }
128         } finally {
129             getDevice().uninstallPackage(WRITE_PKG);
130         }
131     }
132 
133     /**
134      * Verify that app with no external storage permissions works correctly.
135      */
136     @Test
testExternalStorageNone()137     public void testExternalStorageNone() throws Exception {
138         try {
139             wipePrimaryExternalStorage();
140 
141             getDevice().uninstallPackage(NONE_PKG);
142             String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
143             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
144 
145             for (int user : mUsers) {
146                 runDeviceTests(NONE_PKG, COMMON_CLASS, user);
147                 runDeviceTests(NONE_PKG, NONE_CLASS, user);
148             }
149         } finally {
150             getDevice().uninstallPackage(NONE_PKG);
151         }
152     }
153 
154     /**
155      * Verify that app with
156      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} works
157      * correctly.
158      */
159     @Test
testExternalStorageRead()160     public void testExternalStorageRead() throws Exception {
161         try {
162             wipePrimaryExternalStorage();
163 
164             getDevice().uninstallPackage(READ_PKG);
165             String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
166             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
167 
168             for (int user : mUsers) {
169                 runDeviceTests(READ_PKG, COMMON_CLASS, user);
170                 runDeviceTests(READ_PKG, READ_CLASS, user);
171             }
172         } finally {
173             getDevice().uninstallPackage(READ_PKG);
174         }
175     }
176 
177     /**
178      * Verify that app with
179      * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} works
180      * correctly.
181      */
182     @Test
testExternalStorageWrite()183     public void testExternalStorageWrite() throws Exception {
184         try {
185             wipePrimaryExternalStorage();
186 
187             getDevice().uninstallPackage(WRITE_PKG);
188             String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
189             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
190 
191             for (int user : mUsers) {
192                 runDeviceTests(WRITE_PKG, COMMON_CLASS, user);
193                 runDeviceTests(WRITE_PKG, WRITE_CLASS, user);
194             }
195         } finally {
196             getDevice().uninstallPackage(WRITE_PKG);
197         }
198     }
199 
200     /**
201      * Verify that app with WRITE_EXTERNAL can leave gifts in external storage
202      * directories belonging to other apps, and those apps can read.
203      */
204     @Test
testExternalStorageGifts()205     public void testExternalStorageGifts() throws Exception {
206         try {
207             wipePrimaryExternalStorage();
208 
209             getDevice().uninstallPackage(NONE_PKG);
210             getDevice().uninstallPackage(READ_PKG);
211             getDevice().uninstallPackage(WRITE_PKG);
212             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
213 
214             // We purposefully delay the installation of the reading apps to
215             // verify that the daemon correctly invalidates any caches.
216             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
217             for (int user : mUsers) {
218                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testGifts", user);
219             }
220 
221             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
222             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
223             for (int user : mUsers) {
224                 runDeviceTests(READ_PKG, READ_PKG + ".ReadGiftTest", "testGifts", user);
225                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testGifts", user);
226             }
227         } finally {
228             getDevice().uninstallPackage(NONE_PKG);
229             getDevice().uninstallPackage(READ_PKG);
230             getDevice().uninstallPackage(WRITE_PKG);
231         }
232     }
233 
234     @Test
testExternalStorageObbGifts()235     public void testExternalStorageObbGifts() throws Exception {
236         try {
237             wipePrimaryExternalStorage();
238 
239             getDevice().uninstallPackage(WRITE_PKG_2);
240             getDevice().uninstallPackage(NONE_PKG);
241             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
242 
243             // We purposefully delay the installation of the reading apps to
244             // verify that the daemon correctly invalidates any caches.
245             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK_2), false, options));
246             for (int user : mUsers) {
247                 updateAppOp(WRITE_PKG_2, user, "android:request_install_packages", true);
248                 updatePermissions(WRITE_PKG_2, user, new String[] {
249                         PERM_READ_EXTERNAL_STORAGE,
250                         PERM_WRITE_EXTERNAL_STORAGE,
251                 }, true);
252             }
253 
254             for (int user : mUsers) {
255                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest", "testObbGifts", user);
256             }
257 
258             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
259             for (int user : mUsers) {
260                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testObbGifts", user);
261             }
262 
263             for (int user : mUsers) {
264                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
265                         "testAccessObbGifts", user);
266                 updateAppOp(WRITE_PKG_2, user, "android:request_install_packages", false);
267                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
268                         "testCantAccessObbGifts", user);
269             }
270         } finally {
271             getDevice().uninstallPackage(WRITE_PKG_2);
272             getDevice().uninstallPackage(NONE_PKG);
273         }
274     }
275 
276     @Test
testExternalStorageUnsharedObb()277     public void testExternalStorageUnsharedObb() throws Exception {
278         final int numUsers = mUsers.length;
279         Assume.assumeTrue(numUsers > 1);
280 
281         try {
282             wipePrimaryExternalStorage();
283 
284             getDevice().uninstallPackage(NONE_PKG);
285             getDevice().uninstallPackage(WRITE_PKG);
286             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
287 
288             // We purposefully delay the installation of the reading apps to
289             // verify that the daemon correctly invalidates any caches.
290             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
291             updateAppOp(WRITE_PKG, mUsers[0], "android:request_install_packages", true);
292             runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testObbGifts", mUsers[0]);
293 
294             // Create a file in one user and verify that file is not accessible to other users.
295             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
296             for (int i = 1; i < numUsers; ++i) {
297                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testNoObbGifts", mUsers[i]);
298                 updateAppOp(WRITE_PKG, mUsers[i], "android:request_install_packages", true);
299                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testObbGifts", mUsers[i]);
300             }
301 
302             // Delete a file in one user and verify that it doesn't affect files accessible to
303             // other users.
304             runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testRemoveObbGifts", mUsers[0]);
305             for (int i = 1; i < numUsers; ++i) {
306                 runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testObbGifts", mUsers[i]);
307             }
308 
309         } finally {
310             getDevice().uninstallPackage(NONE_PKG);
311             getDevice().uninstallPackage(WRITE_PKG);
312         }
313     }
314 
315     /**
316      * Test multi-user emulated storage environment, ensuring that each user has
317      * isolated storage.
318      */
319     @Test
testMultiUserStorageIsolated()320     public void testMultiUserStorageIsolated() throws Exception {
321         try {
322             if (mUsers.length == 1) {
323                 Log.d(TAG, "Single user device; skipping isolated storage tests");
324                 return;
325             }
326 
327             final int owner = mUsers[0];
328             final int secondary = mUsers[1];
329 
330             // Install our test app
331             getDevice().uninstallPackage(MULTIUSER_PKG);
332             String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
333             final String installResult = getDevice()
334                     .installPackage(getTestAppFile(MULTIUSER_APK), false, options);
335             assertNull("Failed to install: " + installResult, installResult);
336 
337             // Clear data from previous tests
338             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testCleanIsolatedStorage", owner);
339             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testCleanIsolatedStorage", secondary);
340 
341             // Have both users try writing into isolated storage
342             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testWriteIsolatedStorage", owner);
343             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testWriteIsolatedStorage", secondary);
344 
345             // Verify they both have isolated view of storage
346             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", owner);
347             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", secondary);
348 
349             // Verify they can't poke at each other
350             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", owner);
351             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", secondary);
352 
353             // Verify they can't access other users' content using media provider
354             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testMediaProviderUserIsolation", owner);
355             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testMediaProviderUserIsolation", secondary);
356         } finally {
357             getDevice().uninstallPackage(MULTIUSER_PKG);
358         }
359     }
360 
361     /**
362      * Test that apps with read permissions see the appropriate permissions
363      * when apps with r/w permission levels move around their files.
364      */
365     @Test
testMultiViewMoveConsistency()366     public void testMultiViewMoveConsistency() throws Exception {
367         try {
368             wipePrimaryExternalStorage();
369 
370             getDevice().uninstallPackage(NONE_PKG);
371             getDevice().uninstallPackage(READ_PKG);
372             getDevice().uninstallPackage(WRITE_PKG);
373             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
374 
375             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
376             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
377 
378             for (int user : mUsers) {
379                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testFolderSetup", user);
380             }
381             for (int user : mUsers) {
382                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testRWAccess", user);
383             }
384 
385             for (int user : mUsers) {
386                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteMultiViewTest", "testMoveAway", user);
387             }
388             for (int user : mUsers) {
389                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testROAccess", user);
390             }
391 
392             // for fuse file system
393             Thread.sleep(10000);
394             for (int user : mUsers) {
395                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteMultiViewTest", "testMoveBack", user);
396             }
397             for (int user : mUsers) {
398                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testRWAccess", user);
399             }
400         } finally {
401             getDevice().uninstallPackage(NONE_PKG);
402             getDevice().uninstallPackage(READ_PKG);
403             getDevice().uninstallPackage(WRITE_PKG);
404         }
405     }
406 
407     /** Verify that app without READ_EXTERNAL can play default URIs in external storage. */
408     @Test
testExternalStorageReadDefaultUris()409     public void testExternalStorageReadDefaultUris() throws Exception {
410         try {
411             wipePrimaryExternalStorage();
412 
413             getDevice().uninstallPackage(NONE_PKG);
414             getDevice().uninstallPackage(WRITE_PKG);
415             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
416 
417             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
418             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
419 
420             for (int user : mUsers) {
421                 updateAppOp(WRITE_PKG, user, "android:write_settings", true);
422                 runDeviceTests(
423                         WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testChangeDefaultUris", user);
424 
425                 runDeviceTests(
426                         NONE_PKG, NONE_PKG + ".ReadDefaultUris", "testPlayDefaultUris", user);
427             }
428         } finally {
429             // Make sure the provider and uris are reset on failure.
430             for (int user : mUsers) {
431                 runDeviceTests(
432                         WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testResetDefaultUris", user);
433             }
434             getDevice().uninstallPackage(NONE_PKG);
435             getDevice().uninstallPackage(WRITE_PKG);
436         }
437     }
438 
439     /**
440      * For security reasons, the shell user cannot access the shared storage of
441      * secondary users. Instead, developers should use the {@code content} shell
442      * tool to read/write files in those locations.
443      */
444     @Test
testSecondaryUsersInaccessible()445     public void testSecondaryUsersInaccessible() throws Exception {
446         List<String> mounts = new ArrayList<>();
447         for (String line : getDevice().executeShellCommand("cat /proc/mounts").split("\n")) {
448             String[] split = line.split(" ");
449             if (split[1].startsWith("/storage/") || split[1].startsWith("/mnt/")) {
450                 mounts.add(split[1]);
451             }
452         }
453 
454         for (int user : mUsers) {
455             String probe = "/sdcard/../" + user;
456             if (user == Utils.USER_SYSTEM) {
457                 // Primary user should always be visible. Skip checking raw
458                 // mount points, since we'd get false-positives for physical
459                 // devices that aren't multi-user aware.
460                 assertTrue(probe, access(probe));
461             } else {
462                 // Secondary user should never be visible.
463                 assertFalse(probe, access(probe));
464                 for (String mount : mounts) {
465                     probe = mount + "/" + user;
466                     assertFalse(probe, access(probe));
467                 }
468             }
469         }
470     }
471 
472     @Test
testMediaSandboxed()473     public void testMediaSandboxed() throws Exception {
474         doMediaSandboxed(MEDIA, true);
475     }
476     @Test
testMediaSandboxed28()477     public void testMediaSandboxed28() throws Exception {
478         doMediaSandboxed(MEDIA_28, false);
479     }
480     @Test
testMediaSandboxedFull()481     public void testMediaSandboxedFull() throws Exception {
482         doMediaSandboxed(MEDIA_FULL, false);
483     }
484 
doMediaSandboxed(Config config, boolean sandboxed)485     private void doMediaSandboxed(Config config, boolean sandboxed) throws Exception {
486         installPackage(config.apk);
487         installPackage(MEDIA_FULL.apk);
488         for (int user : mUsers) {
489             updatePermissions(config.pkg, user, new String[] {
490                     PERM_READ_EXTERNAL_STORAGE,
491                     PERM_WRITE_EXTERNAL_STORAGE,
492             }, true);
493             updatePermissions(MEDIA_FULL.pkg, user, new String[] {
494                     PERM_READ_EXTERNAL_STORAGE,
495                     PERM_WRITE_EXTERNAL_STORAGE,
496             }, true);
497 
498             // Create the files needed for the test from MEDIA_FULL pkg since shell
499             // can't access secondary user's storage.
500             runDeviceTests(MEDIA_FULL.pkg, MEDIA_FULL.clazz, "testStageFiles", user);
501 
502             if (sandboxed) {
503                 runDeviceTests(config.pkg, config.clazz, "testSandboxed", user);
504             } else {
505                 runDeviceTests(config.pkg, config.clazz, "testNotSandboxed", user);
506             }
507 
508             runDeviceTests(MEDIA_FULL.pkg, MEDIA_FULL.clazz, "testClearFiles", user);
509         }
510     }
511 
512     @Test
testMediaNone()513     public void testMediaNone() throws Exception {
514         doMediaNone(MEDIA);
515     }
516     @Test
testMediaNone28()517     public void testMediaNone28() throws Exception {
518         doMediaNone(MEDIA_28);
519     }
520     @Test
testMediaNoneFull()521     public void testMediaNoneFull() throws Exception {
522         doMediaNone(MEDIA_FULL);
523     }
524 
doMediaNone(Config config)525     private void doMediaNone(Config config) throws Exception {
526         installPackage(config.apk);
527         for (int user : mUsers) {
528             updatePermissions(config.pkg, user, new String[] {
529                     PERM_READ_EXTERNAL_STORAGE,
530                     PERM_WRITE_EXTERNAL_STORAGE,
531             }, false);
532 
533             runDeviceTests(config.pkg, config.clazz, "testMediaNone", user);
534         }
535     }
536 
537     @Test
testMediaRead()538     public void testMediaRead() throws Exception {
539         doMediaRead(MEDIA);
540     }
541     @Test
testMediaRead28()542     public void testMediaRead28() throws Exception {
543         doMediaRead(MEDIA_28);
544     }
545     @Test
testMediaReadFull()546     public void testMediaReadFull() throws Exception {
547         doMediaRead(MEDIA_FULL);
548     }
549 
doMediaRead(Config config)550     private void doMediaRead(Config config) throws Exception {
551         installPackage(config.apk);
552         for (int user : mUsers) {
553             updatePermissions(config.pkg, user, new String[] {
554                     PERM_READ_EXTERNAL_STORAGE,
555             }, true);
556             updatePermissions(config.pkg, user, new String[] {
557                     PERM_WRITE_EXTERNAL_STORAGE,
558             }, false);
559 
560             runDeviceTests(config.pkg, config.clazz, "testMediaRead", user);
561         }
562     }
563 
564     @Test
testMediaWrite()565     public void testMediaWrite() throws Exception {
566         doMediaWrite(MEDIA);
567     }
568     @Test
testMediaWrite28()569     public void testMediaWrite28() throws Exception {
570         doMediaWrite(MEDIA_28);
571     }
572     @Test
testMediaWriteFull()573     public void testMediaWriteFull() throws Exception {
574         doMediaWrite(MEDIA_FULL);
575     }
576 
doMediaWrite(Config config)577     private void doMediaWrite(Config config) throws Exception {
578         installPackage(config.apk);
579         for (int user : mUsers) {
580             updatePermissions(config.pkg, user, new String[] {
581                     PERM_READ_EXTERNAL_STORAGE,
582                     PERM_WRITE_EXTERNAL_STORAGE,
583             }, true);
584 
585             runDeviceTests(config.pkg, config.clazz, "testMediaWrite", user);
586         }
587     }
588 
589     @Test
testMediaEscalation()590     public void testMediaEscalation() throws Exception {
591         doMediaEscalation(MEDIA);
592     }
593     @Test
testMediaEscalation28()594     public void testMediaEscalation28() throws Exception {
595         doMediaEscalation(MEDIA_28);
596     }
597     @Test
testMediaEscalationFull()598     public void testMediaEscalationFull() throws Exception {
599         doMediaEscalation(MEDIA_FULL);
600     }
601 
doMediaEscalation(Config config)602     private void doMediaEscalation(Config config) throws Exception {
603         installPackage(config.apk);
604 
605         // TODO: extend test to exercise secondary users
606         for (int user : Arrays.copyOf(mUsers, 1)) {
607             updatePermissions(config.pkg, user, new String[] {
608                     PERM_READ_EXTERNAL_STORAGE,
609             }, true);
610             updatePermissions(config.pkg, user, new String[] {
611                     PERM_WRITE_EXTERNAL_STORAGE,
612             }, false);
613 
614             runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Open", user);
615             runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Update", user);
616             runDeviceTests(config.pkg, config.clazz, "testMediaEscalation_Delete", user);
617         }
618     }
619 
620     @Test
testExternalStorageClearing()621     public void testExternalStorageClearing() throws Exception {
622         String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
623 
624         try {
625             getDevice().uninstallPackage(WRITE_PKG);
626             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
627             for (int user : mUsers) {
628                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testClearingWrite", user);
629             }
630 
631             // Uninstall and reinstall means all storage should be cleared
632             getDevice().uninstallPackage(WRITE_PKG);
633             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
634             for (int user : mUsers) {
635                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testClearingRead", user);
636             }
637         } finally {
638             getDevice().uninstallPackage(WRITE_PKG);
639         }
640     }
641 
642     @Test
testIsExternalStorageLegacy()643     public void testIsExternalStorageLegacy() throws Exception {
644         String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
645 
646         try {
647             getDevice().uninstallPackage(WRITE_PKG);
648             getDevice().uninstallPackage(WRITE_PKG_2);
649             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
650             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK_2), false, options));
651             for (int user : mUsers) {
652                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest",
653                         "testIsExternalStorageLegacy", user);
654                 updatePermissions(WRITE_PKG, user, new String[] {
655                         PERM_READ_EXTERNAL_STORAGE,
656                         PERM_WRITE_EXTERNAL_STORAGE,
657                 }, false);
658                 runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest",
659                         "testIsExternalStorageLegacy", user);
660 
661                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
662                         "testNotIsExternalStorageLegacy", user);
663                 updateAppOp(WRITE_PKG_2, user, "android:request_install_packages", true);
664                 runDeviceTests(WRITE_PKG_2, WRITE_PKG + ".WriteGiftTest",
665                         "testIsExternalStorageLegacy", user);
666             }
667         } finally {
668             getDevice().uninstallPackage(WRITE_PKG);
669             getDevice().uninstallPackage(WRITE_PKG_2);
670         }
671     }
672 
access(String path)673     private boolean access(String path) throws DeviceNotAvailableException {
674         final long nonce = System.nanoTime();
675         return getDevice().executeShellCommand("ls -la " + path + " && echo " + nonce)
676                 .contains(Long.toString(nonce));
677     }
678 
updatePermissions(String packageName, int userId, String[] permissions, boolean grant)679     private void updatePermissions(String packageName, int userId, String[] permissions,
680             boolean grant) throws Exception {
681         final String verb = grant ? "grant" : "revoke";
682         for (String permission : permissions) {
683             getDevice().executeShellCommand(
684                     "cmd package " + verb + " --user " + userId + " --uid " + packageName + " "
685                             + permission);
686         }
687     }
688 
updateAppOp(String packageName, int userId, String appOp, boolean allow)689     private void updateAppOp(String packageName, int userId, String appOp, boolean allow)
690             throws Exception {
691         updateAppOp(packageName, false, userId, appOp, allow);
692     }
693 
updateAppOp(String packageName, boolean targetsUid, int userId, String appOp, boolean allow)694     private void updateAppOp(String packageName, boolean targetsUid, int userId,
695             String appOp, boolean allow)
696             throws Exception {
697         final String verb = allow ? "allow" : "default";
698         getDevice().executeShellCommand(
699                 "cmd appops set --user " + userId + (targetsUid ? " --uid " : " ") + packageName
700                         + " " + appOp + " " + verb);
701     }
702 
wipePrimaryExternalStorage()703     private void wipePrimaryExternalStorage() throws DeviceNotAvailableException {
704         // Can't delete everything under /sdcard as that's going to remove the mounts.
705         getDevice().executeShellCommand("find /sdcard -type f -delete");
706         getDevice().executeShellCommand("rm -rf /sdcard/DCIM");
707         getDevice().executeShellCommand("rm -rf /sdcard/MUST_*");
708     }
709 
runDeviceTests(String packageName, String testClassName, int userId)710     private void runDeviceTests(String packageName, String testClassName, int userId)
711             throws DeviceNotAvailableException {
712         runDeviceTests(getDevice(), packageName, testClassName, null, userId, null);
713     }
714 
runDeviceTests(String packageName, String testClassName, String testMethodName, int userId)715     private void runDeviceTests(String packageName, String testClassName, String testMethodName,
716             int userId) throws DeviceNotAvailableException {
717         runDeviceTests(getDevice(), packageName, testClassName, testMethodName, userId, null);
718     }
719 }
720