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
diff --git a/api/current.txt b/api/current.txt
index 3fb0545..d24e350 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11483,10 +11483,12 @@
     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<java.lang.String>);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionParams> 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<java.lang.String> RESTRICTED_PERMISSIONS_ALL;
   }
 
   public class PackageItemInfo {
@@ -11523,6 +11525,7 @@
     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 @@
     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<java.lang.String> 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 @@
     method @NonNull public abstract java.util.List<android.content.pm.PermissionInfo> 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 @@
     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 @@
     method @Nullable public CharSequence loadDescription(@NonNull android.content.pm.PackageManager);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> 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 6458909..eb9f82a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -201,6 +201,7 @@
     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 @@
     method public boolean getInstallAsInstantApp(boolean);
     method public boolean getInstallAsVirtualPreload();
     method public boolean getRequestDowngrade();
+    method @NonNull public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions();
   }
 
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
@@ -1651,8 +1653,12 @@
     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 @@
     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 @@
     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 @@
   }
 
   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 @@
     method @NonNull public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String);
     method @NonNull public abstract java.util.List<android.permission.RuntimePermissionUsageInfo> 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 @@
   }
 
   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<android.permission.PermissionManager.SplitPermissionInfo> 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 @@
     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 @@
     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 @@
     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 @@
     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 99cdfb0..973e700 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -655,8 +655,13 @@
     ctor public LauncherApps(android.content.Context);
   }
 
+  public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
+    method @NonNull public java.util.Set<java.lang.String> 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 @@
     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 @@
     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 @@
   }
 
   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 @@
     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 @@
     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 @@
     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 8986c6f..146cf0c 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5453,6 +5453,8 @@
         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 4b0b8cb..15982a7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -30,9 +30,7 @@
 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.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.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 @@
             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 @@
             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 @@
      * @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 a906790..82a34ce 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -89,6 +89,7 @@
 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.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 /** @hide */
 public class ApplicationPackageManager extends PackageManager {
@@ -718,6 +720,43 @@
     }
 
     @Override
+    public @NonNull Set<String> getWhitelistedRestrictedPermissions(
+            @NonNull String packageName, @PermissionWhitelistFlags int whitelistFlags) {
+        try {
+            final List<String> 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) {
         try {
@@ -2634,13 +2673,15 @@
         }
     }
 
-    /**
-     * @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 d67bfb6..8749b10 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -50,6 +50,7 @@
 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 @@
                 new CachedServiceFetcher<PermissionManager>() {
                     @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<PermissionControllerManager>() {
                     @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 a472eac..19762e0 100644
--- a/core/java/android/app/role/IRoleController.aidl
+++ b/core/java/android/app/role/IRoleController.aidl
@@ -33,8 +33,6 @@
 
     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 bd98117..027e152 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -121,13 +121,6 @@
     }
 
     /**
-     * @see RoleControllerService#onSmsKillSwitchToggled(boolean)
-     */
-    public void onSmsKillSwitchToggled(boolean enabled) {
-        mRemoteService.scheduleAsyncRequest(new OnSmsKillSwitchToggledRequest(enabled));
-    }
-
-    /**
      * @see RoleControllerService#onIsApplicationQualifiedForRole(String, String)
      */
     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
@@ -416,28 +409,6 @@
     }
 
     /**
-     * Request for {@link #onSmsKillSwitchToggled(boolean)}
-     */
-    private static final class OnSmsKillSwitchToggledRequest
-            implements AbstractRemoteService.AsyncRequest<IRoleController> {
-
-        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)}
      */
     private static final class IsApplicationQualifiedForRoleRequest extends
diff --git a/core/java/android/app/role/RoleControllerService.java b/core/java/android/app/role/RoleControllerService.java
index 312761d..2bc9456 100644
--- a/core/java/android/app/role/RoleControllerService.java
+++ b/core/java/android/app/role/RoleControllerService.java
@@ -131,15 +131,6 @@
                         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
@@ -259,17 +250,6 @@
             @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.
      *
      * @param roleName name of the role to check for
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index ddfe755..71242fb 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -620,13 +620,7 @@
         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 @@
         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 fb22187..cf704d5 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -130,6 +130,15 @@
 
     void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId);
 
+    List<String> 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 @@
 
     boolean isFirstBoot();
     boolean isOnlyCoreApps();
-    boolean isUpgrade();
+    boolean isDeviceUpgrading();
 
     void setPermissionEnforced(String permission, boolean enforced);
     boolean isPermissionEnforced(String permission);
@@ -757,4 +766,8 @@
     List<ModuleInfo> 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 ec2e8ca..90fb20b 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -30,6 +30,7 @@
 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.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.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 static final int MODE_INHERIT_EXISTING = 2;
 
+        /**
+         * Special constant to refer to all restricted permissions.
+         */
+        public static final @NonNull Set<String> RESTRICTED_PERMISSIONS_ALL = new ArraySet<>();
+
         /** {@hide} */
         public static final int UID_UNKNOWN = -1;
 
@@ -1306,6 +1315,8 @@
         /** {@hide} */
         public String[] grantedRuntimePermissions;
         /** {@hide} */
+        public List<String> whitelistedRestrictedPermissions;
+        /** {@hide} */
         public String installerPackageName;
         /** {@hide} */
         public boolean isMultiPackage;
@@ -1339,6 +1350,7 @@
             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 @@
             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 @@
          *
          * @hide
          */
+        @TestApi
         @SystemApi
         @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
         public void setGrantedRuntimePermissions(String[] permissions) {
@@ -1482,6 +1496,43 @@
         }
 
         /**
+         * 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.
+         *
+         * <p> 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.
+         *
+         * <p>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
+         * <code>null</code> 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<String> 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.
          *
          * <p>If the parent session is staged or has rollback enabled, all children sessions
@@ -1656,6 +1707,7 @@
             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 @@
             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 Uri referrerUri;
         /** {@hide} */
         public String[] grantedRuntimePermissions;
+        /** {@hide}*/
+        public List<String> whitelistedRestrictedPermissions;
         /** {@hide} */
         public int installFlags;
         /** {@hide} */
@@ -1847,6 +1902,8 @@
             originatingUid = source.readInt();
             referrerUri = source.readParcelable(null);
             grantedRuntimePermissions = source.readStringArray();
+            whitelistedRestrictedPermissions = source.createStringArrayList();
+
             installFlags = source.readInt();
             isMultiPackage = source.readBoolean();
             isStaged = source.readBoolean();
@@ -2049,6 +2106,25 @@
         }
 
         /**
+         * 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<String> 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)}.
          *
          * @deprecated use {@link #getRequestDowngrade()}.
@@ -2277,6 +2353,7 @@
             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 025d8f9..83e15e8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -69,8 +69,10 @@
 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 @@
     /** {@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 @@
             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 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 static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED =  1 << 9;
 
     /**
-     * Mask for all permission flags present in Android P
-     *
-     * @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.
+     * 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.
+     *
+     * @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 @@
      *
      * @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.
@@ -3102,6 +3191,35 @@
     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,
      * etc. This library is versioned and backwards compatible. Clients
@@ -3824,6 +3942,10 @@
             /*
             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 {}
@@ -3925,6 +4047,163 @@
             @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.
+     *
+     * <p> 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.
+     *
+     * <p><ol>There are three whitelists:
+     *
+     * <li>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.
+     *
+     * <li>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.
+     *
+     * <li>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<String> getWhitelistedRestrictedPermissions(
+            @NonNull String packageName, @PermissionWhitelistFlags int whitelistFlag) {
+        return Collections.emptySet();
+    }
+
+    /**
+     * Adds a whitelisted restricted permission for an app.
+     *
+     * <p> 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.
+     *
+     * <p><ol>There are three whitelists:
+     *
+     * <li>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.
+     *
+     * <li>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.
+     *
+     * <li>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.
+     *
+     * <p>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.
+     *
+     * <p> 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.
+     *
+     * <p><ol>There are three whitelists:
+     *
+     * <li>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.
+     *
+     * <li>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.
+     *
+     * <li>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.
+     *
+     * <p>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
      * which the permission is requested does not clearly communicate to the user
@@ -6515,6 +6794,13 @@
     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 @@
             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 cd324af..5f54735 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -80,6 +80,8 @@
     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 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 8981000..2b23e7a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3279,6 +3279,19 @@
         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 6a41f33..f838900 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -320,6 +320,27 @@
     public static final int FLAG_REMOVED = 1<<1;
 
     /**
+     * Flag for {@link #flags}, corresponding to <code>hardRestricted</code>
+     * value of {@link android.R.attr#permissionFlags}.
+     *
+     * <p> 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 <code>softRestricted</code>
+     * value of {@link android.R.attr#permissionFlags}.
+     *
+     * <p>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.
      */
@@ -575,10 +596,30 @@
     }
 
     /** @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<PermissionInfo> CREATOR =
         new Creator<PermissionInfo>() {
         @Override
diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java
index 22cf404..047ba1d 100644
--- a/core/java/android/os/RemoteCallback.java
+++ b/core/java/android/os/RemoteCallback.java
@@ -29,7 +29,7 @@
 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 4f65d24..45c01bc 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -40,4 +40,5 @@
     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 55fae30..be89737 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -56,7 +56,7 @@
 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 @@
      * Global remote services (per user) used by all {@link PermissionControllerManager managers}
      */
     @GuardedBy("sLock")
-    private static SparseArray<RemoteService> sRemoteServices = new SparseArray<>(1);
+    private static ArrayMap<Pair<Integer, Thread>, RemoteService> sRemoteServices
+            = new ArrayMap<>(1);
 
     /**
      * The key for retrieving the result from the returned bundle.
@@ -217,20 +218,24 @@
      * 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<Integer, Thread> 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;
@@ -454,6 +459,23 @@
     }
 
     /**
+     * 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<Boolean> callback) {
+        mRemoteService.scheduleRequest(new PendingGrantOrUpgradeDefaultRuntimePermissionsRequest(
+                mRemoteService, executor, callback));
+    }
+
+    /**
      * A connection to the remote service
      */
     static final class RemoteService extends
@@ -469,10 +491,10 @@
          * @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 @@
             }
         }
     }
