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