blob: 1a9295dfb57c392bac1e72689e70801424d3c5fe [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions andf
* limitations under the License.
*/
package android.permission2.cts;
import static android.permission.cts.PermissionUtils.eventually;
import static android.permission.cts.PermissionUtils.isGranted;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.Manifest;
import android.Manifest.permission;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.permission.cts.PermissionUtils.ThrowingRunnable;
import android.platform.test.annotations.AppModeFull;
import android.util.ArraySet;
import androidx.annotation.NonNull;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Collections;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Tests for restricted permission behaviors.
*/
public class RestrictedPermissionsTest {
private static final String APK_USES_SMS_CALL_LOG =
"/data/local/tmp/cts/permissions2/CtsRestrictedPermissionsUser.apk";
private static final String APK_USES_STORAGE_DEFAULT_28 =
"/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk28.apk";
private static final String APK_USES_STORAGE_DEFAULT_29 =
"/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk29.apk";
private static final String APK_USES_STORAGE_OPT_IN_28 =
"/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk28.apk";
private static final String APK_USES_STORAGE_OPT_OUT_29 =
"/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk29.apk";
private static final String PKG = "android.permission2.cts.restrictedpermissionuser";
private static @NonNull BroadcastReceiver sCommandReceiver;
@BeforeClass
public static void setUpOnce() {
sCommandReceiver = new CommandBroadcastReceiver();
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("installRestrictedPermissionUserApp");
intentFilter.addAction("uninstallApp");
getContext().registerReceiver(sCommandReceiver, intentFilter);
}
@AfterClass
public static void tearDownOnce() {
getContext().unregisterReceiver(sCommandReceiver);
}
@Test
@AppModeFull
public void testDefaultAllRestrictedPermissionsWhitelistedAtInstall() throws Exception {
// Install with no changes to whitelisted permissions, not attempting to grant.
installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
null /*grantedPermissions*/);
// All restricted permission should be whitelisted.
assertAllRestrictedPermissionWhitelisted();
// No restricted permission should be granted.
assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testSomeRestrictedPermissionsWhitelistedAtInstall() throws Exception {
// Whitelist only these permissions.
final Set<String> whitelistedPermissions = new ArraySet<>(2);
whitelistedPermissions.add(Manifest.permission.SEND_SMS);
whitelistedPermissions.add(Manifest.permission.READ_CALL_LOG);
// Install with some whitelisted permissions, not attempting to grant.
installRestrictedPermissionUserApp(whitelistedPermissions, null /*grantedPermissions*/);
// Some restricted permission should be whitelisted.
eventually(() -> assertRestrictedPermissionWhitelisted(whitelistedPermissions));
// No restricted permission should be granted.
assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testNoneRestrictedPermissionWhitelistedAtInstall() throws Exception {
// Install with all whitelisted permissions, not attempting to grant.
installRestrictedPermissionUserApp(Collections.emptySet(),
null /*grantedPermissions*/);
// No restricted permission should be whitelisted.
assertNoRestrictedPermissionWhitelisted();
// No restricted permission should be granted.
assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testSomeRestrictedPermissionsGrantedAtInstall() throws Exception {
// Grant only these permissions.
final Set<String> grantedPermissions = new ArraySet<>(1);
grantedPermissions.add(Manifest.permission.SEND_SMS);
grantedPermissions.add(Manifest.permission.READ_CALL_LOG);
// Install with no whitelisted permissions attempting to grant.
installRestrictedPermissionUserApp(null /*whitelistedPermissions*/, grantedPermissions);
// All restricted permission should be whitelisted.
assertAllRestrictedPermissionWhitelisted();
// Some restricted permission should be granted.
assertRestrictedPermissionGranted(grantedPermissions);
}
@Test
@AppModeFull
public void testCanGrantSoftRestrictedNotWhitelistedPermissions() throws Exception {
try {
final Set<String> grantedPermissions = new ArraySet<>();
grantedPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
grantedPermissions.add(permission.WRITE_EXTERNAL_STORAGE);
installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet(), grantedPermissions);
assertRestrictedPermissionGranted(grantedPermissions);
} finally {
uninstallApp();
}
}
@Test
@AppModeFull
public void testAllRestrictedPermissionsGrantedAtInstall() throws Exception {
// Install with whitelisted permissions attempting to grant.
installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
Collections.emptySet());
// All restricted permission should be whitelisted.
assertAllRestrictedPermissionWhitelisted();
// Some restricted permission should be granted.
assertAllRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testWhitelistAccessControl() throws Exception {
// Install with no whitelisted permissions not attempting to grant.
installRestrictedPermissionUserApp(Collections.emptySet(),
Collections.emptySet());
assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE);
assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
}
@Test
@AppModeFull
public void testStorageTargetingSdk28DefaultWhitelistedHasFullAccess() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
// Check expected storage mode
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk28OptInWhitelistedHasIsolatedAccess() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
// Check expected storage mode
assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29DefaultWhitelistedHasIsolatedAccess() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet());
// Check expected storage mode
assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29DefaultNotWhitelistedHasIsolatedAccess() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_29, null /*whitelistedPermissions*/);
// Check expected storage mode
assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29OptOutWhitelistedHasFullAccess() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_OUT_29, null /*whitelistedPermissions*/);
// Check expected storage mode
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29OptOutNotWhitelistedHasIsolatedAccess() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet());
// Check expected storage mode
assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29CanOptOutViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_29, null);
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testStorageTargetingSdk29CanOptOutViaDowngradeTo28() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_29, null);
installApp(APK_USES_STORAGE_DEFAULT_28, null);
eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testStorageTargetingSdk28CanRemoveOptInViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_OPT_IN_28, null);
installApp(APK_USES_STORAGE_DEFAULT_28, null);
eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testStorageTargetingSdk28CanRemoveOptInByOptingOut() throws Exception {
installApp(APK_USES_STORAGE_OPT_IN_28, null);
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testStorageTargetingSdk28DoesNotLooseAccessWhenOptingIn() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_28, null);
installApp(APK_USES_STORAGE_OPT_IN_28, null);
eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testStorageTargetingSdk28DoesNotLooseAccessViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_28, null);
installApp(APK_USES_STORAGE_DEFAULT_29, null);
eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testStorageTargetingSdk29DoesNotLooseAccessViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
installApp(APK_USES_STORAGE_DEFAULT_29, null);
eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testStorageTargetingSdk29DoesNotLooseAccessWhenOptingIn() throws Exception {
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
installApp(APK_USES_STORAGE_OPT_IN_28, null);
eventually(this::assertHasFullStorageAccess);
}
@Test
@AppModeFull
public void testCannotControlStorageWhitelistPostInstall1() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
// Check expected state of restricted permissions.
assertCannotUnWhitelistStorage();
}
@Test
@AppModeFull
public void testCannotControlStorageWhitelistPostInstall2() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
// Check expected state of restricted permissions.
assertCannotWhitelistStorage();
}
@Test
@AppModeFull
public void cannotGrantStorageTargetingSdk28NotWhitelisted() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet(), Collections.emptySet());
// Could not grant permission as targetSDK<29 and not whitelisted
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
}
@Test
@AppModeFull
public void cannotGrantStorageTargetingSdk28OptInNotWhitelisted() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_IN_28, Collections.emptySet(), Collections.emptySet());
// Could not grant permission as targetSDK<29 and not whitelisted
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
}
@Test
@AppModeFull
public void canGrantStorageTargetingSdk28Whitelisted() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_28, null, Collections.emptySet());
// Could grant permission
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
}
@Test
@AppModeFull
public void canGrantStorageTargetingSdk28OptInWhitelisted() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_IN_28, null, Collections.emptySet());
// Could grant permission
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
}
@Test
@AppModeFull
public void canGrantStorageTargetingSdk29NotWhitelisted() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet(), Collections.emptySet());
// Could grant permission as targetSDK=29 apps can always grant
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
}
@Test
@AppModeFull
public void canGrantStorageTargetingSdk29OptOutNotWhitelisted() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet(), Collections.emptySet());
// Could grant permission as targetSDK=29 apps can always grant
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
}
@Test
@AppModeFull
public void canGrantStorageTargetingSdk29Whitelisted() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_29, null, Collections.emptySet());
// Could grant permission as targetSDK=29 apps can always grant
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
}
@Test
@AppModeFull
public void canGrantStorageTargetingSdk29OptOutWhitelisted() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_OUT_29, null, Collections.emptySet());
// Could grant permission as targetSDK=29 apps can always grant
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
}
private void assertHasFullStorageAccess() throws Exception {
runWithShellPermissionIdentity(() -> {
AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
assertThat(appOpsManager.unsafeCheckOpRawNoThrow(AppOpsManager.OPSTR_LEGACY_STORAGE,
uid, PKG)).isEqualTo(AppOpsManager.MODE_ALLOWED);
});
}
private void assertHasIsolatedStorageAccess() throws Exception {
runWithShellPermissionIdentity(() -> {
AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
assertThat(appOpsManager.unsafeCheckOpRawNoThrow(AppOpsManager.OPSTR_LEGACY_STORAGE,
uid, PKG)).isNotEqualTo(AppOpsManager.MODE_ALLOWED);
});
}
private void assertWeCannotReadOrWriteWhileShellCanReadAndWrite(int whitelist)
throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
try {
packageManager.getWhitelistedRestrictedPermissions(PKG, whitelist);
fail();
} catch (SecurityException expected) {
/*ignore*/
}
try {
packageManager.addWhitelistedRestrictedPermission(PKG,
permission.SEND_SMS, whitelist);
fail();
} catch (SecurityException expected) {
/*ignore*/
}
runWithShellPermissionIdentity(() -> {
packageManager.addWhitelistedRestrictedPermission(PKG,
permission.SEND_SMS, whitelist);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
whitelist)).contains(permission.SEND_SMS);
packageManager.removeWhitelistedRestrictedPermission(PKG,
permission.SEND_SMS, whitelist);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
whitelist)).doesNotContain(permission.SEND_SMS);
});
}
private void assertCannotWhitelistStorage()
throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
runWithShellPermissionIdentity(() -> {
// Assert added only to none whitelist.
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
| PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
.doesNotContain(permission.READ_EXTERNAL_STORAGE);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
| PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
.doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
});
// Assert we cannot add.
try {
packageManager.addWhitelistedRestrictedPermission(PKG,
permission.READ_EXTERNAL_STORAGE,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
fail();
} catch (SecurityException expected) {}
try {
packageManager.addWhitelistedRestrictedPermission(PKG,
permission.WRITE_EXTERNAL_STORAGE,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
fail();
} catch (SecurityException expected) {}
runWithShellPermissionIdentity(() -> {
// Assert added only to none whitelist.
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
| PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
.doesNotContain(permission.READ_EXTERNAL_STORAGE);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
| PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
.doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
});
}
private void assertCannotUnWhitelistStorage()
throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
runWithShellPermissionIdentity(() -> {
// Assert added only to install whitelist.
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
.contains(permission.READ_EXTERNAL_STORAGE);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
.contains(permission.WRITE_EXTERNAL_STORAGE);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
.doesNotContain(permission.READ_EXTERNAL_STORAGE);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
.doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
});
try {
// Assert we cannot remove.
packageManager.removeWhitelistedRestrictedPermission(PKG,
permission.READ_EXTERNAL_STORAGE,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
fail();
} catch (SecurityException expected) {}
try {
packageManager.removeWhitelistedRestrictedPermission(PKG,
permission.WRITE_EXTERNAL_STORAGE,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
fail();
} catch (SecurityException expected) {}
runWithShellPermissionIdentity(() -> {
// Assert added only to install whitelist.
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
.contains(permission.READ_EXTERNAL_STORAGE);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
.contains(permission.WRITE_EXTERNAL_STORAGE);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
.doesNotContain(permission.READ_EXTERNAL_STORAGE);
assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
| PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
.doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
});
}
private void assertAllRestrictedPermissionWhitelisted() throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
final PackageInfo packageInfo = packageManager.getPackageInfo(PKG,
PackageManager.GET_PERMISSIONS);
if (packageInfo.requestedPermissions == null) {
return;
}
runWithShellPermissionIdentity(() -> {
final Set<String> whitelistedPermissions = packageManager
.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
| PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
| PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE);
if (packageInfo.requestedPermissions != null) {
final int permissionCount = packageInfo.requestedPermissions.length;
for (int i = 0; i < permissionCount; i++) {
final String permission = packageInfo.requestedPermissions[i];
final PermissionInfo permissionInfo = packageManager
.getPermissionInfo(permission,
0);
if ((permissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0) {
whitelistedPermissions.remove(permission);
}
}
}
assertThat(whitelistedPermissions).isNotNull();
assertThat(whitelistedPermissions).isEmpty();
});
}
private void assertNoRestrictedPermissionWhitelisted() throws Exception {
assertRestrictedPermissionWhitelisted(null /*expectedWhitelistedPermissions*/);
}
private void assertRestrictedPermissionWhitelisted(
@Nullable Set<String> expectedWhitelistedPermissions) throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
runWithShellPermissionIdentity(() -> {
final Set<String> whitelistedPermissions = packageManager
.getWhitelistedRestrictedPermissions(PKG,
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
| PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER
| PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE);
assertThat(whitelistedPermissions).isNotNull();
if (expectedWhitelistedPermissions == null) {
assertThat(whitelistedPermissions.isEmpty()).isTrue();
} else {
assertThat(whitelistedPermissions.size()).isEqualTo(
expectedWhitelistedPermissions.size());
assertThat(whitelistedPermissions.containsAll(
expectedWhitelistedPermissions)).isTrue();
}
// Also assert that apps ops are properly set
final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
final PackageInfo packageInfo = packageManager.getPackageInfo(PKG,
PackageManager.GET_PERMISSIONS);
for (String permission : packageInfo.requestedPermissions) {
String op = AppOpsManager.permissionToOp(permission);
if (expectedWhitelistedPermissions != null
&& expectedWhitelistedPermissions.contains(permission)) {
assertThat(
appOpsManager.unsafeCheckOpNoThrow(op, packageInfo.applicationInfo.uid,
PKG)).named(op).isEqualTo(AppOpsManager.MODE_ALLOWED);
} else {
assertThat(
appOpsManager.unsafeCheckOpNoThrow(op, packageInfo.applicationInfo.uid,
PKG)).named(op).isEqualTo(AppOpsManager.MODE_DEFAULT);
}
}
});
}
private void assertAllHardRestrictedPermissionAppOpsAllowed() throws Exception {
runWithShellPermissionIdentity(() -> {
// Also assert that apps ops are properly set
final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
final PackageInfo packageInfo = getContext().getPackageManager().getPackageInfo(PKG,
PackageManager.GET_PERMISSIONS);
for (String permission : packageInfo.requestedPermissions) {
final PermissionInfo permissionInfo = getContext().getPackageManager()
.getPermissionInfo(permission, 0);
if ((permissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0) {
assertThat(appOpsManager.unsafeCheckOpNoThrow(
AppOpsManager.permissionToOp(permission),
packageInfo.applicationInfo.uid, PKG))
.isEqualTo(AppOpsManager.MODE_ALLOWED);
}
}
});
}
private void assertAllRestrictedPermissionGranted() throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
final PackageInfo packageInfo = packageManager.getPackageInfo(
PKG, PackageManager.GET_PERMISSIONS);
if (packageInfo.requestedPermissions != null) {
final int permissionCount = packageInfo.requestedPermissions.length;
for (int i = 0; i < permissionCount; i++) {
final String permission = packageInfo.requestedPermissions[i];
final PermissionInfo permissionInfo = packageManager.getPermissionInfo(
permission, 0);
if ((permissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0) {
assertThat((packageInfo.requestedPermissionsFlags[i]
& PackageInfo.REQUESTED_PERMISSION_GRANTED)).isNotEqualTo(0);
}
}
}
}
private void assertNoRestrictedPermissionGranted() throws Exception {
assertRestrictedPermissionGranted(null /*expectedGrantedPermissions*/);
}
private void assertRestrictedPermissionGranted(@Nullable Set<String> expectedGrantedPermissions)
throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
final PackageInfo packageInfo = packageManager.getPackageInfo(
PKG, PackageManager.GET_PERMISSIONS);
if (packageInfo.requestedPermissions != null) {
final int permissionCount = packageInfo.requestedPermissions.length;
for (int i = 0; i < permissionCount; i++) {
final String permission = packageInfo.requestedPermissions[i];
final PermissionInfo permissionInfo = packageManager.getPermissionInfo(
permission, 0);
if ((permissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
|| (permissionInfo.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
if (expectedGrantedPermissions != null
&& expectedGrantedPermissions.contains(permission)) {
assertThat((packageInfo.requestedPermissionsFlags[i]
& PackageInfo.REQUESTED_PERMISSION_GRANTED)).isNotEqualTo(0);
} else {
assertThat((packageInfo.requestedPermissionsFlags[i]
& PackageInfo.REQUESTED_PERMISSION_GRANTED)).isEqualTo(0);
}
}
}
}
}
private void installRestrictedPermissionUserApp(@Nullable Set<String> whitelistedPermissions,
@Nullable Set<String> grantedPermissions) throws Exception {
installApp(APK_USES_SMS_CALL_LOG, whitelistedPermissions, grantedPermissions);
}
private void installApp(@NonNull String app, @Nullable Set<String> whitelistedPermissions)
throws Exception {
installApp(app, whitelistedPermissions, null /*grantedPermissions*/);
}
private void installApp(@NonNull String app, @Nullable Set<String> whitelistedPermissions,
@Nullable Set<String> grantedPermissions) throws Exception {
// Install the app and whitelist/grant all permission if requested.
final StringBuilder command = new StringBuilder("pm install -r ");
if (whitelistedPermissions != null) {
command.append("--restrict-permissions ");
}
if (grantedPermissions != null && grantedPermissions.isEmpty()) {
command.append("-g ");
}
command.append(app);
String installResult = runShellCommand(command.toString());
assertThat(installResult.trim()).isEqualTo("Success");
// Whitelist subset of permissions if requested
if (whitelistedPermissions != null && !whitelistedPermissions.isEmpty()) {
runWithShellPermissionIdentity(() -> {
final PackageManager packageManager = getContext().getPackageManager();
for (String permission : whitelistedPermissions) {
packageManager.addWhitelistedRestrictedPermission(PKG, permission,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
}
});
}
// Grant subset of permissions if requested
if (grantedPermissions != null && !grantedPermissions.isEmpty()) {
runWithShellPermissionIdentity(() -> {
final PackageManager packageManager = getContext().getPackageManager();
for (String permission : grantedPermissions) {
packageManager.grantRuntimePermission(PKG, permission,
getContext().getUser());
}
});
}
}
@After
public void uninstallApp() {
runShellCommand("pm uninstall " + PKG);
}
private static @NonNull Context getContext() {
return InstrumentationRegistry.getInstrumentation().getContext();
}
private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable command)
throws Exception {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity();
try {
command.runOrThrow();
} finally {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.dropShellPermissionIdentity();
}
}
}