+
+    /**
+     * Request for {@link #grantOrUpgradeDefaultRuntimePermissions(Executor, Consumer)}
+     */
+    private static final class PendingGrantOrUpgradeDefaultRuntimePermissionsRequest extends
+            AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
+        private final @NonNull Consumer<Boolean> mCallback;
+
+        private final @NonNull RemoteCallback mRemoteCallback;
+
+        private PendingGrantOrUpgradeDefaultRuntimePermissionsRequest(
+                @NonNull RemoteService service,  @NonNull @CallbackExecutor Executor executor,
+                @NonNull Consumer<Boolean> 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 2313d59..ed44367 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -178,6 +178,17 @@
             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.
      *
      * @param callerPackageName The package name of the admin requesting the change
@@ -350,6 +361,18 @@
                         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 @@
         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 2ea7066..1aa5b06 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 @@
 
     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 92dbab3..7167431 100644
--- a/core/java/android/permission/PermissionManagerInternal.java
+++ b/core/java/android/permission/PermissionManagerInternal.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.os.UserHandle;
 
 /**
@@ -28,6 +29,23 @@
  * @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 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 9ec7723..166de3f 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -281,30 +281,7 @@
      */
     @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 ee0c83e..2e1ef38 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13391,18 +13391,6 @@
                 "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 bbede53..4780cb5 100644
--- a/core/java/android/util/StatsLogAtoms.java
+++ b/core/java/android/util/StatsLogAtoms.java
@@ -78,6 +78,13 @@
 
     /**
      * 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
      */
     public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED =
diff --git a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
index 206efa9..c3aa847 100644
--- a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
@@ -32,7 +32,6 @@
  *
  * @param <S> the concrete remote service class
  * @param <I> the interface of the binder service
- * @hide
  */
 public abstract class AbstractMultiplePendingRequestsRemoteService<S
         extends AbstractMultiplePendingRequestsRemoteService<S, I>, I extends IInterface>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index de526ef..b94eb16 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" />
 
     <!-- Allows an application to receive SMS messages.
@@ -738,6 +738,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveSms"
         android:description="@string/permdesc_receiveSms"
+        android:permissionFlags="hardRestricted"
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to read SMS messages.
@@ -747,6 +748,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readSms"
         android:description="@string/permdesc_readSms"
+        android:permissionFlags="hardRestricted"
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to receive WAP push messages.
@@ -756,6 +758,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveWapPush"
         android:description="@string/permdesc_receiveWapPush"
+        android:permissionFlags="hardRestricted"
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to monitor incoming MMS messages.
@@ -765,6 +768,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveMms"
         android:description="@string/permdesc_receiveMms"
+        android:permissionFlags="hardRestricted"
         android:protectionLevel="dangerous" />
 
     <!-- @SystemApi @TestApi Allows an application to read previously received cell broadcast
@@ -783,6 +787,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readCellBroadcasts"
         android:description="@string/permdesc_readCellBroadcasts"
+        android:permissionFlags="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" />
 
     <!-- Allows an application to write (but not read) the user's
@@ -966,6 +972,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_writeCallLog"
         android:description="@string/permdesc_writeCallLog"
+        android:permissionFlags="hardRestricted"
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to see the number being dialed during an outgoing
@@ -980,6 +987,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_processOutgoingCalls"
         android:description="@string/permdesc_processOutgoingCalls"
+        android:permissionFlags="hardRestricted"
         android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
@@ -3427,6 +3435,12 @@
     <permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
                 android:protectionLevel="signature|installer" />
 
+    <!-- @SystemApi Allows an application to whitelist restricted permissions
+         on any of the whitelists.
+    @hide -->
+    <permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS"
+                android:protectionLevel="signature|installer" />
+
     <!-- @hide Allows an application to observe permission changes. -->
     <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
         android:protectionLevel="signature|privileged" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8f3f25a..47c243c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -310,13 +310,24 @@
         <!-- Set to indicate that this permission allows an operation that
              may cost the user money.  Such permissions may be highlighted
              when shown to the user with this additional information.  -->
-        <flag name="costsMoney" value="0x0001" />
+        <flag name="costsMoney" value="0x1" />
         <!-- Additional flag from base permission type: this permission has been
              removed and it is no longer enforced. It shouldn't be shown in the
              UI. Removed permissions are kept as normal permissions for backwards
              compatibility as apps may be checking them before calling an API.
         -->
         <flag name="removed" value="0x2" />
+        <!-- This permission is restricted by the platform and it would be
+             grantable only to apps that meet special criteria per platform
+             policy.
+        -->
+        <flag name="hardRestricted" value="0x4" />
+        <!-- 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.
+        -->
+        <flag name="softRestricted" value="0x8" />
     </attr>
 
     <!-- Specified the name of a group that this permission is associated
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index c36ca82..33c23c4 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -433,7 +433,6 @@
                     Settings.Global.SIGNED_CONFIG_VERSION,
                     Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
                     Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
-                    Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED,
                     Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
                     Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
                     Settings.Global.SMS_SHORT_CODE_CONFIRMATION,
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index 9f38d48..cee4666 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -139,6 +139,9 @@
                         getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
                 params.installReason = PackageManager.INSTALL_REASON_USER;
 
+                // Whitelist all restricted permissions.
+                params.setWhitelistedRestrictedPermissions(null /*permissions*/);
+
                 File file = new File(mPackageURI.getPath());
                 try {
                     PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index f597a1a..c204f26 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1236,11 +1236,6 @@
         dumpSetting(s, p,
                 Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL,
                 GlobalSettingsProto.Sms.SHORT_CODES_UPDATE_METADATA_URL);
-        dumpSetting(s, p,
-                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED,
-                GlobalSettingsProto.Sms.ACCESS_RESTRICTION_ENABLED);
-        p.end(smsToken);
-
         final long soundsToken = p.start(GlobalSettingsProto.SOUNDS);
         dumpSetting(s, p,
                 Settings.Global.CAR_DOCK_SOUND,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 296f7a1..a5b7849 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3610,7 +3610,7 @@
 
                     final boolean isUpgrade;
                     try {
-                        isUpgrade = mPackageManager.isUpgrade();
+                        isUpgrade = mPackageManager.isDeviceUpgrading();
                     } catch (RemoteException e) {
                         throw new IllegalStateException("Package manager not available");
                     }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 2a9456d..d1b7c75 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -99,6 +99,7 @@
     <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />
     <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
+    <uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" />
     <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
     <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
     <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index cb587de..b053d84 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -74,7 +74,6 @@
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS_GLES, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
-        sGlobalSettingToTypeMap.put(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, int.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_ALL_APPS, int.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_IN_APPS, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_OUT_APPS, String.class);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 2bd9198..8847e32 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2269,7 +2269,7 @@
         boolean isFirstBootOrUpgrade() {
             IPackageManager pm = AppGlobals.getPackageManager();
             try {
-                return pm.isFirstBoot() || pm.isUpgrade();
+                return pm.isFirstBoot() || pm.isDeviceUpgrading();
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 1c9028d..9094e1b 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -353,7 +353,7 @@
             throw new IllegalStateException("Should not be ota-dexopting when trying to move.");
         }
 
-        if (!mPackageManagerService.isUpgrade()) {
+        if (!mPackageManagerService.isDeviceUpgrading()) {
             Slog.d(TAG, "No upgrade, skipping A/B artifacts check.");
             return;
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index e4cb283..7f48970 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -531,6 +531,16 @@
                         + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
             }
 
+            // Only system components can circumvent restricted whitelisting when installing.
+            if ((params.installFlags
+                    & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
+                    && mContext.checkCallingOrSelfPermission(Manifest.permission
+                    .WHITELIST_RESTRICTED_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
+                throw new SecurityException("You need the "
+                        + "android.permission.WHITELIST_RESTRICTED_PERMISSIONS permission to"
+                        + " use the PackageManager.INSTALL_WHITELIST_RESTRICTED_PERMISSIONS flag");
+            }
+
             // Defensively resize giant app icons
             if (params.appIcon != null) {
                 final ActivityManager am = (ActivityManager) mContext.getSystemService(
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3306ccd..a935c65 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -139,6 +139,8 @@
     static final String TAG_SESSION = "session";
     static final String TAG_CHILD_SESSION = "childSession";
     private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
+    private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
+            "whitelisted-restricted-permission";
     private static final String ATTR_SESSION_ID = "sessionId";
     private static final String ATTR_USER_ID = "userId";
     private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
@@ -486,6 +488,7 @@
             info.originatingUid = params.originatingUid;
             info.referrerUri = params.referrerUri;
             info.grantedRuntimePermissions = params.grantedRuntimePermissions;
+            info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
             info.installFlags = params.installFlags;
             info.isMultiPackage = params.isMultiPackage;
             info.isStaged = params.isStaged;
@@ -2331,6 +2334,19 @@
         }
     }
 
+    private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull XmlSerializer out,
+            @Nullable List<String> whitelistedRestrictedPermissions) throws IOException {
+        if (whitelistedRestrictedPermissions != null) {
+            final int permissionCount = whitelistedRestrictedPermissions.size();
+            for (int i = 0; i < permissionCount; i++) {
+                out.startTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
+                writeStringAttribute(out, ATTR_NAME, whitelistedRestrictedPermissions.get(i));
+                out.endTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
+            }
+        }
+    }
+
+
     private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
         return new File(sessionsDir, "app_icon." + sessionId + ".png");
     }
@@ -2392,6 +2408,8 @@
             writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
 
             writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
+            writeWhitelistedRestrictedPermissionsLocked(out,
+                    params.whitelistedRestrictedPermissions);
 
             // Persist app icon if changed since last written
             File appIconFile = buildAppIconFile(sessionId, sessionsDir);
@@ -2510,7 +2528,8 @@
 
         // Store the current depth. We should stop parsing when we reach an end tag at the same
         // depth.
-        List<String> permissions = new ArrayList<>();
+        List<String> grantedRuntimePermissions = new ArrayList<>();
+        List<String> whitelistedRestrictedPermissions = new ArrayList<>();
         List<Integer> childSessionIds = new ArrayList<>();
         int outerDepth = in.getDepth();
         int type;
@@ -2520,15 +2539,24 @@
                 continue;
             }
             if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
-                permissions.add(readStringAttribute(in, ATTR_NAME));
+                grantedRuntimePermissions.add(readStringAttribute(in, ATTR_NAME));
+            }
+            if (TAG_WHITELISTED_RESTRICTED_PERMISSION.equals(in.getName())) {
+                whitelistedRestrictedPermissions.add(readStringAttribute(in, ATTR_NAME));
+
             }
             if (TAG_CHILD_SESSION.equals(in.getName())) {
                 childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
             }
         }
 
-        if (permissions.size() > 0) {
-            params.grantedRuntimePermissions = permissions.stream().toArray(String[]::new);
+        if (grantedRuntimePermissions.size() > 0) {
+            params.grantedRuntimePermissions = grantedRuntimePermissions
+                    .stream().toArray(String[]::new);
+        }
+
+        if (whitelistedRestrictedPermissions.size() > 0) {
+            params.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
         }
 
         int[] childSessionIdsArray;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 444d2fa..d5b1ca3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -170,6 +170,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
 import android.content.pm.PackageManager.ModuleInfoFlags;
+import android.content.pm.PackageManager.PermissionWhitelistFlags;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.CheckPermissionDelegate;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
@@ -745,6 +746,9 @@
     @GuardedBy("mPackages")
     final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
 
+    @GuardedBy("mPackages")
+    private final SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray();
+
     private final ModuleInfoProvider mModuleInfoProvider;
 
     private final ApexManager mApexManager;
@@ -1487,10 +1491,15 @@
                         final boolean virtualPreload = ((args.installFlags
                                 & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
                         final String[] grantedPermissions = args.installGrantPermissions;
+                        final List<String> whitelistedRestrictedPermissions = ((args.installFlags
+                                & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0
+                                    && parentRes.pkg != null)
+                                ? parentRes.pkg.requestedPermissions : null;
 
                         // Handle the parent package
-                        handlePackagePostInstall(parentRes, grantPermissions, killApp,
-                                virtualPreload, grantedPermissions, didRestore,
+                        handlePackagePostInstall(parentRes, grantPermissions,
+                                killApp, virtualPreload, grantedPermissions,
+                                whitelistedRestrictedPermissions, didRestore,
                                 args.installerPackageName, args.observer);
 
                         // Handle the child packages
@@ -1498,8 +1507,9 @@
                                 ? parentRes.addedChildPackages.size() : 0;
                         for (int i = 0; i < childCount; i++) {
                             PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
-                            handlePackagePostInstall(childRes, grantPermissions, killApp,
-                                    virtualPreload, grantedPermissions, false /*didRestore*/,
+                            handlePackagePostInstall(childRes, grantPermissions,
+                                    killApp, virtualPreload, grantedPermissions,
+                                    whitelistedRestrictedPermissions, false /*didRestore*/,
                                     args.installerPackageName, args.observer);
                         }
 
@@ -1777,7 +1787,8 @@
     };
 
     private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
-            boolean killApp, boolean virtualPreload, String[] grantedPermissions,
+            boolean killApp, boolean virtualPreload,
+            String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
             boolean launchedForRestore, String installerPackage,
             IPackageInstallObserver2 installObserver) {
         if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
@@ -1786,6 +1797,16 @@
                 res.removedInfo.sendPackageRemovedBroadcasts(killApp);
             }
 
+            // Whitelist any restricted permissions first as some may be runtime
+            // that the installer requested to be granted at install time.
+            if (whitelistedRestrictedPermissions != null
+                    && !whitelistedRestrictedPermissions.isEmpty()) {
+                mPermissionManager.setWhitelistedRestrictedPermissions(
+                        res.pkg, res.newUsers, whitelistedRestrictedPermissions,
+                        Process.myUid(), PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER,
+                        mPermissionCallback);
+            }
+
             // Now that we successfully installed the package, grant runtime
             // permissions if requested before broadcasting the install. Also
             // for legacy apps in permission review mode we clear the permission
@@ -1999,6 +2020,8 @@
 
             if (allNewUsers && !update) {
                 notifyPackageAdded(packageName, res.uid);
+            } else {
+                notifyPackageChanged(packageName, res.uid);
             }
 
             // Log current value of "unknown sources" setting
@@ -2308,6 +2331,7 @@
                         public void onDefaultRuntimePermissionsGranted(int userId) {
                             synchronized(mPackages) {
                                 mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
+                                mDefaultPermissionsGrantedUsers.put(userId, userId);
                             }
                         }
                     }, mPackages /*externalLock*/);
@@ -3475,7 +3499,7 @@
     }
 
     @Override
-    public boolean isUpgrade() {
+    public boolean isDeviceUpgrading() {
         // allow instant applications
         // The system property allows testing ota flow when upgraded to the same image.
         return mIsUpgrade || SystemProperties.getBoolean(
@@ -5527,7 +5551,7 @@
                 == PackageManager.PERMISSION_GRANTED);
 
         mPermissionManager.revokeRuntimePermission(permName, packageName, overridePolicy,
-                getCallingUid(), userId, mPermissionCallback);
+                userId, mPermissionCallback);
     }
 
     @Override
@@ -5619,6 +5643,193 @@
     }
 
     @Override
+    public @Nullable List<String> getWhitelistedRestrictedPermissions(@NonNull String packageName,
+            @PermissionWhitelistFlags int whitelistFlags, @UserIdInt int userId) {
+        Preconditions.checkNotNull(packageName);
+        Preconditions.checkFlagsArgument(whitelistFlags,
+                PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+        Preconditions.checkArgumentNonNegative(userId, null);
+
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS,
+                    "getWhitelistedRestrictedPermissions for user " + userId);
+        }
+
+        synchronized (mPackages) {
+            final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+            if (packageSetting == null) {
+                Slog.w(TAG, "Unknown package: " + packageName);
+                return null;
+            }
+
+            final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
+                    Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+                            == PackageManager.PERMISSION_GRANTED;
+            final PackageSetting installerPackageSetting = mSettings.mPackages.get(
+                    packageSetting.installerPackageName);
+            final boolean isCallerInstallerOnRecord = installerPackageSetting != null
+                    && UserHandle.isSameApp(installerPackageSetting.appId, Binder.getCallingUid());
+
+            if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+                    && !isCallerPrivileged) {
+                throw new SecurityException("Querying system whitelist requires "
+                        + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+            }
+
+            if ((whitelistFlags & (PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                    | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) != 0) {
+                if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+                    throw new SecurityException("Querying upgrade or installer whitelist"
+                            + " requires being installer on record or "
+                            + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+                }
+            }
+
+            if (filterAppAccessLPr(packageSetting, Binder.getCallingUid(),
+                    UserHandle.getCallingUserId())) {
+                return null;
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return mPermissionManager.getWhitelistedRestrictedPermissions(
+                        packageSetting.pkg, whitelistFlags, userId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @Override
+    public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
+            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags,
+            @UserIdInt int userId) {
+        // Other argument checks are done in get/setWhitelistedRestrictedPermissions
+        Preconditions.checkNotNull(permission);
+
+        List<String> permissions = getWhitelistedRestrictedPermissions(packageName,
+                whitelistFlags, userId);
+        if (permissions == null) {
+            permissions = new ArrayList<>(1);
+        }
+        if (permissions.indexOf(permission) < 0) {
+            permissions.add(permission);
+            setWhitelistedRestrictedPermissions(packageName, permissions,
+                    whitelistFlags, userId);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
+            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags,
+            @UserIdInt int userId) {
+        // Other argument checks are done in get/setWhitelistedRestrictedPermissions
+        Preconditions.checkNotNull(permission);
+
+        final List<String> permissions = getWhitelistedRestrictedPermissions(packageName,
+                whitelistFlags, userId);
+        if (permissions != null && permissions.remove(permission)) {
+            setWhitelistedRestrictedPermissions(packageName, permissions,
+                    whitelistFlags, userId);
+            return true;
+        }
+        return false;
+    }
+
+    private void setWhitelistedRestrictedPermissions(@NonNull String packageName,
+            @Nullable List<String> permissions, @PermissionWhitelistFlags int whitelistFlag,
+            @UserIdInt int userId) {
+        Preconditions.checkNotNull(packageName);
+        Preconditions.checkFlagsArgument(whitelistFlag,
+                PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+                        | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+        Preconditions.checkArgument(Integer.bitCount(whitelistFlag) == 1);
+        Preconditions.checkArgumentNonNegative(userId, null);
+
+        if (UserHandle.getCallingUserId() != userId) {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS,
+                    "setWhitelistedRestrictedPermissions for user " + userId);
+        }
+
+        synchronized (mPackages) {
+            final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+            if (packageSetting == null) {
+                Slog.w(TAG, "Unknown package: " + packageName);
+                return;
+            }
+
+            final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
+                    Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+                            == PackageManager.PERMISSION_GRANTED;
+            final PackageSetting installerPackageSetting = mSettings.mPackages.get(
+                    packageSetting.installerPackageName);
+            final boolean isCallerInstallerOnRecord = installerPackageSetting != null
+                    && UserHandle.isSameApp(installerPackageSetting.appId, Binder.getCallingUid());
+
+            if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0
+                    && !isCallerPrivileged) {
+                throw new SecurityException("Modifying system whitelist requires "
+                        + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+            }
+
+            if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
+                if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+                    throw new SecurityException("Modifying upgrade whitelist requires"
+                            + " being installer on record or "
+                            + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+                }
+                final List<String> whitelistedPermissions = getWhitelistedRestrictedPermissions(
+                        packageName, whitelistFlag, userId);
+                if (permissions == null || permissions.isEmpty()) {
+                    if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
+                        return;
+                    }
+                } else {
+                    // Only the system can add and remove while the installer can only remove.
+                    final int permissionCount = permissions.size();
+                    for (int i = 0; i < permissionCount; i++) {
+                        if ((whitelistedPermissions == null
+                                || !whitelistedPermissions.contains(permissions.get(i)))
+                                && !isCallerPrivileged) {
+                            throw new SecurityException("Adding to upgrade whitelist requires"
+                                    + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+                        }
+                    }
+                }
+            }
+
+            if ((whitelistFlag & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
+                if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
+                    throw new SecurityException("Modifying installer whitelist requires"
+                            + " being installer on record or "
+                            + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
+                }
+            }
+
+            if (filterAppAccessLPr(packageSetting, Binder.getCallingUid(),
+                    UserHandle.getCallingUserId())) {
+                return;
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mPermissionManager.setWhitelistedRestrictedPermissions(packageSetting.pkg,
+                        new int[]{userId}, permissions, Process.myUid(), whitelistFlag,
+                        mPermissionCallback);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @Override
     public boolean shouldShowRequestPermissionRationale(String permissionName,
             String packageName, int userId) {
         if (UserHandle.getCallingUserId() != userId) {
@@ -8676,7 +8887,7 @@
     private void maybeClearProfilesForUpgradesLI(
             @Nullable PackageSetting originalPkgSetting,
             @NonNull PackageParser.Package currentPkg) {
-        if (originalPkgSetting == null || !isUpgrade()) {
+        if (originalPkgSetting == null || !isDeviceUpgrading()) {
           return;
         }
         if (originalPkgSetting.versionCode == currentPkg.mVersionCode) {
@@ -9163,7 +9374,7 @@
         enforceSystemOrRoot("Only the system can request package update");
 
         // We need to re-extract after an OTA.
-        boolean causeUpgrade = isUpgrade();
+        boolean causeUpgrade = isDeviceUpgrading();
 
         // First boot or factory reset.
         // Note: we also handle devices that are upgrading to N right now as if it is their
@@ -9224,7 +9435,7 @@
 
             boolean useProfileForDexopt = false;
 
-            if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) {
+            if ((isFirstBoot() || isDeviceUpgrading()) && isSystemApp(pkg)) {
                 // Copy over initial preopt profiles since we won't get any JIT samples for methods
                 // that are already compiled.
                 File profileFile = new File(getPrebuildProfilePath(pkg));
@@ -12551,6 +12762,22 @@
         }
     }
 
+    @Override
+    public void notifyPackageChanged(String packageName, int uid) {
+        final PackageListObserver[] observers;
+        synchronized (mPackages) {
+            if (mPackageListObservers.size() == 0) {
+                return;
+            }
+            final PackageListObserver[] observerArray =
+                    new PackageListObserver[mPackageListObservers.size()];
+            observers = mPackageListObservers.toArray(observerArray);
+        }
+        for (int i = observers.length - 1; i >= 0; --i) {
+            observers[i].onPackageChanged(packageName, uid);
+        }
+    }
+
     private static final Comparator<ProviderInfo> sProviderInitOrderSorter = (p1, p2) -> {
         final int v1 = p1.initOrder;
         final int v2 = p2.initOrder;
@@ -14510,6 +14737,7 @@
         int mRet;
         final String packageAbiOverride;
         final String[] grantedRuntimePermissions;
+        final List<String> whitelistedRestrictedPermissions;
         final VerificationInfo verificationInfo;
         final PackageParser.SigningDetails signingDetails;
         final int installReason;
@@ -14519,8 +14747,8 @@
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
                 VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
-                String[] grantedPermissions, PackageParser.SigningDetails signingDetails,
-                int installReason) {
+                String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
+                PackageParser.SigningDetails signingDetails, int installReason) {
             super(user);
             this.origin = origin;
             this.move = move;
@@ -14531,6 +14759,7 @@
             this.verificationInfo = verificationInfo;
             this.packageAbiOverride = packageAbiOverride;
             this.grantedRuntimePermissions = grantedPermissions;
+            this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
             this.signingDetails = signingDetails;
             this.installReason = installReason;
         }
@@ -14558,8 +14787,10 @@
             installerPackageName = activeInstallSession.getInstallerPackageName();
             volumeUuid = activeInstallSession.getSessionParams().volumeUuid;
             packageAbiOverride = activeInstallSession.getSessionParams().abiOverride;
-            grantedRuntimePermissions =
-                    activeInstallSession.getSessionParams().grantedRuntimePermissions;
+            grantedRuntimePermissions = activeInstallSession.getSessionParams()
+                    .grantedRuntimePermissions;
+            whitelistedRestrictedPermissions = activeInstallSession.getSessionParams()
+                    .whitelistedRestrictedPermissions;
             signingDetails = activeInstallSession.getSigningDetails();
         }
 
@@ -15016,6 +15247,7 @@
         final UserHandle user;
         final String abiOverride;
         final String[] installGrantPermissions;
+        final List<String> whitelistedRestrictedPermissions;
         /** If non-null, drop an async trace when the install completes */
         final String traceMethod;
         final int traceCookie;
@@ -15032,6 +15264,7 @@
                 int installFlags, String installerPackageName, String volumeUuid,
                 UserHandle user, String[] instructionSets,
                 String abiOverride, String[] installGrantPermissions,
+                List<String> whitelistedRestrictedPermissions,
                 String traceMethod, int traceCookie, SigningDetails signingDetails,
                 int installReason,
                 MultiPackageInstallParams multiPackageInstallParams) {
@@ -15045,6 +15278,7 @@
             this.instructionSets = instructionSets;
             this.abiOverride = abiOverride;
             this.installGrantPermissions = installGrantPermissions;
+            this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
             this.traceMethod = traceMethod;
             this.traceCookie = traceCookie;
             this.signingDetails = signingDetails;
@@ -15135,7 +15369,7 @@
             super(params.origin, params.move, params.observer, params.installFlags,
                     params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
-                    params.grantedRuntimePermissions,
+                    params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
                     params.traceMethod, params.traceCookie, params.signingDetails,
                     params.installReason, params.mParentInstallParams);
         }
@@ -15143,7 +15377,7 @@
         /** Existing install */
         FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
             super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
-                    null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
+                    null, null, null, null, 0, PackageParser.SigningDetails.UNKNOWN,
                     PackageManager.INSTALL_REASON_UNKNOWN, null /* parent */);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
@@ -15334,7 +15568,7 @@
             super(params.origin, params.move, params.observer, params.installFlags,
                     params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
-                    params.grantedRuntimePermissions,
+                    params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
                     params.traceMethod, params.traceCookie, params.signingDetails,
                     params.installReason, params.mParentInstallParams);
         }
@@ -20960,6 +21194,7 @@
                 }
             }
         }
+
         sUserManager.systemReady();
         // If we upgraded grant all default permissions before kicking off.
         for (int userId : grantPermissionsUserIds) {
@@ -22809,7 +23044,8 @@
         final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
                 installerPackageName, volumeUuid, null /*verificationInfo*/, user,
                 packageAbiOverride, null /*grantedPermissions*/,
-                PackageParser.SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN);
+                null /*whitelistedRestrictedPermissions*/, PackageParser.SigningDetails.UNKNOWN,
+                PackageManager.INSTALL_REASON_UNKNOWN);
         params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -23904,7 +24140,7 @@
         public void revokeRuntimePermission(String packageName, String permName, int userId,
                 boolean overridePolicy) {
             mPermissionManager.revokeRuntimePermission(
-                    permName, packageName, overridePolicy, getCallingUid(), userId,
+                    permName, packageName, overridePolicy, userId,
                     mPermissionCallback);
         }
 
@@ -24285,6 +24521,13 @@
                         null);
             }
         }
+
+        @Override
+        public boolean wereDefaultPermissionsGrantedSinceBoot(int userId) {
+            synchronized (mPackages) {
+                return mDefaultPermissionPolicy.wereDefaultPermissionsGrantedSinceBoot(userId);
+            }
+        }
     }
 
     @GuardedBy("mPackages")
@@ -24331,6 +24574,29 @@
     }
 
     @Override
