diff options
author | 2025-01-15 15:35:47 -0800 | |
---|---|---|
committer | 2025-01-15 15:35:47 -0800 | |
commit | 46de7db3752c6ef2554b28bea5086ce2682d1780 (patch) | |
tree | 267a6041066466f37080d545c7a1cbfcbb485106 | |
parent | 510656ccc6d01ce3434a569426fb2b7bdbfbe64f (diff) | |
parent | 521fcc503b0cad14017181cd2bb63a295346c480 (diff) |
Merge "Separate per-package and global restricted ECM settings" into main
4 files changed, 80 insertions, 35 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt b/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt index e2d46e519..952274d4a 100644 --- a/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt +++ b/PermissionController/src/com/android/permissioncontroller/ecm/EnhancedConfirmationDialogActivity.kt @@ -55,7 +55,6 @@ class EnhancedConfirmationDialogActivity : FragmentActivity() { companion object { private const val KEY_WAS_CLEAR_RESTRICTION_ALLOWED = "KEY_WAS_CLEAR_RESTRICTION_ALLOWED" private const val REASON_PHONE_STATE = "phone_state" - private const val REASON_APP_OP_RESTRICTED = "app_op_restricted" } private var wasClearRestrictionAllowed: Boolean = false diff --git a/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java b/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java index 290388558..4248a429c 100644 --- a/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java +++ b/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java @@ -213,7 +213,7 @@ public final class EnhancedConfirmationManager { * The setting is restricted because the restricted app op is set for the given package * @hide */ - public static final String REASON_APP_OP_RESTRICTED = "app_op_restricted"; + public static final String REASON_PACKAGE_RESTRICTED = "package_restricted"; /** A map of ECM states to their corresponding app op states */ @@ -367,8 +367,9 @@ public final class EnhancedConfirmationManager { intent.putExtra(Intent.EXTRA_UID, uid); intent.putExtra(Intent.EXTRA_SUBJECT, settingIdentifier); try { - intent.putExtra(Intent.EXTRA_REASON, mService.getRestrictionReason(packageName, - settingIdentifier, UserHandle.getUserHandleForUid(uid).getIdentifier())); + String restrictionReason = mService.getRestrictionReason(packageName, + settingIdentifier, UserHandle.getUserHandleForUid(uid).getIdentifier()); + intent.putExtra(Intent.EXTRA_REASON, restrictionReason); } catch (SecurityException | RemoteException e) { // The caller of this method does not have permission to read the ECM state, so we // won't include it in the return diff --git a/service/java/com/android/ecm/EnhancedConfirmationService.java b/service/java/com/android/ecm/EnhancedConfirmationService.java index dde5404a4..46b5eedbc 100644 --- a/service/java/com/android/ecm/EnhancedConfirmationService.java +++ b/service/java/com/android/ecm/EnhancedConfirmationService.java @@ -16,7 +16,7 @@ package com.android.ecm; -import static android.app.ecm.EnhancedConfirmationManager.REASON_APP_OP_RESTRICTED; +import static android.app.ecm.EnhancedConfirmationManager.REASON_PACKAGE_RESTRICTED; import static android.app.ecm.EnhancedConfirmationManager.REASON_PHONE_STATE; import android.Manifest; @@ -240,7 +240,7 @@ public class EnhancedConfirmationService extends SystemService { int ECM_STATE_IMPLICIT = AppOpsManager.MODE_DEFAULT; } - private static final ArraySet<String> PROTECTED_SETTINGS = new ArraySet<>(); + private static final ArraySet<String> PER_PACKAGE_PROTECTED_SETTINGS = new ArraySet<>(); // Settings restricted when an untrusted call is ongoing. These must also be added to // PROTECTED_SETTINGS @@ -248,28 +248,27 @@ public class EnhancedConfirmationService extends SystemService { static { // Runtime permissions - PROTECTED_SETTINGS.add(Manifest.permission.SEND_SMS); - PROTECTED_SETTINGS.add(Manifest.permission.RECEIVE_SMS); - PROTECTED_SETTINGS.add(Manifest.permission.READ_SMS); - PROTECTED_SETTINGS.add(Manifest.permission.RECEIVE_MMS); - PROTECTED_SETTINGS.add(Manifest.permission.RECEIVE_WAP_PUSH); - PROTECTED_SETTINGS.add(Manifest.permission.READ_CELL_BROADCASTS); - PROTECTED_SETTINGS.add(Manifest.permission_group.SMS); - - PROTECTED_SETTINGS.add(Manifest.permission.BIND_DEVICE_ADMIN); + PER_PACKAGE_PROTECTED_SETTINGS.add(Manifest.permission.SEND_SMS); + PER_PACKAGE_PROTECTED_SETTINGS.add(Manifest.permission.RECEIVE_SMS); + PER_PACKAGE_PROTECTED_SETTINGS.add(Manifest.permission.READ_SMS); + PER_PACKAGE_PROTECTED_SETTINGS.add(Manifest.permission.RECEIVE_MMS); + PER_PACKAGE_PROTECTED_SETTINGS.add(Manifest.permission.RECEIVE_WAP_PUSH); + PER_PACKAGE_PROTECTED_SETTINGS.add(Manifest.permission.READ_CELL_BROADCASTS); + PER_PACKAGE_PROTECTED_SETTINGS.add(Manifest.permission_group.SMS); + + PER_PACKAGE_PROTECTED_SETTINGS.add(Manifest.permission.BIND_DEVICE_ADMIN); // App ops - PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE); - PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS); - PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW); - PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_GET_USAGE_STATS); - PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_LOADER_USAGE_STATS); + PER_PACKAGE_PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE); + PER_PACKAGE_PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS); + PER_PACKAGE_PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW); + PER_PACKAGE_PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_GET_USAGE_STATS); + PER_PACKAGE_PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_LOADER_USAGE_STATS); // Default application roles. - PROTECTED_SETTINGS.add(RoleManager.ROLE_DIALER); - PROTECTED_SETTINGS.add(RoleManager.ROLE_SMS); + PER_PACKAGE_PROTECTED_SETTINGS.add(RoleManager.ROLE_DIALER); + PER_PACKAGE_PROTECTED_SETTINGS.add(RoleManager.ROLE_SMS); if (Flags.unknownCallPackageInstallBlockingEnabled()) { // Requesting package installs, limited during phone calls - PROTECTED_SETTINGS.add(AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES); UNTRUSTED_CALL_RESTRICTED_SETTINGS.add( AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES); UNTRUSTED_CALL_RESTRICTED_SETTINGS.add( @@ -312,11 +311,14 @@ public class EnhancedConfirmationService extends SystemService { if (!isSettingEcmProtected(settingIdentifier)) { return null; } + if (isSettingEcmGuardedForPackage(settingIdentifier, packageName, userId)) { + return REASON_PACKAGE_RESTRICTED; + } String globalProtectionReason = getGlobalProtectionReason(settingIdentifier); if (globalProtectionReason != null) { return globalProtectionReason; } - return isPackageEcmGuarded(packageName, userId) ? REASON_APP_OP_RESTRICTED : null; + return null; } catch (NameNotFoundException e) { throw new IllegalArgumentException(e); } @@ -448,6 +450,14 @@ public class EnhancedConfirmationService extends SystemService { || isAllowlistedInstaller(installingPackageName)); } + private boolean isSettingEcmGuardedForPackage(@NonNull String settingIdentifier, + @NonNull String packageName, @UserIdInt int userId) throws NameNotFoundException { + if (!PER_PACKAGE_PROTECTED_SETTINGS.contains(settingIdentifier)) { + return false; + } + return isPackageEcmGuarded(packageName, userId); + } + private boolean isAllowlistedPackage(String packageName) { return isPackageSignedWithAnyOf(packageName, mTrustedPackageCertDigests.get(packageName)); @@ -518,7 +528,10 @@ public class EnhancedConfirmationService extends SystemService { return false; } - if (PROTECTED_SETTINGS.contains(settingIdentifier)) { + if (PER_PACKAGE_PROTECTED_SETTINGS.contains(settingIdentifier)) { + return true; + } + if (UNTRUSTED_CALL_RESTRICTED_SETTINGS.contains(settingIdentifier)) { return true; } // TODO(b/310218979): Add role selections as protected settings diff --git a/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationInCallTest.kt b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationInCallTest.kt index 16a27c9a8..9a4908c79 100644 --- a/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationInCallTest.kt +++ b/tests/cts/permissionui/src/android/permissionui/cts/EnhancedConfirmationInCallTest.kt @@ -24,6 +24,7 @@ import android.content.Context import android.content.pm.PackageManager import android.net.Uri import android.os.Build +import android.os.Process import android.permission.flags.Flags import android.platform.test.annotations.AppModeFull import android.platform.test.annotations.RequiresFlagsEnabled @@ -56,8 +57,11 @@ import org.junit.Test // @CddTest(requirement = "TBD") class EnhancedConfirmationInCallTest { private val ecm = context.getSystemService(EnhancedConfirmationManager::class.java)!! + private val aom = context.getSystemService(AppOpsManager::class.java)!! private val packageManager = context.packageManager private val addedContacts = mutableMapOf<String, List<Uri>>() + private val phoneOnlyRestrictedSetting = AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES + private val phoneAndEcmRestrictedSetting = AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES @JvmField @Rule @@ -149,20 +153,32 @@ class EnhancedConfirmationInCallTest { fun tearDown() { voipService.endCallAndWaitForInactive() addedContacts.keys.forEach { removeContact(it) } + runWithShellPermissionIdentity { + aom.setUidMode( + AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS, + Process.myUid(), + AppOpsManager.MODE_ALLOWED, + ) + } } - private fun isSettingRestricted(): Boolean { + private fun isSettingRestricted(settingsIdentifier: String): Boolean { return callWithShellPermissionIdentity { - ecm.isRestricted(context.packageName, AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES) + ecm.isRestricted(context.packageName, settingsIdentifier) } } + private fun areSettingsRestricted(): Boolean { + return isSettingRestricted(phoneOnlyRestrictedSetting) && + isSettingRestricted(phoneAndEcmRestrictedSetting) + } + @Test fun testIncomingCall_NonContact() { voipService.createCallAndWaitForActive(NON_CONTACT_DISPLAY_NAME, NON_CONTACT_PHONE_NUMBER) - Assert.assertTrue(isSettingRestricted()) + Assert.assertTrue(areSettingsRestricted()) voipService.endCallAndWaitForInactive() - Assert.assertFalse(isSettingRestricted()) + Assert.assertFalse(areSettingsRestricted()) } @Test @@ -170,9 +186,9 @@ class EnhancedConfirmationInCallTest { addContact(CONTACT_DISPLAY_NAME, CONTACT_PHONE_NUMBER) // If no phone number is given, the display name will be checked voipService.createCallAndWaitForActive(CONTACT_DISPLAY_NAME, CONTACT_PHONE_NUMBER) - Assert.assertFalse(isSettingRestricted()) + Assert.assertFalse(areSettingsRestricted()) voipService.endCallAndWaitForInactive() - Assert.assertFalse(isSettingRestricted()) + Assert.assertFalse(areSettingsRestricted()) } @Test @@ -180,9 +196,9 @@ class EnhancedConfirmationInCallTest { addContact(CONTACT_DISPLAY_NAME, CONTACT_PHONE_NUMBER) // If the phone number matches, the display name is not checked voipService.createCallAndWaitForActive(NON_CONTACT_DISPLAY_NAME, CONTACT_PHONE_NUMBER) - Assert.assertFalse(isSettingRestricted()) + Assert.assertFalse(areSettingsRestricted()) voipService.endCallAndWaitForInactive() - Assert.assertFalse(isSettingRestricted()) + Assert.assertFalse(areSettingsRestricted()) } @Test @@ -192,10 +208,26 @@ class EnhancedConfirmationInCallTest { voipService.createCallAndWaitForActive(tempContactDisplay, tempContactPhone) addContact(tempContactDisplay, tempContactPhone) // State should not be recomputed just because the contact is newly added - Assert.assertTrue(isSettingRestricted()) + Assert.assertTrue(areSettingsRestricted()) voipService.endCallAndWaitForInactive() voipService.createCallAndWaitForActive(tempContactDisplay, tempContactPhone) // A new call should recognize our contact, and mark the call as trusted - Assert.assertFalse(isSettingRestricted()) + Assert.assertFalse(areSettingsRestricted()) + } + + @Test + fun testCallOnlyRestrictedSetting_notRestrictedIfEcmSet() { + // Set the current app to be restricted by ECM + runWithShellPermissionIdentity { + aom.setUidMode( + AppOpsManager.OPSTR_ACCESS_RESTRICTED_SETTINGS, + Process.myUid(), + AppOpsManager.MODE_ERRORED, + ) + } + // The ecm and phone restricted setting is restricted + Assert.assertFalse(isSettingRestricted(phoneOnlyRestrictedSetting)) + // But the phone only restriction is not + Assert.assertFalse(isSettingRestricted(phoneAndEcmRestrictedSetting)) } } |