From d8eb8b2690dd27d5ffe6262dd8ce8594ec8028a6 Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Fri, 5 Apr 2019 18:52:08 -0700 Subject: Restricted permission mechanism - framework This change adds a mechanism for restricting permissions (only runtime for now), so that an app cannot hold the permission if it is not white listed. The whitelisting can happen at install or at any later point. There are three whitelists: system: OS managed with default grants and role holders being on it; upgrade: only OS puts on this list apps when upgrading from a pre to post restriction permission database version and OS and installer on record can remove; installer: only the installer on record can add and remove (and the system of course). Added a permission policy service that sits on top of permissions and app ops and is responsible to sync between permissions and app ops when there is an interdependecy in any direction. Added versioning to the runtime permissions database to allow operations that need to be done once on upgrade such as adding all permissions held by apps pre upgrade to the upgrade whitelist if the new permisison version inctroduces a new restricted permission. The upgrade logic is in the permission controller and we will eventually put the default grants there. NOTE: This change is reacting to a VP feedback for how we would handle SMS/CallLog restriction as we pivoted from role based approach to roles for things the user would understand plus whitelist for everything else. This would also help us roll out softly the storage permisison as there is too much churm coming from developer feedback. Exempt-From-Owner-Approval: trivial change due to APi adjustment Test: atest CtsAppSecurityHostTestCases:android.appsecurity.cts.PermissionsHostTest Test: atest CtsPermissionTestCases Test: atest CtsPermission2TestCases Test: atest RoleManagerTestCases bug:124769181 Change-Id: Ic48e3c728387ecf02f89d517ba1fe785ab9c75fd --- api/current.txt | 11 + api/system-current.txt | 23 +- api/test-current.txt | 19 +- cmds/statsd/src/atoms.proto | 2 + core/java/android/app/AppOpsManager.java | 64 +--- .../android/app/ApplicationPackageManager.java | 49 ++- core/java/android/app/SystemServiceRegistry.java | 7 +- core/java/android/app/role/IRoleController.aidl | 2 - .../android/app/role/RoleControllerManager.java | 29 -- .../android/app/role/RoleControllerService.java | 20 - core/java/android/content/ContentProvider.java | 18 +- core/java/android/content/pm/IPackageManager.aidl | 15 +- core/java/android/content/pm/PackageInstaller.java | 77 ++++ core/java/android/content/pm/PackageManager.java | 300 ++++++++++++++- .../android/content/pm/PackageManagerInternal.java | 11 + core/java/android/content/pm/PackageParser.java | 13 + core/java/android/content/pm/PermissionInfo.java | 41 ++ core/java/android/os/RemoteCallback.java | 2 +- .../android/permission/IPermissionController.aidl | 1 + .../permission/PermissionControllerManager.java | 85 ++++- .../permission/PermissionControllerService.java | 28 ++ .../java/android/permission/PermissionManager.java | 50 ++- .../permission/PermissionManagerInternal.java | 34 ++ core/java/android/provider/DeviceConfig.java | 25 +- core/java/android/provider/Settings.java | 12 - core/java/android/util/StatsLogAtoms.java | 7 + ...stractMultiplePendingRequestsRemoteService.java | 1 - core/res/AndroidManifest.xml | 16 +- core/res/res/values/attrs_manifest.xml | 13 +- .../src/android/provider/SettingsBackupTest.java | 1 - .../packageinstaller/InstallInstalling.java | 3 + .../providers/settings/SettingsProtoDumpUtil.java | 5 - .../providers/settings/SettingsProvider.java | 2 +- packages/Shell/AndroidManifest.xml | 1 + .../android/server/am/CoreSettingsObserver.java | 1 - .../java/com/android/server/am/UserController.java | 2 +- .../com/android/server/pm/OtaDexoptService.java | 2 +- .../android/server/pm/PackageInstallerService.java | 10 + .../android/server/pm/PackageInstallerSession.java | 36 +- .../android/server/pm/PackageManagerService.java | 305 ++++++++++++++- .../server/pm/PackageManagerShellCommand.java | 6 +- .../core/java/com/android/server/pm/Settings.java | 49 ++- .../server/pm/permission/BasePermission.java | 16 + .../permission/DefaultPermissionGrantPolicy.java | 94 +++-- .../pm/permission/PermissionManagerService.java | 418 ++++++++++++++++++++- .../PermissionManagerServiceInternal.java | 11 +- .../server/pm/permission/PermissionsState.java | 4 +- .../server/policy/PermissionPolicyService.java | 281 ++++++++++++++ .../android/server/policy/PhoneWindowManager.java | 2 +- .../android/server/role/RoleManagerService.java | 20 - services/java/com/android/server/SystemServer.java | 9 +- .../backup/testutils/IPackageManagerStub.java | 30 +- .../backup/testutils/PackageManagerStub.java | 5 + .../server/pm/PackageManagerServiceTest.java | 5 + .../internal/telephony/TelephonyPermissions.java | 10 +- .../src/android/test/mock/MockPackageManager.java | 30 ++ 56 files changed, 2021 insertions(+), 312 deletions(-) create mode 100644 services/core/java/com/android/server/policy/PermissionPolicyService.java diff --git a/api/current.txt b/api/current.txt index 3fb05450c16c..d24e350e0f99 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11483,10 +11483,12 @@ package android.content.pm { method public void setOriginatingUri(@Nullable android.net.Uri); method public void setReferrerUri(@Nullable android.net.Uri); method public void setSize(long); + method public void setWhitelistedRestrictedPermissions(@Nullable java.util.Set); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int MODE_FULL_INSTALL = 1; // 0x1 field public static final int MODE_INHERIT_EXISTING = 2; // 0x2 + field @NonNull public static final java.util.Set RESTRICTED_PERMISSIONS_ALL; } public class PackageItemInfo { @@ -11523,6 +11525,7 @@ package android.content.pm { method public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo); method public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo); method @Deprecated public abstract void addPreferredActivity(@NonNull android.content.IntentFilter, int, @Nullable android.content.ComponentName[], @NonNull android.content.ComponentName); + method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean addWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int); method public abstract boolean canRequestPackageInstalls(); method public abstract String[] canonicalToCurrentPackageNames(@NonNull String[]); method @CheckResult public abstract int checkPermission(@NonNull String, @NonNull String); @@ -11592,11 +11595,13 @@ package android.content.pm { method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle, @Nullable android.graphics.Rect, int); method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedIcon(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle); method @NonNull public abstract CharSequence getUserBadgedLabel(@NonNull CharSequence, @NonNull android.os.UserHandle); + method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) @NonNull public java.util.Set getWhitelistedRestrictedPermissions(@NonNull String, int); method @Nullable public abstract android.content.res.XmlResourceParser getXml(@NonNull String, @XmlRes int, @Nullable android.content.pm.ApplicationInfo); method public boolean hasSigningCertificate(@NonNull String, @NonNull byte[], int); method public boolean hasSigningCertificate(int, @NonNull byte[], int); method public abstract boolean hasSystemFeature(@NonNull String); method public abstract boolean hasSystemFeature(@NonNull String, int); + method public boolean isDeviceUpgrading(); method public abstract boolean isInstantApp(); method public abstract boolean isInstantApp(@NonNull String); method public boolean isPackageSuspended(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; @@ -11613,6 +11618,7 @@ package android.content.pm { method @NonNull public abstract java.util.List queryPermissionsByGroup(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException; method @Deprecated public abstract void removePackageFromPreferred(@NonNull String); method public abstract void removePermission(@NonNull String); + method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public boolean removeWhitelistedRestrictedPermission(@NonNull String, @NonNull String, int); method @Nullable public abstract android.content.pm.ResolveInfo resolveActivity(@NonNull android.content.Intent, int); method @Nullable public abstract android.content.pm.ProviderInfo resolveContentProvider(@NonNull String, int); method @Nullable public abstract android.content.pm.ResolveInfo resolveService(@NonNull android.content.Intent, int); @@ -11740,6 +11746,9 @@ package android.content.pm { field public static final String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct"; field public static final String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint"; field public static final String FEATURE_WIFI_RTT = "android.hardware.wifi.rtt"; + field public static final int FLAG_PERMISSION_WHITELIST_INSTALLER = 2; // 0x2 + field public static final int FLAG_PERMISSION_WHITELIST_SYSTEM = 1; // 0x1 + field public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 4; // 0x4 field public static final int GET_ACTIVITIES = 1; // 0x1 field public static final int GET_CONFIGURATIONS = 16384; // 0x4000 field @Deprecated public static final int GET_DISABLED_COMPONENTS = 512; // 0x200 @@ -11840,7 +11849,9 @@ package android.content.pm { method @Nullable public CharSequence loadDescription(@NonNull android.content.pm.PackageManager); field @NonNull public static final android.os.Parcelable.Creator CREATOR; field public static final int FLAG_COSTS_MONEY = 1; // 0x1 + field public static final int FLAG_HARD_RESTRICTED = 4; // 0x4 field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000 + field public static final int FLAG_SOFT_RESTRICTED = 8; // 0x8 field public static final int PROTECTION_DANGEROUS = 1; // 0x1 field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40 field public static final int PROTECTION_FLAG_DEVELOPMENT = 32; // 0x20 diff --git a/api/system-current.txt b/api/system-current.txt index 64589093654e..eb9f82af9312 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -201,6 +201,7 @@ package android { field public static final String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES"; field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY"; field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK"; + field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS"; field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG"; field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE"; field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"; @@ -1581,6 +1582,7 @@ package android.content.pm { method public boolean getInstallAsInstantApp(boolean); method public boolean getInstallAsVirtualPreload(); method public boolean getRequestDowngrade(); + method @NonNull public java.util.Set getWhitelistedRestrictedPermissions(); } public static class PackageInstaller.SessionParams implements android.os.Parcelable { @@ -1651,8 +1653,12 @@ package android.content.pm { field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS"; field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio"; field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock"; + field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000 field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20 field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4 + field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800 + field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000 + field public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 8192; // 0x2000 field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40 field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8 field public static final int FLAG_PERMISSION_SYSTEM_FIXED = 16; // 0x10 @@ -1708,6 +1714,7 @@ package android.content.pm { field public static final int MATCH_ANY_USER = 4194304; // 0x400000 field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000 field public static final int MATCH_INSTANT = 8388608; // 0x800000 + field public static boolean RESTRICTED_PERMISSIONS_ENABLED; field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1 field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2 field public static final int RESTRICTION_NONE = 0; // 0x0 @@ -1722,7 +1729,7 @@ package android.content.pm { method public void onPermissionsChanged(int); } - @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags { + @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags { } public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { @@ -5451,7 +5458,7 @@ package android.os { } public static interface RemoteCallback.OnResultListener { - method public void onResult(android.os.Bundle); + method public void onResult(@Nullable android.os.Bundle); } public class ServiceSpecificException extends java.lang.RuntimeException { @@ -5694,6 +5701,7 @@ package android.permission { method @NonNull public abstract java.util.List onGetAppPermissions(@NonNull String); method @NonNull public abstract java.util.List onGetPermissionUsages(boolean, long); method public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream); + method public abstract void onGrantOrUpgradeDefaultRuntimePermissions(); method @BinderThread public abstract boolean onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle); method @BinderThread public abstract void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream); method public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String); @@ -5703,7 +5711,9 @@ package android.permission { } public final class PermissionManager { + method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public int getRuntimePermissionsVersion(); method @NonNull public java.util.List getSplitPermissions(); + method @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public void setRuntimePermissionsVersion(@IntRange(from=0) int); } public static final class PermissionManager.SplitPermissionInfo { @@ -5871,6 +5881,7 @@ package android.provider { field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention"; field public static final String NAMESPACE_MEDIA_NATIVE = "media_native"; field public static final String NAMESPACE_NETD_NATIVE = "netd_native"; + field public static final String NAMESPACE_PRIVACY = "privacy"; field public static final String NAMESPACE_ROLLBACK = "rollback"; field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; field public static final String NAMESPACE_RUNTIME = "runtime"; @@ -5891,12 +5902,6 @@ package android.provider { method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); } - public static interface DeviceConfig.Privacy { - field public static final String NAMESPACE = "privacy"; - field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled"; - field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; - } - public static class DeviceConfig.Properties { method public boolean getBoolean(@NonNull String, boolean); method public float getFloat(@NonNull String, float); @@ -6075,7 +6080,6 @@ package android.provider { field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis"; field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; field public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt"; - field public static final String SMS_ACCESS_RESTRICTION_ENABLED = "sms_access_restriction_enabled"; field public static final String THEATER_MODE_ON = "theater_mode_on"; field public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess"; field public static final String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds"; @@ -9521,6 +9525,7 @@ package android.util { field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED = 5; // 0x5 field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED = 1; // 0x1 field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED = 3; // 0x3 + field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION = 9; // 0x9 field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED = 2; // 0x2 field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED = 6; // 0x6 field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE = 7; // 0x7 diff --git a/api/test-current.txt b/api/test-current.txt index 99cdfb012155..973e70067c37 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -655,8 +655,13 @@ package android.content.pm { ctor public LauncherApps(android.content.Context); } + public static class PackageInstaller.SessionInfo implements android.os.Parcelable { + method @NonNull public java.util.Set getWhitelistedRestrictedPermissions(); + } + public static class PackageInstaller.SessionParams implements android.os.Parcelable { method public void setEnableRollback(boolean); + method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex(); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged(); } @@ -679,7 +684,11 @@ package android.content.pm { method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, int, int, @NonNull android.os.UserHandle); field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage"; field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption"; + field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000 field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4 + field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800 + field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000 + field public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 8192; // 0x2000 field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40 field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8 field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80 @@ -688,6 +697,7 @@ package android.content.pm { field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1 field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000 field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000 + field public static boolean RESTRICTED_PERMISSIONS_ENABLED; field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services"; field public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared"; } @@ -1820,7 +1830,7 @@ package android.os { } public static interface RemoteCallback.OnResultListener { - method public void onResult(android.os.Bundle); + method public void onResult(@Nullable android.os.Bundle); } public final class StrictMode { @@ -2101,6 +2111,7 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); field public static final String NAMESPACE_AUTOFILL = "autofill"; field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture"; + field public static final String NAMESPACE_PRIVACY = "privacy"; field public static final String NAMESPACE_ROLLBACK = "rollback"; field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot"; } @@ -2113,11 +2124,6 @@ package android.provider { method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String); } - public static interface DeviceConfig.Privacy { - field public static final String NAMESPACE = "privacy"; - field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled"; - } - public static class DeviceConfig.Properties { method public boolean getBoolean(@NonNull String, boolean); method public float getFloat(@NonNull String, float); @@ -2172,7 +2178,6 @@ package android.provider { field public static final String LOW_POWER_MODE = "low_power"; field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky"; field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices"; - field public static final String SMS_ACCESS_RESTRICTION_ENABLED = "sms_access_restriction_enabled"; field public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package"; } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 8986c6fd02c2..146cf0cd2da9 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -5453,6 +5453,8 @@ message PermissionGrantRequestResultReported { USER_DENIED_WITH_PREJUDICE = 7; // permission was automatically denied AUTO_DENIED = 8; + // permission request was ignored because permission is restricted + IGNORED_RESTRICTED_PERMISSION = 9; } // The result of the permission grant optional Result result = 6; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 4b0b8cb12d5e..15982a796a7e 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -30,9 +30,7 @@ import android.app.usage.UsageStatsManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; -import android.database.ContentObserver; import android.media.AudioAttributes.AttributeUsage; -import android.net.Uri; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; @@ -42,7 +40,6 @@ import android.os.RemoteCallback; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserManager; -import android.provider.Settings; import android.util.ArrayMap; import android.util.LongSparseArray; import android.util.LongSparseLongArray; @@ -70,7 +67,6 @@ import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Supplier; @@ -1757,21 +1753,21 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // VIBRATE AppOpsManager.MODE_ALLOWED, // READ_CONTACTS AppOpsManager.MODE_ALLOWED, // WRITE_CONTACTS - AppOpsManager.MODE_ALLOWED, // READ_CALL_LOG - AppOpsManager.MODE_ALLOWED, // WRITE_CALL_LOG + AppOpsManager.MODE_DEFAULT, // READ_CALL_LOG + AppOpsManager.MODE_DEFAULT, // WRITE_CALL_LOG AppOpsManager.MODE_ALLOWED, // READ_CALENDAR AppOpsManager.MODE_ALLOWED, // WRITE_CALENDAR AppOpsManager.MODE_ALLOWED, // WIFI_SCAN AppOpsManager.MODE_ALLOWED, // POST_NOTIFICATION AppOpsManager.MODE_ALLOWED, // NEIGHBORING_CELLS AppOpsManager.MODE_ALLOWED, // CALL_PHONE - AppOpsManager.MODE_ALLOWED, // READ_SMS + AppOpsManager.MODE_DEFAULT, // READ_SMS AppOpsManager.MODE_IGNORED, // WRITE_SMS - AppOpsManager.MODE_ALLOWED, // RECEIVE_SMS + AppOpsManager.MODE_DEFAULT, // RECEIVE_SMS AppOpsManager.MODE_ALLOWED, // RECEIVE_EMERGENCY_BROADCAST - AppOpsManager.MODE_ALLOWED, // RECEIVE_MMS - AppOpsManager.MODE_ALLOWED, // RECEIVE_WAP_PUSH - AppOpsManager.MODE_ALLOWED, // SEND_SMS + AppOpsManager.MODE_DEFAULT, // RECEIVE_MMS + AppOpsManager.MODE_DEFAULT, // RECEIVE_WAP_PUSH + AppOpsManager.MODE_DEFAULT, // SEND_SMS AppOpsManager.MODE_ALLOWED, // READ_ICC_SMS AppOpsManager.MODE_ALLOWED, // WRITE_ICC_SMS AppOpsManager.MODE_DEFAULT, // WRITE_SETTINGS @@ -1805,10 +1801,10 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // READ_PHONE_STATE AppOpsManager.MODE_ALLOWED, // ADD_VOICEMAIL AppOpsManager.MODE_ALLOWED, // USE_SIP - AppOpsManager.MODE_ALLOWED, // PROCESS_OUTGOING_CALLS + AppOpsManager.MODE_DEFAULT, // PROCESS_OUTGOING_CALLS AppOpsManager.MODE_ALLOWED, // USE_FINGERPRINT AppOpsManager.MODE_ALLOWED, // BODY_SENSORS - AppOpsManager.MODE_ALLOWED, // READ_CELL_BROADCASTS + AppOpsManager.MODE_DEFAULT, // READ_CELL_BROADCASTS AppOpsManager.MODE_ERRORED, // MOCK_LOCATION AppOpsManager.MODE_ALLOWED, // READ_EXTERNAL_STORAGE AppOpsManager.MODE_ALLOWED, // WRITE_EXTERNAL_STORAGE @@ -2101,51 +2097,9 @@ public class AppOpsManager { * @hide */ public static @Mode int opToDefaultMode(int op) { - // STOPSHIP b/118520006: Hardcode the default values once the feature is stable. - switch (op) { - // SMS permissions - case AppOpsManager.OP_SEND_SMS: - case AppOpsManager.OP_RECEIVE_SMS: - case AppOpsManager.OP_READ_SMS: - case AppOpsManager.OP_RECEIVE_WAP_PUSH: - case AppOpsManager.OP_RECEIVE_MMS: - case AppOpsManager.OP_READ_CELL_BROADCASTS: - // CallLog permissions - case AppOpsManager.OP_READ_CALL_LOG: - case AppOpsManager.OP_WRITE_CALL_LOG: - case AppOpsManager.OP_PROCESS_OUTGOING_CALLS: { - if (sSmsAndCallLogRestrictionEnabled.get() == 1) { - return AppOpsManager.MODE_DEFAULT; - } - } - } return sOpDefaultMode[op]; } - // STOPSHIP b/118520006: Hardcode the default values once the feature is stable. - private static final AtomicInteger sSmsAndCallLogRestrictionEnabled = new AtomicInteger(-1); - - // STOPSHIP b/118520006: Hardcode the default values once the feature is stable. - static { - final Context context = ActivityThread.currentApplication(); - if (context != null) { - sSmsAndCallLogRestrictionEnabled.set(ActivityThread.currentActivityThread() - .getIntCoreSetting(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0)); - - final Uri uri = - Settings.Global.getUriFor(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED); - context.getContentResolver().registerContentObserver(uri, false, new ContentObserver( - context.getMainThreadHandler()) { - @Override - public void onChange(boolean selfChange) { - sSmsAndCallLogRestrictionEnabled.set(Settings.Global.getInt( - context.getContentResolver(), - Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0)); - } - }); - } - } - /** * Retrieve the default mode for the app op. * diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index a906790c45ab..82a34ceea8b9 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -89,6 +89,7 @@ import android.system.OsConstants; import android.system.StructStat; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.IconDrawableFactory; import android.util.LauncherIcons; import android.util.Log; @@ -111,6 +112,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; /** @hide */ public class ApplicationPackageManager extends PackageManager { @@ -717,6 +719,43 @@ public class ApplicationPackageManager extends PackageManager { } } + @Override + public @NonNull Set getWhitelistedRestrictedPermissions( + @NonNull String packageName, @PermissionWhitelistFlags int whitelistFlags) { + try { + final List whitelist = mPM.getWhitelistedRestrictedPermissions( + packageName, whitelistFlags, getUserId()); + if (whitelist != null) { + return new ArraySet<>(whitelist); + } + return Collections.emptySet(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override + public boolean addWhitelistedRestrictedPermission(@NonNull String packageName, + @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) { + try { + return mPM.addWhitelistedRestrictedPermission(packageName, permission, + whitelistFlags, getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override + public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName, + @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) { + try { + return mPM.removeWhitelistedRestrictedPermission(packageName, permission, + whitelistFlags, getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @Override @UnsupportedAppUsage public boolean shouldShowRequestPermissionRationale(String permission) { @@ -2634,13 +2673,15 @@ public class ApplicationPackageManager extends PackageManager { } } - /** - * @hide - */ @Override public boolean isUpgrade() { + return isDeviceUpgrading(); + } + + @Override + public boolean isDeviceUpgrading() { try { - return mPM.isUpgrade(); + return mPM.isDeviceUpgrading(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index d67bfb6c9c84..8749b108c168 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -50,6 +50,7 @@ import android.content.om.IOverlayManager; import android.content.om.OverlayManager; import android.content.pm.CrossProfileApps; import android.content.pm.ICrossProfileApps; +import android.content.pm.IPackageManager; import android.content.pm.IShortcutService; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; @@ -1239,14 +1240,16 @@ final class SystemServiceRegistry { new CachedServiceFetcher() { @Override public PermissionManager createService(ContextImpl ctx) { - return new PermissionManager(ctx.getOuterContext()); + IPackageManager packageManager = AppGlobals.getPackageManager(); + return new PermissionManager(ctx.getOuterContext(), packageManager); }}); registerService(Context.PERMISSION_CONTROLLER_SERVICE, PermissionControllerManager.class, new CachedServiceFetcher() { @Override public PermissionControllerManager createService(ContextImpl ctx) { - return new PermissionControllerManager(ctx.getOuterContext()); + return new PermissionControllerManager(ctx.getOuterContext(), + ctx.getMainThreadHandler()); }}); registerService(Context.ROLE_SERVICE, RoleManager.class, diff --git a/core/java/android/app/role/IRoleController.aidl b/core/java/android/app/role/IRoleController.aidl index a472eacb28a1..19762e0841b1 100644 --- a/core/java/android/app/role/IRoleController.aidl +++ b/core/java/android/app/role/IRoleController.aidl @@ -33,8 +33,6 @@ oneway interface IRoleController { void onClearRoleHolders(in String roleName, int flags, in RemoteCallback callback); - void onSmsKillSwitchToggled(boolean enabled); - void isApplicationQualifiedForRole(in String roleName, in String packageName, in RemoteCallback callback); diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java index bd981179e2ff..027e152ee95f 100644 --- a/core/java/android/app/role/RoleControllerManager.java +++ b/core/java/android/app/role/RoleControllerManager.java @@ -120,13 +120,6 @@ public class RoleControllerManager { flags, callback)); } - /** - * @see RoleControllerService#onSmsKillSwitchToggled(boolean) - */ - public void onSmsKillSwitchToggled(boolean enabled) { - mRemoteService.scheduleAsyncRequest(new OnSmsKillSwitchToggledRequest(enabled)); - } - /** * @see RoleControllerService#onIsApplicationQualifiedForRole(String, String) */ @@ -415,28 +408,6 @@ public class RoleControllerManager { } } - /** - * Request for {@link #onSmsKillSwitchToggled(boolean)} - */ - private static final class OnSmsKillSwitchToggledRequest - implements AbstractRemoteService.AsyncRequest { - - private final boolean mEnabled; - - private OnSmsKillSwitchToggledRequest(boolean enabled) { - mEnabled = enabled; - } - - @Override - public void run(@NonNull IRoleController service) { - try { - service.onSmsKillSwitchToggled(mEnabled); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Error calling onSmsKillSwitchToggled()", e); - } - } - } - /** * Request for {@link #isApplicationQualifiedForRole(String, String, Executor, Consumer)} */ diff --git a/core/java/android/app/role/RoleControllerService.java b/core/java/android/app/role/RoleControllerService.java index 312761d43afd..2bc94560edd7 100644 --- a/core/java/android/app/role/RoleControllerService.java +++ b/core/java/android/app/role/RoleControllerService.java @@ -131,15 +131,6 @@ public abstract class RoleControllerService extends Service { roleName, flags, callback)); } - @Override - public void onSmsKillSwitchToggled(boolean enabled) { - enforceCallerSystemUid("onSmsKillSwitchToggled"); - - mWorkerHandler.sendMessage(PooledLambda.obtainMessage( - RoleControllerService::onSmsKillSwitchToggled, RoleControllerService.this, - enabled)); - } - private void enforceCallerSystemUid(@NonNull String methodName) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system process can call " + methodName @@ -258,17 +249,6 @@ public abstract class RoleControllerService extends Service { public abstract boolean onClearRoleHolders(@NonNull String roleName, @RoleManager.ManageHoldersFlags int flags); - /** - * Cleanup appop/permissions state in response to sms kill switch toggle - * - * @param enabled whether kill switch was turned on - * - * @hide - */ - //STOPSHIP: remove this api before shipping a final version - @WorkerThread - public abstract void onSmsKillSwitchToggled(boolean enabled); - /** * Check whether an application is qualified for a role. * diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index ddfe75568eee..71242fbac9a5 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -620,13 +620,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall private int noteProxyOp(String callingPkg, int op) { if (op != AppOpsManager.OP_NONE) { int mode = mAppOpsManager.noteProxyOp(op, callingPkg); - int nonDefaultMode = mode == MODE_DEFAULT ? interpretDefaultAppOpMode(op) : mode; - if (mode == MODE_DEFAULT && nonDefaultMode == MODE_IGNORED) { - Log.w(TAG, "Denying access for " + callingPkg + " to " + getClass().getName() - + " (" + AppOpsManager.opToName(op) - + " = " + AppOpsManager.opToName(mode) + ")"); - } - return mode == MODE_DEFAULT ? nonDefaultMode : mode; + return mode == MODE_DEFAULT ? MODE_IGNORED : mode; } return AppOpsManager.MODE_ALLOWED; @@ -654,16 +648,6 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall return mTransport.noteProxyOp(callingPkg, AppOpsManager.permissionToOpCode(permission)); } - /** - * Allows for custom interpretations of {@link AppOpsManager#MODE_DEFAULT} by individual - * content providers - * - * @hide - */ - protected int interpretDefaultAppOpMode(int op) { - return MODE_IGNORED; - } - /** {@hide} */ protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken) throws SecurityException { diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index fb2218778c9b..cf704d52cba0 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -130,6 +130,15 @@ interface IPackageManager { void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId); + List getWhitelistedRestrictedPermissions(String packageName, int flags, + int userId); + + boolean addWhitelistedRestrictedPermission(String packageName, String permission, + int whitelistFlags, int userId); + + boolean removeWhitelistedRestrictedPermission(String packageName, String permission, + int whitelistFlags, int userId); + boolean shouldShowRequestPermissionRationale(String permissionName, String packageName, int userId); @@ -643,7 +652,7 @@ interface IPackageManager { boolean isFirstBoot(); boolean isOnlyCoreApps(); - boolean isUpgrade(); + boolean isDeviceUpgrading(); void setPermissionEnforced(String permission, boolean enforced); boolean isPermissionEnforced(String permission); @@ -757,4 +766,8 @@ interface IPackageManager { List getInstalledModules(int flags); ModuleInfo getModuleInfo(String packageName, int flags); + + int getRuntimePermissionsVersion(int userId); + + void setRuntimePermissionsVersion(int version, int userId); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index ec2e8ca26060..90fb20bb0163 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -30,6 +30,7 @@ import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.AppGlobals; import android.content.Intent; +import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.PackageManager.DeleteFlags; import android.content.pm.PackageManager.InstallReason; @@ -48,6 +49,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.system.ErrnoException; import android.system.Os; +import android.util.ArraySet; import android.util.ExceptionUtils; import com.android.internal.util.IndentingPrintWriter; @@ -62,8 +64,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.security.MessageDigest; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.concurrent.Executor; /** @@ -1265,6 +1269,11 @@ public class PackageInstaller { */ public static final int MODE_INHERIT_EXISTING = 2; + /** + * Special constant to refer to all restricted permissions. + */ + public static final @NonNull Set RESTRICTED_PERMISSIONS_ALL = new ArraySet<>(); + /** {@hide} */ public static final int UID_UNKNOWN = -1; @@ -1306,6 +1315,8 @@ public class PackageInstaller { /** {@hide} */ public String[] grantedRuntimePermissions; /** {@hide} */ + public List whitelistedRestrictedPermissions; + /** {@hide} */ public String installerPackageName; /** {@hide} */ public boolean isMultiPackage; @@ -1339,6 +1350,7 @@ public class PackageInstaller { abiOverride = source.readString(); volumeUuid = source.readString(); grantedRuntimePermissions = source.readStringArray(); + whitelistedRestrictedPermissions = source.createStringArrayList(); installerPackageName = source.readString(); isMultiPackage = source.readBoolean(); isStaged = source.readBoolean(); @@ -1360,6 +1372,7 @@ public class PackageInstaller { ret.abiOverride = abiOverride; ret.volumeUuid = volumeUuid; ret.grantedRuntimePermissions = grantedRuntimePermissions; + ret.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions; ret.installerPackageName = installerPackageName; ret.isMultiPackage = isMultiPackage; ret.isStaged = isStaged; @@ -1474,6 +1487,7 @@ public class PackageInstaller { * * @hide */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[] permissions) { @@ -1481,6 +1495,43 @@ public class PackageInstaller { this.grantedRuntimePermissions = permissions; } + /** + * Sets which restricted permissions to be whitelisted for the app. Whitelisting + * is not granting the permissions, rather it allows the app to hold permissions + * which are otherwise restricted. Whitelisting a non restricted permission has + * no effect. + * + *

Permissions can be hard restricted which means that the app cannot hold + * them or soft restricted where the app can hold the permission but in a weaker + * form. Whether a permission is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard + * restricted} or {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} + * depends on the permission declaration. Whitelisting a hard restricted permission + * allows the app to hold that permission and whitelisting a soft restricted + * permission allows the app to hold the permission in its full, unrestricted form. + * + *