+    public int getRuntimePermissionsVersion(@UserIdInt int userId) {
+        Preconditions.checkArgumentNonnegative(userId);
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+                "setRuntimePermissionVersion");
+        synchronized (mPackages) {
+            return mSettings.getDefaultRuntimePermissionsVersionLPr(userId);
+        }
+    }
+
+    @Override
+    public void setRuntimePermissionsVersion(int version, @UserIdInt int userId) {
+        Preconditions.checkArgumentNonnegative(version);
+        Preconditions.checkArgumentNonnegative(userId);
+        mContext.enforceCallingOrSelfPermission(
+                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+                "setRuntimePermissionVersion");
+        synchronized (mPackages) {
+            mSettings.setDefaultRuntimePermissionsVersionLPr(version, userId);
+        }
+    }
+
+    @Override
     public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
         enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps");
         synchronized (mPackages) {
@@ -24795,5 +25061,6 @@
     void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
         boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
     void notifyPackageAdded(String packageName, int uid);
+    void notifyPackageChanged(String packageName, int uid);
     void notifyPackageRemoved(String packageName, int uid);
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 2d1afa7..4e4a0e4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2347,6 +2347,9 @@
                     break;
                 case "-g":
                     sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
+                case "-w":
+                    sessionParams.installFlags |=
+                            PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;
                     break;
                 case "--dont-kill":
                     sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
@@ -2950,7 +2953,7 @@
         pw.println("       [--user USER_ID] INTENT");
         pw.println("    Prints all broadcast receivers that can handle the given INTENT.");
         pw.println("");
-        pw.println("  install [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
+        pw.println("  install [-lrtsfdgw] [-i PACKAGE] [--user USER_ID|all|current]");
         pw.println("       [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
         pw.println("       [--install-reason 0/1/2/3/4] [--originating-uri URI]");
         pw.println("       [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
@@ -2969,6 +2972,7 @@
         pw.println("      -d: allow version code downgrade (debuggable packages only)");
         pw.println("      -p: partial application install (new split on top of existing pkg)");
         pw.println("      -g: grant all runtime permissions");
+        pw.println("      -w: whitelist all restricted permissions");
         pw.println("      -S: size in bytes of package, required for stdin");
         pw.println("      --user: install under the given user.");
         pw.println("      --dont-kill: installing a new feature split, don't kill running app");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 4f81fd9..41a8a77 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1313,7 +1313,7 @@
 
     boolean areDefaultRuntimePermissionsGrantedLPr(int userId) {
         return mRuntimePermissionsPersistence
-                .areDefaultRuntimPermissionsGrantedLPr(userId);
+                .areDefaultRuntimePermissionsGrantedLPr(userId);
     }
 
     void onDefaultRuntimePermissionsGrantedLPr(int userId) {
@@ -1321,6 +1321,14 @@
                 .onDefaultRuntimePermissionsGrantedLPr(userId);
     }
 
+    int getDefaultRuntimePermissionsVersionLPr(int userId) {
+        return mRuntimePermissionsPersistence.getVersionLPr(userId);
+    }
+
+    void setDefaultRuntimePermissionsVersionLPr(int version, int userId) {
+        mRuntimePermissionsPersistence.setVersionLPr(version, userId);
+    }
+
     public VersionInfo findOrCreateVersion(String volumeUuid) {
         VersionInfo ver = mVersion.get(volumeUuid);
         if (ver == null) {
@@ -4727,7 +4735,13 @@
                         && !permissionNames.contains(perm)) {
                     continue;
                 }
-                pw.print(prefix); pw.print("    "); pw.println(perm);
+                pw.print(prefix); pw.print("    "); pw.print(perm);
+                final BasePermission bp = mPermissions.getPermission(perm);
+                if (bp != null && bp.isRestricted()) {
+                    pw.println(": restricted=true");
+                } else {
+                    pw.println();
+                }
             }
         }
 
@@ -5023,7 +5037,10 @@
             final int flag = 1 << Integer.numberOfTrailingZeros(flags);
             flags &= ~flag;
             flagsString.append(PackageManager.permissionFlagToString(flag));
-            flagsString.append(' ');
+            if (flags != 0) {
+                flagsString.append('|');
+            }
+
         }
         if (flagsString != null) {
             flagsString.append(']');
@@ -5085,6 +5102,8 @@
         private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
         private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;
 
+        private static final int INITIAL_VERSION = 0;
+
         private final Handler mHandler = new MyHandler();
 
         private final Object mPersistenceLock;
@@ -5098,6 +5117,10 @@
 
         @GuardedBy("mLock")
         // The mapping keys are user ids.
+        private final SparseIntArray mVersions = new SparseIntArray();
+
+        @GuardedBy("mLock")
+        // The mapping keys are user ids.
         private final SparseArray<String> mFingerprints = new SparseArray<>();
 
         @GuardedBy("mLock")
@@ -5109,7 +5132,18 @@
         }
 
         @GuardedBy("Settings.this.mLock")
-        public boolean areDefaultRuntimPermissionsGrantedLPr(int userId) {
+        int getVersionLPr(int userId) {
+            return mVersions.get(userId);
+        }
+
+        @GuardedBy("Settings.this.mLock")
+        void setVersionLPr(int version, int userId) {
+            mVersions.put(userId, version);
+            writePermissionsForUserAsyncLPr(userId);
+        }
+
+        @GuardedBy("Settings.this.mLock")
+        public boolean areDefaultRuntimePermissionsGrantedLPr(int userId) {
             return mDefaultPermissionsGranted.get(userId);
         }
 
@@ -5206,6 +5240,9 @@
 
                 serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);
 
+                final int version = mVersions.get(userId, INITIAL_VERSION);
+                serializer.attribute(null, ATTR_VERSION, Integer.toString(version));
+
                 String fingerprint = mFingerprints.get(userId);
                 if (fingerprint != null) {
                     serializer.attribute(null, ATTR_FINGERPRINT, fingerprint);
@@ -5263,6 +5300,7 @@
             }
 
             mDefaultPermissionsGranted.delete(userId);
+            mVersions.delete(userId);
             mFingerprints.remove(userId);
         }
 
@@ -5326,6 +5364,9 @@
 
                 switch (parser.getName()) {
                     case TAG_RUNTIME_PERMISSIONS: {
+                        int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION,
+                                INITIAL_VERSION);
+                        mVersions.put(userId, version);
                         String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
                         mFingerprints.put(userId, fingerprint);
                         final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint);
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 1957eb8..490c647 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -193,6 +193,22 @@
                 && (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0;
     }
 
+    public boolean isSoftRestricted() {
+        return perm != null && perm.info != null
+                && (perm.info.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
+    }
+
+    public boolean isHardRestricted() {
+        return perm != null && perm.info != null
+                && (perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
+    }
+
+    public boolean isRestricted() {
+        return perm != null && perm.info != null
+                && (perm.info.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
+                | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0;
+    }
+
     public boolean isSignature() {
         return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) ==
                 PermissionInfo.PROTECTION_SIGNATURE;
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 5c386b4..5eb2b09 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -62,8 +62,10 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.util.Xml;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
@@ -116,6 +118,7 @@
     private static final String ATTR_PACKAGE = "package";
     private static final String ATTR_NAME = "name";
     private static final String ATTR_FIXED = "fixed";
+    private static final String ATTR_WHITELISTED = "whitelisted";
 
     private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
 
@@ -213,12 +216,16 @@
     private final PackageManagerInternal mServiceInternal;
     private final PermissionManagerService mPermissionManager;
     private final DefaultPermissionGrantedCallback mPermissionGrantedCallback;
+
+    @GuardedBy("mLock")
+    private SparseIntArray mDefaultPermissionsGrantedUsers = new SparseIntArray();
+
     public interface DefaultPermissionGrantedCallback {
         /** Callback when permissions have been granted */
         void onDefaultRuntimePermissionsGranted(int userId);
     }
 
-    public DefaultPermissionGrantPolicy(Context context, Looper looper,
+    DefaultPermissionGrantPolicy(Context context, Looper looper,
             @Nullable DefaultPermissionGrantedCallback callback,
             @NonNull PermissionManagerService permissionManager) {
         mContext = context;
@@ -288,10 +295,19 @@
         }
     }
 
+    public boolean wereDefaultPermissionsGrantedSinceBoot(int userId) {
+        synchronized (mLock) {
+            return mDefaultPermissionsGrantedUsers.indexOfKey(userId) >= 0;
+        }
+    }
+
     public void grantDefaultPermissions(int userId) {
         grantPermissionsToSysComponentsAndPrivApps(userId);
         grantDefaultSystemHandlerPermissions(userId);
         grantDefaultPermissionExceptions(userId);
+        synchronized (mLock) {
+            mDefaultPermissionsGrantedUsers.put(userId, userId);
+        }
     }
 
     private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
@@ -306,7 +322,7 @@
             }
         }
         if (!permissions.isEmpty()) {
-            grantRuntimePermissions(pkg, permissions, true, userId);
+            grantRuntimePermissions(pkg, permissions, true /*systemFixed*/, userId);
         }
     }
 
@@ -334,8 +350,8 @@
     @SafeVarargs
     private final void grantIgnoringSystemPackage(String packageName, int userId,
             Set<String>... permissionGroups) {
-        grantPermissionsToPackage(
-                packageName, userId, true /* ignoreSystemPackage */, permissionGroups);
+        grantPermissionsToPackage(packageName, userId, true /* ignoreSystemPackage */,
+                true /*whitelistRestrictedPermissions*/, permissionGroups);
     }
 
     @SafeVarargs
@@ -359,24 +375,30 @@
             return;
         }
         grantPermissionsToPackage(getSystemPackageInfo(packageName),
-                userId, systemFixed, false /* ignoreSystemPackage */, permissionGroups);
+                userId, systemFixed, false /* ignoreSystemPackage */,
+                true /*whitelistRestrictedPermissions*/, permissionGroups);
     }
 
     @SafeVarargs
     private final void grantPermissionsToPackage(String packageName, int userId,
-            boolean ignoreSystemPackage, Set<String>... permissionGroups) {
+            boolean ignoreSystemPackage, boolean whitelistRestrictedPermissions,
+            Set<String>... permissionGroups) {
         grantPermissionsToPackage(getPackageInfo(packageName),
-                userId, false /* systemFixed */, ignoreSystemPackage, permissionGroups);
+                userId, false /* systemFixed */, ignoreSystemPackage,
+                whitelistRestrictedPermissions, permissionGroups);
     }
 
     @SafeVarargs
