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