blob: 996630ac12f870101b8979c9d7a122bbc538e8e4 [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 android.permission.cts.PermissionUtils.isPermissionGranted;
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.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.Session;
import android.content.pm.PackageInstaller.SessionParams;
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.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
/**
* Tests for restricted permission behaviors.
*/
public class RestrictedPermissionsTest {
private static final String APK_USES_LOCATION_22 =
"/data/local/tmp/cts/permissions2/CtsLocationPermissionsUserSdk22.apk";
private static final String APK_USES_LOCATION_29 =
"/data/local/tmp/cts/permissions2/CtsLocationPermissionsUserSdk29.apk";
private static final String APK_USES_SMS_CALL_LOG_22 =
"/data/local/tmp/cts/permissions2/CtsSMSCallLogPermissionsUserSdk22.apk";
private static final String APK_NAME_USES_SMS_CALL_LOG_29 =
"CtsSMSCallLogPermissionsUserSdk29.apk";
private static final String APK_USES_SMS_CALL_LOG_29 =
"/data/local/tmp/cts/permissions2/CtsSMSCallLogPermissionsUserSdk29.apk";
private static final String APK_USES_STORAGE_DEFAULT_22 =
"/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk22.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_22 =
"/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk22.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 final long UI_TIMEOUT = 5000L;
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 testDefaultAllRestrictedPermissionsWhitelistedAtInstall29() throws Exception {
// Install with no changes to whitelisted permissions, not attempting to grant.
installRestrictedPermissionUserApp(null /*whitelistedPermissions*/,
Collections.EMPTY_SET /*grantedPermissions*/);
// All restricted permission should be whitelisted.
assertAllRestrictedPermissionWhitelisted();
// No restricted permission should be granted.
assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testSomeRestrictedPermissionsWhitelistedAtInstall29() 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,
Collections.EMPTY_SET /*grantedPermissions*/);
// Some restricted permission should be whitelisted.
assertRestrictedPermissionWhitelisted(whitelistedPermissions);
// No restricted permission should be granted.
assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testNoneRestrictedPermissionWhitelistedAtInstall29() throws Exception {
// Install with all whitelisted permissions, not attempting to grant.
installRestrictedPermissionUserApp(Collections.emptySet(),
Collections.EMPTY_SET /*grantedPermissions*/);
// No restricted permission should be whitelisted.
assertNoRestrictedPermissionWhitelisted();
// No restricted permission should be granted.
assertNoRestrictedPermissionGranted();
}
@Test
@AppModeFull
public void testDefaultAllRestrictedPermissionsWhitelistedAtInstall22() throws Exception {
// Install with no changes to whitelisted permissions
runShellCommand("pm install -g " + APK_USES_SMS_CALL_LOG_22);
// All restricted permission should be whitelisted.
assertAllRestrictedPermissionWhitelisted();
}
@Test
@AppModeFull
public void testSomeRestrictedPermissionsWhitelistedAtInstall22() 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
installApp(APK_USES_SMS_CALL_LOG_22, whitelistedPermissions, null /*grantedPermissions*/);
// Some restricted permission should be whitelisted.
assertRestrictedPermissionWhitelisted(whitelistedPermissions);
}
@Test
@AppModeFull
public void testNoneRestrictedPermissionWhitelistedAtInstall22() throws Exception {
// Install with all whitelisted permissions
installApp(APK_USES_SMS_CALL_LOG_22, Collections.emptySet(),
null /*grantedPermissions*/);
// No restricted permission should be whitelisted.
assertNoRestrictedPermissionWhitelisted();
}
@Test
@AppModeFull
public void testLocationBackgroundPermissionWhitelistedAtInstall29() throws Exception {
installApp(APK_USES_LOCATION_29, null, null);
assertAllRestrictedPermissionWhitelisted();
}
@Test
@AppModeFull
public void testLocationBackgroundPermissionNotWhitelistedAtInstall29() throws Exception {
installApp(APK_USES_LOCATION_29, Collections.EMPTY_SET, null);
assertNoRestrictedPermissionWhitelisted();
}
@Test
@AppModeFull
public void testLocationBackgroundPermissionWhitelistedAtInstall22() throws Exception {
installApp(APK_USES_LOCATION_22, null, null);
assertAllRestrictedPermissionWhitelisted();
}
@Test
@AppModeFull
public void testLocationBackgroundPermissionNotWhitelistedAtInstall22() throws Exception {
installApp(APK_USES_LOCATION_22, Collections.EMPTY_SET, null);
assertNoRestrictedPermissionWhitelisted();
}
@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*/,
null);
// 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(), null);
assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE);
assertWeCannotReadOrWriteWhileShellCanReadAndWrite(
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
}
@Test
@AppModeFull
public void testStorageTargetingSdk22DefaultWhitelistedHasFullAccess() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_22, null /*whitelistedPermissions*/);
// Check expected storage mode
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk22OptInWhitelistedHasIsolatedAccess() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_IN_22, null /*whitelistedPermissions*/);
// Check expected storage mode
assertHasIsolatedStorageAccess();
}
@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);
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29CanOptOutViaDowngradeTo28() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_29, null);
installApp(APK_USES_STORAGE_DEFAULT_28, null);
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk28CanRemoveOptInViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_OPT_IN_28, null);
installApp(APK_USES_STORAGE_DEFAULT_28, null);
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk28CanRemoveOptInByOptingOut() throws Exception {
installApp(APK_USES_STORAGE_OPT_IN_28, null);
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk28DoesNotLooseAccessWhenOptingIn() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_28, null);
installApp(APK_USES_STORAGE_OPT_IN_28, null);
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk28DoesNotLooseAccessViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_DEFAULT_28, null);
installApp(APK_USES_STORAGE_DEFAULT_29, null);
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29DoesNotLooseAccessViaUpdate() throws Exception {
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
installApp(APK_USES_STORAGE_DEFAULT_29, null);
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void testStorageTargetingSdk29DoesNotLooseAccessWhenOptingIn() throws Exception {
installApp(APK_USES_STORAGE_OPT_OUT_29, null);
installApp(APK_USES_STORAGE_OPT_IN_28, null);
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 cannotGrantStorageTargetingSdk22NotWhitelisted() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_22, Collections.emptySet(), null);
eventually(() -> {
// Could not grant permission+app-op as targetSDK<29 and not whitelisted
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
// Permissions are always granted for pre-23 apps
assertThat(
isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
});
}
@Test
@AppModeFull
public void cannotGrantStorageTargetingSdk22OptInNotWhitelisted() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_IN_22, Collections.emptySet(), null);
eventually(() -> {
// Could not grant permission as targetSDK<29 and not whitelisted
assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
// Permissions are always granted for pre-23 apps
assertThat(
isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
});
}
@Test
@AppModeFull
public void canGrantStorageTargetingSdk22Whitelisted() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_22, null, null);
// Could grant permission
eventually(() -> assertThat(
isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
}
@Test
@AppModeFull
public void canGrantStorageTargetingSdk22OptInWhitelisted() throws Exception {
// Install with whitelisted permissions.
installApp(APK_USES_STORAGE_OPT_IN_22, null, null);
// Could grant permission
eventually(() -> assertThat(
isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
}
@Test
@AppModeFull
public void cannotGrantStorageTargetingSdk28NotWhitelisted() throws Exception {
// Install with no whitelisted permissions.
installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet(), null);
// Could not grant permission as targetSDK<29 and not whitelisted
eventually(() -> 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(), null);
// Could not grant permission as targetSDK<29 and not whitelisted
eventually(() -> 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, null);
// Could grant permission
eventually(() -> 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, null);
// Could grant permission
eventually(() -> 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(), null);
// Could grant permission as targetSDK=29 apps can always grant
eventually(() -> 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(), null);
// Could grant permission as targetSDK=29 apps can always grant
eventually(() -> 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, null);
// Could grant permission as targetSDK=29 apps can always grant
eventually(() -> 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, null);
// Could grant permission as targetSDK=29 apps can always grant
eventually(() -> assertThat(
isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
}
@Test
@AppModeFull
public void restrictedWritePermDoesNotImplyIsolatedStorageAccess() throws Exception {
// Install with whitelisted read permissions.
installApp(APK_USES_STORAGE_OPT_OUT_29,
Collections.singleton(Manifest.permission.READ_EXTERNAL_STORAGE), null);
// It does not matter that write is restricted as the storage access level is only
// controlled by the read perm
assertHasFullStorageAccess();
}
@Test
@AppModeFull
public void whitelistedWritePermDoesNotImplyFullStorageAccess() throws Exception {
// Install with whitelisted read permissions.
installApp(APK_USES_STORAGE_OPT_OUT_29,
Collections.singleton(Manifest.permission.WRITE_EXTERNAL_STORAGE), null);
// It does not matter that write is white listed as the storage access level is only
// controlled by the read perm
assertHasIsolatedStorageAccess();
}
@Test
@AppModeFull
public void onSideLoadRestrictedPermissionsWhitelistingDefault() throws Exception {
installRestrictedPermissionUserApp(new SessionParams(SessionParams.MODE_FULL_INSTALL));
// All restricted permissions whitelisted on side-load by default
assertAllRestrictedPermissionWhitelisted();
}
@Test
@AppModeFull
public void onSideLoadAllRestrictedPermissionsWhitelisted() throws Exception {
SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
params.setWhitelistedRestrictedPermissions(SessionParams.RESTRICTED_PERMISSIONS_ALL);
installRestrictedPermissionUserApp(params);
assertAllRestrictedPermissionWhitelisted();
}
@Test
@AppModeFull
public void onSideLoadWhitelistSomePermissions() throws Exception {
Set<String> whitelistedPermissions = new ArraySet<>();
whitelistedPermissions.add(Manifest.permission.SEND_SMS);
whitelistedPermissions.add(Manifest.permission.READ_CALL_LOG);
SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
params.setWhitelistedRestrictedPermissions(whitelistedPermissions);
installRestrictedPermissionUserApp(params);
assertRestrictedPermissionWhitelisted(whitelistedPermissions);
}
@Test
@AppModeFull
public void onSideLoadWhitelistNoPermissions() throws Exception {
SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
params.setWhitelistedRestrictedPermissions(Collections.emptySet());
installRestrictedPermissionUserApp(params);
assertNoRestrictedPermissionWhitelisted();
}
private static void installRestrictedPermissionUserApp(@NonNull SessionParams params)
throws Exception {
final CountDownLatch installLatch = new CountDownLatch(1);
// Create an install result receiver.
final BroadcastReceiver installReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE_INVALID)
== PackageInstaller.STATUS_SUCCESS) {
installLatch.countDown();
}
}
};
// Register the result receiver.
final String action = "android.permission2.cts.ACTION_INSTALL_COMMIT";
final IntentFilter intentFilter = new IntentFilter(action);
getContext().registerReceiver(installReceiver, intentFilter);
try {
// Create a session.
final PackageInstaller packageInstaller = getContext()
.getPackageManager().getPackageInstaller();
final int sessionId = packageInstaller.createSession(params);
final Session session = packageInstaller.openSession(sessionId);
// Write the apk.
try (
InputStream in = new BufferedInputStream(new FileInputStream(
new File(APK_USES_SMS_CALL_LOG_29)));
OutputStream out = session.openWrite(
APK_NAME_USES_SMS_CALL_LOG_29, 0, -1);
) {
final byte[] buf = new byte[8192];
int size;
while ((size = in.read(buf)) != -1) {
out.write(buf, 0, size);
}
}
final Intent intent = new Intent(action);
final IntentSender intentSender = PendingIntent.getBroadcast(getContext(),
1, intent, PendingIntent.FLAG_ONE_SHOT).getIntentSender();
// Commit as shell to avoid confirm UI
runWithShellPermissionIdentity(() ->
session.commit(intentSender)
);
installLatch.await(UI_TIMEOUT, TimeUnit.MILLISECONDS);
} finally {
getContext().unregisterReceiver(installReceiver);
}
}
private void assertHasFullStorageAccess() throws Exception {
runWithShellPermissionIdentity(() -> {
AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
eventually(() -> 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);
eventually(() -> 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 @NonNull Set<String> getPermissionsOfAppWithAnyOfFlags(int flags) throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
final PackageInfo packageInfo = packageManager.getPackageInfo(PKG,
PackageManager.GET_PERMISSIONS);
final Set<String> hardRestrictedPermissions = new ArraySet<>();
for (String permission : packageInfo.requestedPermissions) {
PermissionInfo permInfo = packageManager.getPermissionInfo(permission, 0);
if ((permInfo.flags & flags) != 0) {
hardRestrictedPermissions.add(permission);
}
}
return hardRestrictedPermissions;
}
private @NonNull Set<String> getRestrictedPermissionsOfApp() throws Exception {
return getPermissionsOfAppWithAnyOfFlags(
PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED);
}
private void assertAllRestrictedPermissionWhitelisted() throws Exception {
assertRestrictedPermissionWhitelisted(getRestrictedPermissionsOfApp());
}
private void assertNoRestrictedPermissionWhitelisted() throws Exception {
assertRestrictedPermissionWhitelisted(
Collections.EMPTY_SET /*expectedWhitelistedPermissions*/);
}
/**
* Assert that the passed in restrictions are whitelisted and that their app-op is set
* correctly.
*
* @param expectedWhitelistedPermissions The expected white listed permissions
*/
private void assertRestrictedPermissionWhitelisted(
@NonNull Set<String> expectedWhitelistedPermissions) throws Exception {
final PackageManager packageManager = getContext().getPackageManager();
eventually(() -> runWithShellPermissionIdentity(() -> {
final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
final PackageInfo packageInfo = packageManager.getPackageInfo(PKG,
PackageManager.GET_PERMISSIONS);
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();
assertThat(whitelistedPermissions).named("Whitelisted permissions")
.containsExactlyElementsIn(expectedWhitelistedPermissions);
// Also assert that apps ops are properly set
for (String permission : getRestrictedPermissionsOfApp()) {
String op = AppOpsManager.permissionToOp(permission);
ArraySet<Integer> possibleModes = new ArraySet<>();
if (permission.equals(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
op = AppOpsManager.OPSTR_FINE_LOCATION;
// If permission is denied app-op might be allowed/fg or ignored. It does
// not matter. If permission is granted, it has to be allowed/fg.
if (isPermissionGranted(PKG, Manifest.permission.ACCESS_FINE_LOCATION)) {
if (expectedWhitelistedPermissions.contains(permission)
&& isPermissionGranted(PKG, permission)) {
possibleModes.add(AppOpsManager.MODE_ALLOWED);
} else {
possibleModes.add(AppOpsManager.MODE_FOREGROUND);
}
} else {
possibleModes.add(AppOpsManager.MODE_IGNORED);
possibleModes.add(AppOpsManager.MODE_ALLOWED);
possibleModes.add(AppOpsManager.MODE_FOREGROUND);
}
} else {
if (expectedWhitelistedPermissions.contains(permission)) {
// If permission is denied app-op might be allowed or ignored. It does not
// matter. If permission is granted, it has to be allowed.
possibleModes.add(AppOpsManager.MODE_ALLOWED);
if (!isPermissionGranted(PKG, permission)) {
possibleModes.add(AppOpsManager.MODE_IGNORED);
}
} else {
possibleModes.add(AppOpsManager.MODE_DEFAULT);
}
}
assertThat(appOpsManager.unsafeCheckOpRawNoThrow(op,
packageInfo.applicationInfo.uid, PKG)).named(op).isIn(possibleModes);
}
}));
}
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(Collections.EMPTY_SET);
}
private void assertRestrictedPermissionGranted(@NonNull 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.contains(permission)) {
assertThat((packageInfo.requestedPermissionsFlags[i]
& PackageInfo.REQUESTED_PERMISSION_GRANTED)).isNotEqualTo(0);
} else {
assertThat((packageInfo.requestedPermissionsFlags[i]
& PackageInfo.REQUESTED_PERMISSION_GRANTED)).isEqualTo(0);
}
}
}
}
}
/**
* Install {@link #APK_USES_SMS_CALL_LOG_29}.
*
* @param whitelistedPermissions The permission to be whitelisted. {@code null} == all
* @param grantedPermissions The permission to be granted. {@code null} == all
*/
private void installRestrictedPermissionUserApp(@Nullable Set<String> whitelistedPermissions,
@Nullable Set<String> grantedPermissions) throws Exception {
installApp(APK_USES_SMS_CALL_LOG_29, whitelistedPermissions, grantedPermissions);
}
/**
* Install app and grant all permission.
*
* @param app The app to be installed
* @param whitelistedPermissions The permission to be whitelisted. {@code null} == all
*/
private void installApp(@NonNull String app, @Nullable Set<String> whitelistedPermissions)
throws Exception {
installApp(app, whitelistedPermissions, null /*grantedPermissions*/);
}
/**
* Install an app.
*
* @param app The app to be installed
* @param whitelistedPermissions The permission to be whitelisted. {@code null} == all
* @param grantedPermissions The permission to be granted. {@code null} == all
*/
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.
String installResult = runShellCommand("pm install -r --restrict-permissions " + app);
assertThat(installResult.trim()).isEqualTo("Success");
final Set<String> adjustedWhitelistedPermissions;
if (whitelistedPermissions == null) {
adjustedWhitelistedPermissions = getRestrictedPermissionsOfApp();
} else {
adjustedWhitelistedPermissions = whitelistedPermissions;
}
final Set<String> adjustedGrantedPermissions;
if (grantedPermissions == null) {
adjustedGrantedPermissions = getRestrictedPermissionsOfApp();
} else {
adjustedGrantedPermissions = grantedPermissions;
}
// Whitelist subset of permissions if requested
runWithShellPermissionIdentity(() -> {
final PackageManager packageManager = getContext().getPackageManager();
for (String permission : adjustedWhitelistedPermissions) {
packageManager.addWhitelistedRestrictedPermission(PKG, permission,
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
}
});
// Grant subset of permissions if requested
runWithShellPermissionIdentity(() -> {
final PackageManager packageManager = getContext().getPackageManager();
for (String permission : adjustedGrantedPermissions) {
packageManager.grantRuntimePermission(PKG, permission,
getContext().getUser());
}
});
// Mark all permissions as reviewed as for pre-22 apps the restriction state might not be
// applied until reviewed
runWithShellPermissionIdentity(() -> {
final PackageManager packageManager = getContext().getPackageManager();
for (String permission : getRestrictedPermissionsOfApp()) {
packageManager.updatePermissionFlags(permission, PKG,
PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0,
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();
}
}
}