-    private final void grantPermissionsToPackage(PackageInfo packageName, int userId,
-            boolean systemFixed, boolean ignoreSystemPackage, Set<String>... permissionGroups) {
-        if (packageName == null) return;
-        if (doesPackageSupportRuntimePermissions(packageName)) {
+    private final void grantPermissionsToPackage(PackageInfo packageInfo, int userId,
+            boolean systemFixed, boolean ignoreSystemPackage,
+            boolean whitelistRestrictedPermissions, Set<String>... permissionGroups) {
+        if (packageInfo == null) {
+            return;
+        }
+        if (doesPackageSupportRuntimePermissions(packageInfo)) {
             for (Set<String> permissionGroup : permissionGroups) {
-                grantRuntimePermissions(packageName, permissionGroup, systemFixed,
-                        ignoreSystemPackage, userId);
+                grantRuntimePermissions(packageInfo, permissionGroup, systemFixed,
+                        ignoreSystemPackage, whitelistRestrictedPermissions, userId);
             }
         }
     }
@@ -585,8 +607,8 @@
                 browserPackage = null;
             }
         }
-        grantPermissionsToPackage(browserPackage, userId,
-                false /* ignoreSystemPackage */, LOCATION_PERMISSIONS);
+        grantPermissionsToPackage(browserPackage, userId, false /* ignoreSystemPackage */,
+                true /*whitelistRestrictedPermissions*/, LOCATION_PERMISSIONS);
 
         // Voice interaction
         if (voiceInteractPackageNames != null) {
@@ -809,7 +831,7 @@
         }
         Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
         grantPermissionsToPackage(packageName, userId, false /* ignoreSystemPackage */,
-                PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS);
+                true /*whitelistRestrictedPermissions*/, PHONE_PERMISSIONS, MICROPHONE_PERMISSIONS);
     }
 
     private void grantDefaultPermissionsToDefaultSystemSimCallManager(
@@ -854,7 +876,6 @@
             grantSystemFixedPermissionsToSystemPackage(packageName, userId,
                     PHONE_PERMISSIONS, LOCATION_PERMISSIONS);
         }