The whitelisted permissions would be applied as the {@link + * PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER installer whitelist}. + * + * @param permissions The restricted permissions to whitelist. Pass + * {@link #RESTRICTED_PERMISSIONS_ALL} to whitelist all permissions and + * null to clear. If you want to whitelist some permissions + * (not all) the list must contain at least one permission. + * + * @see PackageManager#addWhitelistedRestrictedPermission(String, String, int) + * @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int) + */ + public void setWhitelistedRestrictedPermissions(@Nullable Set permissions) { + if (permissions == RESTRICTED_PERMISSIONS_ALL) { + installFlags |= PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; + } + if (permissions != null) { + this.whitelistedRestrictedPermissions = new ArrayList<>(permissions); + } else { + installFlags &= ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; + this.whitelistedRestrictedPermissions = null; + } + } + /** * Request that rollbacks be enabled or disabled for the given upgrade. * @@ -1656,6 +1707,7 @@ public class PackageInstaller { pw.printPair("abiOverride", abiOverride); pw.printPair("volumeUuid", volumeUuid); pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions); + pw.printPair("whitelistedRestrictedPermissions", whitelistedRestrictedPermissions); pw.printPair("installerPackageName", installerPackageName); pw.printPair("isMultiPackage", isMultiPackage); pw.printPair("isStaged", isStaged); @@ -1683,6 +1735,7 @@ public class PackageInstaller { dest.writeString(abiOverride); dest.writeString(volumeUuid); dest.writeStringArray(grantedRuntimePermissions); + dest.writeStringList(whitelistedRestrictedPermissions); dest.writeString(installerPackageName); dest.writeBoolean(isMultiPackage); dest.writeBoolean(isStaged); @@ -1794,6 +1847,8 @@ public class PackageInstaller { public Uri referrerUri; /** {@hide} */ public String[] grantedRuntimePermissions; + /** {@hide}*/ + public List whitelistedRestrictedPermissions; /** {@hide} */ public int installFlags; /** {@hide} */ @@ -1847,6 +1902,8 @@ public class PackageInstaller { originatingUid = source.readInt(); referrerUri = source.readParcelable(null); grantedRuntimePermissions = source.readStringArray(); + whitelistedRestrictedPermissions = source.createStringArrayList(); + installFlags = source.readInt(); isMultiPackage = source.readBoolean(); isStaged = source.readBoolean(); @@ -2048,6 +2105,25 @@ public class PackageInstaller { return grantedRuntimePermissions; } + /** + * Get the value set in {@link SessionParams#setWhitelistedRestrictedPermissions(Set)}. + * Note that if all permissions are whitelisted this method returns {@link + * SessionParams#RESTRICTED_PERMISSIONS_ALL}. + * + * @hide + */ + @TestApi + @SystemApi + public @NonNull Set getWhitelistedRestrictedPermissions() { + if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0) { + return SessionParams.RESTRICTED_PERMISSIONS_ALL; + } + if (whitelistedRestrictedPermissions != null) { + return new ArraySet<>(whitelistedRestrictedPermissions); + } + return Collections.emptySet(); + } + /** * Get the value set in {@link SessionParams#setAllowDowngrade(boolean)}. * @@ -2277,6 +2353,7 @@ public class PackageInstaller { dest.writeInt(originatingUid); dest.writeParcelable(referrerUri, flags); dest.writeStringArray(grantedRuntimePermissions); + dest.writeStringList(whitelistedRestrictedPermissions); dest.writeInt(installFlags); dest.writeBoolean(isMultiPackage); dest.writeBoolean(isStaged); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 025d8f9507f9..83e15e8daa39 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -69,8 +69,10 @@ import dalvik.system.VMRuntime; import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Set; /** * Class for retrieving various kinds of information related to the application @@ -84,6 +86,11 @@ public abstract class PackageManager { /** {@hide} */ public static final boolean APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE = true; + /** {@hide} */ + @SystemApi + @TestApi + public static boolean RESTRICTED_PERMISSIONS_ENABLED = false; + /** * This exception is thrown when a given package, application, or component * name cannot be found. @@ -712,6 +719,7 @@ public abstract class PackageManager { INSTALL_ALL_USERS, INSTALL_REQUEST_DOWNGRADE, INSTALL_GRANT_RUNTIME_PERMISSIONS, + INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, INSTALL_FORCE_VOLUME_UUID, INSTALL_FORCE_PERMISSION_PROMPT, INSTALL_INSTANT_APP, @@ -794,6 +802,16 @@ public abstract class PackageManager { */ public static final int INSTALL_GRANT_RUNTIME_PERMISSIONS = 0x00000100; + /** + * Flag parameter for {@link #installPackage} to indicate that all restricted + * permissions should be whitelisted. If {@link #INSTALL_ALL_USERS} + * is set the restricted permissions will be whitelisted for all users, otherwise + * only to the owner. + * + * @hide + */ + public static final int INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS = 0x00000200; + /** {@hide} */ public static final int INSTALL_FORCE_VOLUME_UUID = 0x00000200; @@ -3075,14 +3093,72 @@ public abstract class PackageManager { public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED = 1 << 9; /** - * Mask for all permission flags present in Android P + * Permission flag: The permission is restricted but the app is exempt + * from the restriction and is allowed to hold this permission in its + * full form and the exemption is provided by the installer on record. + * + * @hide + */ + @TestApi + @SystemApi + public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 1 << 11; + + /** + * Permission flag: The permission is restricted but the app is exempt + * from the restriction and is allowed to hold this permission in its + * full form and the exemption is provided by the system due to its + * permission policy. * - * @deprecated This constant does not contain useful information and should never have been - * exposed. When checking permission flags always flag each flag explicitly and ignore all - * flags that do not matter for this particular code. + * @hide + */ + @TestApi + @SystemApi + public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 1 << 12; + + /** + * Permission flag: The permission is restricted but the app is exempt + * from the restriction and is allowed to hold this permission and the + * exemption is provided by the system when upgrading from an OS version + * where the permission was not restricted to an OS version where the + * permission is restricted. * * @hide */ + @TestApi + @SystemApi + public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 1 << 13; + + + /** + * Permission flag: The permission is disabled but may be granted. If + * disabled the data protected by the permission should be protected + * by a no-op (empty list, default error, etc) instead of crashing the + * client. + * + * @hide + */ + @TestApi + @SystemApi + public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 1 << 14; + + + /** + * Permission flags: Bitwise or of all permission flags allowing an + * exemption for a restricted permission. + * @hide + */ + public static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT = + FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT + | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT + | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; + + /** + * Mask for all permission flags. + * + * @hide + * + * @deprecated Don't use - does not capture all flags. + */ @Deprecated @SystemApi public static final int MASK_PERMISSION_FLAGS = 0xFF; @@ -3092,7 +3168,20 @@ public abstract class PackageManager { * * @hide */ - public static final int MASK_PERMISSION_FLAGS_ALL = 0x3FF; + public static final int MASK_PERMISSION_FLAGS_ALL = FLAG_PERMISSION_USER_SET + | FLAG_PERMISSION_USER_FIXED + | FLAG_PERMISSION_POLICY_FIXED + | FLAG_PERMISSION_REVOKE_ON_UPGRADE + | FLAG_PERMISSION_SYSTEM_FIXED + | FLAG_PERMISSION_GRANTED_BY_DEFAULT + | FLAG_PERMISSION_REVIEW_REQUIRED + | FLAG_PERMISSION_REVOKE_WHEN_REQUESTED + | FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED + | FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED + | FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT + | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT + | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT + | FLAG_PERMISSION_APPLY_RESTRICTION; /** * Injected activity in app that forwards user to setting activity of that app. @@ -3101,6 +3190,35 @@ public abstract class PackageManager { */ public static final String APP_DETAILS_ACTIVITY_CLASS_NAME = AppDetailsActivity.class.getName(); + /** + * Permission whitelist flag: permissions whitelisted by the system. + * Permissions can also be whitelisted by the installer or on upgrade. + */ + public static final int FLAG_PERMISSION_WHITELIST_SYSTEM = 1 << 0; + + /** + * Permission whitelist flag: permissions whitelisted by the installer. + * Permissions can also be whitelisted by the system or on upgrade. + */ + public static final int FLAG_PERMISSION_WHITELIST_INSTALLER = 1 << 1; + + /** + * Permission whitelist flag: permissions whitelisted by the system + * when upgrading from an OS version where the permission was not + * restricted to an OS version where the permission is restricted. + * Permissions can also be whitelisted by the installer or the system. + */ + public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 1 << 2; + + /** @hide */ + @IntDef(flag = true, prefix = {"FLAG_PERMISSION_WHITELIST_"}, value = { + FLAG_PERMISSION_WHITELIST_SYSTEM, + FLAG_PERMISSION_WHITELIST_INSTALLER, + FLAG_PERMISSION_WHITELIST_UPGRADE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PermissionWhitelistFlags {} + /** * This is a library that contains components apps can invoke. For * example, a services for apps to bind to, or standard chooser UI, @@ -3824,6 +3942,10 @@ public abstract class PackageManager { /* FLAG_PERMISSION_REVOKE_WHEN_REQUESED */ + FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, + FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, + FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, + FLAG_PERMISSION_APPLY_RESTRICTION }) @Retention(RetentionPolicy.SOURCE) public @interface PermissionFlags {} @@ -3924,6 +4046,163 @@ public abstract class PackageManager { @NonNull String packageName, @PermissionFlags int flagMask, @PermissionFlags int flagValues, @NonNull UserHandle user); + /** + * Gets the restricted permissions that have been whitelisted and the app + * is allowed to have them granted in their full form. + * + *

Permissions can be hard restricted which means that the app cannot hold + * them or soft restricted where the app can hold the permission but in a weaker + * form. Whether a permission is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard + * restricted} or {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} + * depends on the permission declaration. Whitelisting a hard restricted permission + * allows for the to hold that permission and whitelisting a soft restricted + * permission allows the app to hold the permission in its full, unrestricted form. + * + *

    There are three whitelists: + * + *
  1. one for cases where the system permission policy whitelists a permission + * This list corresponds to the{@link #FLAG_PERMISSION_WHITELIST_SYSTEM} flag. + * Can only be accessed by pre-installed holders of a dedicated permission. + * + *
  2. one for cases where the system whitelists the permission when upgrading + * from an OS version in which the permission was not restricted to an OS version + * in which the permission is restricted. This list corresponds to the {@link + * #FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be accessed by pre-installed + * holders of a dedicated permission or the installer on record. + * + *
  3. one for cases where the installer of the package whitelists a permission. + * This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_INSTALLER} flag. + * Can be accessed by pre-installed holders of a dedicated permission or the + * installer on record. + * + * @param packageName The app for which to get whitelisted permissions. + * @param whitelistFlag The flag to determine which whitelist to query. Only one flag + * can be passed.s + * @return The whitelisted permissions that are on any of the whitelists you query for. + * + * @see #addWhitelistedRestrictedPermission(String, String, int) + * @see #removeWhitelistedRestrictedPermission(String, String, int) + * @see #FLAG_PERMISSION_WHITELIST_SYSTEM + * @see #FLAG_PERMISSION_WHITELIST_UPGRADE + * @see #FLAG_PERMISSION_WHITELIST_INSTALLER + * + * @throws SecurityException if you try to access a whitelist that you have no access to. + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public @NonNull Set getWhitelistedRestrictedPermissions( + @NonNull String packageName, @PermissionWhitelistFlags int whitelistFlag) { + return Collections.emptySet(); + } + + /** + * Adds a whitelisted restricted permission for an app. + * + *

    Permissions can be hard restricted which means that the app cannot hold + * them or soft restricted where the app can hold the permission but in a weaker + * form. Whether a permission is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard + * restricted} or {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} + * depends on the permission declaration. Whitelisting a hard restricted permission + * allows for the to hold that permission and whitelisting a soft restricted + * permission allows the app to hold the permission in its full, unrestricted form. + * + *

      There are three whitelists: + * + *
    1. one for cases where the system permission policy whitelists a permission + * This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_SYSTEM} flag. + * Can only be modified by pre-installed holders of a dedicated permission. + * + *
    2. one for cases where the system whitelists the permission when upgrading + * from an OS version in which the permission was not restricted to an OS version + * in which the permission is restricted. This list corresponds to the {@link + * #FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be modified by pre-installed + * holders of a dedicated permission. The installer on record can only remove + * permissions from this whitelist. + * + *
    3. one for cases where the installer of the package whitelists a permission. + * This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_INSTALLER} flag. + * Can be modified by pre-installed holders of a dedicated permission or the installer + * on record. + * + *

      You need to specify the whitelists for which to set the whitelisted permissions + * which will clear the previous whitelisted permissions and replace them with the + * provided ones. + * + * @param packageName The app for which to get whitelisted permissions. + * @param permission The whitelisted permission to add. + * @param whitelistFlags The whitelists to which to add. Passing multiple flags + * updates all specified whitelists. + * @return Whether the permission was added to the whitelist. + * + * @see #getWhitelistedRestrictedPermissions(String, int) + * @see #removeWhitelistedRestrictedPermission(String, String, int) + * @see #FLAG_PERMISSION_WHITELIST_SYSTEM + * @see #FLAG_PERMISSION_WHITELIST_UPGRADE + * @see #FLAG_PERMISSION_WHITELIST_INSTALLER + * + * @throws SecurityException if you try to modify a whitelist that you have no access to. + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public boolean addWhitelistedRestrictedPermission(@NonNull String packageName, + @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) { + return false; + } + + /** + * Removes a whitelisted restricted permission for an app. + * + *

      Permissions can be hard restricted which means that the app cannot hold + * them or soft restricted where the app can hold the permission but in a weaker + * form. Whether a permission is {@link PermissionInfo#FLAG_HARD_RESTRICTED hard + * restricted} or {@link PermissionInfo#FLAG_SOFT_RESTRICTED soft restricted} + * depends on the permission declaration. Whitelisting a hard restricted permission + * allows for the to hold that permission and whitelisting a soft restricted + * permission allows the app to hold the permission in its full, unrestricted form. + * + *

        There are three whitelists: + * + *
      1. one for cases where the system permission policy whitelists a permission + * This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_SYSTEM} flag. + * Can only be modified by pre-installed holders of a dedicated permission. + * + *
      2. one for cases where the system whitelists the permission when upgrading + * from an OS version in which the permission was not restricted to an OS version + * in which the permission is restricted. This list corresponds to the {@link + * #FLAG_PERMISSION_WHITELIST_UPGRADE} flag. Can be modified by pre-installed + * holders of a dedicated permission. The installer on record can only remove + * permissions from this whitelist. + * + *
      3. one for cases where the installer of the package whitelists a permission. + * This list corresponds to the {@link #FLAG_PERMISSION_WHITELIST_INSTALLER} flag. + * Can be modified by pre-installed holders of a dedicated permission or the installer + * on record. + * + *

        You need to specify the whitelists for which to set the whitelisted permissions + * which will clear the previous whitelisted permissions and replace them with the + * provided ones. + * + * @param packageName The app for which to get whitelisted permissions. + * @param permission The whitelisted permission to remove. + * @param whitelistFlags The whitelists from which to remove. Passing multiple flags + * updates all specified whitelists. + * @return Whether the permission was removed from the whitelist. + * + * @see #getWhitelistedRestrictedPermissions(String, int) + * @see #addWhitelistedRestrictedPermission(String, String, int) + * @see #FLAG_PERMISSION_WHITELIST_SYSTEM + * @see #FLAG_PERMISSION_WHITELIST_UPGRADE + * @see #FLAG_PERMISSION_WHITELIST_INSTALLER + * + * @throws SecurityException if you try to modify a whitelist that you have no access to. + */ + @RequiresPermission(value = Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS, + conditional = true) + public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName, + @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) { + return false; + } + /** * Gets whether you should show UI with rationale for requesting a permission. * You should do this only if you do not have the permission and the context in @@ -6514,6 +6793,13 @@ public abstract class PackageManager { @UnsupportedAppUsage public abstract boolean isUpgrade(); + /** + * Returns true if the device is upgrading, such as first boot after OTA. + */ + public boolean isDeviceUpgrading() { + return false; + } + /** * Return interface that offers the ability to install, upgrade, and remove * applications on the device. @@ -6739,6 +7025,10 @@ public abstract class PackageManager { case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED"; case FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED: return "USER_SENSITIVE_WHEN_GRANTED"; case FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED: return "USER_SENSITIVE_WHEN_DENIED"; + case FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT: return "RESTRICTION_INSTALLER_EXEMPT"; + case FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT: return "RESTRICTION_SYSTEM_EXEMPT"; + case FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT: return "RESTRICTION_UPGRADE_EXEMPT"; + case FLAG_PERMISSION_APPLY_RESTRICTION: return "FLAG_PERMISSION_APPLY_RESTRICTION"; default: return Integer.toString(flag); } } diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index cd324afb0479..5f5473583907 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -80,6 +80,8 @@ public abstract class PackageManagerInternal { public interface PackageListObserver { /** A package was added to the system. */ void onPackageAdded(@NonNull String packageName, int uid); + /** A package was changed - either installed for a specific user or updated. */ + default void onPackageChanged(@NonNull String packageName, int uid) {} /** A package was removed from the system. */ void onPackageRemoved(@NonNull String packageName, int uid); } @@ -950,4 +952,13 @@ public abstract class PackageManagerInternal { */ public abstract void uninstallApex(String packageName, long versionCode, int userId, IntentSender intentSender); + + /** + * Whether default permission grants have been performed for a user + * since the device booted. + * + * @param userId The user id. + * @return true if default permissions + */ + public abstract boolean wereDefaultPermissionsGrantedSinceBoot(int userId); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 8981000714dd..2b23e7a2a633 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3279,6 +3279,19 @@ public class PackageParser { perm.info.flags = sa.getInt( com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0); + // For now only platform runtime permissions can be restricted + if (!perm.info.isRuntime() || !"android".equals(perm.info.packageName)) { + perm.info.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED; + perm.info.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED; + } else { + // The platform does not get to specify conflicting permissions + if ((perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0 + && (perm.info.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) { + throw new IllegalStateException("Permission cannot be both soft and hard" + + " restricted: " + perm.info.name); + } + } + sa.recycle(); if (perm.info.protectionLevel == -1) { diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index 6a41f334827d..f838900d43d7 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -319,6 +319,27 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { @SystemApi public static final int FLAG_REMOVED = 1<<1; + /** + * Flag for {@link #flags}, corresponding to hardRestricted + * value of {@link android.R.attr#permissionFlags}. + * + *

        This permission is restricted by the platform and it would be + * grantable only to apps that meet special criteria per platform + * policy. + */ + public static final int FLAG_HARD_RESTRICTED = 1<<2; + + /** + * Flag for {@link #flags}, corresponding to softRestricted + * value of {@link android.R.attr#permissionFlags}. + * + *

        This permission is restricted by the platform and it would be + * grantable in its full form to apps that meet special criteria + * per platform policy. Otherwise, a weaker form of the permission + * would be granted. The weak grant depends on the permission. + */ + public static final int FLAG_SOFT_RESTRICTED = 1<<3; + /** * Flag for {@link #flags}, indicating that this permission has been * installed into the system's globally defined permissions. @@ -574,11 +595,31 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { return size; } + /** @hide */ + public boolean isHardRestricted() { + return (flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; + } + + /** @hide */ + public boolean isSoftRestricted() { + return (flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0; + } + + /** @hide */ + public boolean isRestricted() { + return isHardRestricted() || isSoftRestricted(); + } + /** @hide */ public boolean isAppOp() { return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; } + /** @hide */ + public boolean isRuntime() { + return getProtection() == PROTECTION_DANGEROUS; + } + public static final @NonNull Creator CREATOR = new Creator() { @Override diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java index 22cf404c4f57..047ba1d20056 100644 --- a/core/java/android/os/RemoteCallback.java +++ b/core/java/android/os/RemoteCallback.java @@ -29,7 +29,7 @@ import android.annotation.TestApi; public final class RemoteCallback implements Parcelable { public interface OnResultListener { - public void onResult(Bundle result); + void onResult(@Nullable Bundle result); } private final OnResultListener mListener; diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl index 4f65d244d3c1..45c01bcf255b 100644 --- a/core/java/android/permission/IPermissionController.aidl +++ b/core/java/android/permission/IPermissionController.aidl @@ -40,4 +40,5 @@ oneway interface IPermissionController { void getPermissionUsages(boolean countSystem, long numMillis, in RemoteCallback callback); void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName, String packageName, String permission, int grantState, in RemoteCallback callback); + void grantOrUpgradeDefaultRuntimePermissions(in RemoteCallback callback); } diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java index 55fae3014666..be8973751bf8 100644 --- a/core/java/android/permission/PermissionControllerManager.java +++ b/core/java/android/permission/PermissionControllerManager.java @@ -56,7 +56,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; -import android.util.SparseArray; +import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService; @@ -95,7 +95,8 @@ public final class PermissionControllerManager { * Global remote services (per user) used by all {@link PermissionControllerManager managers} */ @GuardedBy("sLock") - private static SparseArray sRemoteServices = new SparseArray<>(1); + private static ArrayMap, RemoteService> sRemoteServices + = new ArrayMap<>(1); /** * The key for retrieving the result from the returned bundle. @@ -217,20 +218,24 @@ public final class PermissionControllerManager { * Create a new {@link PermissionControllerManager}. * * @param context to create the manager for + * @param handler handler to schedule work * * @hide */ - public PermissionControllerManager(@NonNull Context context) { + public PermissionControllerManager(@NonNull Context context, @NonNull Handler handler) { synchronized (sLock) { - RemoteService remoteService = sRemoteServices.get(context.getUserId(), null); + Pair key = new Pair<>(context.getUserId(), + handler.getLooper().getThread()); + RemoteService remoteService = sRemoteServices.get(key); if (remoteService == null) { Intent intent = new Intent(SERVICE_INTERFACE); intent.setPackage(context.getPackageManager().getPermissionControllerPackageName()); ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0); remoteService = new RemoteService(context.getApplicationContext(), - serviceInfo.getComponentInfo().getComponentName(), context.getUser()); - sRemoteServices.put(context.getUserId(), remoteService); + serviceInfo.getComponentInfo().getComponentName(), handler, + context.getUser()); + sRemoteServices.put(key, remoteService); } mRemoteService = remoteService; @@ -453,6 +458,23 @@ public final class PermissionControllerManager { countSystem, numMillis, executor, callback)); } + /** + * Grant or upgrade runtime permissions. The upgrade could be performed + * based on whether the device upgraded, whether the permission database + * version is old, or because the permission policy changed. + * + * @param executor Executor on which to invoke the callback + * @param callback Callback to receive the result + * + * @hide + */ + @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) + public void grantOrUpgradeDefaultRuntimePermissions( + @NonNull @CallbackExecutor Executor executor, @NonNull Consumer callback) { + mRemoteService.scheduleRequest(new PendingGrantOrUpgradeDefaultRuntimePermissionsRequest( + mRemoteService, executor, callback)); + } + /** * A connection to the remote service */ @@ -469,10 +491,10 @@ public final class PermissionControllerManager { * @param user User the remote service should be connected as */ RemoteService(@NonNull Context context, @NonNull ComponentName componentName, - @NonNull UserHandle user) { + @NonNull Handler handler, @NonNull UserHandle user) { super(context, SERVICE_INTERFACE, componentName, user.getIdentifier(), service -> Log.e(TAG, "RemoteService " + service + " died"), - context.getMainThreadHandler(), 0, false, 1); + handler, 0, false, 1); } /** @@ -1147,4 +1169,51 @@ public final class PermissionControllerManager { } } } + + /** + * Request for {@link #grantOrUpgradeDefaultRuntimePermissions(Executor, Consumer)} + */ + private static final class PendingGrantOrUpgradeDefaultRuntimePermissionsRequest extends + AbstractRemoteService.PendingRequest { + private final @NonNull Consumer mCallback; + + private final @NonNull RemoteCallback mRemoteCallback; + + private PendingGrantOrUpgradeDefaultRuntimePermissionsRequest( + @NonNull RemoteService service, @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer callback) { + super(service); + mCallback = callback; + + mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> { + long token = Binder.clearCallingIdentity(); + try { + callback.accept(result != null); + } finally { + Binder.restoreCallingIdentity(token); + finish(); + } + }), null); + } + + @Override + protected void onTimeout(RemoteService remoteService) { + long token = Binder.clearCallingIdentity(); + try { + mCallback.accept(false); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void run() { + try { + getService().getServiceInterface().grantOrUpgradeDefaultRuntimePermissions( + mRemoteCallback); + } catch (RemoteException e) { + Log.e(TAG, "Error granting or upgrading runtime permissions", e); + } + } + } } diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index 2313d5972cbd..ed44367e28c6 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -177,6 +177,17 @@ public abstract class PermissionControllerService extends Service { public abstract @NonNull List onGetPermissionUsages( boolean countSystem, long numMillis); + /** + * Grant or upgrade runtime permissions. The upgrade could be performed + * based on whether the device upgraded, whether the permission database + * version is old, or because the permission policy changed. + * + * @see PackageManager#isDeviceUpgrading() + * @see PermissionManager#getRuntimePermissionsVersion() + * @see PermissionManager#setRuntimePermissionsVersion(int) + */ + public abstract void onGrantOrUpgradeDefaultRuntimePermissions(); + /** * Set the runtime permission state from a device admin. * @@ -350,6 +361,18 @@ public abstract class PermissionControllerService extends Service { PermissionControllerService.this, callerPackageName, packageName, permission, grantState, callback)); } + + @Override + public void grantOrUpgradeDefaultRuntimePermissions(@NonNull RemoteCallback callback) { + checkNotNull(callback, "callback"); + + enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, + null); + + mHandler.sendMessage(obtainMessage( + PermissionControllerService::grantOrUpgradeDefaultRuntimePermissions, + PermissionControllerService.this, callback)); + } }; } @@ -426,4 +449,9 @@ public abstract class PermissionControllerService extends Service { result.putBoolean(PermissionControllerManager.KEY_RESULT, wasSet); callback.sendResult(result); } + + private void grantOrUpgradeDefaultRuntimePermissions(@NonNull RemoteCallback callback) { + onGrantOrUpgradeDefaultRuntimePermissions(); + callback.sendResult(Bundle.EMPTY); + } } diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 2ea706613ef8..1aa5b0656935 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -16,10 +16,19 @@ package android.permission; +import android.Manifest; +import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.content.pm.PermissionInfo; +import android.os.RemoteException; import com.android.internal.annotations.Immutable; import com.android.server.SystemConfig; @@ -46,14 +55,53 @@ public final class PermissionManager { private final @NonNull Context mContext; + private final IPackageManager mPackageManager; + /** * Creates a new instance. * * @param context The current context in which to operate. * @hide */ - public PermissionManager(@NonNull Context context) { + public PermissionManager(@NonNull Context context, IPackageManager packageManager) { mContext = context; + mPackageManager = packageManager; + } + + /** + * Gets the version of the runtime permission database. + * + * @return The database version. + * + * @hide + */ + @TestApi + @SystemApi + @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) + public @IntRange(from = 0) int getRuntimePermissionsVersion() { + try { + return mPackageManager.getRuntimePermissionsVersion(mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets the version of the runtime permission database. + * + * @param version The new version. + * + * @hide + */ + @TestApi + @SystemApi + @RequiresPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) + public void setRuntimePermissionsVersion(@IntRange(from = 0) int version) { + try { + mPackageManager.setRuntimePermissionsVersion(version, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** diff --git a/core/java/android/permission/PermissionManagerInternal.java b/core/java/android/permission/PermissionManagerInternal.java index 92dbab33a2f0..71674311965c 100644 --- a/core/java/android/permission/PermissionManagerInternal.java +++ b/core/java/android/permission/PermissionManagerInternal.java @@ -18,6 +18,7 @@ package android.permission; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.os.UserHandle; /** @@ -28,6 +29,23 @@ import android.os.UserHandle; * @hide */ public abstract class PermissionManagerInternal { + + /** + * Listener for package permission state (permissions or flags) changes. + */ + public interface OnRuntimePermissionStateChangedListener { + + /** + * Called when the runtime permission state (permissions or flags) changed. + * + * @param packageName The package for which the change happened. + * @param userId the user id for which the change happened. + */ + @Nullable + void onRuntimePermissionStateChanged(@NonNull String packageName, + @UserIdInt int userId); + } + /** * Get the state of the runtime permissions as xml file. * @@ -59,4 +77,20 @@ public abstract class PermissionManagerInternal { */ public abstract void restoreDelayedRuntimePermissions(@NonNull String packageName, @NonNull UserHandle user); + + /** + * Adds a listener for runtime permission state (permissions or flags) changes. + * + * @param listener The listener. + */ + public abstract void addOnRuntimePermissionStateChangedListener( + @NonNull OnRuntimePermissionStateChangedListener listener); + + /** + * Removes a listener for runtime permission state (permissions or flags) changes. + * + * @param listener The listener. + */ + public abstract void removeOnRuntimePermissionStateChangedListener( + @NonNull OnRuntimePermissionStateChangedListener listener); } diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 9ec77232ec28..166de3fde741 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -281,30 +281,7 @@ public final class DeviceConfig { */ @SystemApi @TestApi - public interface Privacy { - String NAMESPACE = "privacy"; - - /** - * Whether to show the Permissions Hub. - * - * @hide - */ - @SystemApi - String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; - - /** - * Whether to show location access check notifications. - */ - String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled"; - - /** - * Whether to disable the new device identifier access restrictions. - * - * @hide - */ - String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED = - "device_identifier_access_restrictions_disabled"; - } + public static final String NAMESPACE_PRIVACY = "privacy"; private static final Object sLock = new Object(); @GuardedBy("sLock") diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ee0c83ea72f8..2e1ef38048b2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13390,18 +13390,6 @@ public final class Settings { public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch"; - /** - * If set to 1, app cannot request read sms permission unless it's the default sms handler. - * - * STOPSHIP: Remove this once we ship with the restriction enabled. - * - * @hide - */ - @SystemApi - @TestApi - public static final String SMS_ACCESS_RESTRICTION_ENABLED = - "sms_access_restriction_enabled"; - /** * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE * permission check for 3P apps. diff --git a/core/java/android/util/StatsLogAtoms.java b/core/java/android/util/StatsLogAtoms.java index bbede5394ede..4780cb58ca06 100644 --- a/core/java/android/util/StatsLogAtoms.java +++ b/core/java/android/util/StatsLogAtoms.java @@ -76,6 +76,13 @@ public class StatsLogAtoms { public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED = StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED; + /** + * Possible value of {@link PermissionGrantRequestResultReported_Result}: + * permission request was ignored because it was restricted + */ + public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION = + StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_RESTRICTED_PERMISSION; + /** * Possible value of {@link PermissionGrantRequestResultReported_Result}: * permission was granted by user action diff --git a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java index 206efa94b7f6..c3aa847acae1 100644 --- a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java @@ -32,7 +32,6 @@ import java.util.ArrayList; * * @param the concrete remote service class * @param the interface of the binder service - * @hide */ public abstract class AbstractMultiplePendingRequestsRemoteService, I extends IInterface> diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index de526eff275e..b94eb1626e37 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -728,7 +728,7 @@ android:permissionGroup="android.permission-group.UNDEFINED" android:label="@string/permlab_sendSms" android:description="@string/permdesc_sendSms" - android:permissionFlags="costsMoney" + android:permissionFlags="costsMoney|hardRestricted" android:protectionLevel="dangerous" /> @@ -947,6 +952,7 @@ android:permissionGroup="android.permission-group.UNDEFINED" android:label="@string/permlab_readCallLog" android:description="@string/permdesc_readCallLog" + android:permissionFlags="hardRestricted" android:protectionLevel="dangerous" /> @@ -3427,6 +3435,12 @@ + + + diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 8f3f25aad182..47c243ca1e04 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -310,13 +310,24 @@ - + + + + +