summaryrefslogtreecommitdiff
path: root/tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java')
-rw-r--r--tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java584
1 files changed, 584 insertions, 0 deletions
diff --git a/tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java b/tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java
new file mode 100644
index 000000000..a509b3bfe
--- /dev/null
+++ b/tests/cts/permission/src/android/permission/cts/SplitPermissionTest.java
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2018 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 and
+ * limitations under the License.
+ */
+
+package android.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.READ_CALL_LOG;
+import static android.Manifest.permission.READ_CONTACTS;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.permission.cts.PermissionUtils.getAppOp;
+import static android.permission.cts.PermissionUtils.getPermissionFlags;
+import static android.permission.cts.PermissionUtils.getPermissions;
+import static android.permission.cts.PermissionUtils.grantPermission;
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permission.cts.PermissionUtils.revokePermission;
+import static android.permission.cts.PermissionUtils.setPermissionFlags;
+import static android.permission.cts.PermissionUtils.uninstallApp;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.UiAutomation;
+import android.os.Build;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SystemUserOnly;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests how split permissions behave.
+ *
+ * <ul>
+ * <li>Default permission grant behavior</li>
+ * <li>Changes to the grant state during upgrade of apps with split permissions</li>
+ * <li>Special behavior of background location</li>
+ * </ul>
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "Instant apps cannot read state of other packages.")
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+public class SplitPermissionTest {
+ /** The package name of all apps used in the test */
+ private static final String APP_PKG = "android.permission.cts.appthatrequestpermission";
+
+ private static final String TMP_DIR = "/data/local/tmp/cts-permission/";
+ private static final String APK_CONTACTS_16 =
+ TMP_DIR + "CtsAppThatRequestsContactsPermission16.apk";
+ private static final String APK_CONTACTS_15 =
+ TMP_DIR + "CtsAppThatRequestsContactsPermission15.apk";
+ private static final String APK_CONTACTS_CALLLOG_16 =
+ TMP_DIR + "CtsAppThatRequestsContactsAndCallLogPermission16.apk";
+ private static final String APK_STORAGE_29 =
+ TMP_DIR + "CtsAppThatRequestsStoragePermission29.apk";
+ private static final String APK_STORAGE_28 =
+ TMP_DIR + "CtsAppThatRequestsStoragePermission28.apk";
+ private static final String APK_LOCATION_29 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission29.apk";
+ private static final String APK_LOCATION_28 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission28.apk";
+ private static final String APK_LOCATION_22 =
+ TMP_DIR + "CtsAppThatRequestsLocationPermission22.apk";
+ private static final String APK_LOCATION_BACKGROUND_28 =
+ TMP_DIR + "CtsAppThatRequestsLocationAndBackgroundPermission28.apk";
+ private static final String APK_LOCATION_BACKGROUND_29 =
+ TMP_DIR + "CtsAppThatRequestsLocationAndBackgroundPermission29.apk";
+ private static final String APK_SHARED_UID_LOCATION_29 =
+ TMP_DIR + "CtsAppWithSharedUidThatRequestsLocationPermission29.apk";
+ private static final String APK_SHARED_UID_LOCATION_28 =
+ TMP_DIR + "CtsAppWithSharedUidThatRequestsLocationPermission28.apk";
+
+ private static final UiAutomation sUiAutomation =
+ InstrumentationRegistry.getInstrumentation().getUiAutomation();
+
+ /**
+ * Assert that {@link #APP_PKG} requests a certain permission.
+ *
+ * @param permName The permission that needs to be requested
+ */
+ private void assertRequestsPermission(@NonNull String permName) throws Exception {
+ assertThat(getPermissions(APP_PKG)).contains(permName);
+ }
+
+ /**
+ * Assert that {@link #APP_PKG} <u>does not</u> request a certain permission.
+ *
+ * @param permName The permission that needs to be not requested
+ */
+ private void assertNotRequestsPermission(@NonNull String permName) throws Exception {
+ assertThat(getPermissions(APP_PKG)).doesNotContain(permName);
+ }
+
+ /**
+ * Assert that a permission is granted to {@link #APP_PKG}.
+ *
+ * @param permName The permission that needs to be granted
+ */
+ private void assertPermissionGranted(@NonNull String permName) throws Exception {
+ eventually(() -> assertWithMessage(permName + " is granted").that(
+ isGranted(APP_PKG, permName)).isTrue());
+ }
+
+ /**
+ * Assert that a permission is <u>not </u> granted to {@link #APP_PKG}.
+ *
+ * @param permName The permission that should not be granted
+ */
+ private void assertPermissionRevoked(@NonNull String permName) throws Exception {
+ assertWithMessage(permName + " is granted").that(isGranted(APP_PKG, permName)).isFalse();
+ }
+
+ /**
+ * Install an APK.
+ *
+ * @param apkFile The apk to install
+ */
+ public void install(@NonNull String apkFile) {
+ PermissionUtils.install(apkFile);
+ }
+
+ @After
+ public void uninstallTestApp() {
+ uninstallApp(APP_PKG);
+ }
+
+ /**
+ * Apps with a targetSDK after the split should <u>not</u> have been added implicitly the new
+ * permission.
+ */
+ @Test
+ public void permissionsDoNotSplitWithHighTargetSDK() throws Exception {
+ install(APK_LOCATION_29);
+
+ assertRequestsPermission(ACCESS_COARSE_LOCATION);
+ assertNotRequestsPermission(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * Apps with a targetSDK after the split should <u>not</u> have been added implicitly the new
+ * permission.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void permissionsDoNotSplitWithHighTargetSDKPreM() throws Exception {
+ install(APK_CONTACTS_16);
+
+ assertRequestsPermission(READ_CONTACTS);
+ assertNotRequestsPermission(READ_CALL_LOG);
+ }
+
+ /**
+ * Apps with a targetSDK before the split should have been added implicitly the new permission.
+ */
+ @Test
+ public void permissionsSplitWithLowTargetSDK() throws Exception {
+ install(APK_LOCATION_28);
+
+ assertRequestsPermission(ACCESS_COARSE_LOCATION);
+ assertRequestsPermission(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * Apps with a targetSDK before the split should have been added implicitly the new permission.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void permissionsSplitWithLowTargetSDKPreM() throws Exception {
+ install(APK_CONTACTS_15);
+
+ assertRequestsPermission(READ_CONTACTS);
+ assertRequestsPermission(READ_CALL_LOG);
+ }
+
+ /**
+ * Permissions are revoked by default for post-M apps
+ */
+ @Test
+ public void nonInheritedStateHighTargetSDK() throws Exception {
+ install(APK_LOCATION_29);
+
+ assertPermissionRevoked(ACCESS_COARSE_LOCATION);
+ }
+
+ /**
+ * Permissions are granted by default for pre-M apps
+ */
+ @Test
+ public void nonInheritedStateHighLowTargetSDKPreM() throws Exception {
+ install(APK_CONTACTS_15);
+
+ assertPermissionGranted(READ_CONTACTS);
+ }
+
+ /**
+ * Permissions are revoked by default for post-M apps. This also applies to permissions added
+ * implicitly due to splits.
+ */
+ @Test
+ public void nonInheritedStateLowTargetSDK() throws Exception {
+ install(APK_LOCATION_28);
+
+ assertPermissionRevoked(ACCESS_COARSE_LOCATION);
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * Permissions are granted by default for pre-M apps. This also applies to permissions added
+ * implicitly due to splits.
+ */
+ @Test
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void nonInheritedStateLowTargetSDKPreM() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ install(APK_CONTACTS_15);
+
+ assertPermissionGranted(READ_CONTACTS);
+ assertPermissionGranted(READ_CALL_LOG);
+ }
+
+ /**
+ * The background location permission granted by default for pre-M apps.
+ */
+ @Test
+ public void backgroundLocationPermissionDefaultGrantPreM() throws Exception {
+ install(APK_LOCATION_22);
+
+ assertPermissionGranted(ACCESS_COARSE_LOCATION);
+ assertPermissionGranted(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * If a permission was granted before the split happens, the new permission should inherit the
+ * granted state.
+ */
+ @FlakyTest(bugId = 152580253)
+ @MtsIgnore(bugId = 152580253)
+ @Test
+ public void inheritGrantedPermissionState() throws Exception {
+ install(APK_LOCATION_29);
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ install(APK_LOCATION_28);
+
+ assertPermissionGranted(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * If a permission was granted before the split happens, the new permission should inherit the
+ * granted state.
+ *
+ * <p>App using a shared uid
+ */
+ @Test
+ public void inheritGrantedPermissionStateSharedUidApp() throws Exception {
+ install(APK_SHARED_UID_LOCATION_29);
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ install(APK_SHARED_UID_LOCATION_28);
+
+ assertPermissionGranted(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * If a permission has flags before the split happens, the new permission should inherit the
+ * flags.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @FlakyTest(bugId = 152580253)
+ @MtsIgnore(bugId = 152580253)
+ @Test
+ public void inheritFlagsPreM() {
+ install(APK_CONTACTS_16);
+ setPermissionFlags(APP_PKG, READ_CONTACTS, FLAG_PERMISSION_USER_SET,
+ FLAG_PERMISSION_USER_SET);
+
+ install(APK_CONTACTS_15);
+
+ assertEquals(FLAG_PERMISSION_USER_SET,
+ getPermissionFlags(APP_PKG, READ_CALL_LOG) & FLAG_PERMISSION_USER_SET);
+ }
+
+ /**
+ * If a permission has flags before the split happens, the new permission should inherit the
+ * flags.
+ */
+ @FlakyTest(bugId = 152580253)
+ @MtsIgnore(bugId = 152580253)
+ @Test
+ public void inheritFlags() {
+ install(APK_LOCATION_29);
+ setPermissionFlags(APP_PKG, ACCESS_COARSE_LOCATION, FLAG_PERMISSION_USER_SET,
+ FLAG_PERMISSION_USER_SET);
+
+ install(APK_LOCATION_28);
+
+ assertEquals(FLAG_PERMISSION_USER_SET,
+ getPermissionFlags(APP_PKG, ACCESS_BACKGROUND_LOCATION) & FLAG_PERMISSION_USER_SET);
+ }
+
+ /**
+ * If a permission was granted before the split happens, the new permission should inherit the
+ * granted state.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void inheritGrantedPermissionStatePreM() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ install(APK_CONTACTS_16);
+
+ install(APK_CONTACTS_15);
+
+ assertPermissionGranted(READ_CALL_LOG);
+ }
+
+ /**
+ * If a permission was revoked before the split happens, the new permission should inherit the
+ * revoked state.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void inheritRevokedPermissionState() throws Exception {
+ install(APK_LOCATION_29);
+
+ install(APK_LOCATION_28);
+
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * If a permission was revoked before the split happens, the new permission should inherit the
+ * revoked state.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void inheritRevokedPermissionStatePreM() throws Exception {
+ install(APK_CONTACTS_16);
+ revokePermission(APP_PKG, READ_CONTACTS);
+
+ install(APK_CONTACTS_15);
+
+ /*
+ * Ideally the new permission should inherit from it's base permission, but this is tricky
+ * to implement.
+ * The new permissions need to be reviewed, hence the pre-review state really does not
+ * matter anyway.
+ */
+ // assertPermissionRevoked(READ_CALL_LOG);
+ assertThat(getPermissionFlags(APP_PKG, READ_CALL_LOG)
+ & FLAG_PERMISSION_REVIEW_REQUIRED).isEqualTo(FLAG_PERMISSION_REVIEW_REQUIRED);
+ }
+
+ /**
+ * It should be possible to grant a permission implicitly added due to a split.
+ */
+ @Test
+ public void grantNewSplitPermissionState() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ assertPermissionGranted(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * It should be possible to grant a permission implicitly added due to a split.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void grantNewSplitPermissionStatePreM() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ install(APK_CONTACTS_15);
+ revokePermission(APP_PKG, READ_CONTACTS);
+
+ grantPermission(APP_PKG, READ_CALL_LOG);
+
+ assertPermissionGranted(READ_CALL_LOG);
+ }
+
+ /**
+ * It should be possible to revoke a permission implicitly added due to a split.
+ */
+ @Test
+ public void revokeNewSplitPermissionState() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ revokePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * It should be possible to revoke a permission implicitly added due to a split.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void revokeNewSplitPermissionStatePreM() throws Exception {
+ install(APK_CONTACTS_15);
+
+ revokePermission(APP_PKG, READ_CALL_LOG);
+
+ assertPermissionRevoked(READ_CALL_LOG);
+ }
+
+ /**
+ * An implicit permission should get revoked when the app gets updated and now requests the
+ * permission.
+ */
+ @Test
+ public void newPermissionGetRevokedOnUpgrade() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ install(APK_LOCATION_BACKGROUND_29);
+
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * An implicit background permission should get revoked when the app gets updated and now
+ * requests the permission. Revoking a background permission should have changed the app-op of
+ * the foreground permission.
+ */
+ @Test
+ public void newBackgroundPermissionGetRevokedOnUpgrade() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ install(APK_LOCATION_BACKGROUND_29);
+
+ eventually(() -> assertWithMessage("foreground app-op").that(
+ getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND));
+ }
+
+ /**
+ * An implicit permission should get revoked when the app gets updated and now requests the
+ * permission. This even happens if the app is not targeting the SDK the permission was split
+ * in.
+ */
+ @Test
+ public void newPermissionGetRevokedOnUpgradeBeforeSplitSDK() throws Exception {
+ install(APK_LOCATION_28);
+
+ // Background permission can only be granted together with foreground permission
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+ grantPermission(APP_PKG, ACCESS_BACKGROUND_LOCATION);
+
+ // Background location was introduced in SDK 29. Hence an app targeting 28 is usually
+ // unaware of this permission. If the app declares that it is aware by adding the permission
+ // in the manifest the permission will get revoked. This allows the app to request the
+ // permission from the user.
+ install(APK_LOCATION_BACKGROUND_28);
+
+ assertPermissionRevoked(ACCESS_BACKGROUND_LOCATION);
+ }
+
+ /**
+ * An implicit permission should <u>not</u> get revoked when the app gets updated as pre-M apps
+ * cannot deal with revoked permissions. Hence only the user should ever explicitly do that.
+ */
+ @Test
+ @SystemUserOnly(reason = "Secondary users have the DISALLOW_OUTGOING_CALLS user restriction")
+ public void newPermissionGetRevokedOnUpgradePreM() throws Exception {
+ Assume.assumeTrue("Secondary users have the DISALLOW_OUTGOING_CALLS user restriction",
+ UserHandle.SYSTEM.equals(Process.myUserHandle()));
+
+ install(APK_CONTACTS_15);
+
+ install(APK_CONTACTS_CALLLOG_16);
+
+ assertPermissionGranted(READ_CALL_LOG);
+ }
+
+ /**
+ * When a requested permission was granted before upgrade it should still be granted.
+ */
+ @Test
+ public void oldPermissionStaysGrantedOnUpgrade() throws Exception {
+ install(APK_LOCATION_28);
+ grantPermission(APP_PKG, ACCESS_COARSE_LOCATION);
+
+ install(APK_LOCATION_BACKGROUND_29);
+
+ assertPermissionGranted(ACCESS_COARSE_LOCATION);
+ }
+
+ /**
+ * When a requested permission was granted before upgrade it should still be granted.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void oldPermissionStaysGrantedOnUpgradePreM() throws Exception {
+ install(APK_CONTACTS_15);
+
+ install(APK_CONTACTS_CALLLOG_16);
+
+ assertPermissionGranted(READ_CONTACTS);
+ }
+
+ /**
+ * When a requested permission was revoked before upgrade it should still be revoked.
+ */
+ @Test
+ public void oldPermissionStaysRevokedOnUpgrade() throws Exception {
+ install(APK_LOCATION_28);
+
+ install(APK_LOCATION_BACKGROUND_29);
+
+ assertPermissionRevoked(ACCESS_COARSE_LOCATION);
+ }
+
+ /**
+ * When a requested permission was revoked before upgrade it should still be revoked.
+ *
+ * <p>(Pre-M version of test)
+ */
+ @Test
+ public void oldPermissionStaysRevokedOnUpgradePreM() throws Exception {
+ install(APK_CONTACTS_15);
+ revokePermission(APP_PKG, READ_CONTACTS);
+
+ install(APK_CONTACTS_CALLLOG_16);
+
+ assertPermissionRevoked(READ_CONTACTS);
+ }
+}