-
     }
 
     public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
@@ -980,7 +1001,8 @@
 
     private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissions,
             boolean systemFixed, int userId) {
-        grantRuntimePermissions(pkg, permissions, systemFixed, false, userId);
+        grantRuntimePermissions(pkg, permissions, systemFixed, false,
+                true /*whitelistRestrictedPermissions*/, userId);
     }
 
     private void revokeRuntimePermissions(String packageName, Set<String> permissions,
@@ -1065,11 +1087,10 @@
         }
     }
 
-    private void grantRuntimePermissions(PackageInfo pkg,
-            Set<String> permissionsWithoutSplits, boolean systemFixed, boolean ignoreSystemPackage,
-            int userId) {
-        UserHandle user = UserHandle.of(userId);
-
+    private void grantRuntimePermissions(PackageInfo pkg, Set<String> permissionsWithoutSplits,
+            boolean systemFixed, boolean ignoreSystemPackage,
+            boolean whitelistRestrictedPermissions, int userId) {
+            UserHandle user = UserHandle.of(userId);
         if (pkg == null) {
             return;
         }
@@ -1203,6 +1224,10 @@
                                 .grantRuntimePermission(pkg.packageName, permission, user);
                     }
 
+                    if (whitelistRestrictedPermissions && isPermissionRestricted(permission)) {
+                        newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+                    }
+
                     mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
                             newFlags, newFlags, user);
 
@@ -1354,7 +1379,11 @@
                     permissions.clear();
                 }
                 permissions.add(permissionGrant.name);
-                grantRuntimePermissions(pkg, permissions, permissionGrant.fixed, userId);
+
+
+                grantRuntimePermissions(pkg, permissions, permissionGrant.fixed,
+                        permissionGrant.whitelisted, true /*whitelistRestrictedPermissions*/,
+                        userId);
             }
         }
     }
@@ -1510,8 +1539,10 @@
                 }
 
                 final boolean fixed = XmlUtils.readBooleanAttribute(parser, ATTR_FIXED);
+                final boolean whitelisted = XmlUtils.readBooleanAttribute(parser, ATTR_WHITELISTED);
 
-                DefaultPermissionGrant exception = new DefaultPermissionGrant(name, fixed);
+                DefaultPermissionGrant exception = new DefaultPermissionGrant(
+                        name, fixed, whitelisted);
                 outPackageExceptions.add(exception);
             } else {
                 Log.e(TAG, "Unknown tag " + parser.getName() + "under <exception>");
@@ -1524,6 +1555,14 @@
                 && pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
     }
 
