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