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.permissionpolicy.cts; 18 19 import static android.permission.cts.PermissionUtils.isGranted; 20 import static android.permission.cts.PermissionUtils.isPermissionGranted; 21 22 import static com.android.compatibility.common.util.SystemUtil.eventually; 23 import static com.android.compatibility.common.util.SystemUtil.runShellCommand; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import static org.junit.Assert.fail; 28 29 import android.Manifest; 30 import android.Manifest.permission; 31 import android.app.AppOpsManager; 32 import android.content.Context; 33 import android.content.pm.PackageInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PermissionInfo; 36 import android.platform.test.annotations.AppModeFull; 37 import android.util.ArraySet; 38 39 import androidx.annotation.NonNull; 40 import androidx.test.platform.app.InstrumentationRegistry; 41 42 import com.android.compatibility.common.util.ThrowingRunnable; 43 import com.android.modules.utils.build.SdkLevel; 44 45 import org.junit.After; 46 import org.junit.Test; 47 48 import java.util.Collections; 49 import java.util.Set; 50 51 import javax.annotation.Nullable; 52 53 /** Tests for restricted storage-related permissions. */ 54 public class RestrictedStoragePermissionTest { 55 private static final String APK_USES_STORAGE_DEFAULT_22 = 56 "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk22.apk"; 57 58 private static final String APK_USES_STORAGE_DEFAULT_28 = 59 "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk28.apk"; 60 61 private static final String APK_USES_STORAGE_DEFAULT_29 = 62 "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk29.apk"; 63 64 private static final String APK_USES_STORAGE_OPT_IN_22 = 65 "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk22.apk"; 66 67 private static final String APK_USES_STORAGE_OPT_IN_28 = 68 "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk28.apk"; 69 70 private static final String APK_USES_STORAGE_OPT_OUT_29 = 71 "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk29.apk"; 72 73 private static final String APK_USES_STORAGE_OPT_OUT_30 = 74 "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk30.apk"; 75 76 private static final String APK_USES_STORAGE_PRESERVED_OPT_OUT_30 = 77 "/data/local/tmp/cts/permissions2/CtsStoragePermissionsPreservedUserOptOutSdk30.apk"; 78 79 private static final String PKG = "android.permissionpolicy.cts.restrictedpermissionuser"; 80 81 @Test 82 @AppModeFull testTargetingSdk22DefaultWhitelistedHasFullAccess()83 public void testTargetingSdk22DefaultWhitelistedHasFullAccess() throws Exception { 84 // Install with whitelisted permissions. 85 installApp(APK_USES_STORAGE_DEFAULT_22, null /*whitelistedPermissions*/); 86 87 // Check expected storage mode 88 assertHasFullStorageAccess(); 89 } 90 91 @Test 92 @AppModeFull testTargetingSdk22OptInWhitelistedHasIsolatedAccess()93 public void testTargetingSdk22OptInWhitelistedHasIsolatedAccess() throws Exception { 94 // Install with whitelisted permissions. 95 installApp(APK_USES_STORAGE_OPT_IN_22, null /*whitelistedPermissions*/); 96 97 // Check expected storage mode 98 assertHasIsolatedStorageAccess(); 99 } 100 101 @Test 102 @AppModeFull testTargetingSdk28DefaultWhitelistedHasFullAccess()103 public void testTargetingSdk28DefaultWhitelistedHasFullAccess() throws Exception { 104 // Install with whitelisted permissions. 105 installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/); 106 107 // Check expected storage mode 108 assertHasFullStorageAccess(); 109 } 110 111 @Test 112 @AppModeFull testTargetingSdk28OptInWhitelistedHasIsolatedAccess()113 public void testTargetingSdk28OptInWhitelistedHasIsolatedAccess() throws Exception { 114 // Install with whitelisted permissions. 115 installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/); 116 117 // Check expected storage mode 118 assertHasIsolatedStorageAccess(); 119 } 120 121 @Test 122 @AppModeFull testTargetingSdk29DefaultWhitelistedHasIsolatedAccess()123 public void testTargetingSdk29DefaultWhitelistedHasIsolatedAccess() throws Exception { 124 // Install with whitelisted permissions. 125 installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet()); 126 127 // Check expected storage mode 128 assertHasIsolatedStorageAccess(); 129 } 130 131 @Test 132 @AppModeFull testTargetingSdk29DefaultNotWhitelistedHasIsolatedAccess()133 public void testTargetingSdk29DefaultNotWhitelistedHasIsolatedAccess() throws Exception { 134 // Install with no whitelisted permissions. 135 installApp(APK_USES_STORAGE_DEFAULT_29, null /*whitelistedPermissions*/); 136 137 // Check expected storage mode 138 assertHasIsolatedStorageAccess(); 139 } 140 141 @Test 142 @AppModeFull testTargetingSdk29OptOutWhitelistedHasFullAccess()143 public void testTargetingSdk29OptOutWhitelistedHasFullAccess() throws Exception { 144 // Install with whitelisted permissions. 145 installApp(APK_USES_STORAGE_OPT_OUT_29, null /*whitelistedPermissions*/); 146 147 // Check expected storage mode 148 assertHasFullStorageAccess(); 149 } 150 151 @Test 152 @AppModeFull testTargetingSdk29OptOutNotWhitelistedHasIsolatedAccess()153 public void testTargetingSdk29OptOutNotWhitelistedHasIsolatedAccess() throws Exception { 154 // Install with no whitelisted permissions. 155 installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet()); 156 157 // Check expected storage mode 158 assertHasIsolatedStorageAccess(); 159 } 160 161 @Test 162 @AppModeFull testTargetingSdk29CanOptOutViaUpdate()163 public void testTargetingSdk29CanOptOutViaUpdate() throws Exception { 164 installApp(APK_USES_STORAGE_DEFAULT_29, null); 165 installApp(APK_USES_STORAGE_OPT_OUT_29, null); 166 167 assertHasFullStorageAccess(); 168 } 169 170 @Test 171 @AppModeFull testTargetingSdk29CanOptOutViaDowngradeTo28()172 public void testTargetingSdk29CanOptOutViaDowngradeTo28() throws Exception { 173 installApp(APK_USES_STORAGE_DEFAULT_29, null); 174 installApp(APK_USES_STORAGE_DEFAULT_28, null); 175 176 assertHasFullStorageAccess(); 177 } 178 179 @Test 180 @AppModeFull testTargetingSdk30_cannotOptOut()181 public void testTargetingSdk30_cannotOptOut() throws Exception { 182 // Apps that target R and above cannot opt out of isolated storage. 183 installApp(APK_USES_STORAGE_OPT_OUT_30, null); 184 185 // Check expected storage mode 186 assertHasIsolatedStorageAccess(); 187 } 188 189 @Test 190 @AppModeFull testTargetingSdk28CanRemoveOptInViaUpdate()191 public void testTargetingSdk28CanRemoveOptInViaUpdate() throws Exception { 192 installApp(APK_USES_STORAGE_OPT_IN_28, null); 193 installApp(APK_USES_STORAGE_DEFAULT_28, null); 194 195 assertHasFullStorageAccess(); 196 } 197 198 @Test 199 @AppModeFull testTargetingSdk28CanRemoveOptInByOptingOut()200 public void testTargetingSdk28CanRemoveOptInByOptingOut() throws Exception { 201 installApp(APK_USES_STORAGE_OPT_IN_28, null); 202 installApp(APK_USES_STORAGE_OPT_OUT_29, null); 203 204 assertHasFullStorageAccess(); 205 } 206 207 @Test 208 @AppModeFull testTargetingSdk28DoesNotLoseAccessWhenOptingIn()209 public void testTargetingSdk28DoesNotLoseAccessWhenOptingIn() throws Exception { 210 installApp(APK_USES_STORAGE_DEFAULT_28, null); 211 assertHasFullStorageAccess(); 212 installApp(APK_USES_STORAGE_OPT_IN_28, null); 213 214 assertHasFullStorageAccess(); 215 } 216 217 @Test 218 @AppModeFull testTargetingSdk28DoesNotLoseAccessViaUpdate()219 public void testTargetingSdk28DoesNotLoseAccessViaUpdate() throws Exception { 220 installApp(APK_USES_STORAGE_DEFAULT_28, null); 221 assertHasFullStorageAccess(); 222 installApp(APK_USES_STORAGE_DEFAULT_29, null); 223 224 assertHasFullStorageAccess(); 225 } 226 227 @Test 228 @AppModeFull testTargetingSdk29DoesNotLoseAccessViaUpdate()229 public void testTargetingSdk29DoesNotLoseAccessViaUpdate() throws Exception { 230 installApp(APK_USES_STORAGE_OPT_OUT_29, null); 231 assertHasFullStorageAccess(); 232 installApp(APK_USES_STORAGE_DEFAULT_29, null); 233 234 assertHasFullStorageAccess(); 235 } 236 237 @Test 238 @AppModeFull testTargetingSdk29DoesNotLoseAccessWhenOptingIn()239 public void testTargetingSdk29DoesNotLoseAccessWhenOptingIn() throws Exception { 240 installApp(APK_USES_STORAGE_OPT_OUT_29, null); 241 assertHasFullStorageAccess(); 242 installApp(APK_USES_STORAGE_OPT_IN_28, null); 243 244 assertHasFullStorageAccess(); 245 } 246 247 @Test 248 @AppModeFull testTargetingSdk29LosesAccessViaUpdateToTargetSdk30()249 public void testTargetingSdk29LosesAccessViaUpdateToTargetSdk30() throws Exception { 250 installApp(APK_USES_STORAGE_OPT_OUT_29, null); 251 assertHasFullStorageAccess(); 252 253 installApp(APK_USES_STORAGE_OPT_OUT_30, null); // opt-out is a no-op on 30 254 assertHasIsolatedStorageAccess(); 255 } 256 257 @Test 258 @AppModeFull testTargetingSdk28LosesAccessViaUpdateToTargetSdk30()259 public void testTargetingSdk28LosesAccessViaUpdateToTargetSdk30() throws Exception { 260 installApp(APK_USES_STORAGE_DEFAULT_28, null); 261 assertHasFullStorageAccess(); 262 263 installApp(APK_USES_STORAGE_OPT_OUT_30, null); // opt-out is a no-op on 30 264 assertHasIsolatedStorageAccess(); 265 } 266 267 @Test 268 @AppModeFull testCannotControlStorageWhitelistPostInstall1()269 public void testCannotControlStorageWhitelistPostInstall1() throws Exception { 270 // Install with whitelisted permissions. 271 installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/); 272 273 // Check expected state of restricted permissions. 274 assertCannotUnWhitelistStorage(); 275 } 276 277 @Test 278 @AppModeFull testCannotControlStorageWhitelistPostInstall2()279 public void testCannotControlStorageWhitelistPostInstall2() throws Exception { 280 // Install with no whitelisted permissions. 281 installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet()); 282 283 // Check expected state of restricted permissions. 284 assertCannotWhitelistStorage(); 285 } 286 287 @Test 288 @AppModeFull cannotGrantStorageTargetingSdk22NotWhitelisted()289 public void cannotGrantStorageTargetingSdk22NotWhitelisted() throws Exception { 290 // Install with no whitelisted permissions. 291 installApp(APK_USES_STORAGE_DEFAULT_22, Collections.emptySet()); 292 293 eventually(() -> { 294 // Could not grant permission+app-op as targetSDK<29 and not whitelisted 295 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse(); 296 297 // Permissions are always granted for pre-23 apps 298 assertThat(isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)) 299 .isTrue(); 300 }); 301 } 302 303 @Test 304 @AppModeFull cannotGrantStorageTargetingSdk22OptInNotWhitelisted()305 public void cannotGrantStorageTargetingSdk22OptInNotWhitelisted() throws Exception { 306 // Install with no whitelisted permissions. 307 installApp(APK_USES_STORAGE_OPT_IN_22, Collections.emptySet()); 308 309 eventually(() -> { 310 // Could not grant permission as targetSDK<29 and not whitelisted 311 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse(); 312 313 // Permissions are always granted for pre-23 apps 314 assertThat(isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)) 315 .isTrue(); 316 }); 317 } 318 319 @Test 320 @AppModeFull canGrantStorageTargetingSdk22Whitelisted()321 public void canGrantStorageTargetingSdk22Whitelisted() throws Exception { 322 // Install with whitelisted permissions. 323 installApp(APK_USES_STORAGE_DEFAULT_22, null); 324 325 // Could grant permission 326 eventually(() -> 327 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue()); 328 } 329 330 @Test 331 @AppModeFull canGrantStorageTargetingSdk22OptInWhitelisted()332 public void canGrantStorageTargetingSdk22OptInWhitelisted() throws Exception { 333 // Install with whitelisted permissions. 334 installApp(APK_USES_STORAGE_OPT_IN_22, null); 335 336 // Could grant permission 337 eventually(() -> 338 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue()); 339 } 340 341 @Test 342 @AppModeFull cannotGrantStorageTargetingSdk28NotWhitelisted()343 public void cannotGrantStorageTargetingSdk28NotWhitelisted() throws Exception { 344 // Install with no whitelisted permissions. 345 installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet()); 346 347 // Could not grant permission as targetSDK<29 and not whitelisted 348 eventually(() -> 349 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse()); 350 } 351 352 @Test 353 @AppModeFull cannotGrantStorageTargetingSdk28OptInNotWhitelisted()354 public void cannotGrantStorageTargetingSdk28OptInNotWhitelisted() throws Exception { 355 // Install with no whitelisted permissions. 356 installApp(APK_USES_STORAGE_OPT_IN_28, Collections.emptySet()); 357 358 // Could not grant permission as targetSDK<29 and not whitelisted 359 eventually(() -> 360 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse()); 361 } 362 363 @Test 364 @AppModeFull canGrantStorageTargetingSdk28Whitelisted()365 public void canGrantStorageTargetingSdk28Whitelisted() throws Exception { 366 // Install with whitelisted permissions. 367 installApp(APK_USES_STORAGE_DEFAULT_28, null); 368 369 // Could grant permission 370 eventually(() -> 371 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue()); 372 } 373 374 @Test 375 @AppModeFull canGrantStorageTargetingSdk28OptInWhitelisted()376 public void canGrantStorageTargetingSdk28OptInWhitelisted() throws Exception { 377 // Install with whitelisted permissions. 378 installApp(APK_USES_STORAGE_OPT_IN_28, null); 379 380 // Could grant permission 381 eventually(() -> 382 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue()); 383 } 384 385 @Test 386 @AppModeFull canGrantStorageTargetingSdk29NotWhitelisted()387 public void canGrantStorageTargetingSdk29NotWhitelisted() throws Exception { 388 // Install with no whitelisted permissions. 389 installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet()); 390 391 // Could grant permission as targetSDK=29 apps can always grant 392 eventually(() -> 393 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue()); 394 } 395 396 @Test 397 @AppModeFull canGrantStorageTargetingSdk29OptOutNotWhitelisted()398 public void canGrantStorageTargetingSdk29OptOutNotWhitelisted() throws Exception { 399 // Install with no whitelisted permissions. 400 installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet()); 401 402 // Could grant permission as targetSDK=29 apps can always grant 403 eventually(() -> 404 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue()); 405 } 406 407 @Test 408 @AppModeFull canGrantStorageTargetingSdk29Whitelisted()409 public void canGrantStorageTargetingSdk29Whitelisted() throws Exception { 410 // Install with whitelisted permissions. 411 installApp(APK_USES_STORAGE_DEFAULT_29, null); 412 413 // Could grant permission as targetSDK=29 apps can always grant 414 eventually(() -> 415 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue()); 416 } 417 418 @Test 419 @AppModeFull canGrantStorageTargetingSdk29OptOutWhitelisted()420 public void canGrantStorageTargetingSdk29OptOutWhitelisted() throws Exception { 421 // Install with whitelisted permissions. 422 installApp(APK_USES_STORAGE_OPT_OUT_29, null); 423 424 // Could grant permission as targetSDK=29 apps can always grant 425 eventually(() -> 426 assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue()); 427 } 428 429 @Test 430 @AppModeFull restrictedWritePermDoesNotImplyIsolatedStorageAccess()431 public void restrictedWritePermDoesNotImplyIsolatedStorageAccess() throws Exception { 432 // Install with whitelisted read permissions. 433 installApp( 434 APK_USES_STORAGE_OPT_OUT_29, 435 Collections.singleton(Manifest.permission.READ_EXTERNAL_STORAGE)); 436 437 // It does not matter that write is restricted as the storage access level is only 438 // controlled by the read perm 439 assertHasFullStorageAccess(); 440 } 441 442 @Test 443 @AppModeFull whitelistedWritePermDoesNotImplyFullStorageAccess()444 public void whitelistedWritePermDoesNotImplyFullStorageAccess() throws Exception { 445 // Install with whitelisted read permissions. 446 installApp( 447 APK_USES_STORAGE_OPT_OUT_29, 448 Collections.singleton(Manifest.permission.WRITE_EXTERNAL_STORAGE)); 449 450 // It does not matter that write is white listed as the storage access level is only 451 // controlled by the read perm 452 assertHasIsolatedStorageAccess(); 453 } 454 455 @Test 456 @AppModeFull testStorageTargetingSdk30CanPreserveLegacyOnUpdateFromLegacy()457 public void testStorageTargetingSdk30CanPreserveLegacyOnUpdateFromLegacy() throws Exception { 458 installApp(APK_USES_STORAGE_OPT_OUT_29, null); 459 assertHasFullStorageAccess(); 460 461 // Updating with the flag preserves legacy 462 installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null); 463 assertHasFullStorageAccess(); 464 465 // And with the flag still preserves legacy 466 installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null); 467 assertHasFullStorageAccess(); 468 469 // But without the flag loses legacy 470 installApp(APK_USES_STORAGE_OPT_OUT_30, null); 471 assertHasIsolatedStorageAccess(); 472 473 // And again with the flag doesn't bring back legacy 474 installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null); 475 assertHasIsolatedStorageAccess(); 476 } 477 478 @Test 479 @AppModeFull testStorageTargetingSdk30CannotPreserveLegacyAfterLegacyUninstall()480 public void testStorageTargetingSdk30CannotPreserveLegacyAfterLegacyUninstall() 481 throws Exception { 482 installApp(APK_USES_STORAGE_OPT_OUT_29, null); 483 assertHasFullStorageAccess(); 484 485 runShellCommand("pm uninstall " + PKG); 486 487 installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null); 488 assertHasIsolatedStorageAccess(); 489 } 490 491 @Test 492 @AppModeFull testStorageTargetingSdk30CannotPreserveLegacyOnUpdateFromNonLegacy()493 public void testStorageTargetingSdk30CannotPreserveLegacyOnUpdateFromNonLegacy() 494 throws Exception { 495 installApp(APK_USES_STORAGE_DEFAULT_29, null); 496 installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null); 497 498 assertHasIsolatedStorageAccess(); 499 } 500 501 @Test 502 @AppModeFull testStorageTargetingSdk30CannotPreserveLegacyOnInstall()503 public void testStorageTargetingSdk30CannotPreserveLegacyOnInstall() throws Exception { 504 installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null); 505 506 assertHasIsolatedStorageAccess(); 507 } 508 assertHasFullStorageAccess()509 private void assertHasFullStorageAccess() throws Exception { 510 runWithShellPermissionIdentity(() -> { 511 AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); 512 final int uid = getContext().getPackageManager().getPackageUid(PKG, 0); 513 eventually(() -> assertThat(appOpsManager.unsafeCheckOpRawNoThrow( 514 AppOpsManager.OPSTR_LEGACY_STORAGE, 515 uid, PKG)).isEqualTo(AppOpsManager.MODE_ALLOWED)); 516 }); 517 } 518 assertHasIsolatedStorageAccess()519 private void assertHasIsolatedStorageAccess() throws Exception { 520 runWithShellPermissionIdentity(() -> { 521 AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); 522 final int uid = getContext().getPackageManager().getPackageUid(PKG, 0); 523 eventually(() -> assertThat(appOpsManager.unsafeCheckOpRawNoThrow( 524 AppOpsManager.OPSTR_LEGACY_STORAGE, 525 uid, PKG)).isNotEqualTo(AppOpsManager.MODE_ALLOWED)); 526 }); 527 } 528 assertCannotWhitelistStorage()529 private void assertCannotWhitelistStorage() throws Exception { 530 final PackageManager packageManager = getContext().getPackageManager(); 531 532 runWithShellPermissionIdentity(() -> { 533 // Assert added only to none whitelist. 534 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 535 PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM 536 | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 537 | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) 538 .doesNotContain(permission.READ_EXTERNAL_STORAGE); 539 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 540 PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM 541 | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 542 | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) 543 .doesNotContain(permission.WRITE_EXTERNAL_STORAGE); 544 }); 545 546 // Assert we cannot add. 547 try { 548 packageManager.addWhitelistedRestrictedPermission( 549 PKG, 550 permission.READ_EXTERNAL_STORAGE, 551 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER); 552 fail(); 553 } catch (SecurityException expected) { 554 } 555 try { 556 packageManager.addWhitelistedRestrictedPermission( 557 PKG, 558 permission.WRITE_EXTERNAL_STORAGE, 559 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER); 560 fail(); 561 } catch (SecurityException expected) { 562 } 563 564 runWithShellPermissionIdentity(() -> { 565 // Assert added only to none whitelist. 566 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 567 PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM 568 | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 569 | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) 570 .doesNotContain(permission.READ_EXTERNAL_STORAGE); 571 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 572 PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM 573 | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 574 | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) 575 .doesNotContain(permission.WRITE_EXTERNAL_STORAGE); 576 }); 577 } 578 assertCannotUnWhitelistStorage()579 private void assertCannotUnWhitelistStorage() throws Exception { 580 final PackageManager packageManager = getContext().getPackageManager(); 581 582 runWithShellPermissionIdentity(() -> { 583 // Assert added only to install whitelist. 584 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 585 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) 586 .contains(permission.READ_EXTERNAL_STORAGE); 587 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 588 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) 589 .contains(permission.WRITE_EXTERNAL_STORAGE); 590 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 591 PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 592 | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) 593 .doesNotContain(permission.READ_EXTERNAL_STORAGE); 594 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 595 PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 596 | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) 597 .doesNotContain(permission.WRITE_EXTERNAL_STORAGE); 598 }); 599 600 try { 601 // Assert we cannot remove. 602 packageManager.removeWhitelistedRestrictedPermission( 603 PKG, 604 permission.READ_EXTERNAL_STORAGE, 605 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER); 606 fail(); 607 } catch (SecurityException expected) { 608 } 609 try { 610 packageManager.removeWhitelistedRestrictedPermission( 611 PKG, 612 permission.WRITE_EXTERNAL_STORAGE, 613 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER); 614 fail(); 615 } catch (SecurityException expected) { 616 } 617 618 runWithShellPermissionIdentity(() -> { 619 // Assert added only to install whitelist. 620 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 621 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) 622 .contains(permission.READ_EXTERNAL_STORAGE); 623 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 624 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) 625 .contains(permission.WRITE_EXTERNAL_STORAGE); 626 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 627 PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 628 | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) 629 .doesNotContain(permission.READ_EXTERNAL_STORAGE); 630 assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG, 631 PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE 632 | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) 633 .doesNotContain(permission.WRITE_EXTERNAL_STORAGE); 634 }); 635 } 636 getPermissionsOfAppWithAnyOfFlags(int flags)637 private @NonNull Set<String> getPermissionsOfAppWithAnyOfFlags(int flags) throws Exception { 638 final PackageManager packageManager = getContext().getPackageManager(); 639 final Set<String> restrictedPermissions = new ArraySet<>(); 640 for (String permission : getRequestedPermissionsOfApp()) { 641 PermissionInfo permInfo = packageManager.getPermissionInfo(permission, 0); 642 643 if ((permInfo.flags & flags) != 0) { 644 restrictedPermissions.add(permission); 645 } 646 } 647 return restrictedPermissions; 648 } 649 getRestrictedPermissionsOfApp()650 private @NonNull Set<String> getRestrictedPermissionsOfApp() throws Exception { 651 return getPermissionsOfAppWithAnyOfFlags( 652 PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED); 653 } 654 getRequestedPermissionsOfApp()655 private @NonNull String[] getRequestedPermissionsOfApp() throws Exception { 656 final PackageManager packageManager = getContext().getPackageManager(); 657 final PackageInfo packageInfo = 658 packageManager.getPackageInfo(PKG, PackageManager.GET_PERMISSIONS); 659 return packageInfo.requestedPermissions; 660 } 661 getContext()662 private static @NonNull Context getContext() { 663 return InstrumentationRegistry.getInstrumentation().getContext(); 664 } 665 runWithShellPermissionIdentity(@onNull ThrowingRunnable command)666 private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable command) 667 throws Exception { 668 InstrumentationRegistry.getInstrumentation() 669 .getUiAutomation() 670 .adoptShellPermissionIdentity(); 671 try { 672 command.run(); 673 } finally { 674 InstrumentationRegistry.getInstrumentation() 675 .getUiAutomation() 676 .dropShellPermissionIdentity(); 677 } 678 } 679 680 /** 681 * Install an app. 682 * 683 * @param app The app to be installed 684 * @param whitelistedPermissions The permission to be whitelisted. {@code null} == all 685 * @param grantedPermissions The permission to be granted. {@code null} == all 686 */ installApp( @onNull String app, @Nullable Set<String> whitelistedPermissions)687 private void installApp( 688 @NonNull String app, 689 @Nullable Set<String> whitelistedPermissions) 690 throws Exception { 691 String bypassLowTargetSdkFlag = ""; 692 if (SdkLevel.isAtLeastU()) { 693 bypassLowTargetSdkFlag = " --bypass-low-target-sdk-block"; 694 } 695 696 // Install the app and whitelist/grant all permission if requested. 697 String installResult = runShellCommand("pm install" 698 + bypassLowTargetSdkFlag + " -t -r --restrict-permissions " + app); 699 assertThat(installResult.trim()).isEqualTo("Success"); 700 701 final Set<String> adjustedWhitelistedPermissions; 702 if (whitelistedPermissions == null) { 703 adjustedWhitelistedPermissions = getRestrictedPermissionsOfApp(); 704 } else { 705 adjustedWhitelistedPermissions = whitelistedPermissions; 706 } 707 708 final Set<String> adjustedGrantedPermissions = getRestrictedPermissionsOfApp(); 709 710 // Whitelist subset of permissions if requested 711 runWithShellPermissionIdentity(() -> { 712 final PackageManager packageManager = getContext().getPackageManager(); 713 for (String permission : adjustedWhitelistedPermissions) { 714 packageManager.addWhitelistedRestrictedPermission( 715 PKG, 716 permission, 717 PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER); 718 } 719 }); 720 721 // Grant subset of permissions if requested 722 runWithShellPermissionIdentity(() -> { 723 final PackageManager packageManager = getContext().getPackageManager(); 724 for (String permission : adjustedGrantedPermissions) { 725 packageManager.grantRuntimePermission(PKG, permission, getContext().getUser()); 726 packageManager.updatePermissionFlags( 727 permission, 728 PKG, 729 PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, 730 0, 731 getContext().getUser()); 732 } 733 }); 734 735 // Mark all permissions as reviewed as for pre-22 apps the restriction state might not be 736 // applied until reviewed 737 runWithShellPermissionIdentity(() -> { 738 final PackageManager packageManager = getContext().getPackageManager(); 739 for (String permission : getRequestedPermissionsOfApp()) { 740 packageManager.updatePermissionFlags( 741 permission, 742 PKG, 743 PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 744 0, 745 getContext().getUser()); 746 } 747 }); 748 } 749 750 @After uninstallApp()751 public void uninstallApp() { 752 runShellCommand("pm uninstall " + PKG); 753 } 754 } 755