+    private boolean isPermissionRestricted(String name) {
+        try {
+            return mContext.getPackageManager().getPermissionInfo(name, 0).isRestricted();
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
     private boolean isPermissionDangerous(String name) {
         try {
             final PermissionInfo pi = mContext.getPackageManager().getPermissionInfo(name, 0);
@@ -1537,10 +1576,13 @@
     private static final class DefaultPermissionGrant {
         final String name;
         final boolean fixed;
+        final boolean whitelisted;
 
-        public DefaultPermissionGrant(String name, boolean fixed) {
+        public DefaultPermissionGrant(String name, boolean fixed,
+                boolean whitelisted) {
             this.name = name;
             this.fixed = fixed;
+            this.whitelisted = whitelisted;
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 86a3994..9336c55 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -24,6 +24,8 @@
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.permissionToOp;
 import static android.app.AppOpsManager.permissionToOpCode;
+import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -33,6 +35,10 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
 import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE;
+import static android.content.pm.PackageManager.RESTRICTED_PERMISSIONS_ENABLED;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.UserHandle.getAppId;
 import static android.os.UserHandle.getUid;
@@ -54,6 +60,7 @@
 import android.app.AppOpsManagerInternal;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.PermissionWhitelistFlags;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.Package;
@@ -62,6 +69,7 @@
 import android.metrics.LogMaker;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
@@ -75,6 +83,7 @@
 import android.permission.PermissionManager;
 import android.permission.PermissionManagerInternal;
 import android.provider.Settings;
+import android.permission.PermissionManagerInternal.OnRuntimePermissionStateChangedListener;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -89,6 +98,8 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.RoSystemProperties;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
@@ -216,6 +227,11 @@
     @GuardedBy("mLock")
     private final SparseBooleanArray mHasNoDelayedPermBackup = new SparseBooleanArray();
 
+    /** Listeners for permission state (granting and flags) changes */
+    @GuardedBy("mLock")
+    final private ArrayList<OnRuntimePermissionStateChangedListener>
+            mRuntimePermissionStateChangedListeners = new ArrayList<>();
+
     PermissionManagerService(Context context,
             @Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
             @NonNull Object externalLock) {
@@ -437,6 +453,42 @@
         }
     }
 
+    private void addOnRuntimePermissionStateChangedListener(@NonNull
+            OnRuntimePermissionStateChangedListener listener) {
+        synchronized (mLock) {
+            mRuntimePermissionStateChangedListeners.add(listener);
+        }
+    }
+
+    private void removeOnRuntimePermissionStateChangedListener(@NonNull
+            OnRuntimePermissionStateChangedListener listener) {
+        synchronized (mLock) {
+            mRuntimePermissionStateChangedListeners.remove(listener);
+        }
+    }
+
+    private void notifyRuntimePermissionStateChanged(@NonNull String packageName,
+            @UserIdInt int userId) {
+        FgThread.getHandler().sendMessage(PooledLambda.obtainMessage
+                (PermissionManagerService::doNotifyRuntimePermissionStateChanged,
+                        PermissionManagerService.this, packageName, userId));
+    }
+
+    private void doNotifyRuntimePermissionStateChanged(@NonNull String packageName,
+            @UserIdInt int userId) {
+        final ArrayList<OnRuntimePermissionStateChangedListener> listeners;
+        synchronized (mLock) {
+            if (mRuntimePermissionStateChangedListeners.isEmpty()) {
+                return;
+            }
+            listeners = new ArrayList<>(mRuntimePermissionStateChangedListeners);
+        }
+        final int listenerCount = listeners.size();
+        for (int i = 0; i < listenerCount; i++) {
+            listeners.get(i).onRuntimePermissionStateChanged(packageName, userId);
+        }
+    }
+
     /**
      * Returns {@code true} if the permission can be implied from another granted permission.
      * <p>Some permissions, such as ACCESS_FINE_LOCATION, imply other permissions,
@@ -611,7 +663,7 @@
 
                                 try {
                                     revokeRuntimePermission(permissionName, packageName, false,
-                                            Process.SYSTEM_UID, userId, permissionCallback);
+                                            userId, permissionCallback);
                                 } catch (IllegalArgumentException e) {
                                     Slog.e(TAG, "Could not revoke " + permissionName + " from "
                                             + packageName, e);
@@ -955,9 +1007,10 @@
                 }
 
                 if (grant != GRANT_DENIED) {
-                    if (!ps.isSystem() && ps.areInstallPermissionsFixed()) {
+                    if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
                         // If this is an existing, non-system package, then
-                        // we can't add any new permissions to it.
+                        // we can't add any new permissions to it. Runtime
+                        // permissions can be added any time - they ad dynamic.
                         if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
                             // Except...  if this is a permission that was added
                             // to the platform (note: need to only do this when
@@ -994,6 +1047,9 @@
                         } break;
 
                         case GRANT_RUNTIME: {
+                            boolean hardRestricted = bp.isHardRestricted();
+                            boolean softRestricted = bp.isSoftRestricted();
+
                             for (int userId : currentUserIds) {
                                 PermissionState permState = origPermissions
                                         .getRuntimePermissionState(perm, userId);
@@ -1001,7 +1057,36 @@
 
                                 boolean wasChanged = false;
 
+                                boolean restrictionExempt = !RESTRICTED_PERMISSIONS_ENABLED
+                                        || (origPermissions.getPermissionFlags(bp.name, userId)
+                                                & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+                                boolean restrictionApplied = (origPermissions.getPermissionFlags(
+                                        bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+
                                 if (appSupportsRuntimePermissions) {
+                                    // If hard restricted we don't allow holding it
+                                    if (hardRestricted) {
+                                        if (!restrictionExempt) {
+                                            if (permState != null && permState.isGranted()
+                                                    && permissionsState.revokeRuntimePermission(
+                                                    bp, userId) != PERMISSION_OPERATION_FAILURE) {
+                                                wasChanged = true;
+                                            }
+                                            if (!restrictionApplied) {
+                                                flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
+                                                wasChanged = true;
+                                            }
+                                        }
+                                    // If soft restricted we allow holding in a restricted form
+                                    } else if (softRestricted) {
+                                        // Regardless if granted set the restriction flag as it
+                                        // may affect app treatment based on this permission.
+                                        if (!restrictionExempt && !restrictionApplied) {
+                                            flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
+                                            wasChanged = true;
+                                        }
+                                    }
+
                                     // Remove review flag as it is not necessary anymore
                                     if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
                                         flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -1011,7 +1096,8 @@
                                     if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
                                         flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
                                         wasChanged = true;
-                                    } else {
+                                    // Hard restricted permissions cannot be held.
+                                    } else if (!hardRestricted || restrictionExempt) {
                                         if (permState != null && permState.isGranted()) {
                                             if (permissionsState.grantRuntimePermission(bp, userId)
                                                     == PERMISSION_OPERATION_FAILURE) {
@@ -1032,8 +1118,29 @@
                                         }
                                     }
 
-                                    if (permissionsState.grantRuntimePermission(bp, userId)
-                                            != PERMISSION_OPERATION_FAILURE) {
+                                    if (!permissionsState.hasRuntimePermission(bp.name, userId)
+                                            && permissionsState.grantRuntimePermission(bp, userId)
+                                                    != PERMISSION_OPERATION_FAILURE) {
+                                        wasChanged = true;
+                                    }
+
+                                    // If legacy app always grant the permission but if restricted
+                                    // and not exempt take a note a restriction should be applied.
+                                    if ((hardRestricted || softRestricted)
+                                            && !restrictionExempt && !restrictionApplied) {
+                                        flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
+                                        wasChanged = true;
+                                    }
+                                }
+
+                                // If unrestricted or restriction exempt, don't apply restriction.
+                                if (!(hardRestricted || softRestricted) || restrictionExempt)  {
+                                    if (restrictionApplied) {
+                                        flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
+                                        // Dropping restriction on a legacy app requires a review.
+                                        if (!appSupportsRuntimePermissions) {
+                                            flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+                                        }
                                         wasChanged = true;
                                     }
                                 }
@@ -1058,14 +1165,47 @@
                             if (origPermissions.revokeInstallPermission(bp)
                                     != PERMISSION_OPERATION_FAILURE) {
                                 origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
-                                        MASK_PERMISSION_FLAGS_ALL, 0);
+                                        (MASK_PERMISSION_FLAGS_ALL
+                                                & ~FLAG_PERMISSION_APPLY_RESTRICTION), 0);
                                 changedInstallPermission = true;
                             }
 
+                            boolean hardRestricted = bp.isHardRestricted();
+                            boolean softRestricted = bp.isSoftRestricted();
+
                             for (int userId : currentUserIds) {
                                 boolean wasChanged = false;
 
+                                boolean restrictionExempt = !RESTRICTED_PERMISSIONS_ENABLED
+                                        || (origPermissions.getPermissionFlags(bp.name, userId)
+                                                & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+                                boolean restrictionApplied = (origPermissions.getPermissionFlags(
+                                        bp.name, userId) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+
                                 if (appSupportsRuntimePermissions) {
+                                    // If hard restricted we don't allow holding it
+                                    if (hardRestricted) {
+                                        if (!restrictionExempt) {
+                                            if (permState != null && permState.isGranted()
+                                                    && permissionsState.revokeRuntimePermission(
+                                                    bp, userId) != PERMISSION_OPERATION_FAILURE) {
+                                                wasChanged = true;
+                                            }
+                                            if (!restrictionApplied) {
+                                                flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
+                                                wasChanged = true;
+                                            }
+                                        }
+                                    // If soft restricted we allow holding in a restricted form
+                                    } else if (softRestricted) {
+                                        // Regardless if granted set the  restriction flag as it
+                                        // may affect app treatment based on this permission.
+                                        if (!restrictionExempt && !restrictionApplied) {
+                                            flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
+                                            wasChanged = true;
+                                        }
+                                    }
+
                                     // Remove review flag as it is not necessary anymore
                                     if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
                                         flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -1075,18 +1215,40 @@
                                     if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
                                         flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
                                         wasChanged = true;
-                                    } else {
+                                    // Hard restricted permissions cannot be held.
+                                    } else if (!hardRestricted || restrictionExempt) {
                                         if (permissionsState.grantRuntimePermission(bp, userId) !=
                                                 PERMISSION_OPERATION_FAILURE) {
                                              wasChanged = true;
                                         }
                                     }
                                 } else {
-                                    if (permissionsState.grantRuntimePermission(bp, userId) !=
-                                            PERMISSION_OPERATION_FAILURE) {
+                                    if (!permissionsState.hasRuntimePermission(bp.name, userId)
+                                            && permissionsState.grantRuntimePermission(bp,
+                                                    userId) != PERMISSION_OPERATION_FAILURE) {
                                         flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
                                         wasChanged = true;
                                     }
+
+                                    // If legacy app always grant the permission but if restricted
+                                    // and not exempt take a note a restriction should be applied.
+                                    if ((hardRestricted || softRestricted)
+                                            && !restrictionExempt && !restrictionApplied) {
+                                        flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
+                                        wasChanged = true;
+                                    }
+                                }
+
+                                // If unrestricted or restriction exempt, don't apply restriction.
+                                if (!(hardRestricted || softRestricted) || restrictionExempt)  {
+                                    if (restrictionApplied) {
+                                        flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
+                                        // Dropping restriction on a legacy app requires a review.
+                                        if (!appSupportsRuntimePermissions) {
+                                            flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+                                        }
+                                        wasChanged = true;
+                                    }
                                 }
 
                                 if (wasChanged) {
@@ -1150,6 +1312,7 @@
             updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
                     permissionsState, pkg, updatedUserIds);
 
+            // TODO: Move to PermissionPolicyService
             setAppOpsLocked(permissionsState, pkg);
         }
 
@@ -1159,6 +1322,10 @@
         if (callback != null) {
             callback.onPermissionUpdated(updatedUserIds, runtimePermissionsRevoked);
         }
+
+        for (int userId : updatedUserIds) {
+            notifyRuntimePermissionStateChanged(pkg.packageName, userId);
+        }
     }
 
     /**
@@ -1882,6 +2049,54 @@
         }
     }
 
+    private @Nullable List<String> getWhitelistedRestrictedPermissions(
+            @NonNull PackageParser.Package pkg, @PermissionWhitelistFlags int whitelistFlags,
+            @UserIdInt int userId) {
+        final PackageSetting packageSetting = (PackageSetting) pkg.mExtras;
+        if (packageSetting == null) {
+            return null;
+        }
+
+        final PermissionsState permissionsState = packageSetting.getPermissionsState();
+
+        int queryFlags = 0;
+        if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
+            queryFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+        }
+        if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
+            queryFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+        }
+        if ((whitelistFlags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
+            queryFlags |=  PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+        }
+
+        ArrayList<String> whitelistedPermissions = null;
+
+        final int permissionCount = pkg.requestedPermissions.size();
+        for (int i = 0; i < permissionCount; i++) {
+            final String permissionName = pkg.requestedPermissions.get(i);
+            final int currentFlags = permissionsState.getPermissionFlags(permissionName, userId);
+            if ((currentFlags & queryFlags) != 0) {
+                if (whitelistedPermissions == null) {
+                    whitelistedPermissions = new ArrayList<>();
+                }
+                whitelistedPermissions.add(permissionName);
+            }
+        }
+
+        return whitelistedPermissions;
+    }
+
+    private void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
+            @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
+            @PackageManager.PermissionWhitelistFlags int whitelistFlags,
+            @NonNull PermissionCallback callback) {
+        for (int userId : userIds) {
+            setWhitelistedRestrictedPermissionsForUser(pkg, userId, permissions,
+                    callingUid, whitelistFlags, callback);
+        }
+    }
+
     private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
             String[] grantedPermissions, int callingUid, PermissionCallback callback) {
         PackageSetting ps = (PackageSetting) pkg.mExtras;
@@ -1979,12 +2194,21 @@
 
         final int flags = permissionsState.getPermissionFlags(permName, userId);
         if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
-            throw new SecurityException("Cannot grant system fixed permission "
+            Log.e(TAG, "Cannot grant system fixed permission "
                     + permName + " for package " + packageName);
+            return;
         }
         if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
-            throw new SecurityException("Cannot grant policy fixed permission "
+            Log.e(TAG, "Cannot grant policy fixed permission "
                     + permName + " for package " + packageName);
+            return;
+        }
+
+        if (RESTRICTED_PERMISSIONS_ENABLED && bp.isRestricted()
+                && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
+            Log.e(TAG, "Cannot grant restricted non-exempt permission "
+                    + permName + " for package " + packageName);
+            return;
         }
 
         if (bp.isDevelopment()) {
@@ -2031,6 +2255,10 @@
             callback.onPermissionGranted(uid, userId);
         }
 
+        if (bp.isRuntime()) {
+            notifyRuntimePermissionStateChanged(packageName, userId);
+        }
+
         // Only need to do this if user is initialized. Otherwise it's a new user
         // and there are no processes running as the user yet and there's no need
         // to make an expensive call to remount processes for the changed permissions.
@@ -2051,7 +2279,7 @@
     }
 
     private void revokeRuntimePermission(String permName, String packageName,
-            boolean overridePolicy, int callingUid, int userId, PermissionCallback callback) {
+            boolean overridePolicy, int userId, PermissionCallback callback) {
         if (!mUserManagerInt.exists(userId)) {
             Log.e(TAG, "No such user:" + userId);
             return;
@@ -2067,8 +2295,6 @@
                 false, // requirePermissionWhenSameUser
                 "revokeRuntimePermission");
 
-        final int appId;
-
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null || pkg.mExtras == null) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -2129,9 +2355,126 @@
         }
 
         if (callback != null) {
-            final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
             callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
         }
+
+        if (bp.isRuntime()) {
+            notifyRuntimePermissionStateChanged(packageName, userId);
+        }
+    }
+
+    private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg,
+            @UserIdInt int userId, @Nullable List<String> permissions, int callingUid,
+            @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) {
+        final PackageSetting ps = (PackageSetting) pkg.mExtras;
+        if (ps == null) {
+            return;
+        }
+
+        final PermissionsState permissionsState = ps.getPermissionsState();
+
+        ArraySet<String> oldGrantedRestrictedPermissions = null;
+        boolean updatePermissions = false;
+
+        final int permissionCount = pkg.requestedPermissions.size();
+        for (int i = 0; i < permissionCount; i++) {
+            final String permissionName = pkg.requestedPermissions.get(i);
+
+            final BasePermission bp = mSettings.getPermissionLocked(permissionName);
+            if (bp == null) {
+                Slog.w(TAG, "Cannot whitelist unknown permission: " + permissionName);
+                continue;
+            }
+
+            if (!bp.isRestricted()) {
+                continue;
+            }
+
+            if (permissionsState.hasPermission(permissionName, userId)) {
+                if (oldGrantedRestrictedPermissions == null) {
+                    oldGrantedRestrictedPermissions = new ArraySet<>();
+                }
+                oldGrantedRestrictedPermissions.add(permissionName);
+            }
+
+            final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId);
+
+            int newFlags = oldFlags;
+            int mask = 0;
+            int whitelistFlagsCopy = whitelistFlags;
+            while (whitelistFlagsCopy != 0) {
+                final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
+                whitelistFlagsCopy &= ~flag;
+                switch (flag) {
+                    case FLAG_PERMISSION_WHITELIST_SYSTEM: {
+                        mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+                        if (permissions != null && permissions.contains(permissionName)) {
+                            newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+                        } else {
+                            newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+                        }
+                    } break;
+                    case FLAG_PERMISSION_WHITELIST_UPGRADE: {
+                        mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+                        if (permissions != null && permissions.contains(permissionName)) {
+                            newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+                        } else {
+                            newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+                        }
+                    } break;
+                    case FLAG_PERMISSION_WHITELIST_INSTALLER: {
+                        mask |= PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+                        if (permissions != null && permissions.contains(permissionName)) {
+                            newFlags |= PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+                        } else {
+                            newFlags &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+                        }
+                    } break;
+                }
+            }
+
+            if (oldFlags == newFlags) {
+                continue;
+            }
+
+            updatePermissions = true;
+
+            // If the permission is policy fixed as granted but it is no longer
+            // on any of the whitelists we need to clear the policy fixed flag
+            // as whitelisting trumps policy i.e. policy cannot grant a non
+            // grantable permission.
+            if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+                final boolean isWhitelisted = (newFlags
+                        & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+                final boolean isGranted = permissionsState.hasPermission(permissionName, userId);
+                if (!isWhitelisted && isGranted) {
+                    mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+                    newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+                }
+            }
+
+            updatePermissionFlags(permissionName, pkg.packageName, mask, newFlags,
+                    callingUid, userId, false, null /*callback*/);
+        }
+
+        if (updatePermissions) {
+            // Update app permissions to take into account the new whitelist state.
+            updatePermissions(pkg.packageName, pkg, getVolumeUuidForPackage(pkg),
+                    0 /*flags*/, null /*allPackages*/, callback);
+
+            // If this resulted in losing a permission we need to kill the app.
+            if (oldGrantedRestrictedPermissions != null) {
+                final int oldGrantedCount = oldGrantedRestrictedPermissions.size();
+                for (int i = 0; i < oldGrantedCount; i++) {
+                    final String permission = oldGrantedRestrictedPermissions.valueAt(i);
+                    // Sometimes we create a new permission state instance during update.
+                    if (!ps.getPermissionsState().hasPermission(permission, userId)) {
+                        callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
+                        break;
+                    }
+                }
+            }
+        }
     }
 
     @GuardedBy("mLock")
@@ -2504,11 +2847,16 @@
             flagMask &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
             flagValues &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
             flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+            flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
         }
 
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
         if (pkg == null || pkg.mExtras == null) {
-            throw new IllegalArgumentException("Unknown package: " + packageName);
+            Log.e(TAG, "Unknown package: " + packageName);
+            return;
         }
         if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -2528,6 +2876,9 @@
                 permissionsState.getRuntimePermissionState(permName, userId) != null;
         final boolean permissionUpdated =
                 permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues);
+        if (permissionUpdated && bp.isRuntime()) {
+            notifyRuntimePermissionStateChanged(packageName, userId);
+        }
         if (permissionUpdated && callback != null) {
             // Install and runtime permissions are stored in different places,
             // so figure out what permission changed and persist the change.
@@ -2766,6 +3117,20 @@
                     pkg, userIds, grantedPermissions, callingUid, callback);
         }
         @Override
