1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.scopedstorage.cts.host;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assume.assumeFalse;
22 
23 import android.platform.test.annotations.AppModeFull;
24 
25 import com.android.modules.utils.build.testing.DeviceSdkLevel;
26 import com.android.tradefed.device.DeviceNotAvailableException;
27 import com.android.tradefed.device.ITestDevice;
28 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
29 import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
30 
31 import org.junit.After;
32 import org.junit.Before;
33 import org.junit.Ignore;
34 import org.junit.Test;
35 import org.junit.runner.RunWith;
36 
37 /**
38  * Runs the ScopedStorageTest tests.
39  */
40 @RunWith(DeviceJUnit4ClassRunner.class)
41 @AppModeFull
42 public class ScopedStorageHostTest extends BaseHostTestCase {
43     private boolean mIsExternalStorageSetup;
44 
45     /**
46      * Runs the given phase of ScopedStorageTest by calling into the device.
47      * Throws an exception if the test phase fails.
48      */
runDeviceTest(String phase)49     void runDeviceTest(String phase) throws Exception {
50         assertThat(runDeviceTests("android.scopedstorage.cts",
51                 "android.scopedstorage.cts.ScopedStorageTest", phase)).isTrue();
52     }
53 
54     /**
55      * Runs the given phase of ScopedStorageTest by calling into the device with {@code
56      * --no-isolated-storage} flag.
57      * Throws an exception if the test phase fails.
58      */
runDeviceTestWithDisabledIsolatedStorage(String phase)59     void runDeviceTestWithDisabledIsolatedStorage(String phase) throws Exception {
60         runDeviceTests(new DeviceTestRunOptions("android.scopedstorage.cts")
61             .setDevice(getDevice())
62             .setTestClassName("android.scopedstorage.cts.ScopedStorageTest")
63             .setTestMethodName(phase)
64             .setDisableIsolatedStorage(true));
65     }
66 
setupExternalStorage()67     private void setupExternalStorage() throws Exception {
68         if (!mIsExternalStorageSetup) {
69             runDeviceTest("setupExternalStorage");
70             mIsExternalStorageSetup = true;
71         }
72     }
73 
74     @Before
setup()75     public void setup() throws Exception {
76         // Ignore tests on automotive devices b/319785789
77         assumeFalse(hasDeviceFeature("android.hardware.type.automotive"));
78 
79         setupExternalStorage();
80         executeShellCommand("mkdir /sdcard/Android/data/com.android.shell -m 2770");
81         executeShellCommand("mkdir /sdcard/Android/data/com.android.shell/files -m 2770");
82     }
83 
84     @Before
revokeStoragePermissions()85     public void revokeStoragePermissions() throws Exception {
86         revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE",
87                 "android.permission.READ_EXTERNAL_STORAGE");
88     }
89 
90     @After
tearDown()91     public void tearDown() throws Exception {
92         executeShellCommand("rm -r /sdcard/Android/data/com.android.shell");
93     }
94 
95     @Test
testManageExternalStorageCanDeleteOtherAppsContents()96     public void testManageExternalStorageCanDeleteOtherAppsContents() throws Exception {
97         allowAppOps("android:manage_external_storage");
98         try {
99             runDeviceTest("testManageExternalStorageCanDeleteOtherAppsContents");
100         } finally {
101             denyAppOps("android:manage_external_storage");
102         }
103     }
104 
105     @Test
testManageExternalStorageCanReadRedactedContents()106     public void testManageExternalStorageCanReadRedactedContents() throws Exception {
107         allowAppOps("android:manage_external_storage");
108         try {
109             runDeviceTest("testManageExternalStorageCanReadRedactedContents");
110         } finally {
111             denyAppOps("android:manage_external_storage");
112         }
113     }
114 
115     @Test
testManageExternalStorageCanRenameOtherAppsContents()116     public void testManageExternalStorageCanRenameOtherAppsContents() throws Exception {
117         allowAppOps("android:manage_external_storage");
118         try {
119             runDeviceTest("testManageExternalStorageCanRenameOtherAppsContents");
120         } finally {
121             denyAppOps("android:manage_external_storage");
122         }
123     }
124 
125     @Test
testManageExternalStorageCannotRenameAndroid()126     public void testManageExternalStorageCannotRenameAndroid() throws Exception {
127         allowAppOps("android:manage_external_storage");
128         try {
129             runDeviceTest("testManageExternalStorageCannotRenameAndroid");
130         } finally {
131             denyAppOps("android:manage_external_storage");
132         }
133     }
134 
135     @Test
testManageExternalStorageCantReadWriteOtherAppExternalDir()136     public void testManageExternalStorageCantReadWriteOtherAppExternalDir() throws Exception {
137         allowAppOps("android:manage_external_storage");
138         try {
139             runDeviceTest("testManageExternalStorageCantReadWriteOtherAppExternalDir");
140         } finally {
141             denyAppOps("android:manage_external_storage");
142         }
143     }
144 
145     @Test
testManageExternalStorageCantInsertFilesInOtherAppPrivateDir()146     public void testManageExternalStorageCantInsertFilesInOtherAppPrivateDir() throws Exception {
147         allowAppOps("android:manage_external_storage");
148         try {
149             runDeviceTest("testManageExternalStorageCantInsertFilesInOtherAppPrivateDir");
150         } finally {
151             denyAppOps("android:manage_external_storage");
152         }
153     }
154 
155     @Test
testManageExternalStorageCantUpdateFilesInOtherAppPrivateDir()156     public void testManageExternalStorageCantUpdateFilesInOtherAppPrivateDir() throws Exception {
157         allowAppOps("android:manage_external_storage");
158         try {
159             runDeviceTest("testManageExternalStorageCantUpdateFilesInOtherAppPrivateDir");
160         } finally {
161             denyAppOps("android:manage_external_storage");
162         }
163     }
164 
165     @Test
testCheckInstallerAppAccessToObbDirs()166     public void testCheckInstallerAppAccessToObbDirs() throws Exception {
167         allowAppOps("android:request_install_packages");
168         // WRITE_EXTERNAL_STORAGE is no-op for Installers U onwards
169         if (isSdkLevelLessThanU()) {
170             grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
171         }
172         try {
173             runDeviceTest("testCheckInstallerAppAccessToObbDirs");
174         } finally {
175             denyAppOps("android:request_install_packages");
176             // WRITE_EXTERNAL_STORAGE is no-op for Installers U onwards
177             if (isSdkLevelLessThanU()) {
178                 revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
179             }
180         }
181     }
182 
183     @Test
testCheckInstallerAppCannotAccessDataDirs()184     public void testCheckInstallerAppCannotAccessDataDirs() throws Exception {
185         allowAppOps("android:request_install_packages");
186         // WRITE_EXTERNAL_STORAGE is no-op for Installers U onwards
187         if (isSdkLevelLessThanU()) {
188             grantPermissions("android.permission.WRITE_EXTERNAL_STORAGE");
189         }
190         try {
191             runDeviceTest("testCheckInstallerAppCannotAccessDataDirs");
192         } finally {
193             denyAppOps("android:request_install_packages");
194             // WRITE_EXTERNAL_STORAGE is no-op for Installers U onwards
195             if (isSdkLevelLessThanU()) {
196                 revokePermissions("android.permission.WRITE_EXTERNAL_STORAGE");
197             }
198         }
199     }
200 
201     @Test
testManageExternalStorageQueryOtherAppsFile()202     public void testManageExternalStorageQueryOtherAppsFile() throws Exception {
203         allowAppOps("android:manage_external_storage");
204         try {
205             runDeviceTest("testManageExternalStorageQueryOtherAppsFile");
206         } finally {
207             denyAppOps("android:manage_external_storage");
208         }
209     }
210 
211     @Test
testManageExternalStorageDoesntSkipScanningDirtyNomediaDir()212     public void testManageExternalStorageDoesntSkipScanningDirtyNomediaDir() throws Exception {
213         allowAppOps("android:manage_external_storage");
214         try {
215             runDeviceTest("testManageExternalStorageDoesntSkipScanningDirtyNomediaDir");
216         } finally {
217             denyAppOps("android:manage_external_storage");
218         }
219     }
220 
221     @Test
testScanDoesntSkipDirtySubtree()222     public void testScanDoesntSkipDirtySubtree() throws Exception {
223         allowAppOps("android:manage_external_storage");
224         try {
225             runDeviceTest("testScanDoesntSkipDirtySubtree");
226         } finally {
227             denyAppOps("android:manage_external_storage");
228         }
229     }
230 
231     @Test
testFileManagerCanTrashOtherAndroidMediaFiles()232     public void testFileManagerCanTrashOtherAndroidMediaFiles() throws Exception {
233         allowAppOps("android:manage_external_storage");
234         try {
235             runDeviceTest("testFileManagerCanTrashOtherAndroidMediaFiles");
236         } finally {
237             denyAppOps("android:manage_external_storage");
238         }
239     }
240 
241     @Test
testFileManagerCanUpdateOtherAndroidMediaFiles()242     public void testFileManagerCanUpdateOtherAndroidMediaFiles() throws Exception {
243         allowAppOps("android:manage_external_storage");
244         try {
245             runDeviceTest("testFileManagerCanUpdateOtherAndroidMediaFiles");
246         } finally {
247             denyAppOps("android:manage_external_storage");
248         }
249     }
250 
251     @Test
testOpenOtherPendingFilesFromFuse()252     public void testOpenOtherPendingFilesFromFuse() throws Exception {
253         grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
254         try {
255             runDeviceTest("testOpenOtherPendingFilesFromFuse");
256         } finally {
257             revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
258         }
259     }
260 
261     @Test
testAndroidMedia()262     public void testAndroidMedia() throws Exception {
263         grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
264         try {
265             runDeviceTest("testAndroidMedia");
266         } finally {
267             revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
268         }
269     }
270 
271     @Test
testNoIsolatedStorageInstrumentationFlag()272     public void testNoIsolatedStorageInstrumentationFlag() throws Exception {
273         grantPermissions("android.permission.READ_EXTERNAL_STORAGE",
274                 "android.permission.WRITE_EXTERNAL_STORAGE");
275         try {
276             runDeviceTestWithDisabledIsolatedStorage("testNoIsolatedStorageCanCreateFilesAnywhere");
277             runDeviceTestWithDisabledIsolatedStorage(
278                     "testNoIsolatedStorageCantReadWriteOtherAppExternalDir");
279             runDeviceTestWithDisabledIsolatedStorage("testNoIsolatedStorageStorageReaddir");
280             runDeviceTestWithDisabledIsolatedStorage("testNoIsolatedStorageQueryOtherAppsFile");
281         } finally {
282             revokePermissions("android.permission.READ_EXTERNAL_STORAGE",
283                     "android.permission.WRITE_EXTERNAL_STORAGE");
284         }
285     }
286 
287     @Test
testRenameFromShell()288     public void testRenameFromShell() throws Exception {
289         final ITestDevice device = getDevice();
290         final boolean isAdbRoot = device.isAdbRoot() ? true : false;
291         try {
292             if (isAdbRoot) {
293                 device.disableAdbRoot();
294             }
295             runDeviceTest("testRenameFromShell");
296         } finally {
297             if (isAdbRoot) {
298                 device.enableAdbRoot();
299             }
300         }
301     }
302 
303     @Test
304     @Ignore("b/247099819")
testClearPackageData()305     public void testClearPackageData() throws Exception {
306         grantPermissions("android.permission.READ_EXTERNAL_STORAGE");
307         try {
308             runDeviceTest("testClearPackageData");
309         } finally {
310             revokePermissions("android.permission.READ_EXTERNAL_STORAGE");
311         }
312     }
313 
314     @Test
testInsertExternalFilesViaDataAsFileManager()315     public void testInsertExternalFilesViaDataAsFileManager() throws Exception {
316         allowAppOps("android:manage_external_storage");
317         try {
318             runDeviceTest("testInsertExternalFilesViaData");
319         } finally {
320             denyAppOps("android:manage_external_storage");
321         }
322     }
323 
324     /**
325      * Test that File Manager can't update file path to private directories.
326      */
327     @Test
testUpdateExternalFilesViaDataAsFileManager()328     public void testUpdateExternalFilesViaDataAsFileManager() throws Exception {
329         allowAppOps("android:manage_external_storage");
330         try {
331             runDeviceTest("testUpdateExternalFilesViaData");
332         } finally {
333             denyAppOps("android:manage_external_storage");
334         }
335     }
336 
337     /**
338      * Test that File Manager can't insert files from private directories.
339      */
340     @Test
testInsertExternalFilesViaRelativePathAsFileManager()341     public void testInsertExternalFilesViaRelativePathAsFileManager() throws Exception {
342         allowAppOps("android:manage_external_storage");
343         try {
344             runDeviceTest("testInsertExternalFilesViaRelativePath");
345         } finally {
346             denyAppOps("android:manage_external_storage");
347         }
348     }
349 
350     /**
351      * Test that File Manager can't update file path to private directories.
352      */
353     @Test
testUpdateExternalFilesViaRelativePathAsFileManager()354     public void testUpdateExternalFilesViaRelativePathAsFileManager() throws Exception {
355         allowAppOps("android:manage_external_storage");
356         try {
357             runDeviceTest("testUpdateExternalFilesViaRelativePath");
358         } finally {
359             denyAppOps("android:manage_external_storage");
360         }
361     }
362 
grantPermissionsToPackage(String packageName, String... perms)363     private void grantPermissionsToPackage(String packageName, String... perms) throws Exception {
364         int currentUserId = getCurrentUserId();
365         for (String perm : perms) {
366             executeShellCommand("pm grant --user %d %s %s",
367                     currentUserId, packageName, perm);
368         }
369     }
370 
grantPermissions(String... perms)371     private void grantPermissions(String... perms) throws Exception {
372         grantPermissionsToPackage("android.scopedstorage.cts", perms);
373     }
374 
revokePermissions(String... perms)375     private void revokePermissions(String... perms) throws Exception {
376         int currentUserId = getCurrentUserId();
377         for (String perm : perms) {
378             executeShellCommand("pm revoke --user %d android.scopedstorage.cts %s",
379                     currentUserId, perm);
380         }
381     }
382 
allowAppOps(String... ops)383     private void allowAppOps(String... ops) throws Exception {
384         for (String op : ops) {
385             executeShellCommand("cmd appops set --uid android.scopedstorage.cts " + op + " allow");
386         }
387     }
388 
denyAppOps(String... ops)389     private void denyAppOps(String... ops) throws Exception {
390         for (String op : ops) {
391             executeShellCommand("cmd appops set --uid android.scopedstorage.cts " + op + " deny");
392         }
393     }
394 
isSdkLevelLessThanU()395     private boolean isSdkLevelLessThanU() throws DeviceNotAvailableException {
396         DeviceSdkLevel deviceSdkLevel = new DeviceSdkLevel(getDevice());
397         return !deviceSdkLevel.isDeviceAtLeastU();
398     }
399 }
400