+        public List<String> getWhitelistedRestrictedPermissions(PackageParser.Package pkg,
+                @PackageManager.PermissionWhitelistFlags int whitelistFlags, int userId) {
+            return PermissionManagerService.this.getWhitelistedRestrictedPermissions(pkg,
+                    whitelistFlags, userId);
+        }
+        @Override
+        public void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg,
+                @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid,
+                @PackageManager.PermissionWhitelistFlags int whitelistFlags,
+                @NonNull PermissionCallback callback) {
+            PermissionManagerService.this.setWhitelistedRestrictedPermissions(
+                    pkg, userIds, permissions, callingUid, whitelistFlags, callback);
+        }
+        @Override
         public void grantRuntimePermissionsGrantedToDisabledPackage(PackageParser.Package pkg,
                 int callingUid, PermissionCallback callback) {
             PermissionManagerService.this.grantRuntimePermissionsGrantedToDisabledPackageLocked(
@@ -2773,10 +3138,9 @@
         }
         @Override
         public void revokeRuntimePermission(String permName, String packageName,
-                boolean overridePolicy, int callingUid, int userId,
-                PermissionCallback callback) {
+                boolean overridePolicy, int userId, PermissionCallback callback) {
             PermissionManagerService.this.revokeRuntimePermission(permName, packageName,
-                    overridePolicy, callingUid, userId, callback);
+                    overridePolicy, userId, callback);
         }
         @Override
         public void updatePermissions(String packageName, Package pkg, boolean replaceGrant,
@@ -2894,5 +3258,19 @@
                 @NonNull UserHandle user) {
             PermissionManagerService.this.restoreDelayedRuntimePermissions(packageName, user);
         }
+
+        @Override
+        public void addOnRuntimePermissionStateChangedListener(
+                OnRuntimePermissionStateChangedListener listener) {
+            PermissionManagerService.this.addOnRuntimePermissionStateChangedListener(
+                    listener);
+        }
+
+        @Override
+        public void removeOnRuntimePermissionStateChangedListener(
+                OnRuntimePermissionStateChangedListener listener) {
+            PermissionManagerService.this.removeOnRuntimePermissionStateChangedListener(
+                    listener);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 6c09fa0..34f922e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.PermissionInfoFlags;
 import android.content.pm.PackageParser;
 import android.content.pm.PermissionGroupInfo;
@@ -76,8 +77,16 @@
             @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
             @NonNull String[] grantedPermissions, int callingUid,
             @Nullable PermissionCallback callback);
+    public abstract @Nullable List<String> getWhitelistedRestrictedPermissions(
+            @NonNull PackageParser.Package pkg,
+            @PackageManager.PermissionWhitelistFlags int whitelistFlags, int userId);
+    public abstract void setWhitelistedRestrictedPermissions(
+            @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
+            @NonNull List<String> permissions, int callingUid,
+            @PackageManager.PermissionWhitelistFlags int whitelistFlags,
+            @Nullable PermissionCallback callback);
     public abstract void revokeRuntimePermission(@NonNull String permName,
-            @NonNull String packageName, boolean overridePolicy, int callingUid, int userId,
+            @NonNull String packageName, boolean overridePolicy, int userId,
             @Nullable PermissionCallback callback);
 
     public abstract void updatePermissions(@Nullable String packageName,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java
index c615ee5..505a0e2 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionsState.java
@@ -607,7 +607,7 @@
 
     private int grantPermission(BasePermission permission, int userId) {
         if (hasPermission(permission.getName(), userId)) {
-            return PERMISSION_OPERATION_FAILURE;
+            return PERMISSION_OPERATION_SUCCESS;
         }
 
         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
@@ -632,7 +632,7 @@
     private int revokePermission(BasePermission permission, int userId) {
         final String permName = permission.getName();
         if (!hasPermission(permName, userId)) {
-            return PERMISSION_OPERATION_FAILURE;
+            return PERMISSION_OPERATION_SUCCESS;
         }
 
         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
new file mode 100644
index 0000000..3011808
--- /dev/null
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManagerInternal.PackageListObserver;
+import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
+import android.permission.PermissionControllerManager;
+import android.permission.PermissionManagerInternal;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.util.function.QuadConsumer;
+import com.android.internal.util.function.TriConsumer;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * This is a permission policy that governs over all permission mechanism
+ * such as permissions, app ops, etc. For example, the policy ensures that
+ * permission state and app ops is synchronized for cases where there is a
+ * dependency between permission state (permissions or permission flags)
+ * and app ops - and vise versa.
+ */
+public final class PermissionPolicyService extends SystemService {
+
+    private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName();
+
+    public PermissionPolicyService(@NonNull Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                PackageManagerInternal.class);
+        packageManagerInternal.getPackageList(new PackageListObserver() {
+            @Override
+            public void onPackageAdded(String packageName, int uid) {
+                synchronizePackagePermissionsAndAppOpsForUser(getContext(), packageName,
+                        UserHandle.getUserId(uid));
+            }
+
+            @Override
+            public void onPackageChanged(String packageName, int uid) {
+                synchronizePackagePermissionsAndAppOpsForUser(getContext(), packageName,
+                        UserHandle.getUserId(uid));
+            }
+
+            @Override
+            public void onPackageRemoved(String packageName, int uid) {
+                /* do nothing */
+            }
+        });
+    }
+
+    @Override
+    public void onStartUser(@UserIdInt int userId) {
+        grantOrUpgradeDefaultRuntimePermissionsInNeeded(getContext(), userId);
+        synchronizePermissionsAndAppOpsForUser(getContext(), userId);
+        startWatchingRuntimePermissionChanges(getContext(), userId);
+    }
+
+    private static void grantOrUpgradeDefaultRuntimePermissionsInNeeded(@NonNull Context context,
+            @UserIdInt int userId) {
+        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                PackageManagerInternal.class);
+        if (packageManagerInternal.wereDefaultPermissionsGrantedSinceBoot(userId)) {
+            // Now call into the permission controller to apply policy around permissions
+            final CountDownLatch latch = new CountDownLatch(1);
+
+            // We need to create a local manager that does not schedule work on the main
+            // there as we are on the main thread and want to block until the work is
+            // completed or we time out.
+            final PermissionControllerManager permissionControllerManager =
+                    new PermissionControllerManager(context, FgThread.getHandler());
+            permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
+                    FgThread.getExecutor(),
+                    (Boolean success) -> {
+                        if (!success) {
+                            // We are in an undefined state now, let us crash and have
+                            // rescue party suggest a wipe to recover to a good one.
+                            final String message = "Error granting/upgrading runtime permissions";
+                            Slog.wtf(LOG_TAG, message);
+                            throw new IllegalStateException(message);
+                        }
+                        latch.countDown();
+                    }
+            );
+            try {
+                latch.await();
+            } catch (InterruptedException e) {
+                /* ignore */
+            }
+        }
+    }
+
+    private static void onRestrictedPermissionEnabledChange(@NonNull Context context) {
+        final PermissionManagerInternal permissionManagerInternal = LocalServices
+                .getService(PermissionManagerInternal.class);
+        final UserManagerInternal userManagerInternal = LocalServices.getService(
+                UserManagerInternal.class);
+        for (int userId : userManagerInternal.getUserIds()) {
+            synchronizePermissionsAndAppOpsForUser(context, userId);
+        }
+    }
+
+    private static void startWatchingRuntimePermissionChanges(@NonNull Context context,
+            int userId) {
+        final PermissionManagerInternal permissionManagerInternal = LocalServices.getService(
+                PermissionManagerInternal.class);
+        permissionManagerInternal.addOnRuntimePermissionStateChangedListener(
+                (packageName, changedUserId) -> {
+                    if (userId == changedUserId) {
+                        synchronizePackagePermissionsAndAppOpsForUser(context, packageName, userId);
+                    }
+                });
+    }
+
+    private static void synchronizePackagePermissionsAndAppOpsForUser(@NonNull Context context,
+            @NonNull String packageName, @UserIdInt int userId) {
+        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                PackageManagerInternal.class);
+        final PackageParser.Package pkg = packageManagerInternal
+                .getPackage(packageName);
+        if (pkg != null) {
+            PermissionToOpSynchronizer.syncPackage(context, pkg, userId);
+        }
+    }
+
+    private static void synchronizePermissionsAndAppOpsForUser(@NonNull Context context,
+            @UserIdInt int userId) {
+        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+                PackageManagerInternal.class);
+        final PermissionToOpSynchronizer synchronizer = new PermissionToOpSynchronizer(context);
+        packageManagerInternal.forEachPackage((pkg) ->
+                synchronizer.addPackage(context, pkg, userId));
+        synchronizer.syncPackages();
+    }
+
+    private static class PermissionToOpSynchronizer {
+        private final @NonNull Context mContext;
+
+        private final @NonNull SparseArray<String> mPackageNames = new SparseArray<>();
+        private final @NonNull SparseIntArray mAllowedUidOps = new SparseIntArray();
+        private final @NonNull SparseIntArray mDefaultUidOps = new SparseIntArray();
+
+        PermissionToOpSynchronizer(@NonNull Context context) {
+            mContext = context;
+        }
+
+        private void addPackage(@NonNull Context context,
+                @NonNull PackageParser.Package pkg, @UserIdInt int userId) {
+            addPackage(context, pkg, userId, this::addAllowedEntry, this::addIgnoredEntry);
+        }
+
+        void syncPackages() {
+            final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+            final int allowedCount = mAllowedUidOps.size();
+            for (int i = 0; i < allowedCount; i++) {
+                final int opCode = mAllowedUidOps.keyAt(i);
+                final int uid = mAllowedUidOps.valueAt(i);
+                final String packageName = mPackageNames.valueAt(i);
+                setUidModeAllowed(appOpsManager, opCode, uid, packageName);
+            }
+            final int defaultCount = mDefaultUidOps.size();
+            for (int i = 0; i < defaultCount; i++) {
+                final int opCode = mDefaultUidOps.keyAt(i);
+                final int uid = mDefaultUidOps.valueAt(i);
+                setUidModeDefault(appOpsManager, opCode, uid);
+            }
+        }
+
+        static void syncPackage(@NonNull Context context, @NonNull PackageParser.Package pkg,
+                @UserIdInt int userId) {
+            addPackage(context, pkg, userId, PermissionToOpSynchronizer::setUidModeAllowed,
+                    PermissionToOpSynchronizer::setUidModeDefault);
+        }
+
+        private static void addPackage(@NonNull Context context,
+                @NonNull PackageParser.Package pkg, @UserIdInt int userId,
+                @NonNull QuadConsumer<AppOpsManager, Integer, Integer, String> allowedConsumer,
+                @NonNull TriConsumer<AppOpsManager, Integer, Integer> defaultConsumer) {
+            final PackageManager packageManager = context.getPackageManager();
+            final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
+
+            final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid));
+            final UserHandle userHandle = UserHandle.of(userId);
+
+            final int permissionCount = pkg.requestedPermissions.size();
+            for (int i = 0; i < permissionCount; i++) {
+                final String permission = pkg.requestedPermissions.get(i);
+
+                final int opCode = AppOpsManager.permissionToOpCode(permission);
+                if (opCode == AppOpsManager.OP_NONE) {
+                    continue;
+                }
+
+                final PermissionInfo permissionInfo;
+                try {
+                    permissionInfo = packageManager.getPermissionInfo(permission, 0);
+                } catch (PackageManager.NameNotFoundException e) {
+                    continue;
+                }
+
+                if (!permissionInfo.isRestricted()) {
+                    continue;
+                }
+
+                final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED
+                        && (packageManager.getPermissionFlags(permission, pkg.packageName,
+                                userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+
+                if (permissionInfo.isHardRestricted()) {
+                    if (applyRestriction) {
+                        defaultConsumer.accept(appOpsManager, opCode, uid);
+                    } else {
+                        allowedConsumer.accept(appOpsManager, opCode, uid, pkg.packageName);
+                    }
+                } else if (permissionInfo.isSoftRestricted()) {
+                    //TODO: Implement soft restrictions like storage here.
+                }
+            }
+        }
+
+        @SuppressWarnings("unused")
+        private void addAllowedEntry(@NonNull AppOpsManager appOpsManager, int opCode,
+                int uid, @NonNull String packageName) {
+            mPackageNames.put(opCode, packageName);
+            mAllowedUidOps.put(opCode, uid);
+        }
+
+        @SuppressWarnings("unused")
+        private void addIgnoredEntry(@NonNull AppOpsManager appOpsManager,
+                int opCode, int uid) {
+            mDefaultUidOps.put(opCode, uid);
+        }
+
+        private static void setUidModeAllowed(@NonNull AppOpsManager appOpsManager,
+                int opCode, int uid, @NonNull String packageName) {
+            final int currentMode = appOpsManager.unsafeCheckOpRaw(AppOpsManager
+                    .opToPublicName(opCode), uid, packageName);
+            if (currentMode == AppOpsManager.MODE_DEFAULT) {
+                appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
+            }
+        }
+
+        private static void setUidModeDefault(@NonNull AppOpsManager appOpsManager,
+                int opCode, int uid) {
+            appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0e0fc12..b3f1c55 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4830,7 +4830,7 @@
                             return true;
                         }
                     };
-                    if (mContext.getPackageManager().isUpgrade()) {
+                    if (mContext.getPackageManager().isDeviceUpgrading()) {
                         mBootMsgDialog.setTitle(R.string.android_upgrading_title);
                     } else {
                         mBootMsgDialog.setTitle(R.string.android_start_title);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 6d9e097..325ba07 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -38,9 +38,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
-import android.database.ContentObserver;
 import android.database.CursorWindow;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
@@ -52,7 +50,6 @@
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
-import android.provider.Settings;
 import android.service.sms.FinancialSmsService;
 import android.telephony.IFinancialSmsCallback;
 import android.text.TextUtils;
@@ -205,23 +202,6 @@
                         () -> performInitialGrantsIfNecessaryAsync(userId));
             }
         }, UserHandle.ALL, intentFilter, null, null);
-
-        getContext().getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED), false,
-                new ContentObserver(getContext().getMainThreadHandler()) {
-                    @Override
-                    public void onChange(boolean selfChange, Uri uri, int userId) {
-                        boolean killSwitchEnabled = Settings.Global.getInt(
-                                getContext().getContentResolver(),
-                                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0) == 1;
-                        for (int user : mUserManagerInternal.getUserIds()) {
-                            if (mUserManagerInternal.isUserRunning(user)) {
-                                getOrCreateControllerService(user)
-                                        .onSmsKillSwitchToggled(killSwitchEnabled);
-                            }
-                        }
-                    }
-                }, UserHandle.USER_ALL);
     }
 
     @Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9d09c4c..4824d7b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -32,6 +32,7 @@
 import android.content.Intent;
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.res.Configuration;
 import android.content.res.Resources.Theme;
 import android.database.sqlite.SQLiteCompatibilityWalFlags;
@@ -124,6 +125,7 @@
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.ShortcutService;
 import com.android.server.pm.UserManagerService;
+import com.android.server.policy.PermissionPolicyService;
 import com.android.server.policy.PhoneWindowManager;
 import com.android.server.policy.role.LegacyRoleResolutionPolicy;
 import com.android.server.power.PowerManagerService;
@@ -541,7 +543,7 @@
     }
 
     private boolean isFirstBootOrUpgrade() {
-        return mPackageManagerService.isFirstBoot() || mPackageManagerService.isUpgrade();
+        return mPackageManagerService.isFirstBoot() || mPackageManagerService.isDeviceUpgrading();
     }
 
     private void reportWtf(String msg, Throwable e) {
@@ -1984,6 +1986,11 @@
         mSystemServiceManager.startBootPhase(SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
         traceEnd();
 
+        // Permission policy service
+        traceBeginAndSlog("StartPermissionPolicyService");
+        mSystemServiceManager.startService(PermissionPolicyService.class);
+        traceEnd();
+
         // These are needed to propagate to the runnable below.
         final NetworkManagementService networkManagementF = networkManagement;
         final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 0792414..97a6e66 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -225,6 +225,24 @@
     }
 
     @Override
+    public List<String> getWhitelistedRestrictedPermissions(String packageName, int flags,
+            int userId) throws RemoteException {
+        return null;
+    }
+
+    @Override
+    public boolean addWhitelistedRestrictedPermission(String packageName, String permission,
+            int whitelistFlags, int userId) throws RemoteException {
+        return false;
+    }
+
+    @Override
+    public boolean removeWhitelistedRestrictedPermission(String packageName, String permission,
+            int whitelistFlags, int userId) throws RemoteException {
+        return false;
+    }
+
+    @Override
     public boolean shouldShowRequestPermissionRationale(String permissionName, String packageName,
         int userId) throws RemoteException {
         return false;
@@ -858,7 +876,7 @@
     }
 
     @Override
-    public boolean isUpgrade() throws RemoteException {
+    public boolean isDeviceUpgrading() throws RemoteException {
         return false;
     }
 
@@ -1183,6 +1201,16 @@
     }
 
     @Override
+    public int getRuntimePermissionsVersion(int userId) throws RemoteException {
+        return 0;
+    }
+
+    @Override
+    public void setRuntimePermissionsVersion(int version, int userId) throws RemoteException {
+
+    }
+
+    @Override
     public IBinder asBinder() {
         return null;
     }
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
index 7172752..5fb9c43 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
@@ -951,6 +951,11 @@
     }
 
     @Override
+    public boolean isDeviceUpgrading() {
+        return false;
+    }
+
+    @Override
     public PackageInstaller getPackageInstaller() {
         return null;
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 4cfd098..95ec3d9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -60,6 +60,11 @@
             }
 
             @Override
+            public void notifyPackageChanged(String packageName, int uid) {
+
+            }
+
+            @Override
             public void notifyPackageRemoved(String packageName, int uid) {
             }
         }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index c9b038c..80fb58d 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -54,6 +54,12 @@
     private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
             ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
 
+    /**
+     * Whether to disable the new device identifier access restrictions.
+     */
+    private static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED =
+            "device_identifier_access_restrictions_disabled";
+
     // Contains a mapping of packages that did not meet the new requirements to access device
     // identifiers and the methods they were attempting to invoke; used to prevent duplicate
     // reporting of packages / methods.
@@ -446,8 +452,8 @@
      * Returns true if the new device identifier access restrictions are disabled.
      */
     private static boolean isIdentifierCheckDisabled() {
-        return Boolean.parseBoolean(DeviceConfig.getProperty(DeviceConfig.Privacy.NAMESPACE,
-                DeviceConfig.Privacy.PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED));
+        return DeviceConfig.getInt(DeviceConfig.NAMESPACE_PRIVACY,
+                PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED, 0) == 1;
     }
 
     /**
diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
index 226c0b8..14b847f 100644
--- a/test-mock/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
@@ -56,6 +56,7 @@
 import android.os.storage.VolumeInfo;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * A mock {@link android.content.pm.PackageManager} class.  All methods are non-functional and throw
@@ -296,6 +297,27 @@
 
     /** @hide */
     @Override
+    public @NonNull Set<String> getWhitelistedRestrictedPermissions(
+            @NonNull String packageName, @PermissionWhitelistFlags int whitelistFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
+            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
+            @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
     public boolean shouldShowRequestPermissionRationale(String permission) {
         throw new UnsupportedOperationException();
     }
@@ -1107,6 +1129,14 @@
      * @hide
      */
     @Override
+    public boolean isDeviceUpgrading() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
             int flags) {
         throw new UnsupportedOperationException();