Merge "Add g/setScore and g/setEntityTypes to TextClassifierEvent"
diff --git a/api/current.txt b/api/current.txt
index 26946e7..c0a9c48 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6579,7 +6579,6 @@
   }
 
   public class DevicePolicyManager {
-    method public void addCrossProfileCalendarPackage(@NonNull android.content.ComponentName, @NonNull String);
     method public void addCrossProfileIntentFilter(@NonNull android.content.ComponentName, android.content.IntentFilter, int);
     method public boolean addCrossProfileWidgetProvider(@NonNull android.content.ComponentName, String);
     method public int addOverrideApn(@NonNull android.content.ComponentName, @NonNull android.telephony.data.ApnSetting);
@@ -6601,6 +6600,7 @@
     method @Nullable public String[] getAccountTypesWithManagementDisabled();
     method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins();
     method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
+    method public java.util.List<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
     method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
     method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
@@ -6609,7 +6609,7 @@
     method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
     method public boolean getCameraDisabled(@Nullable android.content.ComponentName);
     method @Deprecated @Nullable public String getCertInstallerPackage(@NonNull android.content.ComponentName) throws java.lang.SecurityException;
-    method @NonNull public java.util.Set<java.lang.String> getCrossProfileCalendarPackages(@NonNull android.content.ComponentName);
+    method @Nullable public java.util.Set<java.lang.String> getCrossProfileCalendarPackages(@NonNull android.content.ComponentName);
     method public boolean getCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName);
     method public boolean getCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName);
     method @NonNull public java.util.List<java.lang.String> getCrossProfileWidgetProviders(@NonNull android.content.ComponentName);
@@ -6675,6 +6675,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(@NonNull android.content.ComponentName);
     method public boolean isAffiliatedUser();
+    method public boolean isAlwaysOnVpnLockdownEnabled(@NonNull android.content.ComponentName);
     method public boolean isApplicationHidden(@NonNull android.content.ComponentName, String);
     method public boolean isBackupServiceEnabled(@NonNull android.content.ComponentName);
     method @Deprecated public boolean isCallerApplicationRestrictionsManagingPackage();
@@ -6699,7 +6700,6 @@
     method public int logoutUser(@NonNull android.content.ComponentName);
     method public void reboot(@NonNull android.content.ComponentName);
     method public void removeActiveAdmin(@NonNull android.content.ComponentName);
-    method public boolean removeCrossProfileCalendarPackage(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean removeCrossProfileWidgetProvider(@NonNull android.content.ComponentName, String);
     method public boolean removeKeyPair(@Nullable android.content.ComponentName, @NonNull String);
     method public boolean removeOverrideApn(@NonNull android.content.ComponentName, int);
@@ -6713,6 +6713,7 @@
     method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
     method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
     method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
+    method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.List<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
     method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
     method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
     method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -6721,6 +6722,7 @@
     method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
     method @Deprecated public void setCertInstallerPackage(@NonNull android.content.ComponentName, @Nullable String) throws java.lang.SecurityException;
+    method public void setCrossProfileCalendarPackages(@NonNull android.content.ComponentName, @Nullable java.util.Set<java.lang.String>);
     method public void setCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
@@ -6788,7 +6790,7 @@
     method public void uninstallCaCert(@Nullable android.content.ComponentName, byte[]);
     method public boolean updateOverrideApn(@NonNull android.content.ComponentName, int, @NonNull android.telephony.data.ApnSetting);
     method public void wipeData(int);
-    method public void wipeData(int, CharSequence);
+    method public void wipeData(int, @NonNull CharSequence);
     field public static final String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final String ACTION_ADMIN_POLICY_COMPLIANCE = "android.app.action.ADMIN_POLICY_COMPLIANCE";
     field public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";
@@ -6932,6 +6934,7 @@
     field public static final int WIPE_EUICC = 4; // 0x4
     field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
+    field public static final int WIPE_SILENTLY = 8; // 0x8
   }
 
   public abstract static class DevicePolicyManager.InstallUpdateCallback {
@@ -10222,6 +10225,7 @@
     field public static final String ACTION_MEDIA_REMOVED = "android.intent.action.MEDIA_REMOVED";
     field public static final String ACTION_MEDIA_SCANNER_FINISHED = "android.intent.action.MEDIA_SCANNER_FINISHED";
     field public static final String ACTION_MEDIA_SCANNER_SCAN_FILE = "android.intent.action.MEDIA_SCANNER_SCAN_FILE";
+    field public static final String ACTION_MEDIA_SCANNER_SCAN_VOLUME = "android.intent.action.MEDIA_SCANNER_SCAN_VOLUME";
     field public static final String ACTION_MEDIA_SCANNER_STARTED = "android.intent.action.MEDIA_SCANNER_STARTED";
     field public static final String ACTION_MEDIA_SHARED = "android.intent.action.MEDIA_SHARED";
     field public static final String ACTION_MEDIA_UNMOUNTABLE = "android.intent.action.MEDIA_UNMOUNTABLE";
@@ -29230,6 +29234,7 @@
     method public android.os.ParcelFileDescriptor establish();
     method public android.net.VpnService.Builder setBlocking(boolean);
     method public android.net.VpnService.Builder setConfigureIntent(android.app.PendingIntent);
+    method public android.net.VpnService.Builder setHttpProxy(android.net.ProxyInfo);
     method public android.net.VpnService.Builder setMtu(int);
     method public android.net.VpnService.Builder setSession(String);
     method public android.net.VpnService.Builder setUnderlyingNetworks(android.net.Network[]);
@@ -35296,11 +35301,16 @@
 
   public abstract class VibrationEffect implements android.os.Parcelable {
     method public static android.os.VibrationEffect createOneShot(long, int);
+    method public static android.os.VibrationEffect createPrebaked(int);
     method public static android.os.VibrationEffect createWaveform(long[], int);
     method public static android.os.VibrationEffect createWaveform(long[], int[], int);
     method public int describeContents();
     field public static final android.os.Parcelable.Creator<android.os.VibrationEffect> CREATOR;
     field public static final int DEFAULT_AMPLITUDE = -1; // 0xffffffff
+    field public static final int EFFECT_CLICK = 0; // 0x0
+    field public static final int EFFECT_DOUBLE_CLICK = 1; // 0x1
+    field public static final int EFFECT_HEAVY_CLICK = 5; // 0x5
+    field public static final int EFFECT_TICK = 2; // 0x2
   }
 
   public abstract class Vibrator {
@@ -44028,7 +44038,9 @@
     field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
     field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
     field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+    field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
     field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
+    field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
     field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
     field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
     field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
@@ -53483,6 +53495,7 @@
 
   public final class TextClassificationManager {
     method @NonNull public android.view.textclassifier.TextClassifier createTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext);
+    method @NonNull public android.view.textclassifier.TextClassifier getLocalTextClassifier();
     method @NonNull public android.view.textclassifier.TextClassifier getTextClassifier();
     method public void setTextClassificationSessionFactory(@Nullable android.view.textclassifier.TextClassificationSessionFactory);
     method public void setTextClassifier(@Nullable android.view.textclassifier.TextClassifier);
diff --git a/api/system-current.txt b/api/system-current.txt
index 315a941..fe2b4d9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1053,6 +1053,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
+    field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
   }
 
   public interface RoleManagerCallback {
@@ -1158,14 +1159,18 @@
   public final class BluetoothDevice implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean getSilenceMode();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
     field public static final int ACCESS_ALLOWED = 1; // 0x1
     field public static final int ACCESS_REJECTED = 2; // 0x2
     field public static final int ACCESS_UNKNOWN = 0; // 0x0
+    field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
+    field public static final String EXTRA_SILENCE_ENABLED = "android.bluetooth.device.extra.SILENCE_ENABLED";
     field public static final int METADATA_COMPANION_APP = 4; // 0x4
     field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
     field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
@@ -1807,9 +1812,16 @@
   }
 
   public final class ColorDisplayManager {
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public int getNightDisplayAutoMode();
     method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public int getTransformCapabilities();
     method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setAppSaturationLevel(@NonNull String, @IntRange(from=0, to=100) int);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayAutoMode(int);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayCustomEndTime(@NonNull java.time.LocalTime);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayCustomStartTime(@NonNull java.time.LocalTime);
     method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setSaturationLevel(@IntRange(from=0, to=100) int);
+    field public static final int AUTO_MODE_CUSTOM_TIME = 1; // 0x1
+    field public static final int AUTO_MODE_DISABLED = 0; // 0x0
+    field public static final int AUTO_MODE_TWILIGHT = 2; // 0x2
     field public static final int CAPABILITY_HARDWARE_ACCELERATION_GLOBAL = 2; // 0x2
     field public static final int CAPABILITY_HARDWARE_ACCELERATION_PER_APP = 4; // 0x4
     field public static final int CAPABILITY_NONE = 0; // 0x0
@@ -4665,6 +4677,7 @@
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(android.net.wifi.hotspot2.OsuProvider, android.net.wifi.hotspot2.ProvisioningCallback, @Nullable android.os.Handler);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
     method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
+    method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void updateWifiUsabilityScore(int, int, int);
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
     field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
@@ -5626,6 +5639,18 @@
     field public static final String NAMESPACE_NOTIFICATION_ASSISTANT = "notification_assistant";
   }
 
+  public static interface DeviceConfig.ActivityManager {
+    field public static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
+    field public static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
+    field public static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
+    field public static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
+    field public static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
+    field public static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
+    field public static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
+    field public static final String KEY_USE_COMPACTION = "use_compaction";
+    field public static final String NAMESPACE = "activity_manager";
+  }
+
   public static interface DeviceConfig.FsiBoot {
     field public static final String NAMESPACE = "fsi_boot";
     field public static final String OOB_ENABLED = "oob_enabled";
@@ -8663,12 +8688,20 @@
 
   public class ProvisioningManager {
     method public static android.telephony.ims.ProvisioningManager createForSubscriptionId(android.content.Context, int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getProvisioningStringValue(int);
+    method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getProvisioningStringValue(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setProvisioningIntValue(int, int);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setProvisioningStringValue(int, String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, String);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+    field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
+    field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
+    field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
+    field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1
+    field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC";
+    field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY";
   }
 
   public static class ProvisioningManager.Callback {
diff --git a/api/test-current.txt b/api/test-current.txt
index 1b5bb10..8e638fd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,10 @@
     field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
   }
 
+  public static final class R.array {
+    field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
+  }
+
 }
 
 package android.animation {
@@ -332,6 +336,7 @@
     method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
     method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
   }
 
   public interface RoleManagerCallback {
@@ -1299,15 +1304,11 @@
     method @Nullable public static android.os.VibrationEffect get(android.net.Uri, android.content.Context);
     method public abstract long getDuration();
     method protected static int scale(int, float, int);
-    field public static final int EFFECT_CLICK = 0; // 0x0
-    field public static final int EFFECT_DOUBLE_CLICK = 1; // 0x1
-    field public static final int EFFECT_HEAVY_CLICK = 5; // 0x5
     field public static final int EFFECT_POP = 4; // 0x4
     field public static final int EFFECT_STRENGTH_LIGHT = 0; // 0x0
     field public static final int EFFECT_STRENGTH_MEDIUM = 1; // 0x1
     field public static final int EFFECT_STRENGTH_STRONG = 2; // 0x2
     field public static final int EFFECT_THUD = 3; // 0x3
-    field public static final int EFFECT_TICK = 2; // 0x2
     field public static final int[] RINGTONES;
   }
 
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 3defdc5..062ba65 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -102,7 +102,17 @@
         String op = nextArg();
         Slog.v(TAG, "Running " + op + " for user:" + userId);
 
-        if (!isBmgrActive(userId)) {
+        if (mBmgr == null) {
+            System.err.println(BMGR_NOT_RUNNING_ERR);
+            return;
+        }
+
+        if ("activate".equals(op)) {
+            doActivateService(userId);
+            return;
+        }
+
+        if (!isBackupActive(userId)) {
             return;
         }
 
@@ -175,12 +185,7 @@
         showUsage();
     }
 
-    boolean isBmgrActive(@UserIdInt int userId) {
-        if (mBmgr == null) {
-            System.err.println(BMGR_NOT_RUNNING_ERR);
-            return false;
-        }
-
+    boolean isBackupActive(@UserIdInt int userId) {
         try {
             if (!mBmgr.isBackupServiceActive(userId)) {
                 System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -845,6 +850,27 @@
         }
     }
 
+    private void doActivateService(int userId) {
+        String arg = nextArg();
+        if (arg == null) {
+            showUsage();
+            return;
+        }
+
+        try {
+            boolean activate = Boolean.parseBoolean(arg);
+            mBmgr.setBackupServiceActive(userId, activate);
+            System.out.println(
+                    "Backup service now "
+                            + (activate ? "activated" : "deactivated")
+                            + " for user "
+                            + userId);
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(BMGR_NOT_RUNNING_ERR);
+        }
+    }
+
     private String nextArg() {
         if (mNextArg >= mArgs.length) {
             return null;
@@ -880,6 +906,7 @@
         System.err.println("       bmgr backupnow [--monitor|--monitor-verbose] --all|PACKAGE...");
         System.err.println("       bmgr cancel backups");
         System.err.println("       bmgr init TRANSPORT...");
+        System.err.println("       bmgr activate BOOL");
         System.err.println("");
         System.err.println("The '--user' option specifies the user on which the operation is run.");
         System.err.println("It must be the first argument before the operation.");
@@ -946,6 +973,11 @@
         System.err.println("");
         System.err.println("The 'init' command initializes the given transports, wiping all data");
         System.err.println("from their backing data stores.");
+        System.err.println("");
+        System.err.println("The 'activate' command activates or deactivates the backup service.");
+        System.err.println("If the argument is 'true' it will be activated, otherwise it will be");
+        System.err.println("deactivated. When deactivated, the service will not be running and no");
+        System.err.println("operations can be performed until activation.");
     }
 
     private static class BackupMonitor extends IBackupManagerMonitor.Stub {
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index c455ac0..0c581f3 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -39,6 +39,7 @@
 using android::idmap2::PolicyFlags;
 using android::idmap2::Result;
 using android::idmap2::utils::kIdmapFilePermissionMask;
+using android::idmap2::utils::UidHasWriteAccessToPath;
 
 bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
   std::string target_apk_path;
@@ -66,6 +67,13 @@
     return false;
   }
 
+  const uid_t uid = getuid();
+  if (!UidHasWriteAccessToPath(uid, idmap_path)) {
+    out_error << "error: uid " << uid << " does not have write access to " << idmap_path
+              << std::endl;
+    return false;
+  }
+
   PolicyBitmask fulfilled_policies = 0;
   if (auto result = PoliciesToBitmask(policies, out_error)) {
     fulfilled_policies |= *result;
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index a3c7527..f30ce9b 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -27,6 +27,7 @@
 
 #include "android-base/macros.h"
 #include "android-base/stringprintf.h"
+#include "binder/IPCThreadState.h"
 #include "utils/String8.h"
 #include "utils/Trace.h"
 
@@ -38,18 +39,19 @@
 
 #include "idmap2d/Idmap2Service.h"
 
+using android::IPCThreadState;
 using android::binder::Status;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::Idmap;
 using android::idmap2::IdmapHeader;
 using android::idmap2::PolicyBitmask;
 using android::idmap2::Result;
+using android::idmap2::utils::kIdmapCacheDir;
 using android::idmap2::utils::kIdmapFilePermissionMask;
+using android::idmap2::utils::UidHasWriteAccessToPath;
 
 namespace {
 
-constexpr const char* kIdmapCacheDir = "/data/resource-cache";
-
 Status ok() {
   return Status::ok();
 }
@@ -77,7 +79,13 @@
 Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
                                   int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
   assert(_aidl_return);
+  const uid_t uid = IPCThreadState::self()->getCallingUid();
   const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+  if (!UidHasWriteAccessToPath(uid, idmap_path)) {
+    *_aidl_return = false;
+    return error(base::StringPrintf("failed to unlink %s: calling uid %d lacks write access",
+                                    idmap_path.c_str(), uid));
+  }
   if (unlink(idmap_path.c_str()) != 0) {
     *_aidl_return = false;
     return error("failed to unlink " + idmap_path + ": " + strerror(errno));
@@ -118,6 +126,13 @@
 
   const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
 
+  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
+  const uid_t uid = IPCThreadState::self()->getCallingUid();
+  if (!UidHasWriteAccessToPath(uid, idmap_path)) {
+    return error(base::StringPrintf("will not write to %s: calling uid %d lacks write accesss",
+                                    idmap_path.c_str(), uid));
+  }
+
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
     return error("failed to load apk " + target_apk_path);
@@ -137,7 +152,6 @@
   }
 
   umask(kIdmapFilePermissionMask);
-  const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
   std::ofstream fout(idmap_path);
   if (fout.fail()) {
     return error("failed to open idmap path " + idmap_path);
diff --git a/cmds/idmap2/include/idmap2/FileUtils.h b/cmds/idmap2/include/idmap2/FileUtils.h
index 5c41c49..3f03236 100644
--- a/cmds/idmap2/include/idmap2/FileUtils.h
+++ b/cmds/idmap2/include/idmap2/FileUtils.h
@@ -17,6 +17,8 @@
 #ifndef IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
 #define IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
 
+#include <sys/types.h>
+
 #include <functional>
 #include <memory>
 #include <string>
@@ -24,6 +26,7 @@
 
 namespace android::idmap2::utils {
 
+constexpr const char* kIdmapCacheDir = "/data/resource-cache";
 constexpr const mode_t kIdmapFilePermissionMask = 0133;  // u=rw,g=r,o=r
 
 typedef std::function<bool(unsigned char type /* DT_* from dirent.h */, const std::string& path)>
@@ -35,6 +38,8 @@
 
 std::unique_ptr<std::string> ReadFile(const std::string& path);
 
+bool UidHasWriteAccessToPath(uid_t uid, const std::string& path);
+
 }  // namespace android::idmap2::utils
 
 #endif  // IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
diff --git a/cmds/idmap2/libidmap2/FileUtils.cpp b/cmds/idmap2/libidmap2/FileUtils.cpp
index 0255727..a9b68cd 100644
--- a/cmds/idmap2/libidmap2/FileUtils.cpp
+++ b/cmds/idmap2/libidmap2/FileUtils.cpp
@@ -19,12 +19,20 @@
 #include <unistd.h>
 
 #include <cerrno>
+#include <climits>
+#include <cstdlib>
+#include <cstring>
 #include <fstream>
 #include <memory>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "android-base/file.h"
+#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "private/android_filesystem_config.h"
+
 #include "idmap2/FileUtils.h"
 
 namespace android::idmap2::utils {
@@ -77,4 +85,26 @@
   return r == 0 ? std::move(str) : nullptr;
 }
 
+#ifdef __ANDROID__
+bool UidHasWriteAccessToPath(uid_t uid, const std::string& path) {
+  // resolve symlinks and relative paths; the directories must exist
+  std::string canonical_path;
+  if (!base::Realpath(base::Dirname(path), &canonical_path)) {
+    return false;
+  }
+
+  const std::string cache_subdir = base::StringPrintf("%s/", kIdmapCacheDir);
+  if (canonical_path == kIdmapCacheDir ||
+      canonical_path.compare(0, cache_subdir.size(), cache_subdir) == 0) {
+    // limit access to /data/resource-cache to root and system
+    return uid == AID_ROOT || uid == AID_SYSTEM;
+  }
+  return true;
+}
+#else
+bool UidHasWriteAccessToPath(uid_t uid ATTRIBUTE_UNUSED, const std::string& path ATTRIBUTE_UNUSED) {
+  return true;
+}
+#endif
+
 }  // namespace android::idmap2::utils
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index d9d9a7f..45f84fe 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -22,6 +22,8 @@
 #include "gtest/gtest.h"
 
 #include "android-base/macros.h"
+#include "android-base/stringprintf.h"
+#include "private/android_filesystem_config.h"
 
 #include "idmap2/FileUtils.h"
 
@@ -71,4 +73,25 @@
   close(pipefd[0]);
 }
 
+#ifdef __ANDROID__
+TEST(FileUtilsTests, UidHasWriteAccessToPath) {
+  constexpr const char* tmp_path = "/data/local/tmp/test@idmap";
+  const std::string cache_path(base::StringPrintf("%s/test@idmap", kIdmapCacheDir));
+  const std::string sneaky_cache_path(base::StringPrintf("/data/../%s/test@idmap", kIdmapCacheDir));
+
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_ROOT, tmp_path));
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_ROOT, cache_path));
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_ROOT, sneaky_cache_path));
+
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_SYSTEM, tmp_path));
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_SYSTEM, cache_path));
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_SYSTEM, sneaky_cache_path));
+
+  constexpr const uid_t AID_SOME_APP = AID_SYSTEM + 1;
+  ASSERT_TRUE(UidHasWriteAccessToPath(AID_SOME_APP, tmp_path));
+  ASSERT_FALSE(UidHasWriteAccessToPath(AID_SOME_APP, cache_path));
+  ASSERT_FALSE(UidHasWriteAccessToPath(AID_SOME_APP, sneaky_cache_path));
+}
+#endif
+
 }  // namespace android::idmap2::utils
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 4334fa6..c550eaf 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -38,6 +38,7 @@
 #include "gtest/gtest.h"
 
 #include "androidfw/PosixUtils.h"
+#include "private/android_filesystem_config.h"
 
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
@@ -69,9 +70,23 @@
     ASSERT_NO_FATAL_FAILURE(AssertIdmap(idmap_ref, target_apk_path, overlay_apk_path)); \
   } while (0)
 
+#ifdef __ANDROID__
+#define SKIP_TEST_IF_CANT_EXEC_IDMAP2           \
+  do {                                          \
+    const uid_t uid = getuid();                 \
+    if (uid != AID_ROOT && uid != AID_SYSTEM) { \
+      GTEST_SKIP();                             \
+    }                                           \
+  } while (0)
+#else
+#define SKIP_TEST_IF_CANT_EXEC_IDMAP2
+#endif
+
 }  // namespace
 
 TEST_F(Idmap2BinaryTests, Create) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   // clang-format off
   auto result = ExecuteBinary({"idmap2",
                                "create",
@@ -97,6 +112,8 @@
 }
 
 TEST_F(Idmap2BinaryTests, Dump) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   // clang-format off
   auto result = ExecuteBinary({"idmap2",
                                "create",
@@ -144,6 +161,8 @@
 }
 
 TEST_F(Idmap2BinaryTests, Scan) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   const std::string overlay_static_1_apk_path = GetTestDataPath() + "/overlay/overlay-static-1.apk";
   const std::string overlay_static_2_apk_path = GetTestDataPath() + "/overlay/overlay-static-2.apk";
   const std::string idmap_static_1_path =
@@ -236,6 +255,8 @@
 }
 
 TEST_F(Idmap2BinaryTests, Lookup) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   // clang-format off
   auto result = ExecuteBinary({"idmap2",
                                "create",
@@ -285,6 +306,8 @@
 }
 
 TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) {
+  SKIP_TEST_IF_CANT_EXEC_IDMAP2;
+
   const std::string invalid_target_apk_path = GetTestDataPath() + "/DOES-NOT-EXIST";
 
   // missing mandatory options
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 008a008..8fb01b4 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -34,6 +34,7 @@
 import "frameworks/base/core/proto/android/server/enums.proto";
 import "frameworks/base/core/proto/android/server/location/enums.proto";
 import "frameworks/base/core/proto/android/service/procstats_enum.proto";
+import "frameworks/base/core/proto/android/service/usb.proto";
 import "frameworks/base/core/proto/android/stats/enums.proto";
 import "frameworks/base/core/proto/android/stats/docsui/docsui_enums.proto";
 import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
@@ -207,6 +208,7 @@
         AttentionManagerServiceResultReported attention_manager_service_result_reported = 143;
         AdbConnectionChanged adb_connection_changed = 144;
         SpeechDspStatReported speech_dsp_stat_reported = 145;
+        UsbContaminantReported usb_contaminant_reported = 146;
     }
 
     // Pulled events will start at field 10000.
@@ -4537,3 +4539,13 @@
     optional int32 total_crash_count = 3;
     optional int32 total_recover_count = 4;
 }
+
+/**
+ * Logs USB connector contaminant status.
+ *
+ * Logged from: USB Service.
+ */
+message UsbContaminantReported {
+    optional string id = 1;
+    optional android.service.usb.ContaminantPresenceStatus status = 2;
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a3243a5..ee3d27c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -77,9 +77,7 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
-import android.net.Network;
 import android.net.Proxy;
-import android.net.ProxyInfo;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -1033,15 +1031,10 @@
             NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
         }
 
-        public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
+        public void updateHttpProxy() {
             final ConnectivityManager cm = ConnectivityManager.from(
                     getApplication() != null ? getApplication() : getSystemContext());
-            final Network network = cm.getBoundNetworkForProcess();
-            if (network != null) {
-                Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
-            } else {
-                Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
-            }
+            Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
         }
 
         public void processInBackground() {
@@ -5960,8 +5953,7 @@
             // crash if we can't get it.
             final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
             try {
-                final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
-                Proxy.setHttpProxySystemProperty(proxyInfo);
+                Proxy.setHttpProxySystemProperty(service.getProxyForNetwork(null));
             } catch (RemoteException e) {
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                 throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index fcb6c14..c64fcf3 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -100,8 +100,7 @@
     void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix,
             in String[] args);
     void clearDnsCache();
-    void setHttpProxy(in String proxy, in String port, in String exclList,
-            in Uri pacFileUrl);
+    void updateHttpProxy();
     void setCoreSettings(in Bundle coreSettings);
     void updatePackageCompatibilityInfo(in String pkg, in CompatibilityInfo info);
     void scheduleTrimMemory(int level);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 55a3acb..8ca3544 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3291,7 +3291,7 @@
      */
     public int getPasswordMaximumLength(int quality) {
         PackageManager pm = mContext.getPackageManager();
-        if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ID_ATTESTATION)) {
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)) {
             return 0;
         }
         // Kind-of arbitrary.
@@ -3980,6 +3980,10 @@
      */
     public static final int WIPE_EUICC = 0x0004;
 
+    /**
+     * Flag for {@link #wipeData(int)}: won't show reason for wiping to the user.
+     */
+    public static final int WIPE_SILENTLY = 0x0008;
 
     /**
      * Ask that all user data be wiped. If called as a secondary user, the user will be removed and
@@ -3991,9 +3995,10 @@
      * be able to call this method; if it has not, a security exception will be thrown.
      *
      * @param flags Bit mask of additional options: currently supported flags are
-     *            {@link #WIPE_EXTERNAL_STORAGE} and {@link #WIPE_RESET_PROTECTION_DATA}.
+     *            {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA},
+     *            {@link #WIPE_EUICC} and {@link #WIPE_SILENTLY}.
      * @throws SecurityException if the calling application does not own an active administrator
-     *             that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
+     *            that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
      */
     public void wipeData(int flags) {
         throwIfParentInstance("wipeData");
@@ -4013,16 +4018,21 @@
      * be able to call this method; if it has not, a security exception will be thrown.
      *
      * @param flags Bit mask of additional options: currently supported flags are
-     *            {@link #WIPE_EXTERNAL_STORAGE} and {@link #WIPE_RESET_PROTECTION_DATA}.
+     *            {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA} and
+     *            {@link #WIPE_EUICC}.
      * @param reason a string that contains the reason for wiping data, which can be
-     *            presented to the user. If the string is null or empty, user won't be notified.
+     *            presented to the user.
      * @throws SecurityException if the calling application does not own an active administrator
-     *             that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
-     * @throws IllegalArgumentException if the input reason string is null or empty.
+     *            that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
+     * @throws IllegalArgumentException if the input reason string is null or empty, or if
+     *            {@link #WIPE_SILENTLY} is set.
      */
-    public void wipeData(int flags, CharSequence reason) {
+    public void wipeData(int flags, @NonNull CharSequence reason) {
         throwIfParentInstance("wipeData");
-        wipeDataInternal(flags, reason != null ? reason.toString() : null);
+        Preconditions.checkNotNull(reason, "reason string is null");
+        Preconditions.checkStringNotEmpty(reason, "reason string is empty");
+        Preconditions.checkArgument((flags & WIPE_SILENTLY) == 0, "WIPE_SILENTLY cannot be set");
+        wipeDataInternal(flags, reason.toString());
     }
 
     /**
@@ -4033,7 +4043,7 @@
      * @see #wipeData(int, CharSequence)
      * @hide
      */
-    private void wipeDataInternal(int flags, String wipeReasonForUser) {
+    private void wipeDataInternal(int flags, @NonNull String wipeReasonForUser) {
         if (mService != null) {
             try {
                 mService.wipeDataWithReason(flags, wipeReasonForUser);
@@ -5049,11 +5059,16 @@
     }
 
     /**
+     * Service-specific error code used in implementation of {@code setAlwaysOnVpnPackage} methods.
+     * @hide
+     */
+    public static final int ERROR_VPN_PACKAGE_NOT_FOUND = 1;
+
+    /**
      * Called by a device or profile owner to configure an always-on VPN connection through a
      * specific application for the current user. This connection is automatically granted and
      * persisted after a reboot.
-     * <p>
-     * To support the always-on feature, an app must
+     * <p> To support the always-on feature, an app must
      * <ul>
      *     <li>declare a {@link android.net.VpnService} in its manifest, guarded by
      *         {@link android.Manifest.permission#BIND_VPN_SERVICE};</li>
@@ -5062,12 +5077,13 @@
      *         {@link android.net.VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}.</li>
      * </ul>
      * The call will fail if called with the package name of an unsupported VPN app.
+     * <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure
+     * of the VPN provider could break networking for all apps.
      *
      * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to
      *        remove an existing always-on VPN configuration.
      * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
-     *        {@code false} otherwise. This carries the risk that any failure of the VPN provider
-     *        could break networking for all apps. This has no effect when clearing.
+     *        {@code false} otherwise. This has no effect when clearing.
      * @throws SecurityException if {@code admin} is not a device or a profile owner.
      * @throws NameNotFoundException if {@code vpnPackage} is not installed.
      * @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
@@ -5076,11 +5092,46 @@
     public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
             boolean lockdownEnabled)
             throws NameNotFoundException, UnsupportedOperationException {
+        setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptyList());
+    }
+
+    /**
+     * A version of {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} that allows the
+     * admin to specify a set of apps that should be able to access the network directly when VPN
+     * is not connected. When VPN connects these apps switch over to VPN if allowed to use that VPN.
+     * System apps can always bypass VPN.
+     * <p> Note that the system doesn't update the whitelist when packages are installed or
+     * uninstalled, the admin app must call this method to keep the list up to date.
+     *
+     * @param vpnPackage package name for an installed VPN app on the device, or {@code null}
+     *         to remove an existing always-on VPN configuration
+     * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
+     *         {@code false} otherwise. This has no effect when clearing.
+     * @param lockdownWhitelist Packages that will be able to access the network directly when VPN
+     *         is in lockdown mode but not connected. Has no effect when clearing.
+     * @throws SecurityException if {@code admin} is not a device or a profile
+     *         owner.
+     * @throws NameNotFoundException if {@code vpnPackage} or one of
+     *         {@code lockdownWhitelist} is not installed.
+     * @throws UnsupportedOperationException if {@code vpnPackage} exists but does
+     *         not support being set as always-on, or if always-on VPN is not
+     *         available.
+     */
+    public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
+            boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist)
+            throws NameNotFoundException, UnsupportedOperationException {
         throwIfParentInstance("setAlwaysOnVpnPackage");
         if (mService != null) {
             try {
-                if (!mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled)) {
-                    throw new NameNotFoundException(vpnPackage);
+                mService.setAlwaysOnVpnPackage(
+                        admin, vpnPackage, lockdownEnabled, lockdownWhitelist);
+            } catch (ServiceSpecificException e) {
+                switch (e.errorCode) {
+                    case ERROR_VPN_PACKAGE_NOT_FOUND:
+                        throw new NameNotFoundException(e.getMessage());
+                    default:
+                        throw new RuntimeException(
+                                "Unknown error setting always-on VPN: " + e.errorCode);
                 }
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
@@ -5089,6 +5140,51 @@
     }
 
     /**
+     * Called by device or profile owner to query whether current always-on VPN is configured in
+     * lockdown mode. Returns {@code false} when no always-on configuration is set.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     *
+     * @throws SecurityException if {@code admin} is not a device or a profile owner.
+     *
+     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean)
+     */
+    public boolean isAlwaysOnVpnLockdownEnabled(@NonNull ComponentName admin) {
+        throwIfParentInstance("isAlwaysOnVpnLockdownEnabled");
+        if (mService != null) {
+            try {
+                return mService.isAlwaysOnVpnLockdownEnabled(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Called by device or profile owner to query the list of packages that are allowed to access
+     * the network directly when always-on VPN is in lockdown mode but not connected. Returns
+     * {@code null} when always-on VPN is not active or not in lockdown mode.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     *
+     * @throws SecurityException if {@code admin} is not a device or a profile owner.
+     *
+     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+     */
+    public List<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
+        throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist");
+        if (mService != null) {
+            try {
+                return mService.getAlwaysOnVpnLockdownWhitelist(admin);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return null;
+    }
+
+    /**
      * Called by a device or profile owner to read the name of the package administering an
      * always-on VPN connection for the current user. If there is no such package, or the always-on
      * VPN is provided by the system instead of by an application, {@code null} will be returned.
@@ -10428,23 +10524,28 @@
     }
 
     /**
-     * Whitelists a package that is allowed to access cross profile calendar APIs.
+     * Whitelists a set of packages that are allowed to access cross-profile calendar APIs.
      *
      * <p>Called by a profile owner of a managed profile.
      *
+     * <p>Calling with a null value for the set disables the restriction so that all packages
+     * are allowed to access cross-profile calendar APIs. Calling with an empty set disallows
+     * all packages from accessing cross-profile calendar APIs. If this method isn't called,
+     * no package will be allowed to access cross-profile calendar APIs by default.
+     *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
-     * @param packageName name of the package to be whitelisted.
+     * @param packageNames set of packages to be whitelisted.
      * @throws SecurityException if {@code admin} is not a profile owner.
      *
-     * @see #removeCrossProfileCalendarPackage(ComponentName, String)
      * @see #getCrossProfileCalendarPackages(ComponentName)
      */
-    public void addCrossProfileCalendarPackage(@NonNull ComponentName admin,
-            @NonNull String packageName) {
-        throwIfParentInstance("addCrossProfileCalendarPackage");
+    public void setCrossProfileCalendarPackages(@NonNull ComponentName admin,
+            @Nullable Set<String> packageNames) {
+        throwIfParentInstance("setCrossProfileCalendarPackages");
         if (mService != null) {
             try {
-                mService.addCrossProfileCalendarPackage(admin, packageName);
+                mService.setCrossProfileCalendarPackages(admin, packageNames == null ? null
+                        : new ArrayList<>(packageNames));
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -10452,52 +10553,24 @@
     }
 
     /**
-     * Removes a package that was allowed to access cross profile calendar APIs
-     * from the whitelist.
-     *
-     * <p>Called by a profile owner of a managed profile.
-     *
-     * @param admin which {@link DeviceAdminReceiver} this request is associated with.
-     * @param packageName name of the package to be removed from the whitelist.
-     * @return {@code true} if the package is successfully removed from the whitelist,
-     * {@code false} otherwise.
-     * @throws SecurityException if {@code admin} is not a profile owner.
-     *
-     * @see #addCrossProfileCalendarPackage(ComponentName, String)
-     * @see #getCrossProfileCalendarPackages(ComponentName)
-     */
-    public boolean removeCrossProfileCalendarPackage(@NonNull ComponentName admin,
-            @NonNull String packageName) {
-        throwIfParentInstance("removeCrossProfileCalendarPackage");
-        if (mService != null) {
-            try {
-                return mService.removeCrossProfileCalendarPackage(admin, packageName);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Gets a set of package names that are whitelisted to access cross profile calendar APIs.
+     * Gets a set of package names that are whitelisted to access cross-profile calendar APIs.
      *
      * <p>Called by a profile owner of a managed profile.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
      * @return the set of names of packages that were previously whitelisted via
-     * {@link #addCrossProfileCalendarPackage(ComponentName, String)}, or an
+     * {@link #setCrossProfileCalendarPackages(ComponentName, Set)}, or an
      * empty set if none have been whitelisted.
      * @throws SecurityException if {@code admin} is not a profile owner.
      *
-     * @see #addCrossProfileCalendarPackage(ComponentName, String)
-     * @see #removeCrossProfileCalendarPackage(ComponentName, String)
+     * @see #setCrossProfileCalendarPackages(ComponentName, Set)
      */
-    public @NonNull Set<String> getCrossProfileCalendarPackages(@NonNull ComponentName admin) {
+    public @Nullable Set<String> getCrossProfileCalendarPackages(@NonNull ComponentName admin) {
         throwIfParentInstance("getCrossProfileCalendarPackages");
         if (mService != null) {
             try {
-                return new ArraySet<>(mService.getCrossProfileCalendarPackages(admin));
+                final List<String> packageNames = mService.getCrossProfileCalendarPackages(admin);
+                return packageNames == null ? null : new ArraySet<>(packageNames);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -10506,22 +10579,21 @@
     }
 
     /**
-     * Returns if a package is whitelisted to access cross profile calendar APIs.
+     * Returns if a package is whitelisted to access cross-profile calendar APIs.
      *
      * <p>To query for a specific user, use
      * {@link Context#createPackageContextAsUser(String, int, UserHandle)} to create a context for
      * that user, and get a {@link DevicePolicyManager} from this context.
      *
      * @param packageName the name of the package
-     * @return {@code true} if the package is whitelisted to access cross profile calendar APIs.
+     * @return {@code true} if the package is whitelisted to access cross-profile calendar APIs.
      * {@code false} otherwise.
      *
-     * @see #addCrossProfileCalendarPackage(ComponentName, String)
-     * @see #removeCrossProfileCalendarPackage(ComponentName, String)
+     * @see #setCrossProfileCalendarPackages(ComponentName, Set)
      * @see #getCrossProfileCalendarPackages(ComponentName)
      * @hide
      */
-    public @NonNull boolean isPackageAllowedToAccessCalendar(@NonNull  String packageName) {
+    public boolean isPackageAllowedToAccessCalendar(@NonNull  String packageName) {
         throwIfParentInstance("isPackageAllowedToAccessCalendar");
         if (mService != null) {
             try {
@@ -10535,27 +10607,27 @@
     }
 
     /**
-     * Gets a set of package names that are whitelisted to access cross profile calendar APIs.
+     * Gets a set of package names that are whitelisted to access cross-profile calendar APIs.
      *
      * <p>To query for a specific user, use
      * {@link Context#createPackageContextAsUser(String, int, UserHandle)} to create a context for
      * that user, and get a {@link DevicePolicyManager} from this context.
      *
      * @return the set of names of packages that were previously whitelisted via
-     * {@link #addCrossProfileCalendarPackage(ComponentName, String)}, or an
+     * {@link #setCrossProfileCalendarPackages(ComponentName, Set)}, or an
      * empty set if none have been whitelisted.
      *
-     * @see #addCrossProfileCalendarPackage(ComponentName, String)
-     * @see #removeCrossProfileCalendarPackage(ComponentName, String)
+     * @see #setCrossProfileCalendarPackages(ComponentName, Set)
      * @see #getCrossProfileCalendarPackages(ComponentName)
      * @hide
      */
-    public @NonNull Set<String>  getCrossProfileCalendarPackages() {
+    public @Nullable Set<String> getCrossProfileCalendarPackages() {
         throwIfParentInstance("getCrossProfileCalendarPackages");
         if (mService != null) {
             try {
-                return new ArraySet<>(mService.getCrossProfileCalendarPackagesForUser(
-                        myUserId()));
+                final List<String> packageNames = mService.getCrossProfileCalendarPackagesForUser(
+                        myUserId());
+                return packageNames == null ? null : new ArraySet<>(packageNames);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 568becf..5790fda 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -187,8 +187,10 @@
     void setCertInstallerPackage(in ComponentName who, String installerPackage);
     String getCertInstallerPackage(in ComponentName who);
 
-    boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown);
+    boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist);
     String getAlwaysOnVpnPackage(in ComponentName who);
+    boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who);
+    List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who);
 
     void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
     void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
@@ -424,8 +426,7 @@
 
     void installUpdateFromFile(in ComponentName admin, in ParcelFileDescriptor updateFileDescriptor, in StartInstallingUpdateCallback listener);
 
-    void addCrossProfileCalendarPackage(in ComponentName admin, String packageName);
-    boolean removeCrossProfileCalendarPackage(in ComponentName admin, String packageName);
+    void setCrossProfileCalendarPackages(in ComponentName admin, in List<String> packageNames);
     List<String> getCrossProfileCalendarPackages(in ComponentName admin);
     boolean isPackageAllowedToAccessCalendarForUser(String packageName, int userHandle);
     List<String> getCrossProfileCalendarPackagesForUser(int userHandle);
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index a6abe0b..ddd5313 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -172,6 +172,15 @@
     public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
 
     /**
+     * The name of the assistant app role.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
+
+    /**
      * The action used to request user approval of a role for an application.
      *
      * @hide
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 17cf702..4d8dc35 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -532,6 +532,28 @@
             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
 
     /**
+     * Intent to broadcast silence mode changed.
+     * Alway contains the extra field {@link #EXTRA_DEVICE}
+     * Alway contains the extra field {@link #EXTRA_SILENCE_ENABLED}
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @SystemApi
+    public static final String ACTION_SILENCE_MODE_CHANGED =
+            "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
+
+    /**
+     * Used as an extra field in {@link #ACTION_SILENCE_MODE_CHANGED} intent,
+     * contains whether device is in silence mode as boolean.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SILENCE_ENABLED =
+            "android.bluetooth.device.extra.SILENCE_ENABLED";
+
+    /**
      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
      *
      * @hide
@@ -1592,6 +1614,70 @@
     }
 
     /**
+     * Set the Bluetooth device silence mode.
+     *
+     * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
+     * is an active device (for A2DP or HFP), the active device for that profile
+     * will be set to null.
+     * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP
+     * active device is null, the {@link BluetoothDevice} will be set as the
+     * active device for that profile.
+     * If the {@link BluetoothDevice} is disconnected, it exits silence mode.
+     * If the {@link BluetoothDevice} is set as the active device for A2DP or
+     * HFP, while silence mode is enabled, then the device will exit silence mode.
+     * If the {@link BluetoothDevice} is in silence mode, AVRCP position change
+     * event and HFP AG indicators will be disabled.
+     * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
+     * enter silence mode.
+     *
+     * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     *
+     * @param silence true to enter silence mode, false to exit
+     * @return true on success, false on error.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean setSilenceMode(boolean silence) {
+        final IBluetooth service = sService;
+        if (service == null) {
+            return false;
+        }
+        try {
+            if (getSilenceMode() == silence) {
+                return true;
+            }
+            return service.setSilenceMode(this, silence);
+        } catch (RemoteException e) {
+            Log.e(TAG, "setSilenceMode fail", e);
+            return false;
+        }
+    }
+
+    /**
+     * Get the device silence mode status
+     *
+     * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     *
+     * @return true on device in silence mode, otherwise false.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean getSilenceMode() {
+        final IBluetooth service = sService;
+        if (service == null) {
+            return false;
+        }
+        try {
+            return service.getSilenceMode(this);
+        } catch (RemoteException e) {
+            Log.e(TAG, "getSilenceMode fail", e);
+            return false;
+        }
+    }
+
+    /**
      * Sets whether the phonebook access is allowed to this device.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b46203c..edd765b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3047,6 +3047,13 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_MEDIA_SCANNER_SCAN_FILE = "android.intent.action.MEDIA_SCANNER_SCAN_FILE";
 
+    /**
+     * Broadcast Action:  Request the media scanner to scan a storage volume and add it to the media database.
+     * The path to the storage volume is contained in the Intent.mData field.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_MEDIA_SCANNER_SCAN_VOLUME = "android.intent.action.MEDIA_SCANNER_SCAN_VOLUME";
+
    /**
      * Broadcast Action:  The "Media Button" was pressed.  Includes a single
      * extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d5636d5..eb59cfc 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -8512,6 +8512,7 @@
             collectCerts ? PackageParser.PARSE_COLLECT_CERTIFICATES : 0);
 
         pi.packageName = apk.packageName;
+        ai.packageName = apk.packageName;
         pi.setLongVersionCode(apk.getLongVersionCode());
         ai.setVersionCode(apk.getLongVersionCode());
 
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index fa335c8..28e9535 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -24,15 +24,19 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.metrics.LogMaker;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 
 import com.android.internal.R;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.LocalTime;
 
 /**
  * Manages the display's color transforms and modes.
@@ -81,7 +85,46 @@
     @SystemApi
     public static final int CAPABILITY_HARDWARE_ACCELERATION_PER_APP = 0x4;
 
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ AUTO_MODE_DISABLED, AUTO_MODE_CUSTOM_TIME, AUTO_MODE_TWILIGHT })
+    public @interface AutoMode {}
+
+    /**
+     * Auto mode value to prevent Night display from being automatically activated. It can still
+     * be activated manually via {@link #setNightDisplayActivated(boolean)}.
+     *
+     * @see #setNightDisplayAutoMode(int)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int AUTO_MODE_DISABLED = 0;
+    /**
+     * Auto mode value to automatically activate Night display at a specific start and end time.
+     *
+     * @see #setNightDisplayAutoMode(int)
+     * @see #setNightDisplayCustomStartTime(LocalTime)
+     * @see #setNightDisplayCustomEndTime(LocalTime)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int AUTO_MODE_CUSTOM_TIME = 1;
+    /**
+     * Auto mode value to automatically activate Night display from sunset to sunrise.
+     *
+     * @see #setNightDisplayAutoMode(int)
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int AUTO_MODE_TWILIGHT = 2;
+
     private final ColorDisplayManagerInternal mManager;
+    private MetricsLogger mMetricsLogger;
 
     /**
      * @hide
@@ -91,6 +134,158 @@
     }
 
     /**
+     * (De)activates the night display transform.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public boolean setNightDisplayActivated(boolean activated) {
+        return mManager.setNightDisplayActivated(activated);
+    }
+
+    /**
+     * Returns whether the night display transform is currently active.
+     *
+     * @hide
+     */
+    public boolean isNightDisplayActivated() {
+        return mManager.isNightDisplayActivated();
+    }
+
+    /**
+     * Sets the color temperature of the night display transform.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public boolean setNightDisplayColorTemperature(int temperature) {
+        return mManager.setNightDisplayColorTemperature(temperature);
+    }
+
+    /**
+     * Gets the color temperature of the night display transform.
+     *
+     * @hide
+     */
+    public int getNightDisplayColorTemperature() {
+        return mManager.getNightDisplayColorTemperature();
+    }
+
+    /**
+     * Returns the current auto mode value controlling when Night display will be automatically
+     * activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM_TIME}, or
+     * {@link #AUTO_MODE_TWILIGHT}.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public @AutoMode int getNightDisplayAutoMode() {
+        return mManager.getNightDisplayAutoMode();
+    }
+
+    /**
+     * Returns the current auto mode value, without validation, or {@code 1} if the auto mode has
+     * never been set.
+     *
+     * @hide
+     */
+    public int getNightDisplayAutoModeRaw() {
+        return mManager.getNightDisplayAutoModeRaw();
+    }
+
+    /**
+     * Sets the current auto mode value controlling when Night display will be automatically
+     * activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM_TIME}, or
+     * {@link #AUTO_MODE_TWILIGHT}.
+     *
+     * @param autoMode the new auto mode to use
+     * @return {@code true} if new auto mode was set successfully
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public boolean setNightDisplayAutoMode(@AutoMode int autoMode) {
+        if (autoMode != AUTO_MODE_DISABLED
+                && autoMode != AUTO_MODE_CUSTOM_TIME
+                && autoMode != AUTO_MODE_TWILIGHT) {
+            throw new IllegalArgumentException("Invalid autoMode: " + autoMode);
+        }
+        if (mManager.getNightDisplayAutoMode() != autoMode) {
+            getMetricsLogger().write(new LogMaker(
+                    MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CHANGED)
+                    .setType(MetricsEvent.TYPE_ACTION)
+                    .setSubtype(autoMode));
+        }
+        return mManager.setNightDisplayAutoMode(autoMode);
+    }
+
+    /**
+     * Returns the local time when Night display will be automatically activated when using
+     * {@link ColorDisplayManager#AUTO_MODE_CUSTOM_TIME}.
+     *
+     * @hide
+     */
+    public @NonNull LocalTime getNightDisplayCustomStartTime() {
+        return mManager.getNightDisplayCustomStartTime().getLocalTime();
+    }
+
+    /**
+     * Sets the local time when Night display will be automatically activated when using
+     * {@link ColorDisplayManager#AUTO_MODE_CUSTOM_TIME}.
+     *
+     * @param startTime the local time to automatically activate Night display
+     * @return {@code true} if the new custom start time was set successfully
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public boolean setNightDisplayCustomStartTime(@NonNull LocalTime startTime) {
+        if (startTime == null) {
+            throw new IllegalArgumentException("startTime cannot be null");
+        }
+        getMetricsLogger().write(new LogMaker(
+                MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
+                .setType(MetricsEvent.TYPE_ACTION)
+                .setSubtype(0));
+        return mManager.setNightDisplayCustomStartTime(new Time(startTime));
+    }
+
+    /**
+     * Returns the local time when Night display will be automatically deactivated when using
+     * {@link #AUTO_MODE_CUSTOM_TIME}.
+     *
+     * @hide
+     */
+    public @NonNull LocalTime getNightDisplayCustomEndTime() {
+        return mManager.getNightDisplayCustomEndTime().getLocalTime();
+    }
+
+    /**
+     * Sets the local time when Night display will be automatically deactivated when using
+     * {@link #AUTO_MODE_CUSTOM_TIME}.
+     *
+     * @param endTime the local time to automatically deactivate Night display
+     * @return {@code true} if the new custom end time was set successfully
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+    public boolean setNightDisplayCustomEndTime(@NonNull LocalTime endTime) {
+        if (endTime == null) {
+            throw new IllegalArgumentException("endTime cannot be null");
+        }
+        getMetricsLogger().write(new LogMaker(
+                MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
+                .setType(MetricsEvent.TYPE_ACTION)
+                .setSubtype(1));
+        return mManager.setNightDisplayCustomEndTime(new Time(endTime));
+    }
+
+    /**
      * Returns whether the device has a wide color gamut display.
      *
      * @hide
@@ -138,6 +333,28 @@
     }
 
     /**
+     * Returns the minimum allowed color temperature (in Kelvin) to tint the display when
+     * activated.
+     *
+     * @hide
+     */
+    public static int getMinimumColorTemperature(Context context) {
+        return context.getResources()
+                .getInteger(R.integer.config_nightDisplayColorTemperatureMin);
+    }
+
+    /**
+     * Returns the maximum allowed color temperature (in Kelvin) to tint the display when
+     * activated.
+     *
+     * @hide
+     */
+    public static int getMaximumColorTemperature(Context context) {
+        return context.getResources()
+                .getInteger(R.integer.config_nightDisplayColorTemperatureMax);
+    }
+
+    /**
      * Returns {@code true} if display white balance is supported by the device.
      *
      * @hide
@@ -167,6 +384,13 @@
         return mManager.getTransformCapabilities();
     }
 
+    private MetricsLogger getMetricsLogger() {
+        if (mMetricsLogger == null) {
+            mMetricsLogger = new MetricsLogger();
+        }
+        return mMetricsLogger;
+    }
+
     private static class ColorDisplayManagerInternal {
 
         private static ColorDisplayManagerInternal sInstance;
@@ -192,6 +416,94 @@
             }
         }
 
+        boolean isNightDisplayActivated() {
+            try {
+                return mCdm.isNightDisplayActivated();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        boolean setNightDisplayActivated(boolean activated) {
+            try {
+                return mCdm.setNightDisplayActivated(activated);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        int getNightDisplayColorTemperature() {
+            try {
+                return mCdm.getNightDisplayColorTemperature();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        boolean setNightDisplayColorTemperature(int temperature) {
+            try {
+                return mCdm.setNightDisplayColorTemperature(temperature);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        int getNightDisplayAutoMode() {
+            try {
+                return mCdm.getNightDisplayAutoMode();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        int getNightDisplayAutoModeRaw() {
+            try {
+                return mCdm.getNightDisplayAutoModeRaw();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        boolean setNightDisplayAutoMode(int autoMode) {
+            try {
+                return mCdm.setNightDisplayAutoMode(autoMode);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        Time getNightDisplayCustomStartTime() {
+            try {
+                return mCdm.getNightDisplayCustomStartTime();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        boolean setNightDisplayCustomStartTime(Time startTime) {
+            try {
+                return mCdm.setNightDisplayCustomStartTime(startTime);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        Time getNightDisplayCustomEndTime() {
+            try {
+                return mCdm.getNightDisplayCustomEndTime();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        boolean setNightDisplayCustomEndTime(Time endTime) {
+            try {
+                return mCdm.setNightDisplayCustomEndTime(endTime);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
         boolean isDeviceColorManaged() {
             try {
                 return mCdm.isDeviceColorManaged();
diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl
index 53cb8db..1918fd5 100644
--- a/core/java/android/hardware/display/IColorDisplayManager.aidl
+++ b/core/java/android/hardware/display/IColorDisplayManager.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.display;
 
+import android.hardware.display.Time;
+
 /** @hide */
 interface IColorDisplayManager {
     boolean isDeviceColorManaged();
@@ -24,4 +26,16 @@
     boolean setAppSaturationLevel(String packageName, int saturationLevel);
 
     int getTransformCapabilities();
+
+    boolean isNightDisplayActivated();
+    boolean setNightDisplayActivated(boolean activated);
+    int getNightDisplayColorTemperature();
+    boolean setNightDisplayColorTemperature(int temperature);
+    int getNightDisplayAutoMode();
+    int getNightDisplayAutoModeRaw();
+    boolean setNightDisplayAutoMode(int autoMode);
+    Time getNightDisplayCustomStartTime();
+    boolean setNightDisplayCustomStartTime(in Time time);
+    Time getNightDisplayCustomEndTime();
+    boolean setNightDisplayCustomEndTime(in Time time);
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/display/Time.aidl b/core/java/android/hardware/display/Time.aidl
new file mode 100644
index 0000000..95cb563
--- /dev/null
+++ b/core/java/android/hardware/display/Time.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.hardware.display;
+
+parcelable Time;
\ No newline at end of file
diff --git a/core/java/android/hardware/display/Time.java b/core/java/android/hardware/display/Time.java
new file mode 100644
index 0000000..b943ac6
--- /dev/null
+++ b/core/java/android/hardware/display/Time.java
@@ -0,0 +1,77 @@
+/*
+ * 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 android.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.time.LocalTime;
+
+/**
+ * @hide
+ */
+public final class Time implements Parcelable {
+
+    private final int mHour;
+    private final int mMinute;
+    private final int mSecond;
+    private final int mNano;
+
+    public Time(LocalTime localTime) {
+        mHour = localTime.getHour();
+        mMinute = localTime.getMinute();
+        mSecond = localTime.getSecond();
+        mNano = localTime.getNano();
+    }
+
+    public Time(Parcel parcel) {
+        mHour = parcel.readInt();
+        mMinute = parcel.readInt();
+        mSecond = parcel.readInt();
+        mNano = parcel.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int parcelableFlags) {
+        parcel.writeInt(mHour);
+        parcel.writeInt(mMinute);
+        parcel.writeInt(mSecond);
+        parcel.writeInt(mNano);
+    }
+
+    public LocalTime getLocalTime() {
+        return LocalTime.of(mHour, mMinute, mSecond, mNano);
+    }
+
+    public static final Parcelable.Creator<Time> CREATOR = new Parcelable.Creator<Time>() {
+
+        @Override
+        public Time createFromParcel(Parcel source) {
+            return new Time(source);
+        }
+
+        @Override
+        public Time[] newArray(int size) {
+            return new Time[size];
+        }
+    };
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5bb24ba..243b0eba 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1014,14 +1014,20 @@
      *                   to remove an existing always-on VPN configuration.
      * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
      *        {@code false} otherwise.
+     * @param lockdownWhitelist The list of packages that are allowed to access network directly
+     *         when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
+     *         this method must be called when a package that should be whitelisted is installed or
+     *         uninstalled.
      * @return {@code true} if the package is set as always-on VPN controller;
      *         {@code false} otherwise.
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
     public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
-            boolean lockdownEnabled) {
+            boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) {
         try {
-            return mService.setAlwaysOnVpnPackage(userId, vpnPackage, lockdownEnabled);
+            return mService.setAlwaysOnVpnPackage(
+                    userId, vpnPackage, lockdownEnabled, lockdownWhitelist);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1036,6 +1042,7 @@
      *         or {@code null} if none is set.
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
     public String getAlwaysOnVpnPackageForUser(int userId) {
         try {
             return mService.getAlwaysOnVpnPackage(userId);
@@ -1045,6 +1052,36 @@
     }
 
     /**
+     * @return whether always-on VPN is in lockdown mode.
+     *
+     * @hide
+     **/
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public boolean isVpnLockdownEnabled(int userId) {
+        try {
+            return mService.isVpnLockdownEnabled(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+    }
+
+    /**
+     * @return the list of packages that are allowed to access network when always-on VPN is in
+     * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
+     *
+     * @hide
+     **/
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public List<String> getVpnLockdownWhitelist(int userId) {
+        try {
+            return mService.getVpnLockdownWhitelist(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns details about the currently active default data network
      * for a given uid.  This is for internal use only to avoid spying
      * other apps.
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e97060a..fd7360f 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -125,8 +125,11 @@
 
     boolean updateLockdownVpn();
     boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
-    boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown);
+    boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
+            in List<String> lockdownWhitelist);
     String getAlwaysOnVpnPackage(int userId);
+    boolean isVpnLockdownEnabled(int userId);
+    List<String> getVpnLockdownWhitelist(int userId);
 
     int checkMobileProvisioning(int suggestedTimeOutMs);
 
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index e926fda..ef2269a 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -39,12 +39,12 @@
  */
 public class ProxyInfo implements Parcelable {
 
-    private String mHost;
-    private int mPort;
-    private String mExclusionList;
-    private String[] mParsedExclusionList;
+    private final String mHost;
+    private final int mPort;
+    private final String mExclusionList;
+    private final String[] mParsedExclusionList;
+    private final Uri mPacFileUrl;
 
-    private Uri mPacFileUrl;
     /**
      *@hide
      */
@@ -96,7 +96,8 @@
     public ProxyInfo(String host, int port, String exclList) {
         mHost = host;
         mPort = port;
-        setExclusionList(exclList);
+        mExclusionList = exclList;
+        mParsedExclusionList = parseExclusionList(mExclusionList);
         mPacFileUrl = Uri.EMPTY;
     }
 
@@ -107,7 +108,8 @@
     public ProxyInfo(Uri pacFileUrl) {
         mHost = LOCAL_HOST;
         mPort = LOCAL_PORT;
-        setExclusionList(LOCAL_EXCL_LIST);
+        mExclusionList = LOCAL_EXCL_LIST;
+        mParsedExclusionList = parseExclusionList(mExclusionList);
         if (pacFileUrl == null) {
             throw new NullPointerException();
         }
@@ -121,7 +123,8 @@
     public ProxyInfo(String pacFileUrl) {
         mHost = LOCAL_HOST;
         mPort = LOCAL_PORT;
-        setExclusionList(LOCAL_EXCL_LIST);
+        mExclusionList = LOCAL_EXCL_LIST;
+        mParsedExclusionList = parseExclusionList(mExclusionList);
         mPacFileUrl = Uri.parse(pacFileUrl);
     }
 
@@ -132,13 +135,22 @@
     public ProxyInfo(Uri pacFileUrl, int localProxyPort) {
         mHost = LOCAL_HOST;
         mPort = localProxyPort;
-        setExclusionList(LOCAL_EXCL_LIST);
+        mExclusionList = LOCAL_EXCL_LIST;
+        mParsedExclusionList = parseExclusionList(mExclusionList);
         if (pacFileUrl == null) {
             throw new NullPointerException();
         }
         mPacFileUrl = pacFileUrl;
     }
 
+    private static String[] parseExclusionList(String exclusionList) {
+        if (exclusionList == null) {
+            return new String[0];
+        } else {
+            return exclusionList.toLowerCase(Locale.ROOT).split(",");
+        }
+    }
+
     private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) {
         mHost = host;
         mPort = port;
@@ -159,6 +171,10 @@
             mExclusionList = source.getExclusionListAsString();
             mParsedExclusionList = source.mParsedExclusionList;
         } else {
+            mHost = null;
+            mPort = 0;
+            mExclusionList = null;
+            mParsedExclusionList = null;
             mPacFileUrl = Uri.EMPTY;
         }
     }
@@ -214,24 +230,14 @@
         return mExclusionList;
     }
 
-    // comma separated
-    private void setExclusionList(String exclusionList) {
-        mExclusionList = exclusionList;
-        if (mExclusionList == null) {
-            mParsedExclusionList = new String[0];
-        } else {
-            mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(",");
-        }
-    }
-
     /**
      * @hide
      */
     public boolean isValid() {
         if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
         return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
-                                                mPort == 0 ? "" : Integer.toString(mPort),
-                                                mExclusionList == null ? "" : mExclusionList);
+                mPort == 0 ? "" : Integer.toString(mPort),
+                mExclusionList == null ? "" : mExclusionList);
     }
 
     /**
@@ -262,7 +268,7 @@
             sb.append("] ");
             sb.append(Integer.toString(mPort));
             if (mExclusionList != null) {
-                    sb.append(" xl=").append(mExclusionList);
+                sb.append(" xl=").append(mExclusionList);
             }
         } else {
             sb.append("[ProxyProperties.mHost == null]");
@@ -308,8 +314,8 @@
      */
     public int hashCode() {
         return ((null == mHost) ? 0 : mHost.hashCode())
-        + ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
-        + mPort;
+                + ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
+                + mPort;
     }
 
     /**
@@ -352,8 +358,7 @@
                 }
                 String exclList = in.readString();
                 String[] parsedExclList = in.readStringArray();
-                ProxyInfo proxyProperties =
-                        new ProxyInfo(host, port, exclList, parsedExclList);
+                ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList);
                 return proxyProperties;
             }
 
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 37bf3a7..dc099a4 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -509,6 +509,15 @@
         }
 
         /**
+         * Sets an HTTP proxy for the VPN network. This proxy is only a recommendation
+         * and it is possible that some apps will ignore it.
+         */
+        public Builder setHttpProxy(ProxyInfo proxyInfo) {
+            mConfig.proxyInfo = proxyInfo;
+            return this;
+        }
+
+        /**
          * Add a network address to the VPN interface. Both IPv4 and IPv6
          * addresses are supported. At least one address must be set before
          * calling {@link #establish}.
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 5bf9095..efcad3e 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -369,26 +369,6 @@
     }
 
     /**
-     * Attempt to setup ANGLE with a (temporary) default rules file: b/121153494
-     * True: Rules file was loaded.
-     * False: Rules file was *not* loaded.
-     */
-    private boolean setupAngleRulesDebug(String packageName, String paths, String devOptIn) {
-        // b/121153494
-        // Skip APK rules file checking.
-        if (!DEBUG) {
-            Log.v(TAG, "Skipping loading the rules file.");
-            // Fill in some default values for now, so the loader can get an answer when it asks.
-            // Most importantly, we need to indicate which app we are init'ing and what the
-            // developer options for it are so we can turn on ANGLE if needed.
-            setAngleInfo(paths, packageName, devOptIn, null, 0, 0);
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
      * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
      * True: APK rules file was loaded.
      * False: APK rules file was *not* loaded.
@@ -425,16 +405,57 @@
     }
 
     /**
+     * Pull ANGLE whitelist from GlobalSettings and compare against current package
+     */
+    private boolean checkAngleWhitelist(Bundle bundle, String packageName) {
+        List<String> angleWhitelist =
+                getGlobalSettingsString(bundle,
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
+
+        return angleWhitelist.contains(packageName);
+    }
+
+    /**
      * Pass ANGLE details down to trigger enable logic
      */
     public void setupAngle(Context context, Bundle bundle, String packageName) {
-        String devOptIn = getDriverForPkg(bundle, packageName);
+        if (packageName.isEmpty()) {
+            Log.v(TAG, "No package name available yet, skipping ANGLE setup");
+            return;
+        }
 
+        String devOptIn = getDriverForPkg(bundle, packageName);
         if (DEBUG) {
             Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
                     + "set to: '" + devOptIn + "'");
         }
 
+        // We only need to check rules if the app is whitelisted or the developer has
+        // explicitly chosen something other than default driver.
+        //
+        // The whitelist will be generated by the ANGLE APK at both boot time and
+        // ANGLE update time. It will only include apps mentioned in the rules file.
+        //
+        // If the user has set the developer option to something other than default,
+        // we need to call setupAngleRulesApk() with the package name and the developer
+        // option value (native/angle/other). Then later when we are actually trying to
+        // load a driver, GraphicsEnv::shouldUseAngle() has seen the package name before
+        // and can confidently answer yes/no based on the previously set developer
+        // option value.
+        boolean whitelisted = checkAngleWhitelist(bundle, packageName);
+        boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT));
+        boolean rulesCheck = (whitelisted || !defaulted);
+        if (!rulesCheck) {
+            return;
+        }
+
+        if (whitelisted) {
+            Log.v(TAG, "ANGLE whitelist includes " + packageName);
+        }
+        if (!defaulted) {
+            Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
+        }
+
         String anglePkgName = getAnglePackageName(context);
         if (anglePkgName.isEmpty()) {
             Log.e(TAG, "Failed to find ANGLE package.");
@@ -466,12 +487,6 @@
             return;
         }
 
-        // b/121153494
-        if (setupAngleRulesDebug(packageName, paths, devOptIn)) {
-            // We setup ANGLE with defaults, so we're done here.
-            return;
-        }
-
         if (setupAngleRulesApk(anglePkgName, angleInfo, context, packageName, paths, devOptIn)) {
             // We setup ANGLE with rules from the APK, so we're done here.
             return;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 63912ec..630bd2e 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -54,6 +54,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InterruptedIOException;
+import java.io.UncheckedIOException;
 import java.net.DatagramSocket;
 import java.net.Socket;
 import java.nio.ByteOrder;
@@ -393,26 +394,41 @@
      * @param socket The Socket whose FileDescriptor is used to create
      *               a new ParcelFileDescriptor.
      *
-     * @return A new ParcelFileDescriptor with the FileDescriptor of the
-     *         specified Socket.
+     * @return A new ParcelFileDescriptor with a duped copy of the
+     * FileDescriptor of the specified Socket.
+     *
+     * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
      */
     public static ParcelFileDescriptor fromSocket(Socket socket) {
         FileDescriptor fd = socket.getFileDescriptor$();
-        return fd != null ? new ParcelFileDescriptor(fd) : null;
+        try {
+            return fd != null ? ParcelFileDescriptor.dup(fd) : null;
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
-     * Create a new ParcelFileDescriptor from the specified DatagramSocket.
+     * Create a new ParcelFileDescriptor from the specified DatagramSocket. The
+     * new ParcelFileDescriptor holds a dup of the original FileDescriptor in
+     * the DatagramSocket, so you must still close the DatagramSocket as well
+     * as the new ParcelFileDescriptor.
      *
      * @param datagramSocket The DatagramSocket whose FileDescriptor is used
      *               to create a new ParcelFileDescriptor.
      *
-     * @return A new ParcelFileDescriptor with the FileDescriptor of the
-     *         specified DatagramSocket.
+     * @return A new ParcelFileDescriptor with a duped copy of the
+     * FileDescriptor of the specified Socket.
+     *
+     * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
      */
     public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
         FileDescriptor fd = datagramSocket.getFileDescriptor$();
-        return fd != null ? new ParcelFileDescriptor(fd) : null;
+        try {
+            return fd != null ? ParcelFileDescriptor.dup(fd) : null;
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
@@ -542,7 +558,7 @@
         }
         file.deactivate();
         FileDescriptor fd = file.getFileDescriptor();
-        return fd != null ? new ParcelFileDescriptor(fd) : null;
+        return fd != null ? ParcelFileDescriptor.dup(fd) : null;
     }
 
     /**
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 01d85c6..99fb608 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.content.ContentResolver;
@@ -25,6 +26,8 @@
 import android.net.Uri;
 import android.util.MathUtils;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 
 /**
@@ -52,26 +55,20 @@
      * A click effect.
      *
      * @see #get(int)
-     * @hide
      */
-    @TestApi
     public static final int EFFECT_CLICK = Effect.CLICK;
 
     /**
      * A double click effect.
      *
      * @see #get(int)
-     * @hide
      */
-    @TestApi
     public static final int EFFECT_DOUBLE_CLICK = Effect.DOUBLE_CLICK;
 
     /**
      * A tick effect.
      * @see #get(int)
-     * @hide
      */
-    @TestApi
     public static final int EFFECT_TICK = Effect.TICK;
 
     /**
@@ -93,9 +90,7 @@
     /**
      * A heavy click effect.
      * @see #get(int)
-     * @hide
      */
-    @TestApi
     public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK;
 
     /** {@hide} */
@@ -136,6 +131,16 @@
         Effect.RINGTONE_15
     };
 
+    /** @hide */
+    @IntDef(prefix = { "EFFECT_" }, value = {
+            EFFECT_TICK,
+            EFFECT_CLICK,
+            EFFECT_HEAVY_CLICK,
+            EFFECT_DOUBLE_CLICK,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EffectType {}
+
     /** @hide to prevent subclassing from outside of the framework */
     public VibrationEffect() { }
 
@@ -219,6 +224,27 @@
     }
 
     /**
+     * Create a predefined vibration effect.
+     *
+     * Predefined effects are a set of common vibration effects that should be identical, regardless
+     * of the app they come from, in order to provide a cohesive experience for users across
+     * the entire device. They also may be custom tailored to the device hardware in order to
+     * provide a better experience than you could otherwise build using the generic building
+     * blocks.
+     *
+     * This will fallback to a generic pattern if one exists and there does not exist a
+     * hardware-specific implementation of the effect.
+     *
+     * @param effectId The ID of the effect to perform:
+     *                 {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK}
+     *
+     * @return The desired effect.
+     */
+    public static VibrationEffect createPrebaked(@EffectType int effectId) {
+        return get(effectId, true);
+    }
+
+    /**
      * Get a predefined vibration effect.
      *
      * Predefined effects are a set of common vibration effects that should be identical, regardless
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index c167ea1..8bd75d7 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -44,6 +44,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Set;
+
 /**
  * <p>
  * The contract between the calendar provider and applications. Contains
@@ -217,7 +219,7 @@
      * The intent will have its action set to
      * {@link CalendarContract#ACTION_VIEW_WORK_CALENDAR_EVENT} and contain extras
      * corresponding to the API's arguments. A calendar app intending to support
-     * cross profile events viewing should handle this intent, parse the arguments
+     * cross-profile events viewing should handle this intent, parse the arguments
      * and show the appropriate UI.
      *
      * @param context the context.
@@ -767,9 +769,10 @@
          * projection of the query to this uri that are not contained in the above list.
          *
          * <p>This uri will return an empty cursor if the calling user is not a parent profile
-         * of a managed profile, or cross profile calendar is disabled in Settings, or this uri is
+         * of a managed profile, or cross-profile calendar is disabled in Settings, or this uri is
          * queried from a package that is not whitelisted by profile owner of the managed profile
-         * via {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
+         * via
+         * {@link DevicePolicyManager#setCrossProfileCalendarPackages(ComponentName, Set)}.
          *
          * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
          * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
@@ -1758,9 +1761,10 @@
          * projection of the query to this uri that are not contained in the above list.
          *
          * <p>This uri will return an empty cursor if the calling user is not a parent profile
-         * of a managed profile, or cross profile calendar is disabled in Settings, or this uri is
+         * of a managed profile, or cross-profile calendar is disabled in Settings, or this uri is
          * queried from a package that is not whitelisted by profile owner of the managed profile
-         * via {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
+         * via
+         * {@link DevicePolicyManager#setCrossProfileCalendarPackages(ComponentName, Set)}.
          *
          * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
          * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
@@ -1968,10 +1972,10 @@
          * projection of the query to this uri that are not contained in the above list.
          *
          * <p>This uri will return an empty cursor if the calling user is not a parent profile
-         * of a managed profile, or cross profile calendar for the managed profile is disabled in
+         * of a managed profile, or cross-profile calendar for the managed profile is disabled in
          * Settings, or this uri is queried from a package that is not whitelisted by
          * profile owner of the managed profile via
-         * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
+         * {@link DevicePolicyManager#setCrossProfileCalendarPackages(ComponentName, Set)}.
          *
          * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
          * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 6ccd296..cd823a9 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -153,6 +153,34 @@
         String OOB_WHITELIST = "oob_whitelist";
     }
 
+    /**
+     * Namespace for activity manager related features. These features will be applied
+     * immediately upon change.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface ActivityManager {
+        String NAMESPACE = "activity_manager";
+
+        /**
+         * App compaction flags. See {@link com.android.server.am.AppCompactor}.
+         */
+        String KEY_USE_COMPACTION = "use_compaction";
+        String KEY_COMPACT_ACTION_1 = "compact_action_1";
+        String KEY_COMPACT_ACTION_2 = "compact_action_2";
+        String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
+        String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
+        String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
+        String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
+
+        /**
+         * Maximum number of cached processes. See
+         * {@link com.android.server.am.ActivityManagerConstants}.
+         */
+        String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
+    }
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bdeacdf..0961bc3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5800,6 +5800,16 @@
         public static final String ALWAYS_ON_VPN_LOCKDOWN = "always_on_vpn_lockdown";
 
         /**
+         * Comma separated list of packages that are allowed to access the network when VPN is in
+         * lockdown mode but not running.
+         * @see #ALWAYS_ON_VPN_LOCKDOWN
+         *
+         * @hide
+         */
+        public static final String ALWAYS_ON_VPN_LOCKDOWN_WHITELIST =
+                "always_on_vpn_lockdown_whitelist";
+
+        /**
          * Whether applications can be installed for this user via the system's
          * {@link Intent#ACTION_INSTALL_PACKAGE} mechanism.
          *
@@ -7802,6 +7812,9 @@
          * or an activity that handles ACTION_ASSIST, or empty which means using the default
          * handling.
          *
+         * <p>This should be set indirectly by setting the {@link
+         * android.app.role.RoleManager#ROLE_ASSISTANT assistant role}.
+         *
          * @hide
          */
         @UnsupportedAppUsage
@@ -8236,6 +8249,16 @@
         private static final Validator NOTIFICATION_BADGING_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
+         * swipe).
+         *
+         * @hide
+         */
+        public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl";
+
+        private static final Validator NOTIFICATION_DISMISS_RTL_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * Comma separated list of QS tiles that have been auto-added already.
          * @hide
          */
@@ -8537,6 +8560,7 @@
             ASSIST_GESTURE_WAKE_ENABLED,
             VR_DISPLAY_MODE,
             NOTIFICATION_BADGING,
+            NOTIFICATION_DISMISS_RTL,
             QS_AUTO_ADDED_TILES,
             SCREENSAVER_ENABLED,
             SCREENSAVER_COMPONENTS,
@@ -8699,6 +8723,7 @@
             VALIDATORS.put(ASSIST_GESTURE_WAKE_ENABLED, ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR);
             VALIDATORS.put(VR_DISPLAY_MODE, VR_DISPLAY_MODE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_BADGING, NOTIFICATION_BADGING_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_DISMISS_RTL, NOTIFICATION_DISMISS_RTL_VALIDATOR);
             VALIDATORS.put(QS_AUTO_ADDED_TILES, QS_AUTO_ADDED_TILES_VALIDATOR);
             VALIDATORS.put(SCREENSAVER_ENABLED, SCREENSAVER_ENABLED_VALIDATOR);
             VALIDATORS.put(SCREENSAVER_COMPONENTS, SCREENSAVER_COMPONENTS_VALIDATOR);
@@ -12138,6 +12163,13 @@
                 "angle_gl_driver_selection_values";
 
         /**
+         * List of package names that should check ANGLE rules
+         * @hide
+         */
+        public static final String GLOBAL_SETTINGS_ANGLE_WHITELIST =
+                "angle_whitelist";
+
+        /**
          * Game Update Package global preference for all Apps.
          * 0 = Default
          * 1 = All Apps use Game Update Package
@@ -13008,28 +13040,6 @@
                 "sms_access_restriction_enabled";
 
         /**
-         * If set to 1, an app must have the READ_PRIVILEGED_PHONE_STATE permission (or be a device
-         * / profile owner with the READ_PHONE_STATE permission) to access device identifiers.
-         *
-         * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
-         *
-         * @hide
-         */
-        public static final String PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED =
-                "privileged_device_identifier_check_enabled";
-
-        /**
-         * If set to 1, an app that is targeting Q and does not meet the new requirements to access
-         * device identifiers will receive a SecurityException.
-         *
-         * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
-         *
-         * @hide
-         */
-        public static final String PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED =
-                "privileged_device_identifier_target_q_behavior_enabled";
-
-        /**
          * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE
          * permission check for 3P apps.
          *
@@ -13052,6 +13062,17 @@
                 "privileged_device_identifier_non_priv_check_relaxed";
 
         /**
+         * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE
+         * permission check for preloaded privileged apps.
+         *
+         * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+         *
+         * @hide
+         */
+        public static final String PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED =
+                "privileged_device_identifier_priv_check_relaxed";
+
+        /**
          * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
          * and restoring to lower version of platform API will be skipped.
          *
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 483280e..991b385 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3985,6 +3985,15 @@
     public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
 
     /**
+     * If a MotionEvent has CLASSIFICATION_AMBIGUOUS_GESTURE set, then certain the default
+     * long press action will be inhibited. However, to account for the possibility of incorrect
+     * classification, the default long press timeout will instead be increased for some situations
+     * by the following factor.
+     * Likewise, the touch slop for allowing long press will be increased when gesture is uncertain.
+     */
+    private static final int AMBIGUOUS_GESTURE_MULTIPLIER = 2;
+
+    /**
      * Controls the over-scroll mode for this view.
      * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
      * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS},
@@ -14780,8 +14789,27 @@
                         drawableHotspotChanged(x, y);
                     }
 
+                    final int motionClassification = event.getClassification();
+                    final boolean ambiguousGesture =
+                            motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE;
+                    int touchSlop = mTouchSlop;
+                    if (ambiguousGesture && hasPendingLongPressCallback()) {
+                        if (!pointInView(x, y, touchSlop)) {
+                            // The default action here is to cancel long press. But instead, we
+                            // just extend the timeout here, in case the classification
+                            // stays ambiguous.
+                            removeLongPressCallback();
+                            long delay = ViewConfiguration.getLongPressTimeout()
+                                    * AMBIGUOUS_GESTURE_MULTIPLIER;
+                            // Subtract the time already spent
+                            delay -= event.getEventTime() - event.getDownTime();
+                            checkForLongClick(delay, x, y);
+                        }
+                        touchSlop *= AMBIGUOUS_GESTURE_MULTIPLIER;
+                    }
+
                     // Be lenient about moving outside of buttons
-                    if (!pointInView(x, y, mTouchSlop)) {
+                    if (!pointInView(x, y, touchSlop)) {
                         // Outside button
                         // Remove any future long press/tap checks
                         removeTapCallback();
@@ -14791,6 +14819,15 @@
                         }
                         mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                     }
+
+                    final boolean deepPress =
+                            motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS;
+                    if (deepPress && hasPendingLongPressCallback()) {
+                        // process the long click action immediately
+                        removeLongPressCallback();
+                        checkForLongClick(0 /* send immediately */, x, y);
+                    }
+
                     break;
             }
 
@@ -14825,6 +14862,21 @@
     }
 
     /**
+     * Return true if the long press callback is scheduled to run sometime in the future.
+     * Return false if there is no scheduled long press callback at the moment.
+     */
+    private boolean hasPendingLongPressCallback() {
+        if (mPendingCheckForLongPress == null) {
+            return false;
+        }
+        final AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo == null) {
+            return false;
+        }
+        return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress);
+    }
+
+   /**
      * Remove the pending click action
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index a35be27..b708323 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.view.WindowInsets.Type.ime;
+
 import android.annotation.NonNull;
 import android.view.WindowInsets.Type.InsetType;
 
@@ -32,11 +34,11 @@
      * <p>
      * Note that if the window currently doesn't have control over a certain type, it will apply the
      * change as soon as the window gains control. The app can listen to the event by observing
-     * {@link View#onApplyWindowInsets} and checking visibility with "TODO at method" in
-     * {@link WindowInsets}.
+     * {@link View#onApplyWindowInsets} and checking visibility with {@link WindowInsets#isVisible}.
      *
      * @param types A bitmask of {@link WindowInsets.Type.InsetType} specifying what windows the app
      *              would like to make appear on screen.
+     * @hide
      */
     void show(@InsetType int types);
 
@@ -45,11 +47,11 @@
      * <p>
      * Note that if the window currently doesn't have control over a certain type, it will apply the
      * change as soon as the window gains control. The app can listen to the event by observing
-     * {@link View#onApplyWindowInsets} and checking visibility with "TODO at method" in
-     * {@link WindowInsets}.
+     * {@link View#onApplyWindowInsets} and checking visibility with {@link WindowInsets#isVisible}.
      *
      * @param types A bitmask of {@link WindowInsets.Type.InsetType} specifying what windows the app
      *              would like to make disappear.
+     * @hide
      */
     void hide(@InsetType int types);
 
@@ -60,7 +62,50 @@
      * @param types The {@link InsetType}s the application has requested to control.
      * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
      *                 windows are ready to be controlled, among other callbacks.
+     * @hide
      */
     void controlWindowInsetsAnimation(@InsetType int types,
             @NonNull WindowInsetsAnimationControlListener listener);
+
+    /**
+     * Lets the application control the animation for showing the IME in a frame-by-frame manner by
+     * modifying the position of the IME when it's causing insets.
+     *
+     * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
+     *                 IME are ready to be controlled, among other callbacks.
+     */
+    default void controlInputMethodAnimation(
+            @NonNull WindowInsetsAnimationControlListener listener) {
+        controlWindowInsetsAnimation(ime(), listener);
+    }
+
+    /**
+     * Makes the IME appear on screen.
+     * <p>
+     * Note that if the window currently doesn't have control over the IME, because it doesn't have
+     * focus, it will apply the change as soon as the window gains control. The app can listen to
+     * the event by observing {@link View#onApplyWindowInsets} and checking visibility with
+     * {@link WindowInsets#isVisible}.
+     *
+     * @see #controlInputMethodAnimation(WindowInsetsAnimationControlListener)
+     * @see #hideInputMethod()
+     */
+    default void showInputMethod() {
+        show(ime());
+    }
+
+    /**
+     * Makes the IME disappear on screen.
+     * <p>
+     * Note that if the window currently doesn't have control over IME, because it doesn't have
+     * focus, it will apply the change as soon as the window gains control. The app can listen to
+     * the event by observing {@link View#onApplyWindowInsets} and checking visibility with
+     * {@link WindowInsets#isVisible}.
+     *
+     * @see #controlInputMethodAnimation(WindowInsetsAnimationControlListener)
+     * @see #showInputMethod()
+     */
+    default void hideInputMethod() {
+        hide(ime());
+    }
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 6ed2d80..c425e7b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -34,8 +34,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
-import dalvik.system.CloseGuard;
-
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -148,9 +146,6 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface FlushReason{}
 
-
-    private final CloseGuard mCloseGuard = CloseGuard.get();
-
     private final Object mLock = new Object();
 
     /**
@@ -185,7 +180,6 @@
     @VisibleForTesting
     public ContentCaptureSession(@NonNull String id) {
         mId = Preconditions.checkNotNull(id);
-        mCloseGuard.open("destroy");
     }
 
     /** @hide */
@@ -251,8 +245,6 @@
             }
             mDestroyed = true;
 
-            mCloseGuard.close();
-
             // TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
             // id) and send it to the cache of batched commands
             if (VERBOSE) {
@@ -288,18 +280,6 @@
         destroy();
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
-            destroy();
-        } finally {
-            super.finalize();
-        }
-    }
-
     /**
      * Notifies the Content Capture Service that a node has been added to the view structure.
      *
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index ed86206..10c7ade 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -73,9 +73,16 @@
     /**
      * Returns the text classifier that was set via {@link #setTextClassifier(TextClassifier)}.
      * If this is null, this method returns a default text classifier (i.e. either the system text
-     * classifier if one exists, or a local text classifier running in this app.)
+     * classifier if one exists, or a local text classifier running in this process.)
+     * <p>
+     * Note that if system textclassifier is in use, requests will be sent to a textclassifier
+     * package provided from OEM. If you want to make sure the requests are handled in your own
+     * process, you should consider {@link #getLocalTextClassifier()} instead. However, the local
+     * textclassifier may return inferior results to those returned by the system
+     * textclassifier.
      *
      * @see #setTextClassifier(TextClassifier)
+     * @see #getLocalTextClassifier()
      */
     @NonNull
     public TextClassifier getTextClassifier() {
@@ -215,7 +222,13 @@
         return TextClassifier.NO_OP;
     }
 
-    private TextClassifier getLocalTextClassifier() {
+    /**
+     * Returns a local textclassifier, which is running in this process.
+     *
+     * @see #getTextClassifier()
+     */
+    @NonNull
+    public TextClassifier getLocalTextClassifier() {
         synchronized (mLock) {
             if (mLocalTextClassifier == null) {
                 if (getSettings().isLocalTextClassifierEnabled()) {
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 3a1c457..de1f3df 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -150,6 +150,7 @@
         }
 
         try {
+            String abi = sPackage.applicationInfo.primaryCpuAbi;
             sZygote = Process.ZYGOTE_PROCESS.startChildZygote(
                     "com.android.internal.os.WebViewZygoteInit",
                     "webview_zygote",
@@ -158,39 +159,40 @@
                     null,  // gids
                     0,  // runtimeFlags
                     "webview_zygote",  // seInfo
-                    sPackage.applicationInfo.primaryCpuAbi,  // abi
+                    abi,  // abi
                     TextUtils.join(",", Build.SUPPORTED_ABIS),
                     null, // instructionSet
                     Process.FIRST_ISOLATED_UID,
                     Process.LAST_ISOLATED_UID);
-
-            // All the work below is usually done by LoadedApk, but the zygote can't talk to
-            // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
-            // doesn't have an ActivityThread and can't use Binder.
-            // Instead, figure out the paths here, in the system server where we have access to
-            // the package manager. Reuse the logic from LoadedApk to determine the correct
-            // paths and pass them to the zygote as strings.
-            final List<String> zipPaths = new ArrayList<>(10);
-            final List<String> libPaths = new ArrayList<>(10);
-            LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths);
-            final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
-            final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
-                    TextUtils.join(File.pathSeparator, zipPaths);
-
-            String libFileName = WebViewFactory.getWebViewLibrary(sPackage.applicationInfo);
-
-            // In the case where the ApplicationInfo has been modified by the stub WebView,
-            // we need to use the original ApplicationInfo to determine what the original classpath
-            // would have been to use as a cache key.
-            LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null);
-            final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
-                    TextUtils.join(File.pathSeparator, zipPaths);
-
             ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
 
-            Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
-            sZygote.preloadPackageForAbi(zip, librarySearchPath, libFileName, cacheKey,
-                                         Build.SUPPORTED_ABIS[0]);
+            if (sPackageOriginalAppInfo.sourceDir.equals(sPackage.applicationInfo.sourceDir)) {
+                // No stub WebView is involved here, so we can preload the package the "clean" way
+                // using the ApplicationInfo.
+                sZygote.preloadApp(sPackage.applicationInfo, abi);
+            } else {
+                // Legacy path to support the stub WebView.
+                // Reuse the logic from LoadedApk to determine the correct paths and pass them to
+                // the zygote as strings.
+                final List<String> zipPaths = new ArrayList<>(10);
+                final List<String> libPaths = new ArrayList<>(10);
+                LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths);
+                final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
+                final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
+                        TextUtils.join(File.pathSeparator, zipPaths);
+
+                String libFileName = WebViewFactory.getWebViewLibrary(sPackage.applicationInfo);
+
+                // Use the original ApplicationInfo to determine what the original classpath would
+                // have been to use as a cache key.
+                LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null);
+                final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
+                        TextUtils.join(File.pathSeparator, zipPaths);
+
+                Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
+                sZygote.preloadPackageForAbi(zip, librarySearchPath, libFileName, cacheKey,
+                                             Build.SUPPORTED_ABIS[0]);
+            }
         } catch (Exception e) {
             Log.e(LOGTAG, "Error connecting to webview zygote", e);
             stopZygoteLocked();
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index 7c371cb..d0102a7 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -17,13 +17,10 @@
 package com.android.internal.app;
 
 import android.annotation.NonNull;
-import android.app.SearchManager;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -31,8 +28,6 @@
 import android.provider.Settings;
 import android.util.Log;
 
-import com.android.internal.R;
-
 import java.util.ArrayList;
 import java.util.Set;
 
@@ -44,14 +39,6 @@
 
     private static final String TAG = "AssistUtils";
 
-    /**
-     * Sentinel value for "no default assistant specified."
-     *
-     * Empty string is already used to represent an explicit setting of No Assistant. null cannot
-     * be used because we can't represent a null value in XML.
-     */
-    private static final String UNSET = "#+UNSET";
-
     private final Context mContext;
     private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
 
@@ -186,37 +173,9 @@
                 Settings.Secure.ASSISTANT, userId);
         if (setting != null) {
             return ComponentName.unflattenFromString(setting);
-        }
-
-        final String defaultSetting = mContext.getResources().getString(
-                R.string.config_defaultAssistantComponentName);
-        if (defaultSetting != null && !defaultSetting.equals(UNSET)) {
-            return ComponentName.unflattenFromString(defaultSetting);
-        }
-
-        // Fallback to keep backward compatible behavior when there is no user setting.
-        if (activeServiceSupportsAssistGesture()) {
-            return getActiveServiceComponentName();
-        }
-
-        if (UNSET.equals(defaultSetting)) {
+        } else {
             return null;
         }
-
-        final SearchManager searchManager =
-                (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
-        if (searchManager == null) {
-            return null;
-        }
-        final Intent intent = searchManager.getAssistIntent(false);
-        PackageManager pm = mContext.getPackageManager();
-        ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY,
-                userId);
-        if (info != null) {
-            return new ComponentName(info.activityInfo.applicationInfo.packageName,
-                    info.activityInfo.name);
-        }
-        return null;
     }
 
     public static boolean isPreinstalledAssistant(Context context, ComponentName assistant) {
diff --git a/core/java/com/android/internal/app/ColorDisplayController.java b/core/java/com/android/internal/app/ColorDisplayController.java
index c093fe5..b03fde7 100644
--- a/core/java/com/android/internal/app/ColorDisplayController.java
+++ b/core/java/com/android/internal/app/ColorDisplayController.java
@@ -22,7 +22,8 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
-import android.metrics.LogMaker;
+import android.hardware.display.ColorDisplayManager;
+import android.hardware.display.ColorDisplayManager.AutoMode;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
@@ -32,12 +33,9 @@
 import android.util.Slog;
 
 import com.android.internal.R;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.time.LocalDateTime;
 import java.time.LocalTime;
 
 /**
@@ -52,33 +50,7 @@
     private static final boolean DEBUG = false;
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ AUTO_MODE_DISABLED, AUTO_MODE_CUSTOM, AUTO_MODE_TWILIGHT })
-    public @interface AutoMode {}
-
-    /**
-     * Auto mode value to prevent Night display from being automatically activated. It can still
-     * be activated manually via {@link #setActivated(boolean)}.
-     *
-     * @see #setAutoMode(int)
-     */
-    public static final int AUTO_MODE_DISABLED = 0;
-    /**
-     * Auto mode value to automatically activate Night display at a specific start and end time.
-     *
-     * @see #setAutoMode(int)
-     * @see #setCustomStartTime(LocalTime)
-     * @see #setCustomEndTime(LocalTime)
-     */
-    public static final int AUTO_MODE_CUSTOM = 1;
-    /**
-     * Auto mode value to automatically activate Night display from sunset to sunrise.
-     *
-     * @see #setAutoMode(int)
-     */
-    public static final int AUTO_MODE_TWILIGHT = 2;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ COLOR_MODE_NATURAL, COLOR_MODE_BOOSTED, COLOR_MODE_SATURATED, COLOR_MODE_AUTOMATIC })
+    @IntDef({COLOR_MODE_NATURAL, COLOR_MODE_BOOSTED, COLOR_MODE_SATURATED, COLOR_MODE_AUTOMATIC})
     public @interface ColorMode {}
 
     /**
@@ -108,10 +80,10 @@
 
     private final Context mContext;
     private final int mUserId;
+    private final ColorDisplayManager mColorDisplayManager;
 
     private ContentObserver mContentObserver;
     private Callback mCallback;
-    private MetricsLogger mMetricsLogger;
 
     public ColorDisplayController(@NonNull Context context) {
         this(context, ActivityManager.getCurrentUser());
@@ -120,14 +92,14 @@
     public ColorDisplayController(@NonNull Context context, int userId) {
         mContext = context.getApplicationContext();
         mUserId = userId;
+        mColorDisplayManager = mContext.getSystemService(ColorDisplayManager.class);
     }
 
     /**
      * Returns {@code true} when Night display is activated (the display is tinted red).
      */
     public boolean isActivated() {
-        return Secure.getIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_ACTIVATED, 0, mUserId) == 1;
+        return mColorDisplayManager.isNightDisplayActivated();
     }
 
     /**
@@ -137,40 +109,16 @@
      * @return {@code true} if the activated value was set successfully
      */
     public boolean setActivated(boolean activated) {
-        if (isActivated() != activated) {
-            Secure.putStringForUser(mContext.getContentResolver(),
-                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
-                    LocalDateTime.now().toString(),
-                    mUserId);
-        }
-        return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_ACTIVATED, activated ? 1 : 0, mUserId);
+        return mColorDisplayManager.setNightDisplayActivated(activated);
     }
 
     /**
      * Returns the current auto mode value controlling when Night display will be automatically
-     * activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM}, or
-     * {@link #AUTO_MODE_TWILIGHT}.
+     * activated. One of {@link ColorDisplayManager#AUTO_MODE_DISABLED}, {@link
+     * ColorDisplayManager#AUTO_MODE_CUSTOM_TIME} or {@link ColorDisplayManager#AUTO_MODE_TWILIGHT}.
      */
     public @AutoMode int getAutoMode() {
-        int autoMode = Secure.getIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_AUTO_MODE, -1, mUserId);
-        if (autoMode == -1) {
-            if (DEBUG) {
-                Slog.d(TAG, "Using default value for setting: " + Secure.NIGHT_DISPLAY_AUTO_MODE);
-            }
-            autoMode = mContext.getResources().getInteger(
-                    R.integer.config_defaultNightDisplayAutoMode);
-        }
-
-        if (autoMode != AUTO_MODE_DISABLED
-                && autoMode != AUTO_MODE_CUSTOM
-                && autoMode != AUTO_MODE_TWILIGHT) {
-            Slog.e(TAG, "Invalid autoMode: " + autoMode);
-            autoMode = AUTO_MODE_DISABLED;
-        }
-
-        return autoMode;
+        return mColorDisplayManager.getNightDisplayAutoMode();
     }
 
     /**
@@ -178,138 +126,64 @@
      * never been set.
      */
     public int getAutoModeRaw() {
-        return Secure.getIntForUser(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
-                -1, mUserId);
+        return mColorDisplayManager.getNightDisplayAutoModeRaw();
     }
 
     /**
      * Sets the current auto mode value controlling when Night display will be automatically
-     * activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM}, or
-     * {@link #AUTO_MODE_TWILIGHT}.
+     * activated. One of {@link ColorDisplayManager#AUTO_MODE_DISABLED}, {@link
+     * ColorDisplayManager#AUTO_MODE_CUSTOM_TIME} or {@link ColorDisplayManager#AUTO_MODE_TWILIGHT}.
      *
      * @param autoMode the new auto mode to use
      * @return {@code true} if new auto mode was set successfully
      */
     public boolean setAutoMode(@AutoMode int autoMode) {
-        if (autoMode != AUTO_MODE_DISABLED
-                && autoMode != AUTO_MODE_CUSTOM
-                && autoMode != AUTO_MODE_TWILIGHT) {
-            throw new IllegalArgumentException("Invalid autoMode: " + autoMode);
-        }
-
-        if (getAutoMode() != autoMode) {
-            Secure.putStringForUser(mContext.getContentResolver(),
-                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
-                    null,
-                    mUserId);
-            getMetricsLogger().write(new LogMaker(
-                    MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CHANGED)
-                    .setType(MetricsEvent.TYPE_ACTION)
-                    .setSubtype(autoMode));
-        }
-
-        return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
+        return mColorDisplayManager.setNightDisplayAutoMode(autoMode);
     }
 
     /**
-     * Returns the local time when Night display will be automatically activated when using
-     * {@link #AUTO_MODE_CUSTOM}.
+     * Returns the local time when Night display will be automatically activated when using {@link
+     * ColorDisplayManager#AUTO_MODE_CUSTOM_TIME}.
      */
     public @NonNull LocalTime getCustomStartTime() {
-        int startTimeValue = Secure.getIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, -1, mUserId);
-        if (startTimeValue == -1) {
-            if (DEBUG) {
-                Slog.d(TAG, "Using default value for setting: "
-                        + Secure.NIGHT_DISPLAY_CUSTOM_START_TIME);
-            }
-            startTimeValue = mContext.getResources().getInteger(
-                    R.integer.config_defaultNightDisplayCustomStartTime);
-        }
-
-        return LocalTime.ofSecondOfDay(startTimeValue / 1000);
+        return mColorDisplayManager.getNightDisplayCustomStartTime();
     }
 
     /**
-     * Sets the local time when Night display will be automatically activated when using
-     * {@link #AUTO_MODE_CUSTOM}.
+     * Sets the local time when Night display will be automatically activated when using {@link
+     * ColorDisplayManager#AUTO_MODE_CUSTOM_TIME}.
      *
      * @param startTime the local time to automatically activate Night display
      * @return {@code true} if the new custom start time was set successfully
      */
     public boolean setCustomStartTime(@NonNull LocalTime startTime) {
-        if (startTime == null) {
-            throw new IllegalArgumentException("startTime cannot be null");
-        }
-        getMetricsLogger().write(new LogMaker(
-                MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
-                .setType(MetricsEvent.TYPE_ACTION)
-                .setSubtype(0));
-        return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
+        return mColorDisplayManager.setNightDisplayCustomStartTime(startTime);
     }
 
     /**
-     * Returns the local time when Night display will be automatically deactivated when using
-     * {@link #AUTO_MODE_CUSTOM}.
+     * Returns the local time when Night display will be automatically deactivated when using {@link
+     * ColorDisplayManager#AUTO_MODE_CUSTOM_TIME}.
      */
     public @NonNull LocalTime getCustomEndTime() {
-        int endTimeValue = Secure.getIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, -1, mUserId);
-        if (endTimeValue == -1) {
-            if (DEBUG) {
-                Slog.d(TAG, "Using default value for setting: "
-                        + Secure.NIGHT_DISPLAY_CUSTOM_END_TIME);
-            }
-            endTimeValue = mContext.getResources().getInteger(
-                    R.integer.config_defaultNightDisplayCustomEndTime);
-        }
-
-        return LocalTime.ofSecondOfDay(endTimeValue / 1000);
+        return mColorDisplayManager.getNightDisplayCustomEndTime();
     }
 
     /**
-     * Sets the local time when Night display will be automatically deactivated when using
-     * {@link #AUTO_MODE_CUSTOM}.
+     * Sets the local time when Night display will be automatically deactivated when using {@link
+     * ColorDisplayManager#AUTO_MODE_CUSTOM_TIME}.
      *
      * @param endTime the local time to automatically deactivate Night display
      * @return {@code true} if the new custom end time was set successfully
      */
     public boolean setCustomEndTime(@NonNull LocalTime endTime) {
-        if (endTime == null) {
-            throw new IllegalArgumentException("endTime cannot be null");
-        }
-        getMetricsLogger().write(new LogMaker(
-                MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
-                .setType(MetricsEvent.TYPE_ACTION)
-                .setSubtype(1));
-        return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
+        return mColorDisplayManager.setNightDisplayCustomEndTime(endTime);
     }
 
     /**
      * Returns the color temperature (in Kelvin) to tint the display when activated.
      */
     public int getColorTemperature() {
-        int colorTemperature = Secure.getIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, -1, mUserId);
-        if (colorTemperature == -1) {
-            if (DEBUG) {
-                Slog.d(TAG, "Using default value for setting: "
-                        + Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE);
-            }
-            colorTemperature = getDefaultColorTemperature();
-        }
-        final int minimumTemperature = getMinimumColorTemperature();
-        final int maximumTemperature = getMaximumColorTemperature();
-        if (colorTemperature < minimumTemperature) {
-            colorTemperature = minimumTemperature;
-        } else if (colorTemperature > maximumTemperature) {
-            colorTemperature = maximumTemperature;
-        }
-
-        return colorTemperature;
+        return mColorDisplayManager.getNightDisplayColorTemperature();
     }
 
     /**
@@ -319,8 +193,7 @@
      * @return {@code true} if new temperature was set successfully.
      */
     public boolean setColorTemperature(int colorTemperature) {
-        return Secure.putIntForUser(mContext.getContentResolver(),
-                Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, colorTemperature, mUserId);
+        return mColorDisplayManager.setNightDisplayColorTemperature(colorTemperature);
     }
 
     /**
@@ -411,24 +284,14 @@
      * Returns the minimum allowed color temperature (in Kelvin) to tint the display when activated.
      */
     public int getMinimumColorTemperature() {
-        return mContext.getResources().getInteger(
-                R.integer.config_nightDisplayColorTemperatureMin);
+        return ColorDisplayManager.getMinimumColorTemperature(mContext);
     }
 
     /**
      * Returns the maximum allowed color temperature (in Kelvin) to tint the display when activated.
      */
     public int getMaximumColorTemperature() {
-        return mContext.getResources().getInteger(
-                R.integer.config_nightDisplayColorTemperatureMax);
-    }
-
-    /**
-     * Returns the default color temperature (in Kelvin) to tint the display when activated.
-     */
-    public int getDefaultColorTemperature() {
-        return mContext.getResources().getInteger(
-                R.integer.config_nightDisplayColorTemperatureDefault);
+        return ColorDisplayManager.getMaximumColorTemperature(mContext);
     }
 
     /**
@@ -526,13 +389,6 @@
         }
     }
 
-    private MetricsLogger getMetricsLogger() {
-        if (mMetricsLogger == null) {
-            mMetricsLogger = new MetricsLogger();
-        }
-        return mMetricsLogger;
-    }
-
     /**
      * Callback invoked whenever the Night display settings are changed.
      */
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 9bacf9b..f848346 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -64,6 +64,9 @@
 
     private boolean mUseBpfStats;
 
+    // A persistent Snapshot since device start for eBPF stats
+    private final NetworkStats mPersistSnapshot;
+
     // TODO: only do adjustments in NetworkStatsService and remove this.
     /**
      * (Stacked interface) -> (base interface) association for all connected ifaces since boot.
@@ -135,6 +138,7 @@
         mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
         mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
         mUseBpfStats = useBpfStats;
+        mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1);
     }
 
     public NetworkStats readBpfNetworkStatsDev() throws IOException {
@@ -268,6 +272,7 @@
         return stats;
     }
 
+    // TODO: delete the lastStats parameter
     private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces,
             int limitTag, NetworkStats lastStats) throws IOException {
         if (USE_NATIVE_PARSING) {
@@ -278,16 +283,28 @@
             } else {
                 stats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
             }
-            if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
-                    limitIfaces, limitTag, mUseBpfStats) != 0) {
-                throw new IOException("Failed to parse network stats");
+            if (mUseBpfStats) {
+                if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
+                        null, TAG_ALL, mUseBpfStats) != 0) {
+                    throw new IOException("Failed to parse network stats");
+                }
+                mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime());
+                mPersistSnapshot.combineAllValues(stats);
+                NetworkStats result = mPersistSnapshot.clone();
+                result.filter(limitUid, limitIfaces, limitTag);
+                return result;
+            } else {
+                if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
+                        limitIfaces, limitTag, mUseBpfStats) != 0) {
+                    throw new IOException("Failed to parse network stats");
+                }
+                if (SANITY_CHECK_NATIVE) {
+                    final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
+                            limitIfaces, limitTag);
+                    assertEquals(javaStats, stats);
+                }
+                return stats;
             }
-            if (SANITY_CHECK_NATIVE) {
-                final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
-                        limitIfaces, limitTag);
-                assertEquals(javaStats, stats);
-            }
-            return stats;
         } else {
             return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag);
         }
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index fd03b3f..da8605e 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -28,6 +28,7 @@
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.Network;
+import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -104,6 +105,7 @@
     public boolean allowIPv4;
     public boolean allowIPv6;
     public Network[] underlyingNetworks;
+    public ProxyInfo proxyInfo;
 
     public void updateAllowedFamilies(InetAddress address) {
         if (address instanceof Inet4Address) {
@@ -164,6 +166,7 @@
         out.writeInt(allowIPv4 ? 1 : 0);
         out.writeInt(allowIPv6 ? 1 : 0);
         out.writeTypedArray(underlyingNetworks, flags);
+        out.writeParcelable(proxyInfo, flags);
     }
 
     public static final Parcelable.Creator<VpnConfig> CREATOR =
@@ -189,6 +192,7 @@
             config.allowIPv4 = in.readInt() != 0;
             config.allowIPv6 = in.readInt() != 0;
             config.underlyingNetworks = in.createTypedArray(Network.CREATOR);
+            config.proxyInfo = in.readParcelable(null);
             return config;
         }
 
@@ -220,6 +224,7 @@
                 .append(", allowIPv4=").append(allowIPv4)
                 .append(", allowIPv6=").append(allowIPv6)
                 .append(", underlyingNetworks=").append(Arrays.toString(underlyingNetworks))
+                .append(", proxyInfo=").append(proxyInfo.toString())
                 .append("}")
                 .toString();
     }
diff --git a/core/java/com/android/internal/net/VpnInfo.java b/core/java/com/android/internal/net/VpnInfo.java
index a676dac..b1a41287 100644
--- a/core/java/com/android/internal/net/VpnInfo.java
+++ b/core/java/com/android/internal/net/VpnInfo.java
@@ -32,11 +32,11 @@
 
     @Override
     public String toString() {
-        return "VpnInfo{" +
-                "ownerUid=" + ownerUid +
-                ", vpnIface='" + vpnIface + '\'' +
-                ", primaryUnderlyingIface='" + primaryUnderlyingIface + '\'' +
-                '}';
+        return "VpnInfo{"
+                + "ownerUid=" + ownerUid
+                + ", vpnIface='" + vpnIface + '\''
+                + ", primaryUnderlyingIface='" + primaryUnderlyingIface + '\''
+                + '}';
     }
 
     @Override
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 6454352..2c272de 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -49,7 +49,7 @@
  * per thread, uid or call description.
  */
 public class BinderCallsStats implements BinderInternal.Observer {
-    public static final boolean ENABLED_DEFAULT = false;
+    public static final boolean ENABLED_DEFAULT = true;
     public static final boolean DETAILED_TRACKING_DEFAULT = true;
     public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100;
     public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000;
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index 0b329d7..c8d30b2 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -17,8 +17,9 @@
 package com.android.internal.os;
 
 import android.app.ApplicationLoaders;
+import android.app.LoadedApk;
+import android.content.pm.ApplicationInfo;
 import android.net.LocalSocket;
-import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 import android.webkit.WebViewFactory;
@@ -66,6 +67,34 @@
         }
 
         @Override
+        protected boolean canPreloadApp() {
+            return true;
+        }
+
+        @Override
+        protected void handlePreloadApp(ApplicationInfo appInfo) {
+            Log.i(TAG, "Beginning application preload for " + appInfo.packageName);
+            LoadedApk loadedApk = new LoadedApk(null, appInfo, null, null, false, true, false);
+            ClassLoader loader = loadedApk.getClassLoader();
+            doPreload(loader, WebViewFactory.getWebViewLibrary(appInfo));
+
+            // Add the APK to the Zygote's list of allowed files for children.
+            Zygote.nativeAllowFileAcrossFork(appInfo.sourceDir);
+            if (appInfo.splitSourceDirs != null) {
+                for (String path : appInfo.splitSourceDirs) {
+                    Zygote.nativeAllowFileAcrossFork(path);
+                }
+            }
+            if (appInfo.sharedLibraryFiles != null) {
+                for (String path : appInfo.sharedLibraryFiles) {
+                    Zygote.nativeAllowFileAcrossFork(path);
+                }
+            }
+
+            Log.i(TAG, "Application preload done");
+        }
+
+        @Override
         protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
                 String cacheKey) {
             Log.i(TAG, "Beginning package preload");
@@ -76,16 +105,22 @@
             ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
                     packagePath, libsPath, cacheKey);
 
-            // Load the native library using WebViewLibraryLoader to share the RELRO data with other
-            // processes.
-            WebViewLibraryLoader.loadNativeLibrary(loader, libFileName);
-
             // Add the APK to the Zygote's list of allowed files for children.
             String[] packageList = TextUtils.split(packagePath, File.pathSeparator);
             for (String packageEntry : packageList) {
                 Zygote.nativeAllowFileAcrossFork(packageEntry);
             }
 
+            doPreload(loader, libFileName);
+
+            Log.i(TAG, "Package preload done");
+        }
+
+        private void doPreload(ClassLoader loader, String libFileName) {
+            // Load the native library using WebViewLibraryLoader to share the RELRO data with other
+            // processes.
+            WebViewLibraryLoader.loadNativeLibrary(loader, libFileName);
+
             // Once we have the classloader, look up the WebViewFactoryProvider implementation and
             // call preloadInZygote() on it to give it the opportunity to preload the native library
             // and perform any other initialisation work that should be shared among the children.
@@ -114,8 +149,6 @@
             } catch (IOException ioe) {
                 throw new IllegalStateException("Error writing to command socket", ioe);
             }
-
-            Log.i(TAG, "Package preload done");
         }
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index df89b26..24a08ca 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -339,6 +339,8 @@
                 mMountExternal = Zygote.MOUNT_EXTERNAL_FULL;
             }  else if (arg.equals("--mount-external-installer")) {
                 mMountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
+            }  else if (arg.equals("--mount-external-legacy")) {
+                mMountExternal = Zygote.MOUNT_EXTERNAL_LEGACY;
             } else if (arg.equals("--query-abi-list")) {
                 mAbiListQuery = true;
             } else if (arg.equals("--get-pid")) {
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index ad51c47..5de0883 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -19,6 +19,7 @@
 #include <hwui/Paint.h>
 #include <hwui/Bitmap.h>
 #include <renderthread/RenderProxy.h>
+#include <utils/Color.h>
 
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 
@@ -602,6 +603,14 @@
     return static_cast<jint>(bitmap->getGenerationID());
 }
 
+static jboolean Bitmap_isConfigF16(JNIEnv* env, jobject, jlong bitmapHandle) {
+    LocalScopedBitmap bitmap(bitmapHandle);
+    if (bitmap->info().colorType() == kRGBA_F16_SkColorType) {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
     if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
@@ -1120,7 +1129,8 @@
     sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
     // To support any color space, we need to pass an additional ColorSpace argument to
     // java Bitmap.createHardwareBitmap.
-    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB());
+    SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat());
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, ct, SkColorSpace::MakeSRGB());
     if (!bitmap.get()) {
         ALOGW("failed to create hardware bitmap from graphic buffer");
         return NULL;
@@ -1133,7 +1143,8 @@
     AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
         hardwareBuffer);
     sp<GraphicBuffer> buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf));
-    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer,
+    SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat());
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, ct,
             GraphicsJNI::getNativeColorSpace(colorSpacePtr));
     if (!bitmap.get()) {
         ALOGW("failed to create hardware bitmap from hardware buffer");
@@ -1193,6 +1204,7 @@
     {   "nativeErase",              "(JJJ)V", (void*)Bitmap_eraseLong },
     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
+    {   "nativeIsConfigF16",        "(J)Z", (void*)Bitmap_isConfigF16 },
     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
     {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
     {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 318ec9b..4052919 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1038,8 +1038,9 @@
         // Continue I guess?
     }
 
+    SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat());
     sk_sp<SkColorSpace> cs = uirenderer::DataSpaceToColorSpace(bufferItem.mDataSpace);
-    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, cs);
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, ct, cs);
     return bitmap::createBitmap(env, bitmap.release(),
             android::bitmap::kBitmapCreateFlag_Premultiplied);
 }
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 53dde80..4e48663 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -72,6 +72,7 @@
       return true;
   }
 
+  // Framework jars are allowed.
   static const char* kFrameworksPrefix = "/system/framework/";
   static const char* kJarSuffix = ".jar";
   if (android::base::StartsWith(path, kFrameworksPrefix)
@@ -79,6 +80,13 @@
     return true;
   }
 
+  // Jars from the runtime apex are allowed.
+  static const char* kRuntimeApexPrefix = "/apex/com.android.runtime/javalib/";
+  if (android::base::StartsWith(path, kRuntimeApexPrefix)
+      && android::base::EndsWith(path, kJarSuffix)) {
+    return true;
+  }
+
   // Whitelist files needed for Runtime Resource Overlay, like these:
   // /system/vendor/overlay/framework-res.apk
   // /system/vendor/overlay-subdir/pg/framework-res.apk
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d79eb94..f06165c 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -451,6 +451,8 @@
         optional SettingProto gup_blacklist = 11;
         // List of Apps that are allowed to use Game Driver package.
         optional SettingProto game_driver_whitelist = 12;
+        // ANGLE - List of Apps that can check ANGLE rules
+        optional SettingProto angle_whitelist = 13;
     }
     optional Gpu gpu = 59;
 
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index e68f9db..188769d 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -31,6 +31,7 @@
 import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
+// Next tag: 21
 message JobSchedulerServiceDumpProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -139,9 +140,13 @@
     // The current limit on the number of concurrent JobServiceContext entries
     // we want to keep actively running a job.
     optional int32 max_active_jobs = 13;
+
+    // Dump from JobConcurrencyManager.
+    optional JobConcurrencyManagerProto concurrency_manager = 20;
 }
 
 // A com.android.server.job.JobSchedulerService.Constants object.
+// Next tag: 29
 message ConstantsProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -273,7 +278,39 @@
     }
     optional QuotaController quota_controller = 24;
 
-    // Next tag: 26
+    // Max number of jobs, when screen is ON.
+    optional MaxJobCountsPerMemoryTrimLevelProto max_job_counts_screen_on = 26;
+
+    // Max number of jobs, when screen is OFF.
+    optional MaxJobCountsPerMemoryTrimLevelProto max_job_counts_screen_off = 27;
+
+    // In this time after screen turns on, we increase job concurrency.
+    optional int32 screen_off_job_concurrency_increase_delay_ms = 28;
+}
+
+// Next tag: 4
+message MaxJobCountsProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Total number of jobs to run simultaneously.
+    optional int32 total_jobs = 1;
+
+    // Max number of BG (== owned by non-TOP apps) jobs to run simultaneously.
+    optional int32 max_bg = 2;
+
+    // We try to run at least this many BG (== owned by non-TOP apps) jobs, when there are any
+    // pending, rather than always running the TOTAL number of FG jobs.
+    optional int32 min_bg = 3;
+}
+
+// Next tag: 5
+message MaxJobCountsPerMemoryTrimLevelProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional MaxJobCountsProto normal = 1;
+    optional MaxJobCountsProto moderate = 2;
+    optional MaxJobCountsProto low = 3;
+    optional MaxJobCountsProto critical = 4;
 }
 
 message StateControllerProto {
@@ -807,3 +844,46 @@
 
     // Next tag: 28
 }
+
+// Dump from com.android.server.job.JobConcurrencyManager.
+// Next tag: 7
+message JobConcurrencyManagerProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Whether the device is interactive (== screen on) now or not.
+    optional bool current_interactive = 1;
+    // Similar to current_interactive, screen on or not, but it takes into account the off timeout.
+    optional bool effective_interactive = 2;
+    // How many milliseconds have passed since the last screen on. (i.e. 1000 == 1 sec ago)
+    optional int64 time_since_last_screen_on_ms = 3;
+    // How many milliseconds have passed since the last screen off. (i.e. 1000 == 1 sec ago)
+    optional int64 time_since_last_screen_off_ms = 4;
+    // Current max number of jobs.
+    optional JobCountTrackerProto job_count_tracker = 5;
+    // Current memory trim level.
+    optional int32 memory_trim_level = 6;
+}
+
+// Dump from com.android.server.job.JobConcurrencyManager.JobCountTracker.
+// Next tag: 8
+message JobCountTrackerProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Number of total jos that can run simultaneously.
+    optional int32 config_num_max_total_jobs = 1;
+    // Number of background jos that can run simultaneously.
+    optional int32 config_num_max_bg_jobs = 2;
+    // Out of total jobs, this many background jobs should be guaranteed to be executed, even if
+    // there are the config_num_max_total_jobs count of foreground jobs pending.
+    optional int32 config_num_min_bg_jobs = 3;
+
+    // Number of running foreground jobs.
+    optional int32 num_running_fg_jobs = 4;
+    // Number of running background jobs.
+    optional int32 num_running_bg_jobs = 5;
+
+    // Number of pending foreground jobs.
+    optional int32 num_pending_fg_jobs = 6;
+    // Number of pending background jobs.
+    optional int32 num_pending_bg_jobs = 7;
+}
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index 00fae3d..367c540 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -228,6 +228,15 @@
     repeated Mode supported_modes = 2;
 }
 
+/* Same as android.hardware.usb.V1_2.Constants.ContaminantPresenceStatus */
+enum ContaminantPresenceStatus {
+    CONTAMINANT_STATUS_UNKNOWN = 0;
+    CONTAMINANT_STATUS_NOT_SUPPORTED = 1;
+    CONTAMINANT_STATUS_DISABLED = 2;
+    CONTAMINANT_STATUS_NOT_DETECTED = 3;
+    CONTAMINANT_STATUS_DETECTED = 4;
+}
+
 message UsbPortStatusProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -245,14 +254,6 @@
         DATA_ROLE_DEVICE = 2;
     }
 
-    /* Same as android.hardware.usb.V1_2.Constants.ContaminantPresenceStatus */
-    enum ContaminantPresenceStatus {
-        CONTAMINANT_STATUS_NOT_SUPPORTED = 0;
-        CONTAMINANT_STATUS_DISABLED = 1;
-        CONTAMINANT_STATUS_NOT_DETECTED = 2;
-        CONTAMINANT_STATUS_DETECTED = 3;
-    }
-
     optional bool connected = 1;
     optional UsbPortProto.Mode current_mode = 2;
     optional PowerRole power_role = 3;
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index 82460ec..a8e64c6 100644
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
@@ -92,8 +92,7 @@
   SET_UNINSTALL_BLOCKED = 67;
   SET_PACKAGES_SUSPENDED = 68;
   ON_LOCK_TASK_MODE_ENTERING = 69;
-  ADD_CROSS_PROFILE_CALENDAR_PACKAGE = 70;
-  REMOVE_CROSS_PROFILE_CALENDAR_PACKAGE = 71;
+  SET_CROSS_PROFILE_CALENDAR_PACKAGES = 70;
   GET_USER_PASSWORD_COMPLEXITY_LEVEL = 72;
   INSTALL_SYSTEM_UPDATE = 73;
   INSTALL_SYSTEM_UPDATE_ERROR = 74;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f92df6a..6f7312f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3528,6 +3528,12 @@
         android:protectionLevel="signature|privileged" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
 
+    <!-- Allows an application to access and modify always-on VPN configuration.
+         <p>Not for use by third-party or privileged applications.
+         @hide -->
+    <permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to capture audio output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bbc55a3..49f2c84 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -957,7 +957,7 @@
     <!-- Default mode to control how Night display is automatically activated.
          One of the following values (see ColorDisplayController.java):
              0 - AUTO_MODE_DISABLED
-             1 - AUTO_MODE_CUSTOM
+             1 - AUTO_MODE_CUSTOM_TIME
              2 - AUTO_MODE_TWILIGHT
     -->
     <integer name="config_defaultNightDisplayAutoMode">0</integer>
@@ -3729,9 +3729,6 @@
     <!-- Whether or not the "SMS app service" feature is enabled -->
     <bool name="config_useSmsAppService">true</bool>
 
-    <!-- Component name for default assistant on this device -->
-    <string name="config_defaultAssistantComponentName">#+UNSET</string>
-
     <!-- Class name for the InputEvent compatibility processor override.
          Empty string means use the default compatibility processor
          (android.view.InputEventCompatProcessor). -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4235341..ec1bac1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2988,7 +2988,7 @@
     </public-group>
 
     <public-group type="array" first-id="0x01070006">
-      <!-- @hide @SystemApi -->
+      <!-- @hide @TestApi @SystemApi -->
       <public name="config_defaultRoleHolders" />
     </public-group>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cbb4cb2..d556130 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3528,8 +3528,6 @@
 
   <java-symbol type="bool" name="config_useSmsAppService" />
 
-  <java-symbol type="string" name="config_defaultAssistantComponentName" />
-
   <java-symbol type="id" name="transition_overlay_view_tag" />
 
   <java-symbol type="dimen" name="rounded_corner_radius" />
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 8604b0c..bdf3aa2 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -38,7 +38,6 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -501,7 +500,7 @@
         }
 
         @Override
-        public void setHttpProxy(String s, String s1, String s2, Uri uri) throws RemoteException {
+        public void updateHttpProxy() throws RemoteException {
         }
 
         @Override
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 7b92cf5..300394d 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -527,12 +527,14 @@
                 R.raw.com_android_tzdata);
         PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexFile, false);
         assertEquals("com.google.android.tzdata", pi.packageName);
+        assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
         assertEquals(1, pi.getLongVersionCode());
         assertEquals(1, pi.applicationInfo.longVersionCode);
         assertNull(pi.signingInfo);
 
         pi = PackageParser.generatePackageInfoFromApex(apexFile, true);
         assertEquals("com.google.android.tzdata", pi.packageName);
+        assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
         assertEquals(1, pi.getLongVersionCode());
         assertEquals(1, pi.applicationInfo.longVersionCode);
         assertNotNull(pi.signingInfo);
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a010cb6..9b79e85 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -390,9 +390,8 @@
                     Settings.Global.POWER_MANAGER_CONSTANTS,
                     Settings.Global.PREFERRED_NETWORK_MODE,
                     Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
-                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED,
-                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED,
+                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED,
                     Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
                     Settings.Global.RADIO_BLUETOOTH,
@@ -482,6 +481,7 @@
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
                     Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
+                    Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
                     Settings.Global.GUP_DEV_ALL_APPS,
                     Settings.Global.GUP_DEV_OPT_IN_APPS,
                     Settings.Global.GUP_DEV_OPT_OUT_APPS,
@@ -574,6 +574,7 @@
                  Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
                  Settings.Secure.ALWAYS_ON_VPN_APP,
                  Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
+                 Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST,
                  Settings.Secure.ANDROID_ID,
                  Settings.Secure.ANR_SHOW_BACKGROUND,
                  Settings.Secure.ASSISTANT,
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index bfbdbc5..8636949 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1711,20 +1711,22 @@
      */
     @Nullable
     public final ColorSpace getColorSpace() {
-        // A reconfigure can change the configuration and rgba16f is
-        // always linear scRGB at this time
-        if (getConfig() == Config.RGBA_F16) {
-            // Reset the color space for potential future reconfigurations
-            mColorSpace = null;
-            return ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
-        }
-
+        checkRecycled("getColorSpace called on a recycled bitmap");
         // Cache the color space retrieval since it can be fairly expensive
         if (mColorSpace == null) {
-            if (nativeIsSRGB(mNativePtr)) {
+            if (nativeIsConfigF16(mNativePtr)) {
+                // an F16 bitmaps is intended to always be linear extended, but due to
+                // inconsistencies in Bitmap.create() functions it is possible to have
+                // rendered into a bitmap in non-linear sRGB.
+                if (nativeIsSRGB(mNativePtr)) {
+                    mColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+                } else {
+                    mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
+                }
+            } else if (nativeIsSRGB(mNativePtr)) {
                 mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
-            } else if (getConfig() == Config.HARDWARE && nativeIsSRGBLinear(mNativePtr)) {
-                mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
+            } else if (nativeIsSRGBLinear(mNativePtr)) {
+                mColorSpace = ColorSpace.get(ColorSpace.Named.LINEAR_SRGB);
             } else {
                 float[] xyz = new float[9];
                 float[] params = new float[7];
@@ -2127,6 +2129,7 @@
     private static native void nativeErase(long nativeBitmap, long colorSpacePtr, long color);
     private static native int nativeRowBytes(long nativeBitmap);
     private static native int nativeConfig(long nativeBitmap);
+    private static native boolean nativeIsConfigF16(long nativeBitmap);
 
     private static native int nativeGetPixel(long nativeBitmap, int x, int y);
     private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 56b1885..4c67513 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -62,10 +62,8 @@
     return displayInfo;
 }
 
-static void queryWideColorGamutPreference(SkColorSpace::Gamut* colorGamut,
-                                          sk_sp<SkColorSpace>* colorSpace, SkColorType* colorType) {
+static void queryWideColorGamutPreference(sk_sp<SkColorSpace>* colorSpace, SkColorType* colorType) {
     if (Properties::isolatedProcess) {
-        *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
         *colorSpace = SkColorSpace::MakeSRGB();
         *colorType = SkColorType::kN32_SkColorType;
         return;
@@ -78,16 +76,13 @@
     LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status);
     switch (wcgDataspace) {
         case ui::Dataspace::DISPLAY_P3:
-            *colorGamut = SkColorSpace::Gamut::kDCIP3_D65_Gamut;
             *colorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
             break;
         case ui::Dataspace::V0_SCRGB:
-            *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
             *colorSpace = SkColorSpace::MakeSRGB();
             break;
         case ui::Dataspace::V0_SRGB:
             // when sRGB is returned, it means wide color gamut is not supported.
-            *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
             *colorSpace = SkColorSpace::MakeSRGB();
             break;
         default:
@@ -112,7 +107,7 @@
         mMaxTextureSize = -1;
 #endif
     mDisplayInfo = QueryDisplayInfo();
-    queryWideColorGamutPreference(&mWideColorGamut, &mWideColorSpace, &mWideColorType);
+    queryWideColorGamutPreference(&mWideColorSpace, &mWideColorType);
 }
 
 int DeviceInfo::maxTextureSize() const {
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 9bcc8e8..2bab5d3 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -38,7 +38,6 @@
     // context or if you are using the HWUI_NULL_GPU
     int maxTextureSize() const;
     const DisplayInfo& displayInfo() const { return mDisplayInfo; }
-    SkColorSpace::Gamut getWideColorGamut() const { return mWideColorGamut; }
     sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
     SkColorType getWideColorType() const { return mWideColorType; }
 
@@ -50,7 +49,6 @@
 
     int mMaxTextureSize;
     DisplayInfo mDisplayInfo;
-    SkColorSpace::Gamut mWideColorGamut;
     sk_sp<SkColorSpace> mWideColorSpace;
     SkColorType mWideColorType;
 };
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 635d0ec..39bfcdd 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -164,15 +164,11 @@
         const SkImageInfo& info = source.info();
         bitmap.allocPixels(
                 SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
-        bitmap.eraseColor(0);
-        if (info.colorType() == kRGBA_F16_SkColorType) {
-            // Drawing RGBA_F16 onto ARGB_8888 is not supported
-            source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
-                              bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
-        } else {
-            SkCanvas canvas(bitmap);
-            canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
-        }
+
+        SkCanvas canvas(bitmap);
+        canvas.drawColor(0);
+        canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
+
         return bitmap;
     }
 }
@@ -253,8 +249,8 @@
         eglDestroySyncKHR(display, fence);
     }
 
-    return Bitmap::createFrom(buffer.get(), bitmap.refColorSpace(), bitmap.alphaType(),
-                              Bitmap::computePalette(bitmap));
+    return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(),
+                              bitmap.alphaType(), Bitmap::computePalette(bitmap));
 }
 
 void HardwareBitmapUploader::terminate() {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 6e0258c..3bbee18 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -133,12 +133,11 @@
 }
 
 
-sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace,
-                                 SkAlphaType alphaType, BitmapPalette palette) {
-    // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can
-    // view the format as RGBA8888.
+sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, SkColorType colorType,
+                                 sk_sp<SkColorSpace> colorSpace, SkAlphaType alphaType,
+                                 BitmapPalette palette) {
     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
-                                         kRGBA_8888_SkColorType, alphaType, colorSpace);
+                                         colorType, alphaType, colorSpace);
     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info, palette));
 }
 
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 2138040..01e4516 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -72,6 +72,7 @@
      * memory that is provided as an input param.
      */
     static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer,
+                                    SkColorType colorType,
                                     sk_sp<SkColorSpace> colorSpace,
                                     SkAlphaType alphaType = kPremul_SkAlphaType,
                                     BitmapPalette palette = BitmapPalette::Unknown);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index cfbb995..570e895 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -167,7 +167,7 @@
 
     if (surface) {
         mRenderThread.requireGlContext();
-        auto newSurface = mEglManager.createSurface(surface, colorMode, mSurfaceColorGamut);
+        auto newSurface = mEglManager.createSurface(surface, colorMode, mSurfaceColorSpace);
         if (!newSurface) {
             return false;
         }
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 47c9094..a00a36f 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -476,11 +476,9 @@
 void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
     if (colorMode == ColorMode::SRGB) {
         mSurfaceColorType = SkColorType::kN32_SkColorType;
-        mSurfaceColorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
         mSurfaceColorSpace = SkColorSpace::MakeSRGB();
     } else if (colorMode == ColorMode::WideColorGamut) {
         mSurfaceColorType = DeviceInfo::get()->getWideColorType();
-        mSurfaceColorGamut = DeviceInfo::get()->getWideColorGamut();
         mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
     } else {
         LOG_ALWAYS_FATAL("Unreachable: unsupported color mode.");
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index e9957df..7381e04 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -116,7 +116,6 @@
 
     renderthread::RenderThread& mRenderThread;
     SkColorType mSurfaceColorType;
-    SkColorSpace::Gamut mSurfaceColorGamut;
     sk_sp<SkColorSpace> mSurfaceColorSpace;
 
 private:
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 53495a7..d0fe022 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -129,7 +129,7 @@
     setSurfaceColorProperties(colorMode);
     if (surface) {
         mVkSurface = mVkManager.createSurface(surface, colorMode, mSurfaceColorSpace,
-                                              mSurfaceColorGamut, mSurfaceColorType);
+                                              mSurfaceColorType);
     }
 
     return mVkSurface != nullptr;
@@ -149,20 +149,8 @@
 
 sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
                                                          SkBitmap& skBitmap) {
-    // TODO: implement this function for Vulkan pipeline
-    // code below is a hack to avoid crashing because of missing HW Bitmap support
-    sp<GraphicBuffer> buffer = new GraphicBuffer(
-            skBitmap.info().width(), skBitmap.info().height(), PIXEL_FORMAT_RGBA_8888,
-            GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
-                    GraphicBuffer::USAGE_SW_READ_NEVER,
-            std::string("SkiaVulkanPipeline::allocateHardwareBitmap pid [") +
-                    std::to_string(getpid()) + "]");
-    status_t error = buffer->initCheck();
-    if (error < 0) {
-        ALOGW("SkiaVulkanPipeline::allocateHardwareBitmap() failed in GraphicBuffer.create()");
-        return nullptr;
-    }
-    return Bitmap::createFrom(buffer, skBitmap.refColorSpace());
+    LOG_ALWAYS_FATAL("Unimplemented");
+    return nullptr;
 }
 
 } /* namespace skiapipeline */
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 8cd97ed..2cc3f36 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -132,11 +132,13 @@
     createPBufferSurface();
     makeCurrent(mPBufferSurface, nullptr, /* force */ true);
 
-    SkColorSpace::Gamut wideColorGamut = DeviceInfo::get()->getWideColorGamut();
+    skcms_Matrix3x3 wideColorGamut;
+    LOG_ALWAYS_FATAL_IF(!DeviceInfo::get()->getWideColorSpace()->toXYZD50(&wideColorGamut),
+                        "Could not get gamut matrix from wideColorSpace");
     bool hasWideColorSpaceExtension = false;
-    if (wideColorGamut == SkColorSpace::Gamut::kDCIP3_D65_Gamut) {
+    if (memcmp(&wideColorGamut, &SkNamedGamut::kDCIP3, sizeof(wideColorGamut)) == 0) {
         hasWideColorSpaceExtension = EglExtensions.displayP3;
-    } else if (wideColorGamut == SkColorSpace::Gamut::kSRGB_Gamut) {
+    } else if (memcmp(&wideColorGamut, &SkNamedGamut::kSRGB, sizeof(wideColorGamut)) == 0) {
         hasWideColorSpaceExtension = EglExtensions.scRGB;
     } else {
         LOG_ALWAYS_FATAL("Unsupported wide color space.");
@@ -297,7 +299,7 @@
 
 Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
                                                      ColorMode colorMode,
-                                                     SkColorSpace::Gamut colorGamut) {
+                                                     sk_sp<SkColorSpace> colorSpace) {
     LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
 
     bool wideColorGamut = colorMode == ColorMode::WideColorGamut && mHasWideColorGamutSupport &&
@@ -330,15 +332,15 @@
     if (EglExtensions.glColorSpace) {
         attribs[0] = EGL_GL_COLORSPACE_KHR;
         if (wideColorGamut) {
-            switch (colorGamut) {
-                case SkColorSpace::Gamut::kDCIP3_D65_Gamut:
-                    attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
-                    break;
-                case SkColorSpace::Gamut::kSRGB_Gamut:
-                    attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
-                    break;
-                default:
-                    LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+            skcms_Matrix3x3 colorGamut;
+            LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
+                                "Could not get gamut matrix from color space");
+            if (memcmp(&colorGamut, &SkNamedGamut::kDCIP3, sizeof(colorGamut)) == 0) {
+                attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
+            } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
+                attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
+            } else {
+                LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
             }
         } else {
             attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 4dd9096..27d41d2 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -49,7 +49,7 @@
     bool hasEglContext();
 
     Result<EGLSurface, EGLint> createSurface(EGLNativeWindowType window, ColorMode colorMode,
-                                             SkColorSpace::Gamut colorGamut);
+                                             sk_sp<SkColorSpace> colorSpace);
     void destroySurface(EGLSurface surface);
 
     void destroy();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 5c6cb9a..1e75202 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -516,10 +516,9 @@
     if (windowWidth != surface->mWindowWidth || windowHeight != surface->mWindowHeight) {
         ColorMode colorMode = surface->mColorMode;
         sk_sp<SkColorSpace> colorSpace = surface->mColorSpace;
-        SkColorSpace::Gamut colorGamut = surface->mColorGamut;
         SkColorType colorType = surface->mColorType;
         destroySurface(surface);
-        *surfaceOut = createSurface(window, colorMode, colorSpace, colorGamut, colorType);
+        *surfaceOut = createSurface(window, colorMode, colorSpace, colorType);
         surface = *surfaceOut;
     }
 
@@ -841,9 +840,12 @@
     }
 
     if (surface->mColorMode == ColorMode::WideColorGamut) {
-        if (surface->mColorGamut == SkColorSpace::Gamut::kSRGB_Gamut) {
+        skcms_Matrix3x3 surfaceGamut;
+        LOG_ALWAYS_FATAL_IF(!surface->mColorSpace->toXYZD50(&surfaceGamut),
+                            "Could not get gamut matrix from color space");
+        if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
             colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
-        } else if (surface->mColorGamut == SkColorSpace::Gamut::kDCIP3_D65_Gamut) {
+        } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
             colorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
         } else {
             LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
@@ -922,7 +924,6 @@
 
 VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
                                             sk_sp<SkColorSpace> surfaceColorSpace,
-                                            SkColorSpace::Gamut surfaceColorGamut,
                                             SkColorType surfaceColorType) {
     initialize();
 
@@ -931,7 +932,7 @@
     }
 
     VulkanSurface* surface = new VulkanSurface(colorMode, window, surfaceColorSpace,
-                                               surfaceColorGamut, surfaceColorType);
+                                               surfaceColorType);
 
     VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
     memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index b06eb82..abe78ef 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -39,9 +39,9 @@
 class VulkanSurface {
 public:
     VulkanSurface(ColorMode colorMode, ANativeWindow* window, sk_sp<SkColorSpace> colorSpace,
-                  SkColorSpace::Gamut colorGamut, SkColorType colorType)
+                  SkColorType colorType)
             : mColorMode(colorMode), mNativeWindow(window), mColorSpace(colorSpace),
-              mColorGamut(colorGamut), mColorType(colorType) {}
+              mColorType(colorType) {}
 
     sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
 
@@ -90,7 +90,6 @@
     int mWindowWidth = 0;
     int mWindowHeight = 0;
     sk_sp<SkColorSpace> mColorSpace;
-    SkColorSpace::Gamut mColorGamut;
     SkColorType mColorType;
     VkSurfaceTransformFlagBitsKHR mTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
     SkMatrix mPreTransform;
@@ -113,7 +112,6 @@
     // VulkanSurface object which is returned.
     VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
                                  sk_sp<SkColorSpace> surfaceColorSpace,
-                                 SkColorSpace::Gamut surfaceColorGamut,
                                  SkColorType surfaceColorType);
 
     // Destroy the VulkanSurface and all associated vulkan objects.
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index ec81f62..2af955f 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -50,7 +50,8 @@
             pixels[4000 + 4 * i + 3] = 255;
         }
         buffer->unlock();
-        sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer, SkColorSpace::MakeSRGB()));
+        sk_sp<Bitmap> hardwareBitmap(Bitmap::createFrom(buffer, kRGBA_8888_SkColorType,
+                                                        SkColorSpace::MakeSRGB()));
         sk_sp<SkShader> hardwareShader(createBitmapShader(*hardwareBitmap));
 
         SkPoint center;
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 4415a59..d14116f 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -45,6 +45,20 @@
     }
 }
 
+SkColorType PixelFormatToColorType(android::PixelFormat format) {
+    switch (format) {
+        case PIXEL_FORMAT_RGBX_8888:    return kRGB_888x_SkColorType;
+        case PIXEL_FORMAT_RGBA_8888:    return kRGBA_8888_SkColorType;
+        case PIXEL_FORMAT_RGBA_FP16:    return kRGBA_F16_SkColorType;
+        case PIXEL_FORMAT_RGB_565:      return kRGB_565_SkColorType;
+        case PIXEL_FORMAT_RGBA_1010102: return kRGBA_1010102_SkColorType;
+        case PIXEL_FORMAT_RGBA_4444:    return kARGB_4444_SkColorType;
+        default:
+            ALOGW("Unsupported PixelFormat: %d, return kUnknown_SkColorType by default", format);
+            return kUnknown_SkColorType;
+    }
+}
+
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
 
     skcms_Matrix3x3 gamut;
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 3880252..b67d10d 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -112,6 +112,7 @@
 }
 
 android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
+ANDROID_API SkColorType PixelFormatToColorType(android::PixelFormat format);
 
 ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
 
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 9b6ad38..9064ebe 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -81,5 +81,5 @@
         "com.android.keyguard",
     ],
 
-    annotation_processors: ["dagger2-compiler-2.19"],
+    plugins: ["dagger2-compiler-2.19"],
 }
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index 052566d..e591ea9 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -65,8 +65,9 @@
         <com.android.systemui.statusbar.car.CarFacetButton
             android:id="@+id/music_nav"
             style="@style/NavigationBarButton"
+            systemui:categories="android.intent.category.APP_MUSIC"
             systemui:icon="@drawable/car_ic_music"
-            systemui:intent="intent:#Intent;component=com.android.car.media/.MediaActivity;launchFlags=0x14000000;end"
+            systemui:intent="intent:#Intent;action=android.car.intent.action.MEDIA_TEMPLATE;launchFlags=0x10000000;end"
             systemui:packages="com.android.car.media"
             systemui:selectedIcon="@drawable/car_ic_music_selected"
             systemui:useMoreIcon="false"
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 74aaf3c..93f6a94 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -47,6 +47,7 @@
 import com.android.internal.widget.LockPatternUtils;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * Utility class to host methods usable in adding a restricted padlock icon and showing admin
@@ -325,7 +326,8 @@
         if (admin == null) {
             return null;
         }
-        if (dpm.getCrossProfileCalendarPackages().isEmpty()) {
+        final Set<String> packages = dpm.getCrossProfileCalendarPackages();
+        if (packages != null && packages.isEmpty()) {
             return admin;
         }
         return null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index 7357fe6..42afb69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.applications;
 
+import android.app.Application;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentFilter;
@@ -123,4 +124,12 @@
         return null;
     }
 
+    /**
+     * Returns a boolean indicating whether the given package is a hidden system module
+     */
+    public static boolean isHiddenSystemModule(Context context, String packageName) {
+        return ApplicationsState.getInstance((Application) context.getApplicationContext())
+            .isHiddenModule(packageName);
+    }
+
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index a936df2..c9fbc7b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -29,6 +29,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.ModuleInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageStats;
@@ -71,6 +72,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
@@ -95,9 +97,14 @@
     static ApplicationsState sInstance;
 
     public static ApplicationsState getInstance(Application app) {
+        return getInstance(app, AppGlobals.getPackageManager());
+    }
+
+    @VisibleForTesting
+    static ApplicationsState getInstance(Application app, IPackageManager iPackageManager) {
         synchronized (sLock) {
             if (sInstance == null) {
-                sInstance = new ApplicationsState(app);
+                sInstance = new ApplicationsState(app, iPackageManager);
             }
             return sInstance;
         }
@@ -132,6 +139,7 @@
     String mCurComputingSizePkg;
     int mCurComputingSizeUserId;
     boolean mSessionsChanged;
+    final HashSet<String> mHiddenModules = new HashSet<>();
 
     // Temporary for dispatching session callbacks.  Only touched by main thread.
     final ArrayList<WeakReference<Session>> mActiveSessions = new ArrayList<>();
@@ -172,11 +180,11 @@
             FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
             FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER;
 
-    private ApplicationsState(Application app) {
+    private ApplicationsState(Application app, IPackageManager iPackageManager) {
         mContext = app;
         mPm = mContext.getPackageManager();
         mDrawableFactory = IconDrawableFactory.newInstance(mContext);
-        mIpm = AppGlobals.getPackageManager();
+        mIpm = iPackageManager;
         mUm = mContext.getSystemService(UserManager.class);
         mStats = mContext.getSystemService(StorageStatsManager.class);
         for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
@@ -194,6 +202,13 @@
         mRetrieveFlags = PackageManager.MATCH_DISABLED_COMPONENTS |
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
 
+        final List<ModuleInfo> moduleInfos = mPm.getInstalledModules(0 /* flags */);
+        for (ModuleInfo info : moduleInfos) {
+            if (info.isHidden()) {
+                mHiddenModules.add(info.getPackageName());
+            }
+        }
+
         /**
          * This is a trick to prevent the foreground thread from being delayed.
          * The problem is that Dalvik monitors are initially spin locks, to keep
@@ -283,6 +298,10 @@
                 }
                 mHaveDisabledApps = true;
             }
+            if (isHiddenModule(info.packageName)) {
+                mApplications.remove(i--);
+                continue;
+            }
             if (!mHaveInstantApps && AppUtils.isInstant(info)) {
                 mHaveInstantApps = true;
             }
@@ -314,10 +333,15 @@
     public boolean haveDisabledApps() {
         return mHaveDisabledApps;
     }
+
     public boolean haveInstantApps() {
         return mHaveInstantApps;
     }
 
+    boolean isHiddenModule(String packageName) {
+        return mHiddenModules.contains(packageName);
+    }
+
     void doPauseIfNeededLocked() {
         if (!mResumed) {
             return;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
index ccec175a..a098ecc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
@@ -18,7 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.shadow.api.Shadow.extract;
@@ -33,12 +35,16 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.ModuleInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.IconDrawableFactory;
 
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -46,11 +52,11 @@
 import com.android.settingslib.applications.ApplicationsState.Session;
 import com.android.settingslib.testutils.shadow.ShadowUserManager;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatchers;
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -78,6 +84,8 @@
 
     /** Class under test */
     private ApplicationsState mApplicationsState;
+    private Session mSession;
+
 
     @Mock
     private Callbacks mCallbacks;
@@ -85,6 +93,8 @@
     private ArgumentCaptor<ArrayList<AppEntry>> mAppEntriesCaptor;
     @Mock
     private StorageStatsManager mStorageStatsManager;
+    @Mock
+    private IPackageManager mPackageManagerService;
 
     @Implements(value = IconDrawableFactory.class)
     public static class ShadowIconDrawableFactory {
@@ -99,6 +109,11 @@
     public static class ShadowPackageManager extends
             org.robolectric.shadows.ShadowApplicationPackageManager {
 
+        // test installed modules, 2 regular, 2 hidden
+        private final String[] mModuleNames = {
+            "test.module.1", "test.hidden.module.2", "test.hidden.module.3", "test.module.4"};
+        private final List<ModuleInfo> mInstalledModules = new ArrayList<>();
+
         @Implementation
         protected ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
             ResolveInfo resolveInfo = new ResolveInfo();
@@ -109,6 +124,16 @@
             return ComponentName.createRelative(resolveInfo.activityInfo.packageName, "foo");
         }
 
+        @Implementation
+        public List<ModuleInfo> getInstalledModules(int flags) {
+            if (mInstalledModules.isEmpty()) {
+                for (String moduleName : mModuleNames) {
+                    mInstalledModules.add(createModuleInfo(moduleName));
+                }
+            }
+            return mInstalledModules;
+        }
+
         public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
                 @PackageManager.ResolveInfoFlags int flags, @UserIdInt int userId) {
             List<ResolveInfo> resolveInfos = new ArrayList<>();
@@ -121,6 +146,15 @@
             resolveInfos.add(resolveInfo);
             return resolveInfos;
         }
+
+        private ModuleInfo createModuleInfo(String packageName) {
+            final ModuleInfo info = new ModuleInfo();
+            info.setName(packageName);
+            info.setPackageName(packageName);
+            // will treat any app with package name that contains "hidden" as hidden module
+            info.setHidden(!TextUtils.isEmpty(packageName) && packageName.contains("hidden"));
+            return info;
+        }
     }
 
     @Before
@@ -136,12 +170,28 @@
         storageStats.codeBytes = 10;
         storageStats.dataBytes = 20;
         storageStats.cacheBytes = 30;
-        when(mStorageStatsManager.queryStatsForPackage(ArgumentMatchers.any(UUID.class),
-                anyString(), ArgumentMatchers.any(UserHandle.class))).thenReturn(storageStats);
+        when(mStorageStatsManager.queryStatsForPackage(any(UUID.class),
+                anyString(), any(UserHandle.class))).thenReturn(storageStats);
+
+        // Set up 3 installed apps, in which 1 is hidden module
+        final List<ApplicationInfo> infos = new ArrayList<>();
+        infos.add(createApplicationInfo("test.package.1"));
+        infos.add(createApplicationInfo("test.hidden.module.2"));
+        infos.add(createApplicationInfo("test.package.3"));
+        when(mPackageManagerService.getInstalledApplications(
+            anyInt() /* flags */, anyInt() /* userId */)).thenReturn(new ParceledListSlice(infos));
 
         ApplicationsState.sInstance = null;
-        mApplicationsState = ApplicationsState.getInstance(RuntimeEnvironment.application);
+        mApplicationsState =
+            ApplicationsState.getInstance(RuntimeEnvironment.application, mPackageManagerService);
         mApplicationsState.clearEntries();
+
+        mSession = mApplicationsState.newSession(mCallbacks);
+    }
+
+    @After
+    public void tearDown() {
+        mSession.onDestroy();
     }
 
     private ApplicationInfo createApplicationInfo(String packageName) {
@@ -187,12 +237,11 @@
 
     @Test
     public void testDefaultSessionLoadsAll() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.onResume();
+        mSession.onResume();
 
         addApp(HOME_PACKAGE_NAME, 1);
         addApp(LAUNCHABLE_PACKAGE_NAME, 2);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -211,17 +260,15 @@
         AppEntry launchableEntry = findAppEntry(appEntries, 2);
         assertThat(launchableEntry.hasLauncherEntry).isTrue();
         assertThat(launchableEntry.launcherEntryEnabled).isTrue();
-        session.onDestroy();
     }
 
     @Test
     public void testCustomSessionLoadsIconsOnly() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS);
-        session.onResume();
+        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS);
+        mSession.onResume();
 
         addApp(LAUNCHABLE_PACKAGE_NAME, 1);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -232,17 +279,15 @@
         assertThat(launchableEntry.icon).isNotNull();
         assertThat(launchableEntry.size).isEqualTo(-1);
         assertThat(launchableEntry.hasLauncherEntry).isFalse();
-        session.onDestroy();
     }
 
     @Test
     public void testCustomSessionLoadsSizesOnly() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_SIZES);
-        session.onResume();
+        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_SIZES);
+        mSession.onResume();
 
         addApp(LAUNCHABLE_PACKAGE_NAME, 1);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -253,17 +298,15 @@
         assertThat(launchableEntry.icon).isNull();
         assertThat(launchableEntry.hasLauncherEntry).isFalse();
         assertThat(launchableEntry.size).isGreaterThan(0L);
-        session.onDestroy();
     }
 
     @Test
     public void testCustomSessionLoadsHomeOnly() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_HOME_APP);
-        session.onResume();
+        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_HOME_APP);
+        mSession.onResume();
 
         addApp(HOME_PACKAGE_NAME, 1);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -275,17 +318,15 @@
         assertThat(launchableEntry.hasLauncherEntry).isFalse();
         assertThat(launchableEntry.size).isEqualTo(-1);
         assertThat(launchableEntry.isHomeApp).isTrue();
-        session.onDestroy();
     }
 
     @Test
     public void testCustomSessionLoadsLeanbackOnly() {
-        Session session = mApplicationsState.newSession(mCallbacks);
-        session.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER);
-        session.onResume();
+        mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER);
+        mSession.onResume();
 
         addApp(LAUNCHABLE_PACKAGE_NAME, 1);
-        session.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
         processAllMessages();
         verify(mCallbacks).onRebuildComplete(mAppEntriesCaptor.capture());
 
@@ -298,6 +339,16 @@
         assertThat(launchableEntry.isHomeApp).isFalse();
         assertThat(launchableEntry.hasLauncherEntry).isTrue();
         assertThat(launchableEntry.launcherEntryEnabled).isTrue();
-        session.onDestroy();
     }
+
+    @Test
+    public void onResume_shouldNotIncludeSystemHiddenModule() {
+        mSession.onResume();
+
+        final List<ApplicationInfo> mApplications = mApplicationsState.mApplications;
+        assertThat(mApplications).hasSize(2);
+        assertThat(mApplications.get(0).packageName).isEqualTo("test.package.1");
+        assertThat(mApplications.get(1).packageName).isEqualTo("test.package.3");
+    }
+
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 850a3c2..aff6f04 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -698,6 +698,9 @@
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
                 GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES);
         dumpSetting(s, p,
+                Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST,
+                GlobalSettingsProto.Gpu.ANGLE_WHITELIST);
+        dumpSetting(s, p,
                 Settings.Global.GPU_DEBUG_LAYER_APP,
                 GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 8be67d9..0a62b7c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -73,7 +73,7 @@
         "com.android.keyguard",
     ],
 
-    annotation_processors: ["dagger2-compiler-2.19"],
+    plugins: ["dagger2-compiler-2.19"],
 }
 
 android_library {
@@ -127,7 +127,7 @@
         "--extra-packages",
         "com.android.keyguard:com.android.systemui",
     ],
-    annotation_processors: ["dagger2-compiler-2.19"],
+    plugins: ["dagger2-compiler-2.19"],
 }
 
 android_app {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
index 0b1dab1..fc84332 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java
@@ -20,14 +20,14 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import java.util.ArrayList;
-
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.annotations.DependsOn;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
+
+import java.util.ArrayList;
 
 @ProvidesInterface(action = NotificationMenuRowPlugin.ACTION,
         version = NotificationMenuRowPlugin.VERSION)
@@ -149,6 +149,12 @@
     public boolean canBeDismissed();
 
     /**
+     * Informs the menu whether dismiss gestures are left-to-right or right-to-left.
+     */
+    default void setDismissRtl(boolean dismissRtl) {
+    }
+
+    /**
      * Determines whether the menu should remain open given its current state, or snap closed.
      * @return true if the menu should remain open, false otherwise.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index b04132d..43ce0b5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -82,7 +82,7 @@
         if ("1".equals(Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE))
                 && mController.getAutoModeRaw() == -1) {
-            mController.setAutoMode(ColorDisplayController.AUTO_MODE_CUSTOM);
+            mController.setAutoMode(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
             Log.i("NightDisplayTile", "Enrolled in forced night display auto mode");
         }
 
@@ -127,7 +127,7 @@
     @Nullable
     private String getSecondaryLabel(boolean isNightLightActivated) {
         switch(mController.getAutoMode()) {
-            case ColorDisplayController.AUTO_MODE_TWILIGHT:
+            case ColorDisplayManager.AUTO_MODE_TWILIGHT:
                 // Auto mode related to sunrise & sunset. If the light is on, it's guaranteed to be
                 // turned off at sunrise. If it's off, it's guaranteed to be turned on at sunset.
                 return isNightLightActivated
@@ -136,7 +136,7 @@
                         : mContext.getString(
                                 R.string.quick_settings_night_secondary_label_on_at_sunset);
 
-            case ColorDisplayController.AUTO_MODE_CUSTOM:
+            case ColorDisplayManager.AUTO_MODE_CUSTOM_TIME:
                 // User-specified time, approximated to the nearest hour.
                 final @StringRes int toggleTimeStringRes;
                 final LocalTime toggleTime;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
new file mode 100644
index 0000000..4944732
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.systemui.statusbar
+
+import android.annotation.ColorInt
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Point
+import android.graphics.Rect
+import android.renderscript.Allocation
+import android.renderscript.Element
+import android.renderscript.RenderScript
+import android.renderscript.ScriptIntrinsicBlur
+import android.util.MathUtils
+import com.android.internal.graphics.ColorUtils
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+private const val COLOR_ALPHA = (255 * 0.7f).toInt()
+private const val BLUR_RADIUS = 25f
+private const val DOWNSAMPLE = 6
+
+@Singleton
+class MediaArtworkProcessor @Inject constructor() {
+
+    private val mTmpSize = Point()
+    private var mArtworkCache: Bitmap? = null
+
+    fun processArtwork(context: Context, artwork: Bitmap, @ColorInt color: Int): Bitmap {
+        if (mArtworkCache != null) {
+            return mArtworkCache!!
+        }
+
+        context.display.getSize(mTmpSize)
+        val renderScript = RenderScript.create(context)
+        val rect = Rect(0, 0,artwork.width, artwork.height)
+        MathUtils.fitRect(rect, Math.max(mTmpSize.x / DOWNSAMPLE, mTmpSize.y / DOWNSAMPLE))
+        val inBitmap = Bitmap.createScaledBitmap(artwork, rect.width(), rect.height(),
+                true /* filter */)
+        val input = Allocation.createFromBitmap(renderScript, inBitmap,
+                Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_GRAPHICS_TEXTURE)
+        val outBitmap = Bitmap.createBitmap(inBitmap.width, inBitmap.height,
+                Bitmap.Config.ARGB_8888)
+        val output = Allocation.createFromBitmap(renderScript, outBitmap)
+        val blur = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript))
+        blur.setRadius(BLUR_RADIUS)
+        blur.setInput(input)
+        blur.forEach(output)
+        output.copyTo(outBitmap)
+
+        input.destroy()
+        output.destroy()
+        inBitmap.recycle()
+
+        val canvas = Canvas(outBitmap)
+        canvas.drawColor(ColorUtils.setAlphaComponent(color, COLOR_ALPHA))
+        return outBitmap
+    }
+
+    fun clearCache() {
+        mArtworkCache?.recycle()
+        mArtworkCache = null
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index f46ded4d..c25b7cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -39,6 +39,9 @@
 
     boolean isCurrentProfile(int userId);
 
+    /** Adds a listener to be notified when the current user changes. */
+    void addUserChangedListener(UserChangedListener listener);
+
     void destroy();
 
     SparseArray<UserInfo> getCurrentProfiles();
@@ -58,4 +61,9 @@
     boolean needsRedaction(NotificationEntry entry);
 
     boolean userAllowsPrivateNotificationsInPublic(int currentUserId);
+
+    /** Notified when the current user changes. */
+    interface UserChangedListener {
+        void onUserChanged(int userId);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index d2ce31d..4f9d428 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -55,6 +55,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Handles keeping track of the current user, profiles, and various things related to hiding
@@ -78,6 +80,7 @@
     private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
     private final UserManager mUserManager;
     private final IStatusBarService mBarService;
+    private final List<UserChangedListener> mListeners = new ArrayList<>();
 
     private boolean mShowLockscreenNotifications;
     private boolean mAllowLockscreenRemoteInput;
@@ -112,6 +115,10 @@
                 updatePublicMode();
                 mPresenter.onUserSwitched(mCurrentUserId);
                 getEntryManager().getNotificationData().filterAndSort();
+
+                for (UserChangedListener listener : mListeners) {
+                    listener.onUserChanged(mCurrentUserId);
+                }
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                 updateCurrentProfilesCache();
             } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
@@ -502,6 +509,10 @@
         }
     }
 
+    @Override
+    public void addUserChangedListener(UserChangedListener listener) {
+        mListeners.add(listener);
+    }
 
 //    public void updatePublicMode() {
 //        //TODO: I think there may be a race condition where mKeyguardViewManager.isShowing() returns
@@ -541,6 +552,7 @@
     public void destroy() {
         mContext.unregisterReceiver(mBaseBroadcastReceiver);
         mContext.unregisterReceiver(mAllUsersReceiver);
+        mListeners.clear();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 7412702..98a3a54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -25,6 +25,7 @@
 import android.app.Notification;
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -102,6 +103,7 @@
     private final Context mContext;
     private final MediaSessionManager mMediaSessionManager;
     private final ArrayList<MediaListener> mMediaListeners;
+    private final MediaArtworkProcessor mMediaArtworkProcessor;
 
     protected NotificationPresenter mPresenter;
     private MediaController mMediaController;
@@ -133,6 +135,7 @@
             if (DEBUG_MEDIA) {
                 Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
             }
+            mMediaArtworkProcessor.clearCache();
             mMediaMetadata = metadata;
             dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */);
         }
@@ -143,8 +146,10 @@
             Context context,
             Lazy<ShadeController> shadeController,
             Lazy<StatusBarWindowController> statusBarWindowController,
-            NotificationEntryManager notificationEntryManager) {
+            NotificationEntryManager notificationEntryManager,
+            MediaArtworkProcessor mediaArtworkProcessor) {
         mContext = context;
+        mMediaArtworkProcessor = mediaArtworkProcessor;
         mMediaListeners = new ArrayList<>();
         mMediaSessionManager
                 = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
@@ -366,6 +371,7 @@
     }
 
     private void clearCurrentMediaNotificationSession() {
+        mMediaArtworkProcessor.clearCache();
         mMediaMetadata = null;
         if (mMediaController != null) {
             if (DEBUG_MEDIA) {
@@ -418,7 +424,19 @@
                 // might still be null
             }
             if (artworkBitmap != null) {
-                artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
+                int notificationColor;
+                synchronized (mEntryManager.getNotificationData()) {
+                    NotificationEntry entry = mEntryManager.getNotificationData()
+                            .get(mMediaNotificationKey);
+                    if (entry == null || entry.getRow() == null) {
+                        notificationColor = Color.TRANSPARENT;
+                    } else {
+                        notificationColor = entry.getRow().calculateBgColor();
+                    }
+                }
+                Bitmap bmp = mMediaArtworkProcessor.processArtwork(mContext, artworkBitmap,
+                        notificationColor);
+                artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), bmp);
             }
         }
         boolean allowWhenShade = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 296c061..bed2426 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -3092,6 +3092,11 @@
         }
     }
 
+    /** Sets whether dismiss gestures are right-to-left (instead of left-to-right). */
+    public void setDismissRtl(boolean dismissRtl) {
+        mMenuRow.setDismissRtl(dismissRtl);
+    }
+
     private static class NotificationViewState extends ExpandableViewState {
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index d97162c..eafaba8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -78,6 +78,8 @@
     private ArrayList<MenuItem> mRightMenuItems;
     private final Map<View, MenuItem> mMenuItemsByView = new ArrayMap<>();
     private OnMenuEventListener mMenuListener;
+    private boolean mDismissRtl;
+    private boolean mIsForeground;
 
     private ValueAnimator mFadeAnimator;
     private boolean mAnimating;
@@ -238,6 +240,8 @@
     }
 
     private void createMenuViews(boolean resetState, final boolean isForeground) {
+        mIsForeground = isForeground;
+
         final Resources res = mContext.getResources();
         mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
         mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
@@ -268,10 +272,11 @@
             mRightMenuItems.add(mAppOpsItem);
             mLeftMenuItems.addAll(mRightMenuItems);
         } else {
-            mRightMenuItems.add(mInfoItem);
-            mRightMenuItems.add(mAppOpsItem);
+            ArrayList<MenuItem> menuItems = mDismissRtl ? mLeftMenuItems : mRightMenuItems;
+            menuItems.add(mInfoItem);
+            menuItems.add(mAppOpsItem);
             if (!isForeground) {
-                mRightMenuItems.add(mSnoozeItem);
+                menuItems.add(mSnoozeItem);
             }
         }
 
@@ -729,6 +734,14 @@
         return getParent().canViewBeDismissed();
     }
 
+    @Override
+    public void setDismissRtl(boolean dismissRtl) {
+        mDismissRtl = dismissRtl;
+        if (mMenuContainer != null) {
+            createMenuViews(true, mIsForeground);
+        }
+    }
+
     public static class NotificationMenuItem implements MenuItem {
         View mMenuView;
         GutsContent mGutsContent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 2129b81..8d57ea5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -174,6 +174,7 @@
     private final boolean mShouldDrawNotificationBackground;
     private boolean mLowPriorityBeforeSpeedBump;
     private final boolean mAllowLongPress;
+    private boolean mDismissRtl;
 
     private float mExpandedHeight;
     private int mOwnScrollY;
@@ -533,8 +534,10 @@
         tunerService.addTunable((key, newValue) -> {
             if (key.equals(LOW_PRIORITY)) {
                 mLowPriorityBeforeSpeedBump = "1".equals(newValue);
+            } else if (key.equals(Settings.Secure.NOTIFICATION_DISMISS_RTL)) {
+                updateDismissRtlSetting("1".equals(newValue));
             }
-        }, LOW_PRIORITY);
+        }, LOW_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL);
 
         mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
@@ -548,6 +551,16 @@
         });
     }
 
+    private void updateDismissRtlSetting(boolean dismissRtl) {
+        mDismissRtl = dismissRtl;
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child instanceof ExpandableNotificationRow) {
+                ((ExpandableNotificationRow) child).setDismissRtl(dismissRtl);
+            }
+        }
+    }
+
     @Override
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     protected void onFinishInflate() {
@@ -3255,6 +3268,9 @@
         generateAddAnimation(child, false /* fromMoreCard */);
         updateAnimationState(child);
         updateChronometerForChild(child);
+        if (child instanceof ExpandableNotificationRow) {
+            ((ExpandableNotificationRow) child).setDismissRtl(mDismissRtl);
+        }
         if (ANCHOR_SCROLLING) {
             // TODO: once we're recycling this will need to check the adapter position of the child
             if (child == getFirstChildNotGone() && (isScrolledToTop() || !mIsExpanded)) {
@@ -6315,7 +6331,7 @@
         public boolean canChildBeDismissedInDirection(View v, boolean isRightOrDown) {
             boolean isValidDirection;
             if (NotificationUtils.useNewInterruptionModel(mContext)) {
-                isValidDirection = isLayoutRtl() ? !isRightOrDown : isRightOrDown;
+                isValidDirection = mDismissRtl ? !isRightOrDown : isRightOrDown;
             } else {
                 isValidDirection = true;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index fac4dbb..b96c55b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -168,8 +168,8 @@
 
         @Override
         public void onAutoModeChanged(int autoMode) {
-            if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM
-                    || autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
+            if (autoMode == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME
+                    || autoMode == ColorDisplayManager.AUTO_MODE_TWILIGHT) {
                 addNightTile();
             }
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index c0f7f0c..1ded835 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -85,7 +85,7 @@
             return;
         }
         mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
-                ColorDisplayController.AUTO_MODE_TWILIGHT);
+                ColorDisplayManager.AUTO_MODE_TWILIGHT);
         verify(mQsTileHost).addTile("night");
     }
 
@@ -95,7 +95,7 @@
             return;
         }
         mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
-                ColorDisplayController.AUTO_MODE_CUSTOM);
+                ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
         verify(mQsTileHost).addTile("night");
     }
 
@@ -105,7 +105,7 @@
             return;
         }
         mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
-                ColorDisplayController.AUTO_MODE_DISABLED);
+                ColorDisplayManager.AUTO_MODE_DISABLED);
         verify(mQsTileHost, never()).addTile("night");
     }
 }
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 12f666e..c063e82 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -965,6 +965,10 @@
 
   // NetworkAgent Wifi usability score of connected wifi
   optional int32 last_wifi_usability_score = 15 [default = -1];
+
+  // Prediction horizon (in second) of Wifi usability score provided by external
+  // system app
+  optional int32 last_prediction_horizon_sec = 16 [default = -1];
 }
 
 // Wi-Fi Aware metrics
@@ -1682,6 +1686,10 @@
   // NetworkAgent wifi usability score of connected wifi.
   // Defaults to -1 if the score was never set.
   optional int32 last_wifi_usability_score = 11 [default = -1];
+
+  // Prediction horizon (in second) of Wifi usability score provided by external
+  // system app
+  optional int32 last_prediction_horizon_sec = 12 [default = -1];
 }
 
 message PasspointProfileTypeCount {
@@ -1814,6 +1822,10 @@
 
   // The total number of beacons received from the last radio chip reset
   optional int64 total_beacon_rx = 22;
+
+  // Prediction horizon (in second) of Wifi usability score provided by external
+  // system app
+  optional int32 prediction_horizon_sec = 23;
 }
 
 message WifiUsabilityStats {
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 4f58d79..303734a 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.backup.BackupManagerService.TAG;
 
+import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.admin.DevicePolicyManager;
@@ -41,9 +42,10 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.provider.Settings;
+import android.os.UserManager;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.DumpUtils;
 
 import java.io.File;
@@ -75,19 +77,25 @@
  * system user is unlocked before any other users.
  */
 public class Trampoline extends IBackupManager.Stub {
-    // When this file is present, the backup service is inactive.
+    /**
+     * Name of file that disables the backup service. If this file exists, then backup is disabled
+     * for all users.
+     */
     private static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress";
 
+    /**
+     * Name of file for non-system users that enables the backup service for the user. Backup is
+     * disabled by default in non-system users.
+     */
+    private static final String BACKUP_ACTIVATED_FILENAME = "backup-activated";
+
     // Product-level suppression of backup/restore.
     private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
 
     private static final String BACKUP_THREAD = "backup";
 
-    /** Values for setting {@link Settings.Global#BACKUP_MULTI_USER_ENABLED} */
-    private static final int MULTI_USER_DISABLED = 0;
-    private static final int MULTI_USER_ENABLED = 1;
-
     private final Context mContext;
+    private final UserManager mUserManager;
 
     private final boolean mGlobalDisable;
     // Lock to write backup suppress files.
@@ -104,20 +112,13 @@
         mHandlerThread = new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND);
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
+        mUserManager = UserManager.get(context);
     }
 
     protected boolean isBackupDisabled() {
         return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
     }
 
-    private boolean isMultiUserEnabled() {
-        return Settings.Global.getInt(
-                mContext.getContentResolver(),
-                Settings.Global.BACKUP_MULTI_USER_ENABLED,
-                MULTI_USER_DISABLED)
-                == MULTI_USER_ENABLED;
-    }
-
     protected int binderGetCallingUserId() {
         return Binder.getCallingUserHandle().getIdentifier();
     }
@@ -126,21 +127,65 @@
         return Binder.getCallingUid();
     }
 
-    protected File getSuppressFileForUser(int userId) {
-        return new File(UserBackupManagerFiles.getBaseStateDir(userId),
+    /** Stored in the system user's directory. */
+    protected File getSuppressFileForSystemUser() {
+        return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
                 BACKUP_SUPPRESS_FILENAME);
     }
 
-    protected void createBackupSuppressFileForUser(int userId) throws IOException {
-        synchronized (mStateLock) {
-            getSuppressFileForUser(userId).getParentFile().mkdirs();
-            getSuppressFileForUser(userId).createNewFile();
+    /** Stored in the system user's directory and the file is indexed by the user it refers to. */
+    protected File getActivatedFileForNonSystemUser(int userId) {
+        return new File(UserBackupManagerFiles.getBaseStateDir(UserHandle.USER_SYSTEM),
+                BACKUP_ACTIVATED_FILENAME + "-" + userId);
+    }
+
+    private void createFile(File file) throws IOException {
+        if (file.exists()) {
+            return;
+        }
+
+        file.getParentFile().mkdirs();
+        if (!file.createNewFile()) {
+            Slog.w(TAG, "Failed to create file " + file.getPath());
         }
     }
 
-    private void deleteBackupSuppressFileForUser(int userId) {
-        if (!getSuppressFileForUser(userId).delete()) {
-            Slog.w(TAG, "Failed deleting backup suppressed file for user: " + userId);
+    private void deleteFile(File file) {
+        if (!file.exists()) {
+            return;
+        }
+
+        if (!file.delete()) {
+            Slog.w(TAG, "Failed to delete file " + file.getPath());
+        }
+    }
+
+    /**
+     * Deactivates the backup service for user {@code userId}. If this is the system user, it
+     * creates a suppress file which disables backup for all users. If this is a non-system user, it
+     * only deactivates backup for that user by deleting its activate file.
+     */
+    @GuardedBy("mStateLock")
+    private void deactivateBackupForUserLocked(int userId) throws IOException {
+        if (userId == UserHandle.USER_SYSTEM) {
+            createFile(getSuppressFileForSystemUser());
+        } else {
+            deleteFile(getActivatedFileForNonSystemUser(userId));
+        }
+    }
+
+    /**
+     * Enables the backup service for user {@code userId}. If this is the system user, it deletes
+     * the suppress file. If this is a non-system user, it creates the user's activate file. Note,
+     * deleting the suppress file does not automatically enable backup for non-system users, they
+     * need their own activate file in order to participate in the service.
+     */
+    @GuardedBy("mStateLock")
+    private void activateBackupForUserLocked(int userId) throws IOException {
+        if (userId == UserHandle.USER_SYSTEM) {
+            deleteFile(getSuppressFileForSystemUser());
+        } else {
+            createFile(getActivatedFileForNonSystemUser(userId));
         }
     }
 
@@ -148,24 +193,31 @@
     // admin (device owner or profile owner).
     private boolean isUserReadyForBackup(int userId) {
         return mService != null && mService.getServiceUsers().get(userId) != null
-                && !isBackupSuppressedForUser(userId);
+                && isBackupActivatedForUser(userId);
     }
 
-    private boolean isBackupSuppressedForUser(int userId) {
-        // If backup is disabled for system user, it's disabled for all other users on device.
-        if (getSuppressFileForUser(UserHandle.USER_SYSTEM).exists()) {
-            return true;
+    /**
+     * Backup is activated for the system user if the suppress file does not exist. Backup is
+     * activated for non-system users if the suppress file does not exist AND the user's activated
+     * file exists.
+     */
+    private boolean isBackupActivatedForUser(int userId) {
+        if (getSuppressFileForSystemUser().exists()) {
+            return false;
         }
-        if (userId != UserHandle.USER_SYSTEM) {
-            return getSuppressFileForUser(userId).exists();
-        }
-        return false;
+
+        return userId == UserHandle.USER_SYSTEM
+                || getActivatedFileForNonSystemUser(userId).exists();
     }
 
     protected Context getContext() {
         return mContext;
     }
 
+    protected UserManager getUserManager() {
+        return mUserManager;
+    }
+
     protected BackupManagerService createBackupManagerService() {
         return new BackupManagerService(mContext, this, mHandlerThread);
     }
@@ -198,23 +250,17 @@
 
     /**
      * Called from {@link BackupManagerService.Lifecycle} when a user {@code userId} is unlocked.
-     * Starts the backup service for this user if it's the system user or if the service supports
-     * multi-user. Offloads work onto the handler thread {@link #mHandlerThread} to keep unlock time
-     * low.
+     * Starts the backup service for this user if backup is active for this user. Offloads work onto
+     * the handler thread {@link #mHandlerThread} to keep unlock time low.
      */
     void unlockUser(int userId) {
-        if (userId != UserHandle.USER_SYSTEM && !isMultiUserEnabled()) {
-            Slog.i(TAG, "Multi-user disabled, cannot start service for user: " + userId);
-            return;
-        }
-
         postToHandler(() -> startServiceForUser(userId));
     }
 
     private void startServiceForUser(int userId) {
         // We know that the user is unlocked here because it is called from setBackupServiceActive
         // and unlockUser which have these guarantees. So we can check if the file exists.
-        if (mService != null && !isBackupSuppressedForUser(userId)) {
+        if (mService != null && isBackupActivatedForUser(userId)) {
             Slog.i(TAG, "Starting service for user: " + userId);
             mService.startServiceForUser(userId);
         }
@@ -225,11 +271,6 @@
      * Offloads work onto the handler thread {@link #mHandlerThread} to keep stopping time low.
      */
     void stopUser(int userId) {
-        if (userId != UserHandle.USER_SYSTEM && !isMultiUserEnabled()) {
-            Slog.i(TAG, "Multi-user disabled, cannot stop service for user: " + userId);
-            return;
-        }
-
         postToHandler(
                 () -> {
                     if (mService != null) {
@@ -240,45 +281,63 @@
     }
 
     /**
-     * Only privileged callers should be changing the backup state. This method only acts on {@link
-     * UserHandle#USER_SYSTEM} and is a no-op if passed non-system users. Deactivating backup in the
-     * system user also deactivates backup in all users.
-     *
-     * This call will only work if the calling {@code userID} is unlocked.
+     * The system user and managed profiles can only be acted on by callers in the system or root
+     * processes. Other users can be acted on by callers who have both android.permission.BACKUP and
+     * android.permission.INTERACT_ACROSS_USERS_FULL permissions.
+     */
+    private void enforcePermissionsOnUser(int userId) throws SecurityException {
+        boolean isRestrictedUser =
+                userId == UserHandle.USER_SYSTEM
+                        || getUserManager().getUserInfo(userId).isManagedProfile();
+
+        if (isRestrictedUser) {
+            int caller = binderGetCallingUid();
+            if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) {
+                throw new SecurityException("No permission to configure backup activity");
+            }
+        } else {
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.BACKUP, "No permission to configure backup activity");
+            mContext.enforceCallingOrSelfPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "No permission to configure backup activity");
+        }
+    }
+
+    /**
+     * Only privileged callers should be changing the backup state. Deactivating backup in the
+     * system user also deactivates backup in all users. We are not guaranteed that {@code userId}
+     * is unlocked at this point yet, so handle both cases.
      */
     public void setBackupServiceActive(int userId, boolean makeActive) {
-        int caller = binderGetCallingUid();
-        if (caller != Process.SYSTEM_UID && caller != Process.ROOT_UID) {
-            throw new SecurityException("No permission to configure backup activity");
-        }
+        enforcePermissionsOnUser(userId);
 
         if (mGlobalDisable) {
             Slog.i(TAG, "Backup service not supported");
             return;
         }
 
-        if (userId != UserHandle.USER_SYSTEM) {
-            Slog.i(TAG, "Cannot set backup service activity for non-system user: " + userId);
-            return;
-        }
-
-        if (makeActive == isBackupServiceActive(userId)) {
-            Slog.i(TAG, "No change in backup service activity");
-            return;
-        }
-
         synchronized (mStateLock) {
             Slog.i(TAG, "Making backup " + (makeActive ? "" : "in") + "active");
             if (makeActive) {
                 if (mService == null) {
                     mService = createBackupManagerService();
                 }
-                deleteBackupSuppressFileForUser(userId);
-                startServiceForUser(userId);
+                try {
+                    activateBackupForUserLocked(userId);
+                } catch (IOException e) {
+                    Slog.e(TAG, "Unable to persist backup service activity");
+                }
+
+                // If the user is unlocked, we can start the backup service for it. Otherwise we
+                // will start the service when the user is unlocked as part of its unlock callback.
+                if (getUserManager().isUserUnlocked(userId)) {
+                    startServiceForUser(userId);
+                }
             } else {
                 try {
                     //TODO(b/121198006): what if this throws an exception?
-                    createBackupSuppressFileForUser(userId);
+                    deactivateBackupForUserLocked(userId);
                 } catch (IOException e) {
                     Slog.e(TAG, "Unable to persist backup service inactivity");
                 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8b32afb..1519c17 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -515,7 +515,8 @@
 
     // A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
     // the world when it changes.
-    private final ProxyTracker mProxyTracker;
+    @VisibleForTesting
+    protected final ProxyTracker mProxyTracker;
 
     final private SettingsObserver mSettingsObserver;
 
@@ -824,7 +825,7 @@
         mPolicyManagerInternal = checkNotNull(
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
-        mProxyTracker = new ProxyTracker(context, mHandler, EVENT_PROXY_HAS_CHANGED);
+        mProxyTracker = makeProxyTracker();
 
         mNetd = NetdService.getInstance();
         mKeyStore = KeyStore.getInstance();
@@ -990,6 +991,11 @@
                 deps);
     }
 
+    @VisibleForTesting
+    protected ProxyTracker makeProxyTracker() {
+        return new ProxyTracker(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
+    }
+
     private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
         final NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -1878,6 +1884,12 @@
                 "ConnectivityService");
     }
 
+    private void enforceControlAlwaysOnVpnPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
+                "ConnectivityService");
+    }
+
     private void enforceNetworkStackSettingsOrSetup() {
         enforceAnyPermissionOf(
             android.Manifest.permission.NETWORK_SETTINGS,
@@ -1885,6 +1897,12 @@
             android.Manifest.permission.NETWORK_STACK);
     }
 
+    private void enforceNetworkStackPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.NETWORK_STACK,
+                "ConnectivityService");
+    }
+
     private boolean checkNetworkStackPermission() {
         return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.NETWORK_STACK);
@@ -3724,20 +3742,46 @@
         }
     }
 
+    /**
+     * Returns information about the proxy a certain network is using. If given a null network, it
+     * it will return the proxy for the bound network for the caller app or the default proxy if
+     * none.
+     *
+     * @param network the network we want to get the proxy information for.
+     * @return Proxy information if a network has a proxy configured, or otherwise null.
+     */
     @Override
     public ProxyInfo getProxyForNetwork(Network network) {
-        if (network == null) return mProxyTracker.getDefaultProxy();
         final ProxyInfo globalProxy = mProxyTracker.getGlobalProxy();
         if (globalProxy != null) return globalProxy;
-        if (!NetworkUtils.queryUserAccess(Binder.getCallingUid(), network.netId)) return null;
-        // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
-        // caller may not have.
+        if (network == null) {
+            // Get the network associated with the calling UID.
+            final Network activeNetwork = getActiveNetworkForUidInternal(Binder.getCallingUid(),
+                    true);
+            if (activeNetwork == null) {
+                return null;
+            }
+            return getLinkPropertiesProxyInfo(activeNetwork);
+        } else if (queryUserAccess(Binder.getCallingUid(), network.netId)) {
+            // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
+            // caller may not have.
+            return getLinkPropertiesProxyInfo(network);
+        }
+        // No proxy info available if the calling UID does not have network access.
+        return null;
+    }
+
+    @VisibleForTesting
+    protected boolean queryUserAccess(int uid, int netId) {
+        return NetworkUtils.queryUserAccess(uid, netId);
+    }
+
+    private ProxyInfo getLinkPropertiesProxyInfo(Network network) {
         final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
         if (nai == null) return null;
         synchronized (nai) {
-            final ProxyInfo proxyInfo = nai.linkProperties.getHttpProxy();
-            if (proxyInfo == null) return null;
-            return new ProxyInfo(proxyInfo);
+            final ProxyInfo linkHttpProxy = nai.linkProperties.getHttpProxy();
+            return linkHttpProxy == null ? null : new ProxyInfo(linkHttpProxy);
         }
     }
 
@@ -3761,11 +3805,10 @@
         mProxyTracker.setDefaultProxy(proxy);
     }
 
-    // If the proxy has changed from oldLp to newLp, resend proxy broadcast with default proxy.
-    // This method gets called when any network changes proxy, but the broadcast only ever contains
-    // the default proxy (even if it hasn't changed).
-    // TODO: Deprecate the broadcast extras as they aren't necessarily applicable in a multi-network
-    // world where an app might be bound to a non-default network.
+    // If the proxy has changed from oldLp to newLp, resend proxy broadcast. This method gets called
+    // when any network changes proxy.
+    // TODO: Remove usage of broadcast extras as they are deprecated and not applicable in a
+    // multi-network world where an app might be bound to a non-default network.
     private void updateProxy(LinkProperties newLp, LinkProperties oldLp) {
         ProxyInfo newProxyInfo = newLp == null ? null : newLp.getHttpProxy();
         ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
@@ -4116,8 +4159,9 @@
     }
 
     @Override
-    public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown) {
-        enforceConnectivityInternalPermission();
+    public boolean setAlwaysOnVpnPackage(
+            int userId, String packageName, boolean lockdown, List<String> lockdownWhitelist) {
+        enforceControlAlwaysOnVpnPermission();
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
@@ -4131,11 +4175,11 @@
                 Slog.w(TAG, "User " + userId + " has no Vpn configuration");
                 return false;
             }
-            if (!vpn.setAlwaysOnPackage(packageName, lockdown)) {
+            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist)) {
                 return false;
             }
             if (!startAlwaysOnVpn(userId)) {
-                vpn.setAlwaysOnPackage(null, false);
+                vpn.setAlwaysOnPackage(null, false, null);
                 return false;
             }
         }
@@ -4144,7 +4188,7 @@
 
     @Override
     public String getAlwaysOnVpnPackage(int userId) {
-        enforceConnectivityInternalPermission();
+        enforceControlAlwaysOnVpnPermission();
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
@@ -4158,6 +4202,36 @@
     }
 
     @Override
+    public boolean isVpnLockdownEnabled(int userId) {
+        enforceControlAlwaysOnVpnPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                return false;
+            }
+            return vpn.getLockdown();
+        }
+    }
+
+    @Override
+    public List<String> getVpnLockdownWhitelist(int userId) {
+        enforceControlAlwaysOnVpnPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                return null;
+            }
+            return vpn.getLockdownWhitelist();
+        }
+    }
+
+    @Override
     public int checkMobileProvisioning(int suggestedTimeOutMs) {
         // TODO: Remove?  Any reason to trigger a provisioning check?
         return -1;
@@ -4386,7 +4460,7 @@
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
                 Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user "
                         + userId);
-                vpn.setAlwaysOnPackage(null, false);
+                vpn.setAlwaysOnPackage(null, false, null);
             }
         }
     }
@@ -5932,12 +6006,6 @@
             }
             scheduleUnvalidatedPrompt(networkAgent);
 
-            if (networkAgent.isVPN()) {
-                // Temporarily disable the default proxy (not global).
-                mProxyTracker.setDefaultProxyEnabled(false);
-                // TODO: support proxy per network.
-            }
-
             // Whether a particular NetworkRequest listen should cause signal strength thresholds to
             // be communicated to a particular NetworkAgent depends only on the network's immutable,
             // capabilities, so it only needs to be done once on initial connect, not every time the
@@ -5956,10 +6024,16 @@
         } else if (state == NetworkInfo.State.DISCONNECTED) {
             networkAgent.asyncChannel.disconnect();
             if (networkAgent.isVPN()) {
-                mProxyTracker.setDefaultProxyEnabled(true);
                 updateUids(networkAgent, networkAgent.networkCapabilities, null);
             }
             disconnectAndDestroyNetwork(networkAgent);
+            if (networkAgent.isVPN()) {
+                // As the active or bound network changes for apps, broadcast the default proxy, as
+                // apps may need to update their proxy data. This is called after disconnecting from
+                // VPN to make sure we do not broadcast the old proxy data.
+                // TODO(b/122649188): send the broadcast only to VPN users.
+                mProxyTracker.sendProxyBroadcast();
+            }
         } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
                 state == NetworkInfo.State.SUSPENDED) {
             // going into or coming out of SUSPEND: re-score and notify
@@ -6266,7 +6340,7 @@
             synchronized (mVpns) {
                 final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
                 if (alwaysOnPackage != null) {
-                    setAlwaysOnVpnPackage(userId, null, false);
+                    setAlwaysOnVpnPackage(userId, null, false, null);
                     setVpnPackageAuthorization(alwaysOnPackage, userId, false);
                 }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index dd2b33a..d025d73 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -16,13 +16,19 @@
 
 package com.android.server.am;
 
+import static android.provider.DeviceConfig.ActivityManager.KEY_MAX_CACHED_PROCESSES;
+
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
 
+import android.app.ActivityThread;
 import android.content.ContentResolver;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.OnPropertyChangedListener;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.KeyValueListParser;
 import android.util.Slog;
 
@@ -34,7 +40,6 @@
 final class ActivityManagerConstants extends ContentObserver {
 
     // Key names stored in the settings value.
-    private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
     private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
     private static final String KEY_FGSERVICE_MIN_SHOWN_TIME
             = "fgservice_min_shown_time";
@@ -69,13 +74,6 @@
     static final String KEY_PROCESS_START_ASYNC = "process_start_async";
     static final String KEY_MEMORY_INFO_THROTTLE_TIME = "memory_info_throttle_time";
     static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
-    static final String KEY_USE_COMPACTION = "use_compaction";
-    static final String KEY_COMPACT_ACTION_1 = "compact_action_1";
-    static final String KEY_COMPACT_ACTION_2 = "compact_action_2";
-    static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1";
-    static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2";
-    static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3";
-    static final String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -106,13 +104,6 @@
     private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
     private static final long DEFAULT_MEMORY_INFO_THROTTLE_TIME = 5*60*1000;
     private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000;
-    private static final boolean DEFAULT_USE_COMPACTION = false;
-    public static final int DEFAULT_COMPACT_ACTION_1 = 1;
-    public static final int DEFAULT_COMPACT_ACTION_2 = 3;
-    public static final long DEFAULT_COMPACT_THROTTLE_1 = 5000;
-    public static final long DEFAULT_COMPACT_THROTTLE_2 = 10000;
-    public static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
-    public static final long DEFAULT_COMPACT_THROTTLE_4 = 10000;
 
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -232,23 +223,6 @@
     // this long.
     public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION;
 
-    // Use compaction for background apps.
-    public boolean USE_COMPACTION = DEFAULT_USE_COMPACTION;
-
-    // Action for compactAppSome.
-    public int COMPACT_ACTION_1 = DEFAULT_COMPACT_ACTION_1;
-    // Action for compactAppFull;
-    public int COMPACT_ACTION_2 = DEFAULT_COMPACT_ACTION_2;
-
-    // How long we'll skip second compactAppSome after first compactAppSome
-    public long COMPACT_THROTTLE_1 = DEFAULT_COMPACT_THROTTLE_1;
-    // How long we'll skip compactAppSome after compactAppFull
-    public long COMPACT_THROTTLE_2 = DEFAULT_COMPACT_THROTTLE_2;
-    // How long we'll skip compactAppFull after compactAppSome
-    public long COMPACT_THROTTLE_3 = DEFAULT_COMPACT_THROTTLE_3;
-    // How long we'll skip second compactAppFull after first compactAppFull
-    public long COMPACT_THROTTLE_4 = DEFAULT_COMPACT_THROTTLE_4;
-
     // Indicates whether the activity starts logging is enabled.
     // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
     volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -295,10 +269,19 @@
                 Settings.Global.getUriFor(
                         Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED);
 
+    private final OnPropertyChangedListener mOnDeviceConfigChangedListener =
+            new OnPropertyChangedListener() {
+                @Override
+                public void onPropertyChanged(String namespace, String name, String value) {
+                    if (KEY_MAX_CACHED_PROCESSES.equals(name)) {
+                        updateMaxCachedProcesses();
+                    }
+                }
+            };
+
     public ActivityManagerConstants(ActivityManagerService service, Handler handler) {
         super(handler);
         mService = service;
-        updateMaxCachedProcesses();
     }
 
     public void start(ContentResolver resolver) {
@@ -309,6 +292,11 @@
         updateConstants();
         updateActivityStartsLoggingEnabled();
         updateBackgroundActivityStartsEnabled();
+        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.ActivityManager.NAMESPACE,
+                ActivityThread.currentApplication().getMainExecutor(),
+                mOnDeviceConfigChangedListener);
+        updateMaxCachedProcesses();
+
     }
 
     public void setOverrideMaxCachedProcesses(int value) {
@@ -347,8 +335,6 @@
                 // with defaults.
                 Slog.e("ActivityManagerConstants", "Bad activity manager config settings", e);
             }
-            MAX_CACHED_PROCESSES = mParser.getInt(KEY_MAX_CACHED_PROCESSES,
-                    DEFAULT_MAX_CACHED_PROCESSES);
             BACKGROUND_SETTLE_TIME = mParser.getLong(KEY_BACKGROUND_SETTLE_TIME,
                     DEFAULT_BACKGROUND_SETTLE_TIME);
             FGSERVICE_MIN_SHOWN_TIME = mParser.getLong(KEY_FGSERVICE_MIN_SHOWN_TIME,
@@ -406,13 +392,9 @@
                     DEFAULT_MEMORY_INFO_THROTTLE_TIME);
             TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION,
                     DEFAULT_TOP_TO_FGS_GRACE_DURATION);
-            USE_COMPACTION = mParser.getBoolean(KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
-            COMPACT_ACTION_1 = mParser.getInt(KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
-            COMPACT_ACTION_2 = mParser.getInt(KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
-            COMPACT_THROTTLE_1 = mParser.getLong(KEY_COMPACT_THROTTLE_1, DEFAULT_COMPACT_THROTTLE_1);
-            COMPACT_THROTTLE_2 = mParser.getLong(KEY_COMPACT_THROTTLE_2, DEFAULT_COMPACT_THROTTLE_2);
-            COMPACT_THROTTLE_3 = mParser.getLong(KEY_COMPACT_THROTTLE_3, DEFAULT_COMPACT_THROTTLE_3);
-            COMPACT_THROTTLE_4 = mParser.getLong(KEY_COMPACT_THROTTLE_4, DEFAULT_COMPACT_THROTTLE_4);
+
+            // For new flags that are intended for server-side experiments, please use the new
+            // DeviceConfig package.
 
             updateMaxCachedProcesses();
         }
@@ -429,8 +411,19 @@
     }
 
     private void updateMaxCachedProcesses() {
-        CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0
-                ? MAX_CACHED_PROCESSES : mOverrideMaxCachedProcesses;
+        String maxCachedProcessesFlag = DeviceConfig.getProperty(
+                DeviceConfig.ActivityManager.NAMESPACE, KEY_MAX_CACHED_PROCESSES);
+        try {
+            CUR_MAX_CACHED_PROCESSES = mOverrideMaxCachedProcesses < 0
+                    ? (TextUtils.isEmpty(maxCachedProcessesFlag)
+                    ? DEFAULT_MAX_CACHED_PROCESSES : Integer.parseInt(maxCachedProcessesFlag))
+                    : mOverrideMaxCachedProcesses;
+        } catch (NumberFormatException e) {
+            // Bad flag value from Phenotype, revert to default.
+            Slog.e("ActivityManagerConstants",
+                    "Unable to parse flag for max_cached_processes: " + maxCachedProcessesFlag, e);
+            CUR_MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
+        }
         CUR_MAX_EMPTY_PROCESSES = computeEmptyProcessLimit(CUR_MAX_CACHED_PROCESSES);
 
         // Note the trim levels do NOT depend on the override process limit, we want
@@ -503,8 +496,6 @@
         pw.println(MEMORY_INFO_THROTTLE_TIME);
         pw.print("  "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("=");
         pw.println(TOP_TO_FGS_GRACE_DURATION);
-        pw.print("  "); pw.print(KEY_USE_COMPACTION); pw.print("=");
-        pw.println(USE_COMPACTION);
 
         pw.println();
         if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b24290f..eb643b6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1607,19 +1607,8 @@
                 }
             } break;
             case UPDATE_HTTP_PROXY_MSG: {
-                ProxyInfo proxy = (ProxyInfo)msg.obj;
-                String host = "";
-                String port = "";
-                String exclList = "";
-                Uri pacFileUrl = Uri.EMPTY;
-                if (proxy != null) {
-                    host = proxy.getHost();
-                    port = Integer.toString(proxy.getPort());
-                    exclList = proxy.getExclusionListAsString();
-                    pacFileUrl = proxy.getPacFileUrl();
-                }
                 synchronized (ActivityManagerService.this) {
-                    mProcessList.setAllHttpProxyLocked(host, port, exclList, pacFileUrl);
+                    mProcessList.setAllHttpProxyLocked();
                 }
             } break;
             case PROC_START_TIMEOUT_MSG: {
@@ -7228,6 +7217,7 @@
         mActivityTaskManager.installSystemProviders();
         mDevelopmentSettingsObserver = new DevelopmentSettingsObserver();
         SettingsToPropertiesMapper.start(mContext.getContentResolver());
+        mOomAdjuster.initSettings();
 
         // Now that the settings provider is published we can consider sending
         // in a rescue party.
@@ -9340,6 +9330,7 @@
 
         synchronized(this) {
             mConstants.dump(pw);
+            mOomAdjuster.dumpAppCompactorSettings(pw);
             pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
@@ -9739,6 +9730,7 @@
             } else if ("settings".equals(cmd)) {
                 synchronized (this) {
                     mConstants.dump(pw);
+                    mOomAdjuster.dumpAppCompactorSettings(pw);
                 }
             } else if ("services".equals(cmd) || "s".equals(cmd)) {
                 if (dumpClient) {
@@ -14656,8 +14648,7 @@
                     mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
                     break;
                 case Proxy.PROXY_CHANGE_ACTION:
-                    ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
-                    mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
+                    mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG));
                     break;
                 case android.hardware.Camera.ACTION_NEW_PICTURE:
                 case android.hardware.Camera.ACTION_NEW_VIDEO:
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index fd402cc..bb55ec31 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -16,34 +16,63 @@
 
 package com.android.server.am;
 
-import com.android.internal.annotations.GuardedBy;
+import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_4;
+import static android.provider.DeviceConfig.ActivityManager.KEY_USE_COMPACTION;
 
 import android.app.ActivityManager;
-
+import android.app.ActivityThread;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.Trace;
-
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.OnPropertyChangedListener;
+import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.StatsLog;
 
-import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
-
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.ServiceThread;
 
 import java.io.FileOutputStream;
-import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 public final class AppCompactor {
-    /**
-     * Processes to compact.
-     */
-    final ArrayList<ProcessRecord> mPendingCompactionProcesses = new ArrayList<ProcessRecord>();
 
+    // Phenotype sends int configurations and we map them to the strings we'll use on device,
+    // preventing a weird string value entering the kernel.
+    private static final int COMPACT_ACTION_FILE_FLAG = 1;
+    private static final int COMPACT_ACTION_ANON_FLAG = 2;
+    private static final int COMPACT_ACTION_FULL_FLAG = 3;
+    private static final String COMPACT_ACTION_FILE = "file";
+    private static final String COMPACT_ACTION_ANON = "anon";
+    private static final String COMPACT_ACTION_FULL = "all";
+
+    // Defaults for phenotype flags.
+    @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false;
+    @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_1 = COMPACT_ACTION_FILE_FLAG;
+    @VisibleForTesting static final int DEFAULT_COMPACT_ACTION_2 = COMPACT_ACTION_FULL_FLAG;
+    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_1 = 5_000;
+    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000;
+    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500;
+    @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000;
+
+    @VisibleForTesting
+    interface PropertyChangedCallbackForTest {
+        void onPropertyChanged();
+    }
+    private PropertyChangedCallbackForTest mTestCallback;
+
+    // Handler constants.
     static final int COMPACT_PROCESS_SOME = 1;
     static final int COMPACT_PROCESS_FULL = 2;
     static final int COMPACT_PROCESS_MSG = 1;
@@ -57,70 +86,106 @@
      */
     final ServiceThread mCompactionThread;
 
-    final private Handler mCompactionHandler;
+    private final ArrayList<ProcessRecord> mPendingCompactionProcesses =
+            new ArrayList<ProcessRecord>();
+    private final ActivityManagerService mAm;
+    private final OnPropertyChangedListener mOnFlagsChangedListener =
+            new OnPropertyChangedListener() {
+                @Override
+                public void onPropertyChanged(String namespace, String name, String value) {
+                    synchronized (mPhenotypeFlagLock) {
+                        if (KEY_USE_COMPACTION.equals(name)) {
+                            updateUseCompaction();
+                        } else if (KEY_COMPACT_ACTION_1.equals(name)
+                                || KEY_COMPACT_ACTION_2.equals(name)) {
+                            updateCompactionActions();
+                        } else if (KEY_COMPACT_THROTTLE_1.equals(name)
+                                || KEY_COMPACT_THROTTLE_2.equals(name)
+                                || KEY_COMPACT_THROTTLE_3.equals(name)
+                                || KEY_COMPACT_THROTTLE_4.equals(name)) {
+                            updateCompactionThrottles();
+                        }
+                    }
+                    if (mTestCallback != null) {
+                        mTestCallback.onPropertyChanged();
+                    }
+                }
+            };
 
-    final private ActivityManagerService mAm;
-    final private ActivityManagerConstants mConstants;
+    private final Object mPhenotypeFlagLock = new Object();
 
-    final private String COMPACT_ACTION_FILE = "file";
-    final private String COMPACT_ACTION_ANON = "anon";
-    final private String COMPACT_ACTION_FULL = "all";
+    // Configured by phenotype. Updates from the server take effect immediately.
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting String mCompactActionSome =
+            compactActionIntToString(DEFAULT_COMPACT_ACTION_1);
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting String mCompactActionFull =
+            compactActionIntToString(DEFAULT_COMPACT_ACTION_2);
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
+    @GuardedBy("mPhenotypeFlagLock")
+    @VisibleForTesting long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
+    @GuardedBy("mPhenotypeFlagLock")
+    private boolean mUseCompaction = DEFAULT_USE_COMPACTION;
 
-    final private String compactActionSome;
-    final private String compactActionFull;
-
-    final private long throttleSomeSome;
-    final private long throttleSomeFull;
-    final private long throttleFullSome;
-    final private long throttleFullFull;
+    // Handler on which compaction runs.
+    private Handler mCompactionHandler;
 
     public AppCompactor(ActivityManagerService am) {
         mAm = am;
-        mConstants = am.mConstants;
-
         mCompactionThread = new ServiceThread("CompactionThread",
                 THREAD_PRIORITY_FOREGROUND, true);
-        mCompactionThread.start();
-        mCompactionHandler = new MemCompactionHandler(this);
-
-        switch(mConstants.COMPACT_ACTION_1) {
-            case 1:
-                compactActionSome = COMPACT_ACTION_FILE;
-                break;
-            case 2:
-                compactActionSome = COMPACT_ACTION_ANON;
-                break;
-            case 3:
-                compactActionSome = COMPACT_ACTION_FULL;
-                break;
-            default:
-                compactActionSome = COMPACT_ACTION_FILE;
-                break;
-        }
-
-        switch(mConstants.COMPACT_ACTION_2) {
-            case 1:
-                compactActionFull = COMPACT_ACTION_FILE;
-                break;
-            case 2:
-                compactActionFull = COMPACT_ACTION_ANON;
-                break;
-            case 3:
-                compactActionFull = COMPACT_ACTION_FULL;
-                break;
-            default:
-                compactActionFull = COMPACT_ACTION_FULL;
-                break;
-        }
-
-        throttleSomeSome = mConstants.COMPACT_THROTTLE_1;
-        throttleSomeFull = mConstants.COMPACT_THROTTLE_2;
-        throttleFullSome = mConstants.COMPACT_THROTTLE_3;
-        throttleFullFull = mConstants.COMPACT_THROTTLE_4;
     }
 
-    // Must be called while holding AMS lock.
-    final void compactAppSome(ProcessRecord app) {
+    @VisibleForTesting
+    AppCompactor(ActivityManagerService am, PropertyChangedCallbackForTest callback) {
+        this(am);
+        mTestCallback = callback;
+    }
+
+    /**
+     * Reads phenotype config to determine whether app compaction is enabled or not and
+     * starts the background thread if necessary.
+     */
+    public void init() {
+        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.ActivityManager.NAMESPACE,
+                ActivityThread.currentApplication().getMainExecutor(), mOnFlagsChangedListener);
+        synchronized (mPhenotypeFlagLock) {
+            updateUseCompaction();
+            updateCompactionActions();
+            updateCompactionThrottles();
+        }
+    }
+
+    /**
+     * Returns whether compaction is enabled.
+     */
+    public boolean useCompaction() {
+        synchronized (mPhenotypeFlagLock) {
+            return mUseCompaction;
+        }
+    }
+
+    @GuardedBy("mAm")
+    void dump(PrintWriter pw) {
+        pw.println("AppCompactor settings");
+        synchronized (mPhenotypeFlagLock) {
+            pw.println("  " + KEY_USE_COMPACTION + "=" + mUseCompaction);
+            pw.println("  " + KEY_COMPACT_ACTION_1 + "=" + mCompactActionSome);
+            pw.println("  " + KEY_COMPACT_ACTION_2 + "=" + mCompactActionFull);
+            pw.println("  " + KEY_COMPACT_THROTTLE_1 + "=" + mCompactThrottleSomeSome);
+            pw.println("  " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull);
+            pw.println("  " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome);
+            pw.println("  " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull);
+        }
+    }
+
+    @GuardedBy("mAm")
+    void compactAppSome(ProcessRecord app) {
         app.reqCompactAction = COMPACT_PROCESS_SOME;
         mPendingCompactionProcesses.add(app);
         mCompactionHandler.sendMessage(
@@ -128,8 +193,8 @@
                 COMPACT_PROCESS_MSG, app.curAdj, app.setProcState));
     }
 
-    // Must be called while holding AMS lock.
-    final void compactAppFull(ProcessRecord app) {
+    @GuardedBy("mAm")
+    void compactAppFull(ProcessRecord app) {
         app.reqCompactAction = COMPACT_PROCESS_FULL;
         mPendingCompactionProcesses.add(app);
         mCompactionHandler.sendMessage(
@@ -137,97 +202,205 @@
                 COMPACT_PROCESS_MSG, app.curAdj, app.setProcState));
 
     }
-    final class MemCompactionHandler extends Handler {
-        AppCompactor mAc;
 
-        private MemCompactionHandler(AppCompactor ac) {
-            super(ac.mCompactionThread.getLooper());
-            mAc = ac;
+    /**
+     * Reads the flag value from DeviceConfig to determine whether app compaction
+     * should be enabled, and starts/stops the compaction thread as needed.
+     */
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateUseCompaction() {
+        String useCompactionFlag =
+                DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                    KEY_USE_COMPACTION);
+        mUseCompaction = TextUtils.isEmpty(useCompactionFlag)
+                ? DEFAULT_USE_COMPACTION : Boolean.parseBoolean(useCompactionFlag);
+        if (mUseCompaction && !mCompactionThread.isAlive()) {
+            mCompactionThread.start();
+            mCompactionHandler = new MemCompactionHandler();
+        }
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateCompactionActions() {
+        String compactAction1Flag =
+                DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                        KEY_COMPACT_ACTION_1);
+        String compactAction2Flag =
+                DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                        KEY_COMPACT_ACTION_2);
+
+        int compactAction1 = DEFAULT_COMPACT_ACTION_1;
+        try {
+            compactAction1 = TextUtils.isEmpty(compactAction1Flag)
+                    ? DEFAULT_COMPACT_ACTION_1 : Integer.parseInt(compactAction1Flag);
+        } catch (NumberFormatException e) {
+          // Do nothing, leave default.
+        }
+
+        int compactAction2 = DEFAULT_COMPACT_ACTION_2;
+        try {
+            compactAction2 = TextUtils.isEmpty(compactAction2Flag)
+                    ? DEFAULT_COMPACT_ACTION_2 : Integer.parseInt(compactAction2Flag);
+        } catch (NumberFormatException e) {
+            // Do nothing, leave default.
+        }
+
+        mCompactActionSome = compactActionIntToString(compactAction1);
+        mCompactActionFull = compactActionIntToString(compactAction2);
+    }
+
+    @GuardedBy("mPhenotypeFlagLock")
+    private void updateCompactionThrottles() {
+        boolean useThrottleDefaults = false;
+        String throttleSomeSomeFlag =
+                DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                    KEY_COMPACT_THROTTLE_1);
+        String throttleSomeFullFlag =
+                DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                    KEY_COMPACT_THROTTLE_2);
+        String throttleFullSomeFlag =
+                DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                    KEY_COMPACT_THROTTLE_3);
+        String throttleFullFullFlag =
+                DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                    KEY_COMPACT_THROTTLE_4);
+
+        if (TextUtils.isEmpty(throttleSomeSomeFlag) || TextUtils.isEmpty(throttleSomeFullFlag)
+                || TextUtils.isEmpty(throttleFullSomeFlag)
+                || TextUtils.isEmpty(throttleFullFullFlag)) {
+            // Set defaults for all if any are not set.
+            useThrottleDefaults = true;
+        } else {
+            try {
+                mCompactThrottleSomeSome = Integer.parseInt(throttleSomeSomeFlag);
+                mCompactThrottleSomeFull = Integer.parseInt(throttleSomeFullFlag);
+                mCompactThrottleFullSome = Integer.parseInt(throttleFullSomeFlag);
+                mCompactThrottleFullFull = Integer.parseInt(throttleFullFullFlag);
+            } catch (NumberFormatException e) {
+                useThrottleDefaults = true;
+            }
+        }
+
+        if (useThrottleDefaults) {
+            mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1;
+            mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2;
+            mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3;
+            mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4;
+        }
+    }
+
+    @VisibleForTesting
+    static String compactActionIntToString(int action) {
+        switch(action) {
+            case COMPACT_ACTION_FILE_FLAG:
+                return COMPACT_ACTION_FILE;
+            case COMPACT_ACTION_ANON_FLAG:
+                return COMPACT_ACTION_ANON;
+            case COMPACT_ACTION_FULL_FLAG:
+                return COMPACT_ACTION_FULL;
+            default:
+                return COMPACT_ACTION_FILE;
+        }
+    }
+
+    private final class MemCompactionHandler extends Handler {
+        private MemCompactionHandler() {
+            super(mCompactionThread.getLooper());
         }
 
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-            case COMPACT_PROCESS_MSG: {
-                long start = SystemClock.uptimeMillis();
-                ProcessRecord proc;
-                int pid;
-                String action;
-                final String name;
-                int pendingAction, lastCompactAction;
-                long lastCompactTime;
-                synchronized(mAc.mAm) {
-                    proc = mAc.mPendingCompactionProcesses.remove(0);
+                case COMPACT_PROCESS_MSG: {
+                    long start = SystemClock.uptimeMillis();
+                    ProcessRecord proc;
+                    int pid;
+                    String action;
+                    final String name;
+                    int pendingAction, lastCompactAction;
+                    long lastCompactTime;
+                    synchronized (mAm) {
+                        proc = mPendingCompactionProcesses.remove(0);
 
-                    // don't compact if the process has returned to perceptible
-                    if (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
+                        // don't compact if the process has returned to perceptible
+                        if (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
+                            return;
+                        }
+
+                        pid = proc.pid;
+                        name = proc.processName;
+                        pendingAction = proc.reqCompactAction;
+                        lastCompactAction = proc.lastCompactAction;
+                        lastCompactTime = proc.lastCompactTime;
+                    }
+
+                    if (pid == 0) {
+                        // not a real process, either one being launched or one being killed
                         return;
                     }
 
-                    pid = proc.pid;
-                    name = proc.processName;
-                    pendingAction = proc.reqCompactAction;
-                    lastCompactAction = proc.lastCompactAction;
-                    lastCompactTime = proc.lastCompactTime;
-                }
-                if (pid == 0) {
-                    // not a real process, either one being launched or one being killed
-                    return;
-                }
+                    // basic throttling
+                    // use the Phenotype flag knobs to determine whether current/prevous
+                    // compaction combo should be throtted or not
 
-                // basic throttling
-                // use the ActivityManagerConstants knobs to determine whether current/prevous
-                // compaction combo should be throtted or not
-                if (pendingAction == COMPACT_PROCESS_SOME) {
-                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < throttleSomeSome)) ||
-                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < throttleSomeFull))) {
-                        return;
-                    }
-                } else {
-                    if ((lastCompactAction == COMPACT_PROCESS_SOME && (start - lastCompactTime < throttleFullSome)) ||
-                        (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < throttleFullFull))) {
-                        return;
-                    }
-                }
-
-                try {
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact " +
-                            ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full") +
-                            ": " + name);
-                    long[] rssBefore = Process.getRss(pid);
-                    FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
+                    // Note that we explicitly don't take mPhenotypeFlagLock here as the flags
+                    // should very seldom change, and taking the risk of using the wrong action is
+                    // preferable to taking the lock for every single compaction action.
                     if (pendingAction == COMPACT_PROCESS_SOME) {
-                        action = compactActionSome;
+                        if ((lastCompactAction == COMPACT_PROCESS_SOME
+                                  && (start - lastCompactTime < mCompactThrottleSomeSome))
+                                  || (lastCompactAction == COMPACT_PROCESS_FULL
+                                      && (start - lastCompactTime
+                                          < mCompactThrottleSomeFull))) {
+                            return;
+                        }
                     } else {
-                        action = compactActionFull;
+                        if ((lastCompactAction == COMPACT_PROCESS_SOME
+                                  && (start - lastCompactTime < mCompactThrottleFullSome))
+                                  || (lastCompactAction == COMPACT_PROCESS_FULL
+                                      && (start - lastCompactTime
+                                          < mCompactThrottleFullFull))) {
+                            return;
+                        }
                     }
-                    fos.write(action.getBytes());
-                    fos.close();
-                    long[] rssAfter = Process.getRss(pid);
-                    long end = SystemClock.uptimeMillis();
-                    long time = end - start;
-                    EventLog.writeEvent(EventLogTags.AM_COMPACT, pid, name, action,
-                            rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
-                            rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
-                            lastCompactAction, lastCompactTime, msg.arg1, msg.arg2);
-                    StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction,
-                            rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
-                            rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
-                            lastCompactAction, lastCompactTime, msg.arg1,
-                            ActivityManager.processStateAmToProto(msg.arg2));
-                    synchronized(mAc.mAm) {
-                        proc.lastCompactTime = end;
-                        proc.lastCompactAction = pendingAction;
+
+                    if (pendingAction == COMPACT_PROCESS_SOME) {
+                        action = mCompactActionSome;
+                    } else {
+                        action = mCompactActionFull;
                     }
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                } catch (Exception e) {
-                    // nothing to do, presumably the process died
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+                    try {
+                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact "
+                                + ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full")
+                                + ": " + name);
+                        long[] rssBefore = Process.getRss(pid);
+                        FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
+                        fos.write(action.getBytes());
+                        fos.close();
+                        long[] rssAfter = Process.getRss(pid);
+                        long end = SystemClock.uptimeMillis();
+                        long time = end - start;
+                        EventLog.writeEvent(EventLogTags.AM_COMPACT, pid, name, action,
+                                rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
+                                rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
+                                lastCompactAction, lastCompactTime, msg.arg1, msg.arg2);
+                        StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction,
+                                rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
+                                rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
+                                lastCompactAction, lastCompactTime, msg.arg1,
+                                ActivityManager.processStateAmToProto(msg.arg2));
+                        synchronized (mAm) {
+                            proc.lastCompactTime = end;
+                            proc.lastCompactAction = pendingAction;
+                        }
+                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+                    } catch (Exception e) {
+                        // nothing to do, presumably the process died
+                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+                    }
                 }
             }
-            }
         }
     }
-
-
 }
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index aabb587..dc9a4bf 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -16,8 +16,6 @@
 
 package com.android.server.am;
 
-import com.android.internal.R;
-
 import android.app.AlertDialog;
 import android.content.Context;
 import android.os.Handler;
@@ -26,6 +24,8 @@
 import android.view.WindowManager;
 import android.widget.Button;
 
+import com.android.internal.R;
+
 public class BaseErrorDialog extends AlertDialog {
     private static final int ENABLE_BUTTONS = 0;
     private static final int DISABLE_BUTTONS = 1;
@@ -36,7 +36,7 @@
         super(context, com.android.internal.R.style.Theme_DeviceDefault_Dialog_AppError);
         context.assertRuntimeOverlayThemable();
 
-        getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index d3953b5..3d69aa8 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -61,6 +61,8 @@
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, String.class);
         sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
+        sGlobalSettingToTypeMap.put(
+                Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
         sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index be910d4..1e03f6c 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -134,10 +134,11 @@
 
         mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
         mConstants = mService.mConstants;
-        // mConstants can be null under test, which causes AppCompactor to crash
-        if (mConstants != null) {
-            mAppCompact = new AppCompactor(mService);
-        }
+        mAppCompact = new AppCompactor(mService);
+    }
+
+    void initSettings() {
+        mAppCompact.init();
     }
 
     /**
@@ -1679,7 +1680,7 @@
 
         if (app.curAdj != app.setAdj) {
             // don't compact during bootup
-            if (mConstants.USE_COMPACTION && mService.mBooted) {
+            if (mAppCompact.useCompaction() && mService.mBooted) {
                 // Perform a minor compaction when a perceptible app becomes the prev/home app
                 // Perform a major compaction when any app enters cached
                 // reminder: here, setAdj is previous state, curAdj is upcoming state
@@ -2104,4 +2105,8 @@
                 + " mNewNumServiceProcs=" + mNewNumServiceProcs);
     }
 
+    @GuardedBy("mService")
+    void dumpAppCompactorSettings(PrintWriter pw) {
+        mAppCompact.dump(pw);
+    }
 }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 55cca95..0b27a8a 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -379,6 +379,10 @@
             if (userId == UserHandle.USER_CURRENT) {
                 userId = controller.mUserController.getCurrentOrTargetUserId();
             }
+            // temporarily allow receivers and services to open activities from background if the
+            // PendingIntent.send() caller was foreground at the time of sendInner() call
+            final boolean allowTrampoline = uid != callingUid
+                    && controller.mAtmInternal.isUidForeground(callingUid);
 
             switch (key.type) {
                 case ActivityManager.INTENT_SENDER_ACTIVITY:
@@ -419,7 +423,8 @@
                                 uid, finalIntent, resolvedType, finishedReceiver, code, null, null,
                                 requiredPermission, options, (finishedReceiver != null),
                                 false, userId,
-                                mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken));
+                                mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)
+                                || allowTrampoline);
                         if (sent == ActivityManager.BROADCAST_SUCCESS) {
                             sendFinish = false;
                         }
@@ -433,7 +438,8 @@
                         controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
                                 key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
                                 key.packageName, userId,
-                                mAllowBgActivityStartsForServiceSender.contains(whitelistToken));
+                                mAllowBgActivityStartsForServiceSender.contains(whitelistToken)
+                                || allowTrampoline);
                     } catch (RuntimeException e) {
                         Slog.w(TAG, "Unable to send startService intent", e);
                     } catch (TransactionTooLargeException e) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 64ee30a..003ddd1 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2384,14 +2384,14 @@
     }
 
     @GuardedBy("mService")
-    void setAllHttpProxyLocked(String host, String port, String exclList, Uri pacFileUrl) {
+    void setAllHttpProxyLocked() {
         for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
             ProcessRecord r = mLruProcesses.get(i);
             // Don't dispatch to isolated processes as they can't access
             // ConnectivityManager and don't have network privileges anyway.
             if (r.thread != null && !r.isolated) {
                 try {
-                    r.thread.setHttpProxy(host, port, exclList, pacFileUrl);
+                    r.thread.updateHttpProxy();
                 } catch (RemoteException ex) {
                     Slog.w(TAG, "Failed to update http proxy for: " +
                             r.info.processName);
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index fdddccd..a671287 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -309,22 +309,4 @@
             }
         }
     }
-
-    /**
-     * Enable or disable the default proxy.
-     *
-     * This sets the flag for enabling/disabling the default proxy and sends the broadcast
-     * if applicable.
-     * @param enabled whether the default proxy should be enabled.
-     */
-    public void setDefaultProxyEnabled(final boolean enabled) {
-        synchronized (mProxyLock) {
-            if (mDefaultProxyEnabled != enabled) {
-                mDefaultProxyEnabled = enabled;
-                if (mGlobalProxy == null && mDefaultProxy != null) {
-                    sendProxyBroadcast();
-                }
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c72c9dd..2508844 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -151,7 +151,7 @@
                 .divide(BigInteger.valueOf(100));
     }
     // How many routes to evaluate before bailing and declaring this Vpn should provide
-    // the INTERNET capability. This is necessary because computing the adress space is
+    // the INTERNET capability. This is necessary because computing the address space is
     // O(n²) and this is running in the system service, so a limit is needed to alleviate
     // the risk of attack.
     // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
@@ -194,6 +194,12 @@
     private boolean mLockdown = false;
 
     /**
+     * Set of packages in addition to the VPN app itself that can access the network directly when
+     * VPN is not connected even if {@code mLockdown} is set.
+     */
+    private @NonNull List<String> mLockdownWhitelist = Collections.emptyList();
+
+    /**
      * List of UIDs for which networking should be blocked until VPN is ready, during brief periods
      * when VPN is not running. For example, during system startup or after a crash.
      * @see mLockdown
@@ -320,9 +326,9 @@
      *
      * Used to enable/disable legacy VPN lockdown.
      *
-     * This uses the same ip rule mechanism as {@link #setAlwaysOnPackage(String, boolean)};
-     * previous settings from calling that function will be replaced and saved with the
-     * always-on state.
+     * This uses the same ip rule mechanism as
+     * {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling
+     * that function will be replaced and saved with the always-on state.
      *
      * @param lockdown whether to prevent all traffic outside of a VPN.
      */
@@ -419,12 +425,14 @@
      *
      * @param packageName the package to designate as always-on VPN supplier.
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
+     * @param lockdownWhitelist packages to be whitelisted from lockdown.
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
-    public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
+    public synchronized boolean setAlwaysOnPackage(
+            String packageName, boolean lockdown, List<String> lockdownWhitelist) {
         enforceControlPermissionOrInternalCaller();
 
-        if (setAlwaysOnPackageInternal(packageName, lockdown)) {
+        if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist)) {
             saveAlwaysOnPackage();
             return true;
         }
@@ -439,15 +447,27 @@
      *
      * @param packageName the package to designate as always-on VPN supplier.
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
+     * @param lockdownWhitelist packages to be whitelisted from lockdown. This is only used if
+     *        {@code lockdown} is {@code true}. Packages must not contain commas.
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
     @GuardedBy("this")
-    private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) {
+    private boolean setAlwaysOnPackageInternal(
+            String packageName, boolean lockdown, List<String> lockdownWhitelist) {
         if (VpnConfig.LEGACY_VPN.equals(packageName)) {
             Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
             return false;
         }
 
+        if (lockdownWhitelist != null) {
+            for (String pkg : lockdownWhitelist) {
+                if (pkg.contains(",")) {
+                    Log.w(TAG, "Not setting always-on vpn, invalid whitelisted package: " + pkg);
+                    return false;
+                }
+            }
+        }
+
         if (packageName != null) {
             // Pre-authorize new always-on VPN package.
             if (!setPackageAuthorization(packageName, true)) {
@@ -460,13 +480,18 @@
         }
 
         mLockdown = (mAlwaysOn && lockdown);
+        mLockdownWhitelist = (mLockdown && lockdownWhitelist != null)
+                ? Collections.unmodifiableList(new ArrayList<>(lockdownWhitelist))
+                : Collections.emptyList();
+
         if (isCurrentPreparedPackage(packageName)) {
             updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
+            setVpnForcedLocked(mLockdown);
         } else {
             // Prepare this app. The notification will update as a side-effect of updateState().
+            // It also calls setVpnForcedLocked().
             prepareInternal(packageName);
         }
-        setVpnForcedLocked(mLockdown);
         return true;
     }
 
@@ -478,7 +503,6 @@
      * @return the package name of the VPN controller responsible for always-on VPN,
      *         or {@code null} if none is set or always-on VPN is controlled through
      *         lockdown instead.
-     * @hide
      */
     public synchronized String getAlwaysOnPackage() {
         enforceControlPermissionOrInternalCaller();
@@ -486,6 +510,13 @@
     }
 
     /**
+     * @return an immutable list of packages whitelisted from always-on VPN lockdown.
+     */
+    public synchronized List<String> getLockdownWhitelist() {
+        return mLockdown ? mLockdownWhitelist : null;
+    }
+
+    /**
      * Save the always-on package and lockdown config into Settings.Secure
      */
     @GuardedBy("this")
@@ -496,6 +527,9 @@
                     getAlwaysOnPackage(), mUserHandle);
             mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
                     (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
+            mSystemServices.settingsSecurePutStringForUser(
+                    Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST,
+                    String.join(",", mLockdownWhitelist), mUserHandle);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -512,7 +546,11 @@
                     Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
             final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
                     Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
-            setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown);
+            final String whitelistString = mSystemServices.settingsSecureGetStringForUser(
+                    Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, mUserHandle);
+            final List<String> whitelistedPackages = TextUtils.isEmpty(whitelistString)
+                    ? Collections.emptyList() : Arrays.asList(whitelistString.split(","));
+            setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown, whitelistedPackages);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -532,7 +570,7 @@
             }
             // Remove always-on VPN if it's not supported.
             if (!isAlwaysOnPackageSupported(alwaysOnPackage)) {
-                setAlwaysOnPackage(null, false);
+                setAlwaysOnPackage(null, false, null);
                 return false;
             }
             // Skip if the service is already established. This isn't bulletproof: it's not bound
@@ -793,6 +831,8 @@
             }
         }
 
+        lp.setHttpProxy(mConfig.proxyInfo);
+
         if (!allowIPv4) {
             lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
         }
@@ -1247,9 +1287,10 @@
     }
 
     /**
-     * Restrict network access from all UIDs affected by this {@link Vpn}, apart from the VPN
-     * service app itself, to only sockets that have had {@code protect()} called on them. All
-     * non-VPN traffic is blocked via a {@code PROHIBIT} response from the kernel.
+     * Restricts network access from all UIDs affected by this {@link Vpn}, apart from the VPN
+     * service app itself and whitelisted packages, to only sockets that have had {@code protect()}
+     * called on them. All non-VPN traffic is blocked via a {@code PROHIBIT} response from the
+     * kernel.
      *
      * The exception for the VPN UID isn't technically necessary -- setup should use protected
      * sockets -- but in practice it saves apps that don't protect their sockets from breaking.
@@ -1265,8 +1306,13 @@
      */
     @GuardedBy("this")
     private void setVpnForcedLocked(boolean enforce) {
-        final List<String> exemptedPackages =
-                isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage);
+        final List<String> exemptedPackages;
+        if (isNullOrLegacyVpn(mPackage)) {
+            exemptedPackages = null;
+        } else {
+            exemptedPackages = new ArrayList<>(mLockdownWhitelist);
+            exemptedPackages.add(mPackage);
+        }
         final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
 
         Set<UidRange> addedRanges = Collections.emptySet();
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 3a58160..58c88b3 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -16,6 +16,10 @@
 
 package com.android.server.display;
 
+import static android.hardware.display.ColorDisplayManager.AUTO_MODE_CUSTOM_TIME;
+import static android.hardware.display.ColorDisplayManager.AUTO_MODE_DISABLED;
+import static android.hardware.display.ColorDisplayManager.AUTO_MODE_TWILIGHT;
+
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION;
@@ -40,7 +44,9 @@
 import android.database.ContentObserver;
 import android.graphics.ColorSpace;
 import android.hardware.display.ColorDisplayManager;
+import android.hardware.display.ColorDisplayManager.AutoMode;
 import android.hardware.display.IColorDisplayManager;
+import android.hardware.display.Time;
 import android.net.Uri;
 import android.opengl.Matrix;
 import android.os.Binder;
@@ -103,59 +109,17 @@
     private static final int MSG_APPLY_GLOBAL_SATURATION = 2;
 
     /**
+     * Return value if a setting has not been set.
+     */
+    private static final int NOT_SET = -1;
+
+    /**
      * Evaluator used to animate color matrix transitions.
      */
     private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
 
-    private final TintController mNightDisplayTintController = new TintController() {
-
-        private float[] mMatrixNightDisplay = new float[16];
-        private final float[] mColorTempCoefficients = new float[9];
-
-        /**
-         * Set coefficients based on whether the color matrix is linear or not.
-         */
-        @Override
-        public void setUp(Context context, boolean needsLinear) {
-            final String[] coefficients = context.getResources().getStringArray(needsLinear
-                    ? R.array.config_nightDisplayColorTemperatureCoefficients
-                    : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
-            for (int i = 0; i < 9 && i < coefficients.length; i++) {
-                mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
-            }
-        }
-
-        @Override
-        public void setMatrix(int cct) {
-            if (mMatrixNightDisplay.length != 16) {
-                Slog.d(TAG, "The display transformation matrix must be 4x4");
-                return;
-            }
-
-            Matrix.setIdentityM(mMatrixNightDisplay, 0);
-
-            final float squareTemperature = cct * cct;
-            final float red = squareTemperature * mColorTempCoefficients[0]
-                    + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
-            final float green = squareTemperature * mColorTempCoefficients[3]
-                    + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
-            final float blue = squareTemperature * mColorTempCoefficients[6]
-                    + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
-            mMatrixNightDisplay[0] = red;
-            mMatrixNightDisplay[5] = green;
-            mMatrixNightDisplay[10] = blue;
-        }
-
-        @Override
-        public float[] getMatrix() {
-            return isActivated() ? mMatrixNightDisplay : MATRIX_IDENTITY;
-        }
-
-        @Override
-        public int getLevel() {
-            return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
-        }
-    };
+    private final NightDisplayTintController mNightDisplayTintController =
+            new NightDisplayTintController();
 
     private final TintController mDisplayWhiteBalanceTintController = new TintController() {
         // Three chromaticity coordinates per color: X, Y, and Z
@@ -386,7 +350,7 @@
                 float saturation = saturationLevel * 0.1f;
                 float desaturation = 1.0f - saturation;
                 float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
-                    0.072f * desaturation};
+                        0.072f * desaturation};
                 mMatrixGlobalSaturation[0] = luminance[0] + saturation;
                 mMatrixGlobalSaturation[1] = luminance[0];
                 mMatrixGlobalSaturation[2] = luminance[0];
@@ -445,7 +409,7 @@
 
     public ColorDisplayService(Context context) {
         super(context);
-        mHandler = new TintHandler(Looper.getMainLooper());
+        mHandler = new TintHandler(DisplayThread.get().getLooper());
     }
 
     @Override
@@ -548,23 +512,30 @@
                     if (setting != null) {
                         switch (setting) {
                             case Secure.NIGHT_DISPLAY_ACTIVATED:
-                                onNightDisplayActivated(mNightDisplayController.isActivated());
+                                final boolean activated = isNightDisplayActivatedSetting();
+                                if (mNightDisplayTintController.isActivatedStateNotSet()
+                                        || mNightDisplayTintController.isActivated() != activated) {
+                                    mNightDisplayTintController.onActivated(activated);
+                                }
                                 break;
                             case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
-                                onNightDisplayColorTemperatureChanged(
-                                        mNightDisplayController.getColorTemperature());
+                                final int temperature = getNightDisplayColorTemperatureSetting();
+                                if (mNightDisplayTintController.getColorTemperature()
+                                        != temperature) {
+                                    mNightDisplayTintController
+                                            .onColorTemperatureChanged(temperature);
+                                }
                                 break;
                             case Secure.NIGHT_DISPLAY_AUTO_MODE:
-                                onNightDisplayAutoModeChanged(
-                                        mNightDisplayController.getAutoMode());
+                                onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
                                 break;
                             case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
                                 onNightDisplayCustomStartTimeChanged(
-                                        mNightDisplayController.getCustomStartTime());
+                                        getNightDisplayCustomStartTimeInternal().getLocalTime());
                                 break;
                             case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
                                 onNightDisplayCustomEndTimeChanged(
-                                        mNightDisplayController.getCustomEndTime());
+                                        getNightDisplayCustomEndTimeInternal().getLocalTime());
                                 break;
                             case System.DISPLAY_COLOR_MODE:
                                 onDisplayColorModeChanged(mNightDisplayController.getColorMode());
@@ -624,14 +595,14 @@
             // Prepare the night display color transformation matrix.
             mNightDisplayTintController
                     .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
-            mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
+            mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting());
 
             // Initialize the current auto mode.
-            onNightDisplayAutoModeChanged(mNightDisplayController.getAutoMode());
+            onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
 
-            // Force the initialization current activated state.
+            // Force the initialization of the current saved activation state.
             if (mNightDisplayTintController.isActivatedStateNotSet()) {
-                onNightDisplayActivated(mNightDisplayController.isActivated());
+                mNightDisplayTintController.onActivated(isNightDisplayActivatedSetting());
             }
         }
 
@@ -665,23 +636,6 @@
         }
     }
 
-    private void onNightDisplayActivated(boolean activated) {
-        if (mNightDisplayTintController.isActivatedStateNotSet()
-                || mNightDisplayTintController.isActivated() != activated) {
-            Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
-
-            mNightDisplayTintController.setActivated(activated);
-
-            if (mNightDisplayAutoMode != null) {
-                mNightDisplayAutoMode.onActivated(activated);
-            }
-
-            updateDisplayWhiteBalanceStatus();
-
-            applyTint(mNightDisplayTintController, false);
-        }
-    }
-
     private void onNightDisplayAutoModeChanged(int autoMode) {
         Slog.d(TAG, "onNightDisplayAutoModeChanged: autoMode=" + autoMode);
 
@@ -690,9 +644,9 @@
             mNightDisplayAutoMode = null;
         }
 
-        if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM) {
+        if (autoMode == AUTO_MODE_CUSTOM_TIME) {
             mNightDisplayAutoMode = new CustomNightDisplayAutoMode();
-        } else if (autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
+        } else if (autoMode == AUTO_MODE_TWILIGHT) {
             mNightDisplayAutoMode = new TwilightNightDisplayAutoMode();
         }
 
@@ -717,13 +671,8 @@
         }
     }
 
-    private void onNightDisplayColorTemperatureChanged(int colorTemperature) {
-        mNightDisplayTintController.setMatrix(colorTemperature);
-        applyTint(mNightDisplayTintController, true);
-    }
-
     private void onDisplayColorModeChanged(int mode) {
-        if (mode == -1) {
+        if (mode == NOT_SET) {
             return;
         }
 
@@ -732,7 +681,7 @@
 
         mNightDisplayTintController
                 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
-        mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
+        mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting());
 
         updateDisplayWhiteBalanceStatus();
 
@@ -901,6 +850,71 @@
         return availabilityFlags;
     }
 
+    private boolean setNightDisplayAutoModeInternal(@AutoMode int autoMode) {
+        if (getNightDisplayAutoModeInternal() != autoMode) {
+            Secure.putStringForUser(getContext().getContentResolver(),
+                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                    null,
+                    mCurrentUser);
+        }
+        return Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mCurrentUser);
+    }
+
+    private int getNightDisplayAutoModeInternal() {
+        int autoMode = getNightDisplayAutoModeRawInternal();
+        if (autoMode == NOT_SET) {
+            autoMode = getContext().getResources().getInteger(
+                    R.integer.config_defaultNightDisplayAutoMode);
+        }
+        if (autoMode != AUTO_MODE_DISABLED
+                && autoMode != AUTO_MODE_CUSTOM_TIME
+                && autoMode != AUTO_MODE_TWILIGHT) {
+            Slog.e(TAG, "Invalid autoMode: " + autoMode);
+            autoMode = AUTO_MODE_DISABLED;
+        }
+        return autoMode;
+    }
+
+    private int getNightDisplayAutoModeRawInternal() {
+        return Secure
+                .getIntForUser(getContext().getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
+                        NOT_SET, mCurrentUser);
+    }
+
+    private Time getNightDisplayCustomStartTimeInternal() {
+        int startTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NOT_SET, mCurrentUser);
+        if (startTimeValue == NOT_SET) {
+            startTimeValue = getContext().getResources().getInteger(
+                    R.integer.config_defaultNightDisplayCustomStartTime);
+        }
+        return new Time(LocalTime.ofSecondOfDay(startTimeValue / 1000));
+    }
+
+    private boolean setNightDisplayCustomStartTimeInternal(Time startTime) {
+        return Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
+                startTime.getLocalTime().toSecondOfDay() * 1000,
+                mCurrentUser);
+    }
+
+    private Time getNightDisplayCustomEndTimeInternal() {
+        int endTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NOT_SET, mCurrentUser);
+        if (endTimeValue == NOT_SET) {
+            endTimeValue = getContext().getResources().getInteger(
+                    R.integer.config_defaultNightDisplayCustomEndTime);
+        }
+        return new Time(LocalTime.ofSecondOfDay(endTimeValue / 1000));
+    }
+
+    private boolean setNightDisplayCustomEndTimeInternal(Time endTime) {
+        return Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.getLocalTime().toSecondOfDay() * 1000,
+                mCurrentUser);
+    }
+
     /**
      * Returns the last time the night display transform activation state was changed, or {@link
      * LocalDateTime#MIN} if night display has never been activated.
@@ -941,6 +955,33 @@
         mAppSaturationController.dump(pw);
     }
 
+    private boolean isNightDisplayActivatedSetting() {
+        return Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
+    }
+
+    private int getNightDisplayColorTemperatureSetting() {
+        return clampNightDisplayColorTemperature(Secure.getIntForUser(
+                getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, NOT_SET,
+                mCurrentUser));
+    }
+
+    private int clampNightDisplayColorTemperature(int colorTemperature) {
+        if (colorTemperature == NOT_SET) {
+            colorTemperature = getContext().getResources().getInteger(
+                    R.integer.config_nightDisplayColorTemperatureDefault);
+        }
+        final int minimumTemperature = ColorDisplayManager.getMinimumColorTemperature(getContext());
+        final int maximumTemperature = ColorDisplayManager.getMaximumColorTemperature(getContext());
+        if (colorTemperature < minimumTemperature) {
+            colorTemperature = minimumTemperature;
+        } else if (colorTemperature > maximumTemperature) {
+            colorTemperature = maximumTemperature;
+        }
+
+        return colorTemperature;
+    }
+
     private abstract class NightDisplayAutoMode {
 
         public abstract void onActivated(boolean activated);
@@ -987,13 +1028,13 @@
                 // Maintain the existing activated state if within the current period.
                 if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
                         && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
-                    activate = mNightDisplayController.isActivated();
+                    activate = isNightDisplayActivatedSetting();
                 }
             }
 
             if (mNightDisplayTintController.isActivatedStateNotSet() || (
                     mNightDisplayTintController.isActivated() != activate)) {
-                mNightDisplayController.setActivated(activate);
+                mNightDisplayTintController.setActivated(activate);
             }
 
             updateNextAlarm(mNightDisplayTintController.isActivated(), now);
@@ -1014,8 +1055,8 @@
             intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
             getContext().registerReceiver(mTimeChangedReceiver, intentFilter);
 
-            mStartTime = mNightDisplayController.getCustomStartTime();
-            mEndTime = mNightDisplayController.getCustomEndTime();
+            mStartTime = getNightDisplayCustomStartTimeInternal().getLocalTime();
+            mEndTime = getNightDisplayCustomEndTimeInternal().getLocalTime();
 
             mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
 
@@ -1083,13 +1124,13 @@
                 // Maintain the existing activated state if within the current period.
                 if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise)
                         ^ mLastActivatedTime.isBefore(sunset))) {
-                    activate = mNightDisplayController.isActivated();
+                    activate = isNightDisplayActivatedSetting();
                 }
             }
 
             if (mNightDisplayTintController.isActivatedStateNotSet() || (
                     mNightDisplayTintController.isActivated() != activate)) {
-                mNightDisplayController.setActivated(activate);
+                mNightDisplayTintController.setActivated(activate);
             }
         }
 
@@ -1211,6 +1252,114 @@
         public abstract int getLevel();
     }
 
+    private final class NightDisplayTintController extends TintController {
+
+        private float[] mMatrix = new float[16];
+        private final float[] mColorTempCoefficients = new float[9];
+        private Integer mColorTemp;
+
+        /**
+         * Set coefficients based on whether the color matrix is linear or not.
+         */
+        @Override
+        public void setUp(Context context, boolean needsLinear) {
+            final String[] coefficients = context.getResources().getStringArray(needsLinear
+                    ? R.array.config_nightDisplayColorTemperatureCoefficients
+                    : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
+            for (int i = 0; i < 9 && i < coefficients.length; i++) {
+                mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
+            }
+        }
+
+        @Override
+        public void setMatrix(int cct) {
+            if (mMatrix.length != 16) {
+                Slog.d(TAG, "The display transformation matrix must be 4x4");
+                return;
+            }
+
+            Matrix.setIdentityM(mMatrix, 0);
+
+            final float squareTemperature = cct * cct;
+            final float red = squareTemperature * mColorTempCoefficients[0]
+                    + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
+            final float green = squareTemperature * mColorTempCoefficients[3]
+                    + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
+            final float blue = squareTemperature * mColorTempCoefficients[6]
+                    + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
+            mMatrix[0] = red;
+            mMatrix[5] = green;
+            mMatrix[10] = blue;
+        }
+
+        @Override
+        public float[] getMatrix() {
+            return isActivated() ? mMatrix : MATRIX_IDENTITY;
+        }
+
+        @Override
+        public void setActivated(Boolean activated) {
+            if (activated == null) {
+                super.setActivated(null);
+                return;
+            }
+
+            boolean activationStateChanged = activated != isActivated();
+
+            if (!isActivatedStateNotSet() && activationStateChanged) {
+                // This is a true state change, so set this as the last activation time.
+                Secure.putStringForUser(getContext().getContentResolver(),
+                        Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                        LocalDateTime.now().toString(),
+                        mCurrentUser);
+            }
+
+            if (isActivatedStateNotSet() || activationStateChanged) {
+                super.setActivated(activated);
+                Secure.putIntForUser(getContext().getContentResolver(),
+                        Secure.NIGHT_DISPLAY_ACTIVATED,
+                        activated ? 1 : 0, mCurrentUser);
+                onActivated(activated);
+            }
+        }
+
+        @Override
+        public int getLevel() {
+            return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+        }
+
+        void onActivated(boolean activated) {
+            Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
+            if (mNightDisplayAutoMode != null) {
+                mNightDisplayAutoMode.onActivated(activated);
+            }
+
+            if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
+                updateDisplayWhiteBalanceStatus();
+            }
+
+            mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_ANIMATED);
+        }
+
+        int getColorTemperature() {
+            return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp)
+                    : getNightDisplayColorTemperatureSetting();
+        }
+
+        boolean setColorTemperature(int temperature) {
+            mColorTemp = temperature;
+            final boolean success = Secure.putIntForUser(getContext().getContentResolver(),
+                    Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, temperature, mCurrentUser);
+            onColorTemperatureChanged(temperature);
+            return success;
+        }
+
+        void onColorTemperatureChanged(int temperature) {
+            setMatrix(temperature);
+            mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE);
+        }
+    }
+
     /**
      * Local service that allows color transforms to be enabled from other system services.
      */
@@ -1270,7 +1419,7 @@
 
     private final class TintHandler extends Handler {
 
-        TintHandler(Looper looper) {
+        private TintHandler(Looper looper) {
             super(looper, null, true /* async */);
         }
 
@@ -1281,6 +1430,12 @@
                     mGlobalSaturationTintController.setMatrix(msg.arg1);
                     applyTint(mGlobalSaturationTintController, false);
                     break;
+                case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
+                    applyTint(mNightDisplayTintController, true);
+                    break;
+                case MSG_APPLY_NIGHT_DISPLAY_ANIMATED:
+                    applyTint(mNightDisplayTintController, false);
+                    break;
             }
         }
     }
@@ -1294,7 +1449,8 @@
         void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation);
     }
 
-    private final class BinderService extends IColorDisplayManager.Stub {
+    @VisibleForTesting
+    final class BinderService extends IColorDisplayManager.Stub {
 
         @Override
         public boolean isDeviceColorManaged() {
@@ -1354,6 +1510,135 @@
         }
 
         @Override
+        public boolean setNightDisplayActivated(boolean activated) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display activated");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mNightDisplayTintController.setActivated(activated);
+                return true;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean isNightDisplayActivated() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return mNightDisplayTintController.isActivated();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean setNightDisplayColorTemperature(int temperature) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display temperature");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return mNightDisplayTintController.setColorTemperature(temperature);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public int getNightDisplayColorTemperature() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return mNightDisplayTintController.getColorTemperature();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean setNightDisplayAutoMode(int autoMode) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display auto mode");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return setNightDisplayAutoModeInternal(autoMode);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public int getNightDisplayAutoMode() {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to get night display auto mode");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getNightDisplayAutoModeInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public int getNightDisplayAutoModeRaw() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getNightDisplayAutoModeRawInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean setNightDisplayCustomStartTime(Time startTime) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display custom start time");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return setNightDisplayCustomStartTimeInternal(startTime);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public Time getNightDisplayCustomStartTime() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getNightDisplayCustomStartTimeInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean setNightDisplayCustomEndTime(Time endTime) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display custom end time");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return setNightDisplayCustomEndTimeInternal(endTime);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public Time getNightDisplayCustomEndTime() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getNightDisplayCustomEndTimeInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
 
diff --git a/services/core/java/com/android/server/job/JobConcurrencyManager.java b/services/core/java/com/android/server/job/JobConcurrencyManager.java
index 4d9b5f5..bec1947 100644
--- a/services/core/java/com/android/server/job/JobConcurrencyManager.java
+++ b/services/core/java/com/android/server/job/JobConcurrencyManager.java
@@ -36,6 +36,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.StatLogger;
 import com.android.server.job.JobSchedulerService.Constants;
+import com.android.server.job.JobSchedulerService.MaxJobCountsPerMemoryTrimLevel;
 import com.android.server.job.controllers.JobStatus;
 import com.android.server.job.controllers.StateController;
 
@@ -148,14 +149,14 @@
                 Slog.d(TAG, "Interactive: " + interactive);
             }
 
-            final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+            final long nowRealtime = JobSchedulerService.sElapsedRealtimeClock.millis();
             if (interactive) {
-                mLastScreenOnRealtime = now;
+                mLastScreenOnRealtime = nowRealtime;
                 mEffectiveInteractiveState = true;
 
                 mHandler.removeCallbacks(mRampUpForScreenOff);
             } else {
-                mLastScreenOffRealtime = now;
+                mLastScreenOffRealtime = nowRealtime;
 
                 // Set mEffectiveInteractiveState to false after the delay, when we may increase
                 // the concurrency.
@@ -232,38 +233,24 @@
     private void updateMaxCountsLocked() {
         refreshSystemStateLocked();
 
-        if (mEffectiveInteractiveState) {
-            // Screen on
-            switch (mLastMemoryTrimLevel) {
-                case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
-                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_ON_MODERATE;
-                    break;
-                case ProcessStats.ADJ_MEM_FACTOR_LOW:
-                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_ON_LOW;
-                    break;
-                case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
-                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_ON_CRITICAL;
-                    break;
-                default:
-                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_ON_NORMAL;
-                    break;
-            }
-        } else {
-            // Screen off
-            switch (mLastMemoryTrimLevel) {
-                case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
-                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_OFF_MODERATE;
-                    break;
-                case ProcessStats.ADJ_MEM_FACTOR_LOW:
-                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_OFF_LOW;
-                    break;
-                case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
-                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_OFF_CRITICAL;
-                    break;
-                default:
-                    mMaxJobCounts = mConstants.MAX_JOB_COUNTS_OFF_NORMAL;
-                    break;
-            }
+        final MaxJobCountsPerMemoryTrimLevel jobCounts = mEffectiveInteractiveState
+                ? mConstants.MAX_JOB_COUNTS_SCREEN_ON
+                : mConstants.MAX_JOB_COUNTS_SCREEN_OFF;
+
+
+        switch (mLastMemoryTrimLevel) {
+            case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
+                mMaxJobCounts = jobCounts.moderate;
+                break;
+            case ProcessStats.ADJ_MEM_FACTOR_LOW:
+                mMaxJobCounts = jobCounts.low;
+                break;
+            case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
+                mMaxJobCounts = jobCounts.critical;
+                break;
+            default:
+                mMaxJobCounts = jobCounts.normal;
+                break;
         }
     }
 
@@ -303,7 +290,7 @@
 
         // Initialize the work variables and also count running jobs.
         mJobCountTracker.reset(
-                mMaxJobCounts.getTotalMax(),
+                mMaxJobCounts.getMaxTotal(),
                 mMaxJobCounts.getMaxBg(),
                 mMaxJobCounts.getMinBg());
 
@@ -482,10 +469,7 @@
     }
 
 
-    public void dumpLocked(IndentingPrintWriter pw) {
-        final long now = System.currentTimeMillis();
-        final long nowRealtime = JobSchedulerService.sElapsedRealtimeClock.millis();
-
+    public void dumpLocked(IndentingPrintWriter pw, long now, long nowRealtime) {
         pw.println("Concurrency:");
 
         pw.increaseIndent();
@@ -522,19 +506,36 @@
         }
     }
 
-    public void dumpProtoLocked(ProtoOutputStream proto) {
-        // TODO Implement it.
+    public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
+        final long token = proto.start(tag);
+
+        proto.write(JobConcurrencyManagerProto.CURRENT_INTERACTIVE,
+                mCurrentInteractiveState);
+        proto.write(JobConcurrencyManagerProto.EFFECTIVE_INTERACTIVE,
+                mEffectiveInteractiveState);
+
+        proto.write(JobConcurrencyManagerProto.TIME_SINCE_LAST_SCREEN_ON_MS,
+                nowRealtime - mLastScreenOnRealtime);
+        proto.write(JobConcurrencyManagerProto.TIME_SINCE_LAST_SCREEN_OFF_MS,
+                nowRealtime - mLastScreenOffRealtime);
+
+        mJobCountTracker.dumpProto(proto, JobConcurrencyManagerProto.JOB_COUNT_TRACKER);
+
+        proto.write(JobConcurrencyManagerProto.MEMORY_TRIM_LEVEL,
+                mLastMemoryTrimLevel);
+
+        proto.end(token);
     }
 
     /**
-     * This class decides, taking into account {@link #mMaxJobCounts} and how many jos are running /
+     * This class decides, taking into account {@link #mMaxJobCounts} and how mny jos are running /
      * pending, how many more job can start.
      *
      * Extracted for testing and logging.
      */
     @VisibleForTesting
     static class JobCountTracker {
-        private int mConfigNumTotalMaxJobs;
+        private int mConfigNumMaxTotalJobs;
         private int mConfigNumMaxBgJobs;
         private int mConfigNumMinBgJobs;
 
@@ -552,7 +553,7 @@
         private int mNumActualMaxBgJobs;
 
         void reset(int numTotalMaxJobs, int numMaxBgJobs, int numMinBgJobs) {
-            mConfigNumTotalMaxJobs = numTotalMaxJobs;
+            mConfigNumMaxTotalJobs = numTotalMaxJobs;
             mConfigNumMaxBgJobs = numMaxBgJobs;
             mConfigNumMinBgJobs = numMinBgJobs;
 
@@ -607,12 +608,12 @@
 
             // However, if there are FG jobs already running, we have to adjust it.
             mNumReservedForBg = Math.min(reservedForBg,
-                    mConfigNumTotalMaxJobs - mNumRunningFgJobs);
+                    mConfigNumMaxTotalJobs - mNumRunningFgJobs);
 
             // Max FG is [total - [number needed for BG jobs]]
             // [number needed for BG jobs] is the bigger one of [running BG] or [reserved BG]
             final int maxFg =
-                    mConfigNumTotalMaxJobs - Math.max(mNumRunningBgJobs, mNumReservedForBg);
+                    mConfigNumMaxTotalJobs - Math.max(mNumRunningBgJobs, mNumReservedForBg);
 
             // The above maxFg is the theoretical max. If there are less FG jobs, the actual
             // max FG will be lower accordingly.
@@ -623,7 +624,7 @@
             // Max BG is [total - actual max FG], but cap at [config max BG].
             final int maxBg = Math.min(
                     mConfigNumMaxBgJobs,
-                    mConfigNumTotalMaxJobs - mNumActualMaxFgJobs);
+                    mConfigNumMaxTotalJobs - mNumActualMaxFgJobs);
 
             // If there are less BG jobs than maxBg, then reduce the actual max BG accordingly.
             // This isn't needed for the logic to work, but this will give consistent output
@@ -669,12 +670,13 @@
             final int totalBg = mNumRunningBgJobs + mNumStartingBgJobs;
             return String.format(
                     "Config={tot=%d bg min/max=%d/%d}"
-                            + " Running: %d / %d (%d)"
+                            + " Running[FG/BG (total)]: %d / %d (%d)"
                             + " Pending: %d / %d (%d)"
                             + " Actual max: %d%s / %d%s (%d%s)"
+                            + " Res BG: %d"
                             + " Starting: %d / %d (%d)"
                             + " Total: %d%s / %d%s (%d%s)",
-                    mConfigNumTotalMaxJobs,
+                    mConfigNumMaxTotalJobs,
                     mConfigNumMinBgJobs,
                     mConfigNumMaxBgJobs,
 
@@ -684,19 +686,37 @@
                     mNumPendingFgJobs, mNumPendingBgJobs,
                     mNumPendingFgJobs + mNumPendingBgJobs,
 
-                    mNumActualMaxFgJobs, (totalFg <= mConfigNumTotalMaxJobs) ? "" : "*",
+                    mNumActualMaxFgJobs, (totalFg <= mConfigNumMaxTotalJobs) ? "" : "*",
                     mNumActualMaxBgJobs, (totalBg <= mConfigNumMaxBgJobs) ? "" : "*",
 
                     mNumActualMaxFgJobs + mNumActualMaxBgJobs,
-                    (mNumActualMaxFgJobs + mNumActualMaxBgJobs <= mConfigNumTotalMaxJobs)
+                    (mNumActualMaxFgJobs + mNumActualMaxBgJobs <= mConfigNumMaxTotalJobs)
                             ? "" : "*",
 
+                    mNumReservedForBg,
+
                     mNumStartingFgJobs, mNumStartingBgJobs, mNumStartingFgJobs + mNumStartingBgJobs,
 
                     totalFg, (totalFg <= mNumActualMaxFgJobs) ? "" : "*",
                     totalBg, (totalBg <= mNumActualMaxBgJobs) ? "" : "*",
-                    totalFg + totalBg, (totalFg + totalBg <= mConfigNumTotalMaxJobs) ? "" : "*"
+                    totalFg + totalBg, (totalFg + totalBg <= mConfigNumMaxTotalJobs) ? "" : "*"
             );
         }
+
+        public void dumpProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+
+            proto.write(JobCountTrackerProto.CONFIG_NUM_MAX_TOTAL_JOBS, mConfigNumMaxTotalJobs);
+            proto.write(JobCountTrackerProto.CONFIG_NUM_MAX_BG_JOBS, mConfigNumMaxBgJobs);
+            proto.write(JobCountTrackerProto.CONFIG_NUM_MIN_BG_JOBS, mConfigNumMinBgJobs);
+
+            proto.write(JobCountTrackerProto.NUM_RUNNING_FG_JOBS, mNumRunningFgJobs);
+            proto.write(JobCountTrackerProto.NUM_RUNNING_BG_JOBS, mNumRunningBgJobs);
+
+            proto.write(JobCountTrackerProto.NUM_PENDING_FG_JOBS, mNumPendingFgJobs);
+            proto.write(JobCountTrackerProto.NUM_PENDING_BG_JOBS, mNumPendingBgJobs);
+
+            proto.end(token);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index bd12075..7625aaf 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -366,14 +366,20 @@
             }
         }
 
-        public int getTotalMax() {
+        /** Total number of jobs to run simultaneously. */
+        public int getMaxTotal() {
             return mTotal.getValue();
         }
 
+        /** Max number of BG (== owned by non-TOP apps) jobs to run simultaneously. */
         public int getMaxBg() {
             return mMaxBg.getValue();
         }
 
+        /**
+         * We try to run at least this many BG (== owned by non-TOP apps) jobs, when there are any
+         * pending, rather than always running the TOTAL number of FG jobs.
+         */
         public int getMinBg() {
             return mMinBg.getValue();
         }
@@ -384,10 +390,39 @@
             mMinBg.dump(pw, prefix);
         }
 
-        public void dumpProto(ProtoOutputStream proto, long tagTotal, long tagBg) {
-            mTotal.dumpProto(proto, tagTotal);
-            mMaxBg.dumpProto(proto, tagBg);
-            mMinBg.dumpProto(proto, tagBg);
+        public void dumpProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+            mTotal.dumpProto(proto, MaxJobCountsProto.TOTAL_JOBS);
+            mMaxBg.dumpProto(proto, MaxJobCountsProto.MAX_BG);
+            mMinBg.dumpProto(proto, MaxJobCountsProto.MIN_BG);
+            proto.end(token);
+        }
+    }
+
+    /** {@link MaxJobCounts} for each memory trim level. */
+    static class MaxJobCountsPerMemoryTrimLevel {
+        public final MaxJobCounts normal;
+        public final MaxJobCounts moderate;
+        public final MaxJobCounts low;
+        public final MaxJobCounts critical;
+
+        MaxJobCountsPerMemoryTrimLevel(
+                MaxJobCounts normal,
+                MaxJobCounts moderate, MaxJobCounts low,
+                MaxJobCounts critical) {
+            this.normal = normal;
+            this.moderate = moderate;
+            this.low = low;
+            this.critical = critical;
+        }
+
+        public void dumpProto(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+            normal.dumpProto(proto, MaxJobCountsPerMemoryTrimLevelProto.NORMAL);
+            moderate.dumpProto(proto, MaxJobCountsPerMemoryTrimLevelProto.MODERATE);
+            low.dumpProto(proto, MaxJobCountsPerMemoryTrimLevelProto.LOW);
+            critical.dumpProto(proto, MaxJobCountsPerMemoryTrimLevelProto.CRITICAL);
+            proto.end(token);
         }
     }
 
@@ -546,45 +581,44 @@
         float MODERATE_USE_FACTOR = DEFAULT_MODERATE_USE_FACTOR;
 
         // Max job counts for screen on / off, for each memory trim level.
-        final MaxJobCounts MAX_JOB_COUNTS_ON_NORMAL = new MaxJobCounts(
-                8, "max_job_total_on_normal",
-                6, "max_job_max_bg_on_normal",
-                2, "max_job_min_bg_on_normal");
+        final MaxJobCountsPerMemoryTrimLevel MAX_JOB_COUNTS_SCREEN_ON =
+                new MaxJobCountsPerMemoryTrimLevel(
+                        new MaxJobCounts(
+                                8, "max_job_total_on_normal",
+                                6, "max_job_max_bg_on_normal",
+                                2, "max_job_min_bg_on_normal"),
+                        new MaxJobCounts(
+                                8, "max_job_total_on_moderate",
+                                4, "max_job_max_bg_on_moderate",
+                                2, "max_job_min_bg_on_moderate"),
+                        new MaxJobCounts(
+                                5, "max_job_total_on_low",
+                                1, "max_job_max_bg_on_low",
+                                1, "max_job_min_bg_on_low"),
+                        new MaxJobCounts(
+                                5, "max_job_total_on_critical",
+                                1, "max_job_max_bg_on_critical",
+                                1, "max_job_min_bg_on_critical"));
 
-        final MaxJobCounts MAX_JOB_COUNTS_ON_MODERATE = new MaxJobCounts(
-                8, "max_job_total_on_moderate",
-                4, "max_job_max_bg_on_moderate",
-                2, "max_job_min_bg_on_moderate");
+        final MaxJobCountsPerMemoryTrimLevel MAX_JOB_COUNTS_SCREEN_OFF =
+                new MaxJobCountsPerMemoryTrimLevel(
+                        new MaxJobCounts(
+                                10, "max_job_total_off_normal",
+                                6, "max_job_max_bg_off_normal",
+                                2, "max_job_min_bg_off_normal"),
+                        new MaxJobCounts(
+                                10, "max_job_total_off_moderate",
+                                4, "max_job_max_bg_off_moderate",
+                                2, "max_job_min_bg_off_moderate"),
+                        new MaxJobCounts(
+                                5, "max_job_total_off_low",
+                                1, "max_job_max_bg_off_low",
+                                1, "max_job_min_bg_off_low"),
+                        new MaxJobCounts(
+                                5, "max_job_total_off_critical",
+                                1, "max_job_max_bg_off_critical",
+                                1, "max_job_min_bg_off_critical"));
 
-        final MaxJobCounts MAX_JOB_COUNTS_ON_LOW = new MaxJobCounts(
-                5, "max_job_total_on_low",
-                1, "max_job_max_bg_on_low",
-                1, "max_job_min_bg_on_low");
-
-        final MaxJobCounts MAX_JOB_COUNTS_ON_CRITICAL = new MaxJobCounts(
-                5, "max_job_total_on_critical",
-                1, "max_job_max_bg_on_critical",
-                1, "max_job_min_bg_on_critical");
-
-        final MaxJobCounts MAX_JOB_COUNTS_OFF_NORMAL = new MaxJobCounts(
-                10, "max_job_total_off_normal",
-                6, "max_job_max_bg_off_normal",
-                2, "max_job_min_bg_off_normal");
-
-        final MaxJobCounts MAX_JOB_COUNTS_OFF_MODERATE = new MaxJobCounts(
-                10, "max_job_total_off_moderate",
-                4, "max_job_max_bg_off_moderate",
-                2, "max_job_min_bg_off_moderate");
-
-        final MaxJobCounts MAX_JOB_COUNTS_OFF_LOW = new MaxJobCounts(
-                5, "max_job_total_off_low",
-                1, "max_job_max_bg_off_low",
-                1, "max_job_min_bg_off_low");
-
-        final MaxJobCounts MAX_JOB_COUNTS_OFF_CRITICAL = new MaxJobCounts(
-                5, "max_job_total_off_critical",
-                1, "max_job_max_bg_off_critical",
-                1, "max_job_min_bg_off_critical");
 
         /** Wait for this long after screen off before increasing the job concurrency. */
         final KeyValueListParser.IntValue SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS =
@@ -766,15 +800,15 @@
             MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR,
                     DEFAULT_MODERATE_USE_FACTOR);
 
-            MAX_JOB_COUNTS_ON_NORMAL.parse(mParser);
-            MAX_JOB_COUNTS_ON_MODERATE.parse(mParser);
-            MAX_JOB_COUNTS_ON_LOW.parse(mParser);
-            MAX_JOB_COUNTS_ON_CRITICAL.parse(mParser);
+            MAX_JOB_COUNTS_SCREEN_ON.normal.parse(mParser);
+            MAX_JOB_COUNTS_SCREEN_ON.moderate.parse(mParser);
+            MAX_JOB_COUNTS_SCREEN_ON.low.parse(mParser);
+            MAX_JOB_COUNTS_SCREEN_ON.critical.parse(mParser);
 
-            MAX_JOB_COUNTS_OFF_NORMAL.parse(mParser);
-            MAX_JOB_COUNTS_OFF_MODERATE.parse(mParser);
-            MAX_JOB_COUNTS_OFF_LOW.parse(mParser);
-            MAX_JOB_COUNTS_OFF_CRITICAL.parse(mParser);
+            MAX_JOB_COUNTS_SCREEN_OFF.normal.parse(mParser);
+            MAX_JOB_COUNTS_SCREEN_OFF.moderate.parse(mParser);
+            MAX_JOB_COUNTS_SCREEN_OFF.low.parse(mParser);
+            MAX_JOB_COUNTS_SCREEN_OFF.critical.parse(mParser);
 
             MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
                     DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
@@ -851,15 +885,17 @@
             pw.printPair(KEY_HEAVY_USE_FACTOR, HEAVY_USE_FACTOR).println();
             pw.printPair(KEY_MODERATE_USE_FACTOR, MODERATE_USE_FACTOR).println();
 
-            MAX_JOB_COUNTS_ON_NORMAL.dump(pw, "");
-            MAX_JOB_COUNTS_ON_MODERATE.dump(pw, "");
-            MAX_JOB_COUNTS_ON_LOW.dump(pw, "");
-            MAX_JOB_COUNTS_ON_CRITICAL.dump(pw, "");
+            MAX_JOB_COUNTS_SCREEN_ON.normal.dump(pw, "");
+            MAX_JOB_COUNTS_SCREEN_ON.moderate.dump(pw, "");
+            MAX_JOB_COUNTS_SCREEN_ON.low.dump(pw, "");
+            MAX_JOB_COUNTS_SCREEN_ON.critical.dump(pw, "");
 
-            MAX_JOB_COUNTS_OFF_NORMAL.dump(pw, "");
-            MAX_JOB_COUNTS_OFF_MODERATE.dump(pw, "");
-            MAX_JOB_COUNTS_OFF_LOW.dump(pw, "");
-            MAX_JOB_COUNTS_OFF_CRITICAL.dump(pw, "");
+            MAX_JOB_COUNTS_SCREEN_OFF.normal.dump(pw, "");
+            MAX_JOB_COUNTS_SCREEN_OFF.moderate.dump(pw, "");
+            MAX_JOB_COUNTS_SCREEN_OFF.low.dump(pw, "");
+            MAX_JOB_COUNTS_SCREEN_OFF.critical.dump(pw, "");
+
+            SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dump(pw, "");
 
             pw.printPair(KEY_MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT).println();
             pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println();
@@ -917,7 +953,11 @@
             proto.write(ConstantsProto.HEAVY_USE_FACTOR, HEAVY_USE_FACTOR);
             proto.write(ConstantsProto.MODERATE_USE_FACTOR, MODERATE_USE_FACTOR);
 
-            // TODO Dump max job counts.
+            MAX_JOB_COUNTS_SCREEN_ON.dumpProto(proto, ConstantsProto.MAX_JOB_COUNTS_SCREEN_ON);
+            MAX_JOB_COUNTS_SCREEN_OFF.dumpProto(proto, ConstantsProto.MAX_JOB_COUNTS_SCREEN_OFF);
+
+            SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS.dumpProto(proto,
+                    ConstantsProto.SCREEN_OFF_JOB_CONCURRENCY_INCREASE_DELAY_MS);
 
             proto.write(ConstantsProto.MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT);
             proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT);
@@ -3371,8 +3411,10 @@
 
     void dumpInternal(final IndentingPrintWriter pw, int filterUid) {
         final int filterUidFinal = UserHandle.getAppId(filterUid);
+        final long now = sSystemClock.millis();
         final long nowElapsed = sElapsedRealtimeClock.millis();
         final long nowUptime = sUptimeMillisClock.millis();
+
         final Predicate<JobStatus> predicate = (js) -> {
             return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal
                     || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal;
@@ -3548,7 +3590,7 @@
             }
             pw.println();
 
-            mConcurrencyManager.dumpLocked(pw);
+            mConcurrencyManager.dumpLocked(pw, now, nowElapsed);
 
             pw.println();
             pw.print("PersistStats: ");
@@ -3560,6 +3602,7 @@
     void dumpInternalProto(final FileDescriptor fd, int filterUid) {
         ProtoOutputStream proto = new ProtoOutputStream(fd);
         final int filterUidFinal = UserHandle.getAppId(filterUid);
+        final long now = sSystemClock.millis();
         final long nowElapsed = sElapsedRealtimeClock.millis();
         final long nowUptime = sUptimeMillisClock.millis();
         final Predicate<JobStatus> predicate = (js) -> {
@@ -3703,7 +3746,8 @@
                 proto.write(JobSchedulerServiceDumpProto.IS_READY_TO_ROCK, mReadyToRock);
                 proto.write(JobSchedulerServiceDumpProto.REPORTED_ACTIVE, mReportedActive);
             }
-            mConcurrencyManager.dumpProtoLocked(proto);
+            mConcurrencyManager.dumpProtoLocked(proto,
+                    JobSchedulerServiceDumpProto.CONCURRENCY_MANAGER, now, nowElapsed);
         }
 
         proto.flush();
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index aaa1874..8d64b81 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -666,6 +666,7 @@
 
             case android.provider.Settings.Secure.ALWAYS_ON_VPN_APP:
             case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN:
+            case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST:
                 // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn
                 final int appId = UserHandle.getAppId(callingUid);
                 if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0e40a00..13c4d88 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2569,6 +2569,7 @@
     }
 
     private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
+            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
             WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
             WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
         };
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index e1a911e..1d82970 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -825,16 +825,16 @@
                 // like the ANR / app crashed dialogs
                 return  canAddInternalSystemWindow ? 11 : 10;
             case TYPE_APPLICATION_OVERLAY:
-                return  12;
+                return  canAddInternalSystemWindow ? 13 : 12;
             case TYPE_DREAM:
                 // used for Dreams (screensavers with TYPE_DREAM windows)
-                return  13;
+                return  14;
             case TYPE_INPUT_METHOD:
                 // on-screen keyboards and other such input method user interfaces go here.
-                return  14;
+                return  15;
             case TYPE_INPUT_METHOD_DIALOG:
                 // on-screen keyboards and other such input method user interfaces go here.
-                return  15;
+                return  16;
             case TYPE_STATUS_BAR:
                 return  17;
             case TYPE_STATUS_BAR_PANEL:
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 055c941..7f2dedb 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.app.role.RoleManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.os.Debug;
 import android.provider.Settings;
@@ -90,6 +91,17 @@
 
                 return CollectionUtils.singletonOrEmpty(result);
             }
+            case RoleManager.ROLE_ASSISTANT: {
+                String legacyAssistant = Settings.Secure.getStringForUser(
+                        mContext.getContentResolver(), Settings.Secure.ASSISTANT, userId);
+
+                if (legacyAssistant == null || legacyAssistant.isEmpty()) {
+                    return Collections.emptyList();
+                } else {
+                    return Collections.singletonList(
+                            ComponentName.unflattenFromString(legacyAssistant).getPackageName());
+                }
+            }
             default: {
                 Slog.e(LOG_TAG, "Don't know how to find legacy role holders for " + roleName);
                 return Collections.emptyList();
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index c0517fd..1c7596b 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -198,6 +198,7 @@
             // Make sure to implement LegacyRoleResolutionPolicy#getRoleHolders
             // for a given role before adding a migration statement for it here
             migrateRoleIfNecessary(RoleManager.ROLE_SMS, userId);
+            migrateRoleIfNecessary(RoleManager.ROLE_ASSISTANT, userId);
 
             // Some vital packages state has changed since last role grant
             // Run grants again
diff --git a/services/core/java/com/android/server/rollback/LocalIntentReceiver.java b/services/core/java/com/android/server/rollback/LocalIntentReceiver.java
new file mode 100644
index 0000000..504a349
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/LocalIntentReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.rollback;
+
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.os.IBinder;
+
+import java.util.function.Consumer;
+
+/** {@code IntentSender} implementation for RollbackManager internal use. */
+class LocalIntentReceiver {
+    final Consumer<Intent> mConsumer;
+
+    LocalIntentReceiver(Consumer<Intent> consumer) {
+        mConsumer = consumer;
+    }
+
+    private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+        @Override
+        public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
+                IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
+            mConsumer.accept(intent);
+        }
+    };
+
+    public IntentSender getIntentSender() {
+        return new IntentSender((IIntentSender) mLocalSender);
+    }
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 693d5d6..8b4c410 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -19,8 +19,6 @@
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.IIntentReceiver;
-import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
@@ -36,11 +34,9 @@
 import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.RollbackInfo;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.storage.StorageManager;
@@ -66,7 +62,6 @@
 import java.util.Map;
 import java.util.Random;
 import java.util.Set;
-import java.util.function.Consumer;
 
 /**
  * Implementation of service that manages APK level rollbacks.
@@ -116,6 +111,7 @@
     private final Context mContext;
     private final HandlerThread mHandlerThread;
     private final Installer mInstaller;
+    private final RollbackPackageHealthObserver mPackageHealthObserver;
 
     RollbackManagerServiceImpl(Context context) {
         mContext = context;
@@ -128,6 +124,8 @@
 
         mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
 
+        mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
+
         // Kick off loading of the rollback data from strorage in a background
         // thread.
         // TODO: Consider loading the rollback data directly here instead, to
@@ -376,28 +374,32 @@
 
             final LocalIntentReceiver receiver = new LocalIntentReceiver(
                     (Intent result) -> {
-                        // We've now completed the rollback, so we mark it as no longer in
-                        // progress.
-                        data.inProgress = false;
+                        getHandler().post(() -> {
+                            // We've now completed the rollback, so we mark it as no longer in
+                            // progress.
+                            data.inProgress = false;
 
-                        int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                                PackageInstaller.STATUS_FAILURE);
-                        if (status != PackageInstaller.STATUS_SUCCESS) {
-                            sendFailure(statusReceiver, "Rollback downgrade install failed: "
-                                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
-                            return;
-                        }
+                            int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                                    PackageInstaller.STATUS_FAILURE);
+                            if (status != PackageInstaller.STATUS_SUCCESS) {
+                                sendFailure(statusReceiver,
+                                        "Rollback downgrade install failed: "
+                                        + result.getStringExtra(
+                                                PackageInstaller.EXTRA_STATUS_MESSAGE));
+                                return;
+                            }
 
-                        addRecentlyExecutedRollback(rollback);
-                        sendSuccess(statusReceiver);
+                            addRecentlyExecutedRollback(rollback);
+                            sendSuccess(statusReceiver);
 
-                        Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+                            Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
 
-                        // TODO: This call emits the warning "Calling a method in the
-                        // system process without a qualified user". Fix that.
-                        // TODO: Limit this to receivers holding the
-                        // MANAGE_ROLLBACKS permission?
-                        mContext.sendBroadcast(broadcast);
+                            // TODO: This call emits the warning "Calling a method in the
+                            // system process without a qualified user". Fix that.
+                            // TODO: Limit this to receivers holding the
+                            // MANAGE_ROLLBACKS permission?
+                            mContext.sendBroadcast(broadcast);
+                        });
                     }
             );
 
@@ -820,26 +822,6 @@
         });
     }
 
-    private class LocalIntentReceiver {
-        final Consumer<Intent> mConsumer;
-
-        LocalIntentReceiver(Consumer<Intent> consumer) {
-            mConsumer = consumer;
-        }
-
-        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
-            @Override
-            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
-                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
-                getHandler().post(() -> mConsumer.accept(intent));
-            }
-        };
-
-        public IntentSender getIntentSender() {
-            return new IntentSender((IIntentSender) mLocalSender);
-        }
-    }
-
     /**
      * Gets the version of the package currently installed.
      * Returns null if the package is not currently installed.
@@ -906,7 +888,17 @@
                             ensureRollbackDataLoadedLocked();
                             mAvailableRollbacks.add(data);
                         }
-
+                        // TODO(zezeozue): Provide API to explicitly start observing instead
+                        // of doing this for all rollbacks. If we do this for all rollbacks,
+                        // should document in PackageInstaller.SessionParams#setEnableRollback
+                        // After enabling and commiting any rollback, observe packages and
+                        // prepare to rollback if packages crashes too frequently.
+                        List<String> packages = new ArrayList<>();
+                        for (int i = 0; i < data.packages.size(); i++) {
+                            packages.add(data.packages.get(i).getPackageName());
+                        }
+                        mPackageHealthObserver.startObservingHealth(packages,
+                                ROLLBACK_LIFETIME_DURATION_MILLIS);
                         scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
                     } catch (IOException e) {
                         Log.e(TAG, "Unable to enable rollback", e);
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
new file mode 100644
index 0000000..1f2f1cc
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -0,0 +1,94 @@
+/*
+ * 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.rollback;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInstaller;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.server.PackageWatchdog;
+import com.android.server.PackageWatchdog.PackageHealthObserver;
+
+import java.util.List;
+
+/**
+ * {@code PackageHealthObserver} for {@code RollbackManagerService}.
+ *
+ * @hide
+ */
+public final class RollbackPackageHealthObserver implements PackageHealthObserver {
+    private static final String TAG = "RollbackPackageHealthObserver";
+    private static final String NAME = "rollback-observer";
+    private Context mContext;
+    private Handler mHandler;
+
+    RollbackPackageHealthObserver(Context context) {
+        mContext = context;
+        HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
+        handlerThread.start();
+        mHandler = handlerThread.getThreadHandler();
+        PackageWatchdog.getInstance(mContext).registerHealthObserver(this);
+    }
+
+    @Override
+    public boolean onHealthCheckFailed(String packageName) {
+        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
+        RollbackInfo rollback = rollbackManager.getAvailableRollback(packageName);
+        if (rollback != null) {
+            // TODO(zezeozue): Only rollback if rollback version == failed package version
+            mHandler.post(() -> executeRollback(rollbackManager, rollback));
+            return true;
+        }
+        // Don't handle the notification, no rollbacks available
+        return false;
+    }
+
+    /**
+     * Start observing health of {@code packages} for {@code durationMs}.
+     * This may cause {@code packages} to be rolled back if they crash too freqeuntly.
+     */
+    public void startObservingHealth(List<String> packages, long durationMs) {
+        PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
+    }
+
+    private void executeRollback(RollbackManager manager, RollbackInfo rollback) {
+        // TODO(zezeozue): Log initiated metrics
+        LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
+            mHandler.post(() -> {
+                int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                        PackageInstaller.STATUS_FAILURE);
+                if (status == PackageInstaller.STATUS_SUCCESS) {
+                    // TODO(zezeozue); Log success metrics
+                    // Rolledback successfully, no action required by other observers
+                } else {
+                    // TODO(zezeozue); Log failure metrics
+                    // Rollback failed other observers should have a shot
+                }
+            });
+        });
+        manager.executeRollback(rollback, rollbackReceiver.getIntentSender());
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d36e545..3a077b8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -747,12 +747,23 @@
         abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                 callingPid, resolvedType, aInfo.applicationInfo);
 
-        // not sure if we need to create START_ABORTED_BACKGROUND so for now piggybacking
-        // on START_ABORTED
+        boolean abortBackgroundStart = false;
         if (!abort) {
-            abort |= shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage,
-                    realCallingUid, callerApp, originatingPendingIntent,
+            abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid, callingPid,
+                    callingPackage, realCallingUid, callerApp, originatingPendingIntent,
                     allowBackgroundActivityStart, intent);
+            abort |= (abortBackgroundStart && !mService.isBackgroundActivityStartsEnabled());
+            // TODO: remove this toast after feature development is done
+            if (abortBackgroundStart) {
+                final String toastMsg = abort
+                        ? "Background activity start from " + callingPackage
+                                + " blocked. See go/q-bg-block."
+                        : "This background activity start from " + callingPackage
+                                + " will be blocked in future Q builds. See go/q-bg-block.";
+                mService.mUiHandler.post(() -> {
+                    Toast.makeText(mService.mContext, toastMsg, Toast.LENGTH_LONG).show();
+                });
+            }
         }
 
         // Merge the two options bundles, while realCallerOptions takes precedence.
@@ -798,8 +809,6 @@
             // We pretend to the caller that it was really started, but
             // they will just get a cancel result.
             ActivityOptions.abort(checkedOptions);
-            maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp,
-                    null /*r*/, originatingPendingIntent, true /*abortedStart*/);
             return START_ABORTED;
         }
 
@@ -892,8 +901,11 @@
         mService.onStartActivitySetDidAppSwitch();
         mController.doPendingActivityLaunches(false);
 
-        maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp, r,
-                originatingPendingIntent, false /*abortedStart*/);
+        // maybe log to TRON, but only if we haven't already in shouldAbortBackgroundActivityStart()
+        if (!abortBackgroundStart) {
+            maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp, r,
+                    originatingPendingIntent, false /*abortedStart*/);
+        }
 
         return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                 true /* doResume */, checkedOptions, inTask, outActivity);
@@ -903,11 +915,9 @@
             final String callingPackage, int realCallingUid, WindowProcessController callerApp,
             PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart,
             Intent intent) {
-        if (mService.isBackgroundActivityStartsEnabled()) {
-            return false;
-        }
         // don't abort for the most important UIDs
-        if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID) {
+        if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID
+                || callingUid == Process.NFC_UID) {
             return false;
         }
         // don't abort if the callerApp has any visible activity
@@ -915,14 +925,15 @@
             return false;
         }
         // don't abort if the callingUid is in the foreground or is a persistent system process
-        final boolean isCallingUidForeground = isUidForeground(callingUid);
+        final boolean isCallingUidForeground = mService.isUidForeground(callingUid);
         final boolean isCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
                 callingUid);
         if (isCallingUidForeground || isCallingUidPersistentSystemProcess) {
             return false;
         }
         // take realCallingUid into consideration
-        final boolean isRealCallingUidForeground = isUidForeground(realCallingUid);
+        final boolean isRealCallingUidForeground = mService.isUidForeground(
+                realCallingUid);
         final boolean isRealCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
                 realCallingUid);
         if (realCallingUid != callingUid) {
@@ -949,8 +960,8 @@
         if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
             return false;
         }
-        // anything that has fallen through will currently be aborted
-        Slog.w(TAG, "Blocking background activity start [callingPackage: " + callingPackage
+        // anything that has fallen through would currently be aborted
+        Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
                 + "; callingUid: " + callingUid
                 + "; isCallingUidForeground: " + isCallingUidForeground
                 + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
@@ -962,21 +973,11 @@
                 + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
                 + "; intent: " + intent
                 + "]");
-        // TODO: remove this toast after feature development is done
-        mService.mUiHandler.post(() -> {
-            Toast.makeText(mService.mContext,
-                    "Blocking background activity start for " + callingPackage,
-                    Toast.LENGTH_SHORT).show();
-        });
+        maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp,
+                null /*r*/, originatingPendingIntent, true /*abortedStart*/);
         return true;
     }
 
-    /** Returns true if uid has a visible window or its process is in a top state. */
-    private boolean isUidForeground(int uid) {
-        return (mService.getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
-            || mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
-    }
-
     /** Returns true if uid is in a persistent state. */
     private boolean isUidPersistentSystemProcess(int uid) {
         return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 67b00b2..1a5e6a1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -489,4 +489,7 @@
      */
     public abstract ActivityManager.TaskSnapshot getTaskSnapshot(int taskId,
             boolean reducedResolution);
+
+    /** Returns true if uid has a visible window or its process is in a top state. */
+    public abstract boolean isUidForeground(int uid);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ea6f4cc..e5a66cb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5632,6 +5632,11 @@
         return mActiveUids.get(uid, PROCESS_STATE_NONEXISTENT);
     }
 
+    boolean isUidForeground(int uid) {
+        return (getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
+                || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
+    }
+
     /**
      * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
      * the whitelist
@@ -7041,5 +7046,12 @@
                 return ActivityTaskManagerService.this.getTaskSnapshot(taskId, reducedResolution);
             }
         }
+
+        @Override
+        public boolean isUidForeground(int uid) {
+            synchronized (mGlobalLock) {
+                return ActivityTaskManagerService.this.isUidForeground(uid);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6d3c693..4006332 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -58,6 +58,7 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -2029,7 +2030,8 @@
                     of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
-                } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
+                } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT
+                        || type == TYPE_APPLICATION_OVERLAY) {
                     // These dialogs are stable to interim decor changes.
                     cf.set(displayFrames.mStable);
                     of.set(displayFrames.mStable);
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index c90113f..26f6d74 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -39,37 +39,7 @@
 template<typename T>
 using Return     = ::android::hardware::Return<T>;
 
-class LightHal {
-private:
-    static sp<ILight> sLight;
-    static bool sLightInit;
-
-    LightHal() {}
-
-public:
-    static void disassociate() {
-        sLightInit = false;
-        sLight = nullptr;
-    }
-
-    static sp<ILight> associate() {
-        if ((sLight == nullptr && !sLightInit) ||
-                (sLight != nullptr && !sLight->ping().isOk())) {
-            // will return the hal if it exists the first time.
-            sLight = ILight::getService();
-            sLightInit = true;
-
-            if (sLight == nullptr) {
-                ALOGE("Unable to get ILight interface.");
-            }
-        }
-
-        return sLight;
-    }
-};
-
-sp<ILight> LightHal::sLight = nullptr;
-bool LightHal::sLightInit = false;
+static bool sLightSupported = true;
 
 static bool validate(jint light, jint flash, jint brightness) {
     bool valid = true;
@@ -134,7 +104,6 @@
         const LightState &state) {
     if (!ret.isOk()) {
         ALOGE("Failed to issue set light command.");
-        LightHal::disassociate();
         return;
     }
 
@@ -164,13 +133,11 @@
         jint offMS,
         jint brightnessMode) {
 
-    if (!validate(light, flashMode, brightnessMode)) {
+    if (!sLightSupported) {
         return;
     }
 
-    sp<ILight> hal = LightHal::associate();
-
-    if (hal == nullptr) {
+    if (!validate(light, flashMode, brightnessMode)) {
         return;
     }
 
@@ -180,6 +147,11 @@
 
     {
         android::base::Timer t;
+        sp<ILight> hal = ILight::getService();
+        if (hal == nullptr) {
+            sLightSupported = false;
+            return;
+        }
         Return<Status> ret = hal->setLight(type, state);
         processReturn(ret, type, state);
         if (t.duration() > 50ms) ALOGD("Excessive delay setting light");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index d8225b3..2bf6f35 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -108,12 +108,7 @@
             ParcelFileDescriptor updateFileDescriptor, StartInstallingUpdateCallback listener) {}
 
     @Override
-    public void addCrossProfileCalendarPackage(ComponentName admin, String packageName) {
-    }
-
-    @Override
-    public boolean removeCrossProfileCalendarPackage(ComponentName admin, String packageName) {
-        return false;
+    public void setCrossProfileCalendarPackages(ComponentName admin, List<String> packageNames) {
     }
 
     @Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 54053a8..9088820 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -70,6 +70,7 @@
 import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
+import static android.app.admin.DevicePolicyManager.WIPE_SILENTLY;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -77,14 +78,10 @@
 import static android.provider.Telephony.Carriers.ENFORCE_KEY;
 import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
 
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
-        .PROVISIONING_ENTRY_POINT_ADB;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
-        .STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
-import static com.android.server.devicepolicy.TransferOwnershipMetadataManager
-        .ADMIN_TYPE_DEVICE_OWNER;
-import static com.android.server.devicepolicy.TransferOwnershipMetadataManager
-        .ADMIN_TYPE_PROFILE_OWNER;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER;
+import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -949,8 +946,8 @@
                 "metered_data_disabled_packages";
         private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES =
                 "cross-profile-calendar-packages";
-        private static final String TAG_PACKAGE = "package";
-
+        private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL =
+                "cross-profile-calendar-packages-null";
 
         DeviceAdminInfo info;
 
@@ -1072,7 +1069,9 @@
         String endUserSessionMessage = null;
 
         // The whitelist of packages that can access cross profile calendar APIs.
-        final Set<String> mCrossProfileCalendarPackages = new ArraySet<>();
+        // This whitelist should be in default an empty list, which indicates that no package
+        // is whitelisted.
+        List<String> mCrossProfileCalendarPackages = Collections.emptyList();
 
         ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
             info = _info;
@@ -1343,11 +1342,12 @@
                 out.text(endUserSessionMessage);
                 out.endTag(null, TAG_END_USER_SESSION_MESSAGE);
             }
-            if (!mCrossProfileCalendarPackages.isEmpty()) {
-                out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES);
-                writeAttributeValuesToXml(
-                        out, TAG_PACKAGE, mCrossProfileCalendarPackages);
-                out.endTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES);
+            if (mCrossProfileCalendarPackages == null) {
+                out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL);
+                out.endTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL);
+            } else {
+                writePackageListToXml(out, TAG_CROSS_PROFILE_CALENDAR_PACKAGES,
+                        mCrossProfileCalendarPackages);
             }
         }
 
@@ -1542,8 +1542,9 @@
                         Log.w(LOG_TAG, "Missing text when loading end session message");
                     }
                 } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) {
-                    readAttributeValues(
-                            parser, TAG_PACKAGE, mCrossProfileCalendarPackages);
+                    mCrossProfileCalendarPackages = readPackageList(parser, tag);
+                } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL.equals(tag)) {
+                    mCrossProfileCalendarPackages = null;
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1759,8 +1760,10 @@
                 pw.print(prefix);  pw.println("parentAdmin:");
                 parentAdmin.dump(prefix + "  ", pw);
             }
-            pw.print(prefix); pw.print("mCrossProfileCalendarPackages=");
-            pw.println(mCrossProfileCalendarPackages);
+            if (mCrossProfileCalendarPackages != null) {
+                pw.print(prefix); pw.print("mCrossProfileCalendarPackages=");
+                pw.println(mCrossProfileCalendarPackages);
+            }
         }
     }
 
@@ -1916,7 +1919,11 @@
         }
 
         AlarmManager getAlarmManager() {
-            return (AlarmManager) mContext.getSystemService(AlarmManager.class);
+            return mContext.getSystemService(AlarmManager.class);
+        }
+
+        ConnectivityManager getConnectivityManager() {
+            return mContext.getSystemService(ConnectivityManager.class);
         }
 
         IWindowManager getIWindowManager() {
@@ -6299,7 +6306,8 @@
      * @throws UnsupportedOperationException if the package does not support being set as always-on.
      */
     @Override
-    public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown)
+    public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown,
+            List<String> lockdownWhitelist)
             throws SecurityException {
         enforceProfileOrDeviceOwner(admin);
 
@@ -6307,11 +6315,23 @@
         final long token = mInjector.binderClearCallingIdentity();
         try {
             if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) {
-                return false;
+                Slog.w(LOG_TAG, "Non-existent VPN package specified: " + vpnPackage);
+                throw new ServiceSpecificException(
+                        DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, vpnPackage);
             }
-            ConnectivityManager connectivityManager = (ConnectivityManager)
-                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-            if (!connectivityManager.setAlwaysOnVpnPackageForUser(userId, vpnPackage, lockdown)) {
+
+            if (vpnPackage != null && lockdown && lockdownWhitelist != null) {
+                for (String packageName : lockdownWhitelist) {
+                    if (!isPackageInstalledForUser(packageName, userId)) {
+                        Slog.w(LOG_TAG, "Non-existent package in VPN whitelist: " + packageName);
+                        throw new ServiceSpecificException(
+                                DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, packageName);
+                    }
+                }
+            }
+            // If some package is uninstalled after the check above, it will be ignored by CM.
+            if (!mInjector.getConnectivityManager().setAlwaysOnVpnPackageForUser(
+                    userId, vpnPackage, lockdown, lockdownWhitelist)) {
                 throw new UnsupportedOperationException();
             }
             DevicePolicyEventLogger
@@ -6328,16 +6348,40 @@
     }
 
     @Override
-    public String getAlwaysOnVpnPackage(ComponentName admin)
+    public String getAlwaysOnVpnPackage(ComponentName admin) throws SecurityException {
+        enforceProfileOrDeviceOwner(admin);
+
+        final int userId = mInjector.userHandleGetCallingUserId();
+        final long token = mInjector.binderClearCallingIdentity();
+        try {
+            return mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(userId);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
+        enforceProfileOrDeviceOwner(admin);
+
+        final int userId = mInjector.userHandleGetCallingUserId();
+        final long token = mInjector.binderClearCallingIdentity();
+        try {
+            return mInjector.getConnectivityManager().isVpnLockdownEnabled(userId);
+        } finally {
+            mInjector.binderRestoreCallingIdentity(token);
+        }
+    }
+
+    @Override
+    public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin)
             throws SecurityException {
         enforceProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
         final long token = mInjector.binderClearCallingIdentity();
-        try{
-            ConnectivityManager connectivityManager = (ConnectivityManager)
-                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-            return connectivityManager.getAlwaysOnVpnPackageForUser(userId);
+        try {
+            return mInjector.getConnectivityManager().getVpnLockdownWhitelist(userId);
         } finally {
             mInjector.binderRestoreCallingIdentity(token);
         }
@@ -6362,7 +6406,7 @@
         }
     }
 
-    private void forceWipeUser(int userId, String wipeReasonForUser) {
+    private void forceWipeUser(int userId, String wipeReasonForUser, boolean wipeSilently) {
         boolean success = false;
         try {
             IActivityManager am = mInjector.getIActivityManager();
@@ -6373,7 +6417,7 @@
             success = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
             if (!success) {
                 Slog.w(LOG_TAG, "Couldn't remove user " + userId);
-            } else if (isManagedProfile(userId) && !TextUtils.isEmpty(wipeReasonForUser)) {
+            } else if (isManagedProfile(userId) && !wipeSilently) {
                 sendWipeProfileNotification(wipeReasonForUser);
             }
         } catch (RemoteException re) {
@@ -6388,6 +6432,7 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkStringNotEmpty(wipeReasonForUser, "wipeReasonForUser is null or empty");
         enforceFullCrossUsersPermission(mInjector.userHandleGetCallingUserId());
 
         final ActiveAdmin admin;
@@ -6447,7 +6492,7 @@
                         internalReason,
                         /*wipeEuicc=*/ (flags & WIPE_EUICC) != 0);
             } else {
-                forceWipeUser(userId, wipeReasonForUser);
+                forceWipeUser(userId, wipeReasonForUser, (flags & WIPE_SILENTLY) != 0);
             }
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -6809,9 +6854,7 @@
         enforceDeviceOwner(who);
         long token = mInjector.binderClearCallingIdentity();
         try {
-            ConnectivityManager connectivityManager = (ConnectivityManager)
-                    mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-            connectivityManager.setGlobalProxy(proxyInfo);
+            mInjector.getConnectivityManager().setGlobalProxy(proxyInfo);
         } finally {
             mInjector.binderRestoreCallingIdentity(token);
         }
@@ -13988,55 +14031,27 @@
     }
 
     @Override
-    public void addCrossProfileCalendarPackage(ComponentName who, String packageName) {
+    public void setCrossProfileCalendarPackages(ComponentName who, List<String> packageNames) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkStringNotEmpty(packageName, "Package name is null or empty");
 
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            if (admin.mCrossProfileCalendarPackages.add(packageName)) {
-                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
-            }
+            admin.mCrossProfileCalendarPackages = packageNames;
+            saveSettingsLocked(mInjector.userHandleGetCallingUserId());
         }
         DevicePolicyEventLogger
-                .createEvent(DevicePolicyEnums.ADD_CROSS_PROFILE_CALENDAR_PACKAGE)
+                .createEvent(DevicePolicyEnums.SET_CROSS_PROFILE_CALENDAR_PACKAGES)
                 .setAdmin(who)
-                .setStrings(packageName)
+                .setStrings(packageNames == null ? null
+                        : packageNames.toArray(new String[packageNames.size()]))
                 .write();
     }
 
     @Override
-    public boolean removeCrossProfileCalendarPackage(ComponentName who, String packageName) {
-        if (!mHasFeature) {
-            return false;
-        }
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkStringNotEmpty(packageName, "Package name is null or empty");
-
-        boolean isRemoved = false;
-        synchronized (getLockObject()) {
-            final ActiveAdmin admin = getActiveAdminForCallerLocked(
-                    who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            isRemoved = admin.mCrossProfileCalendarPackages.remove(packageName);
-            if (isRemoved) {
-                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
-            }
-        }
-        if (isRemoved) {
-            DevicePolicyEventLogger
-                    .createEvent(DevicePolicyEnums.REMOVE_CROSS_PROFILE_CALENDAR_PACKAGE)
-                    .setAdmin(who)
-                    .setStrings(packageName)
-                    .write();
-        }
-        return isRemoved;
-    }
-
-    @Override
     public List<String> getCrossProfileCalendarPackages(ComponentName who) {
         if (!mHasFeature) {
             return Collections.emptyList();
@@ -14046,7 +14061,7 @@
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getActiveAdminForCallerLocked(
                     who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            return new ArrayList<String>(admin.mCrossProfileCalendarPackages);
+            return admin.mCrossProfileCalendarPackages;
         }
     }
 
@@ -14062,6 +14077,9 @@
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
             if (admin != null) {
+                if (admin.mCrossProfileCalendarPackages == null) {
+                    return true;
+                }
                 return admin.mCrossProfileCalendarPackages.contains(packageName);
             }
         }
@@ -14077,7 +14095,7 @@
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
             if (admin != null) {
-                return new ArrayList<String>(admin.mCrossProfileCalendarPackages);
+                return admin.mCrossProfileCalendarPackages;
             }
         }
         return Collections.emptyList();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 65eaf554..5861368 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1561,6 +1561,12 @@
                 traceEnd();
             }
 
+            // Grants default permissions and defines roles
+            traceBeginAndSlog("StartRoleManagerService");
+            mSystemServiceManager.startService(new RoleManagerService(
+                    mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
+            traceEnd();
+
             // We need to always start this service, regardless of whether the
             // FEATURE_VOICE_RECOGNIZERS feature is set, because it needs to take care
             // of initializing various settings.  It will internally modify its behavior
@@ -2011,12 +2017,6 @@
             }
             traceEnd();
 
-            // Grants default permissions and defines roles
-            traceBeginAndSlog("StartRoleManagerService");
-            mSystemServiceManager.startService(new RoleManagerService(
-                    mSystemContext, new LegacyRoleResolutionPolicy(mSystemContext)));
-            traceEnd();
-
             // No dependency on Webview preparation in system server. But this should
             // be completed before allowing 3rd party
             final String WEBVIEW_PREPARATION = "WebViewFactoryPreparation";
diff --git a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
new file mode 100644
index 0000000..1a231cf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
@@ -0,0 +1,379 @@
+/*
+ * 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.am;
+
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3;
+import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_4;
+import static android.provider.DeviceConfig.ActivityManager.KEY_USE_COMPACTION;
+
+import static com.android.server.am.ActivityManagerService.Injector;
+import static com.android.server.am.AppCompactor.compactActionIntToString;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.provider.DeviceConfig;
+import android.support.test.uiautomator.UiDevice;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.appop.AppOpsService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link AppCompactor}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:AppCompactorTest
+ */
+@RunWith(AndroidJUnit4.class)
+public final class AppCompactorTest {
+
+    @Mock private AppOpsService mAppOpsService;
+    private AppCompactor mCompactorUnderTest;
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+    private CountDownLatch mCountDown;
+
+    private static void clearDeviceConfig() throws IOException  {
+        UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        uiDevice.executeShellCommand(
+                "device_config delete activity_manager " + KEY_USE_COMPACTION);
+        uiDevice.executeShellCommand(
+                "device_config delete activity_manager " + KEY_COMPACT_ACTION_1);
+        uiDevice.executeShellCommand(
+                "device_config delete activity_manager " + KEY_COMPACT_ACTION_2);
+        uiDevice.executeShellCommand(
+                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_1);
+        uiDevice.executeShellCommand(
+                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_2);
+        uiDevice.executeShellCommand(
+                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_3);
+        uiDevice.executeShellCommand(
+                "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_4);
+    }
+
+    @Before
+    public void setUp() throws IOException {
+        MockitoAnnotations.initMocks(this);
+        clearDeviceConfig();
+        mHandlerThread = new HandlerThread("");
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+        ActivityManagerService ams = new ActivityManagerService(new TestInjector());
+        mCompactorUnderTest = new AppCompactor(ams,
+                new AppCompactor.PropertyChangedCallbackForTest() {
+                    @Override
+                    public void onPropertyChanged() {
+                        if (mCountDown != null) {
+                            mCountDown.countDown();
+                        }
+                    }
+                });
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        mHandlerThread.quit();
+        mCountDown = null;
+        clearDeviceConfig();
+    }
+
+    @Test
+    public void init_setsDefaults() {
+        mCompactorUnderTest.init();
+        assertThat(mCompactorUnderTest.useCompaction(),
+                is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
+        assertThat(mCompactorUnderTest.mCompactActionSome, is(
+                compactActionIntToString(mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1)));
+        assertThat(mCompactorUnderTest.mCompactActionFull, is(
+                compactActionIntToString(mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2)));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
+    }
+
+    @Test
+    public void init_withDeviceConfigSetsParameters() {
+        // When the DeviceConfig already has a flag value stored (note this test will need to
+        // change if the default value changes from false).
+        assertThat(mCompactorUnderTest.DEFAULT_USE_COMPACTION, is(false));
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_USE_COMPACTION, "true", false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_ACTION_1,
+                Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 3) + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_ACTION_2,
+                Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 3) + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_1,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_2,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_3,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_4,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
+
+        // Then calling init will read and set that flag.
+        mCompactorUnderTest.init();
+        assertThat(mCompactorUnderTest.useCompaction(), is(true));
+        assertThat(mCompactorUnderTest.mCompactionThread.isAlive(), is(true));
+
+        assertThat(mCompactorUnderTest.mCompactActionSome,
+                is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 3) + 1)));
+        assertThat(mCompactorUnderTest.mCompactActionFull,
+                is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 3) + 1)));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1));
+    }
+
+    @Test
+    public void useCompaction_listensToDeviceConfigChanges() throws InterruptedException {
+        assertThat(mCompactorUnderTest.useCompaction(),
+                is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
+        // When we call init and change some the flag value...
+        mCompactorUnderTest.init();
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_USE_COMPACTION, "true", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        // Then that new flag value is updated in the implementation.
+        assertThat(mCompactorUnderTest.useCompaction(), is(true));
+        assertThat(mCompactorUnderTest.mCompactionThread.isAlive(), is(true));
+
+        // And again, setting the flag the other way.
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_USE_COMPACTION, "false", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+        assertThat(mCompactorUnderTest.useCompaction(), is(false));
+    }
+
+    @Test
+    public void useCompaction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
+        assertThat(mCompactorUnderTest.useCompaction(),
+                is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
+        mCompactorUnderTest.init();
+
+        // When we push an invalid flag value...
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_USE_COMPACTION, "foobar", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        // Then we set the default.
+        assertThat(mCompactorUnderTest.useCompaction(), is(AppCompactor.DEFAULT_USE_COMPACTION));
+    }
+
+    @Test
+    public void compactAction_listensToDeviceConfigChanges() throws InterruptedException {
+        mCompactorUnderTest.init();
+
+        // When we override new values for the compaction action with reasonable values...
+
+        // There are three possible values for compactAction[Some|Full].
+        for (int i = 1; i < 4; i++) {
+            mCountDown = new CountDownLatch(2);
+            int expectedSome = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1 + i) % 3 + 1;
+            DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                    KEY_COMPACT_ACTION_1, Integer.toString(expectedSome), false);
+            int expectedFull = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2 + i) % 3 + 1;
+            DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                    KEY_COMPACT_ACTION_2, Integer.toString(expectedFull), false);
+            assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+            // Then the updates are reflected in the flags.
+            assertThat(mCompactorUnderTest.mCompactActionSome,
+                    is(compactActionIntToString(expectedSome)));
+            assertThat(mCompactorUnderTest.mCompactActionFull,
+                    is(compactActionIntToString(expectedFull)));
+        }
+    }
+
+    @Test
+    public void compactAction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
+        mCompactorUnderTest.init();
+
+        // When we override new values for the compaction action with bad values ...
+        mCountDown = new CountDownLatch(2);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_ACTION_1, "foo", false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_ACTION_2, "foo", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        // Then the default values are reflected in the flag
+        assertThat(mCompactorUnderTest.mCompactActionSome,
+                is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1)));
+        assertThat(mCompactorUnderTest.mCompactActionFull,
+                is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2)));
+
+        mCountDown = new CountDownLatch(2);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_ACTION_1, "", false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_ACTION_2, "", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        assertThat(mCompactorUnderTest.mCompactActionSome,
+                is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1)));
+        assertThat(mCompactorUnderTest.mCompactActionFull,
+                is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2)));
+    }
+
+    @Test
+    public void compactThrottle_listensToDeviceConfigChanges() throws InterruptedException {
+        mCompactorUnderTest.init();
+
+        // When we override new reasonable throttle values after init...
+        mCountDown = new CountDownLatch(4);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_1,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_2,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_3,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_4,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+
+        // Then those flags values are reflected in the compactor.
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1));
+    }
+
+    @Test
+    public void compactThrottle_listensToDeviceConfigChangesBadValues()
+            throws IOException, InterruptedException {
+        mCompactorUnderTest.init();
+
+        // When one of the throttles is overridden with a bad value...
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_1, "foo", false);
+        // Then all the throttles have the defaults set.
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
+        clearDeviceConfig();
+
+        // Repeat for each of the throttle keys.
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_2, "foo", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
+        clearDeviceConfig();
+
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_3, "foo", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
+        clearDeviceConfig();
+
+        mCountDown = new CountDownLatch(1);
+        DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
+                KEY_COMPACT_THROTTLE_4, "foo", false);
+        assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
+        assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
+        assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
+                is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
+    }
+
+    private class TestInjector extends Injector {
+        @Override
+        public AppOpsService getAppOpsService(File file, Handler handler) {
+            return mAppOpsService;
+        }
+
+        @Override
+        public Handler getUiHandler(ActivityManagerService service) {
+            return mHandler;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index ac4a5fe..a3f36b7 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -24,11 +24,15 @@
 import static junit.framework.Assert.fail;
 
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.Manifest;
 import android.annotation.UserIdInt;
 import android.app.backup.BackupManager;
 import android.app.backup.IBackupManagerMonitor;
@@ -39,21 +43,21 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
-import android.provider.Settings;
-import android.test.mock.MockContentResolver;
 import android.util.SparseArray;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.util.test.FakeSettingsProvider;
-
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -99,10 +103,6 @@
     @Mock
     private Context mContextMock;
     @Mock
-    private File mSuppressFileMock;
-    @Mock
-    private File mSuppressFileParentMock;
-    @Mock
     private IBinder mAgentMock;
     @Mock
     private ParcelFileDescriptor mParcelFileDescriptorMock;
@@ -114,95 +114,53 @@
     private IBackupManagerMonitor mBackupManagerMonitorMock;
     @Mock
     private PrintWriter mPrintWriterMock;
+    @Mock
+    private UserManager mUserManagerMock;
+    @Mock
+    private UserInfo mUserInfoMock;
 
     private FileDescriptor mFileDescriptorStub = new FileDescriptor();
 
     private TrampolineTestable mTrampoline;
-    private MockContentResolver mContentResolver;
+    private File mTestDir;
+    private File mSuppressFile;
+    private File mActivatedFile;
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mUserId = NON_USER_SYSTEM;
+        mUserId = UserHandle.USER_SYSTEM;
 
         SparseArray<UserBackupManagerService> serviceUsers = new SparseArray<>();
-        serviceUsers.append(UserHandle.SYSTEM.getIdentifier(), mUserBackupManagerService);
+        serviceUsers.append(UserHandle.USER_SYSTEM, mUserBackupManagerService);
         serviceUsers.append(NON_USER_SYSTEM, mUserBackupManagerService);
         when(mBackupManagerServiceMock.getServiceUsers()).thenReturn(serviceUsers);
 
+        when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);
+        when(mUserManagerMock.getUserInfo(NON_USER_SYSTEM)).thenReturn(mUserInfoMock);
+
         TrampolineTestable.sBackupManagerServiceMock = mBackupManagerServiceMock;
         TrampolineTestable.sCallingUserId = UserHandle.USER_SYSTEM;
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
         TrampolineTestable.sBackupDisabled = false;
+        TrampolineTestable.sUserManagerMock = mUserManagerMock;
 
-        when(mSuppressFileMock.getParentFile()).thenReturn(mSuppressFileParentMock);
+        mTestDir = InstrumentationRegistry.getContext().getFilesDir();
+        mTestDir.mkdirs();
+
+        mSuppressFile = new File(mTestDir, "suppress");
+        TrampolineTestable.sSuppressFile = mSuppressFile;
+
+        mActivatedFile = new File(mTestDir, "activate-" + NON_USER_SYSTEM);
+        TrampolineTestable.sActivatedFiles.append(NON_USER_SYSTEM, mActivatedFile);
 
         mTrampoline = new TrampolineTestable(mContextMock);
-
-        mContentResolver = new MockContentResolver();
-        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
-        when(mContextMock.getContentResolver()).thenReturn(mContentResolver);
     }
 
-    @Test
-    public void unlockUser_whenMultiUserSettingDisabled_callsBackupManagerServiceForSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
-        mTrampoline.initializeService();
-
-        mTrampoline.unlockUser(UserHandle.USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock).startServiceForUser(UserHandle.USER_SYSTEM);
-    }
-
-    @Test
-    public void unlockUser_whenMultiUserSettingDisabled_isIgnoredForNonSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
-        mTrampoline.initializeService();
-
-        mTrampoline.unlockUser(NON_USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock, never()).startServiceForUser(NON_USER_SYSTEM);
-    }
-
-    @Test
-    public void unlockUser_whenMultiUserSettingEnabled_callsBackupManagerServiceForNonSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1);
-        mTrampoline.initializeService();
-
-        mTrampoline.unlockUser(NON_USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock).startServiceForUser(NON_USER_SYSTEM);
-    }
-
-    @Test
-    public void stopUser_whenMultiUserSettingDisabled_callsBackupManagerServiceForSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
-        mTrampoline.initializeService();
-
-        mTrampoline.stopUser(UserHandle.USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock).stopServiceForUser(UserHandle.USER_SYSTEM);
-    }
-
-    @Test
-    public void stopUser_whenMultiUserSettingDisabled_isIgnoredForNonSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
-        mTrampoline.initializeService();
-
-        mTrampoline.stopUser(NON_USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock, never()).stopServiceForUser(NON_USER_SYSTEM);
-    }
-
-    @Test
-    public void stopUser_whenMultiUserSettingEnabled_callsBackupManagerServiceForNonSystemUser() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1);
-
-        mTrampoline.initializeService();
-
-        mTrampoline.stopUser(NON_USER_SYSTEM);
-
-        verify(mBackupManagerServiceMock).stopServiceForUser(NON_USER_SYSTEM);
+    @After
+    public void tearDown() throws Exception {
+        mSuppressFile.delete();
+        mActivatedFile.delete();
     }
 
     @Test
@@ -222,18 +180,6 @@
         assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
     }
 
-    // Verify that BackupManagerService is not initialized if suppress file exists.
-    @Test
-    public void initializeService_suppressFileExists_nonInitialized() throws Exception {
-        TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
-        trampoline.createBackupSuppressFileForUser(UserHandle.USER_SYSTEM);
-
-
-        trampoline.initializeService();
-
-        assertFalse(trampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
-    }
-
     @Test
     public void initializeService_doesNotStartServiceForUsers() {
         mTrampoline.initializeService();
@@ -247,15 +193,55 @@
     }
 
     @Test
-    public void isBackupServiceActive_forNonSysUser_whenSysUserIsDeactivated_returnsFalse() {
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+    public void isBackupServiceActive_forSystemUser_returnsTrueWhenActivated() throws Exception {
+        mTrampoline.initializeService();
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+    }
+
+    @Test
+    public void isBackupServiceActive_forSystemUser_returnsFalseWhenDeactivated() throws Exception {
+        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
+        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+    }
+
+    @Test
+    public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenSystemUserDeactivated()
+            throws Exception {
+        mTrampoline.initializeService();
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
         assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
     }
 
     @Test
-    public void setBackupServiceActive_callerSystemUid_serviceCreated() {
+    public void isBackupServiceActive_forNonSystemUser_returnsFalseWhenNonSystemUserDeactivated()
+            throws Exception {
+        mTrampoline.initializeService();
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        // Don't activate non-system user.
+
+        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void
+            isBackupServiceActive_forNonSystemUser_returnsTrueWhenSystemAndNonSystemUserActivated()
+                throws Exception {
+        mTrampoline.initializeService();
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void setBackupServiceActive_forSystemUserAndCallerSystemUid_serviceCreated() {
+        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -264,7 +250,8 @@
     }
 
     @Test
-    public void setBackupServiceActive_callerRootUid_serviceCreated() {
+    public void setBackupServiceActive_forSystemUserAndCallerRootUid_serviceCreated() {
+        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.ROOT_UID;
 
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
@@ -273,7 +260,8 @@
     }
 
     @Test
-    public void setBackupServiceActive_callerNonRootNonSystem_securityExceptionThrown() {
+    public void setBackupServiceActive_forSystemUserAndCallerNonRootNonSystem_throws() {
+        mTrampoline.initializeService();
         TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
 
         try {
@@ -281,14 +269,77 @@
             fail();
         } catch (SecurityException expected) {
         }
+    }
 
-        assertFalse(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
+    @Test
+    public void setBackupServiceActive_forManagedProfileAndCallerSystemUid_serviceCreated() {
+        when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+        mTrampoline.initializeService();
+        TrampolineTestable.sCallingUid = Process.SYSTEM_UID;
+
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void setBackupServiceActive_forManagedProfileAndCallerRootUid_serviceCreated() {
+        when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+        mTrampoline.initializeService();
+        TrampolineTestable.sCallingUid = Process.ROOT_UID;
+
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+    }
+
+    @Test
+    public void setBackupServiceActive_forManagedProfileAndCallerNonRootNonSystem_throws() {
+        when(mUserInfoMock.isManagedProfile()).thenReturn(true);
+        mTrampoline.initializeService();
+        TrampolineTestable.sCallingUid = Process.FIRST_APPLICATION_UID;
+
+        try {
+            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            fail();
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void setBackupServiceActive_forNonSystemUserAndCallerWithoutBackupPermission_throws() {
+        doThrow(new SecurityException())
+                .when(mContextMock)
+                .enforceCallingOrSelfPermission(eq(Manifest.permission.BACKUP), anyString());
+        mTrampoline.initializeService();
+
+        try {
+            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            fail();
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void setBackupServiceActive_forNonSystemUserAndCallerWithoutUserPermission_throws() {
+        doThrow(new SecurityException())
+                .when(mContextMock)
+                .enforceCallingOrSelfPermission(
+                        eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString());
+        mTrampoline.initializeService();
+
+        try {
+            mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+            fail();
+        } catch (SecurityException expected) {
+        }
     }
 
     @Test
     public void setBackupServiceActive_backupDisabled_ignored() {
         TrampolineTestable.sBackupDisabled = true;
         TrampolineTestable trampoline = new TrampolineTestable(mContextMock);
+        trampoline.initializeService();
 
         trampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
@@ -296,14 +347,8 @@
     }
 
     @Test
-    public void setBackupServiceActive_nonUserSystem_ignored() {
-        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
-
-        assertFalse(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
-    }
-
-    @Test
     public void setBackupServiceActive_alreadyActive_ignored() {
+        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
         assertEquals(1, mTrampoline.getCreateServiceCallsCount());
@@ -315,6 +360,7 @@
 
     @Test
     public void setBackupServiceActive_makeNonActive_alreadyNonActive_ignored() {
+        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
 
@@ -323,6 +369,7 @@
 
     @Test
     public void setBackupServiceActive_makeActive_serviceCreatedAndSuppressFileDeleted() {
+        mTrampoline.initializeService();
         mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
 
         assertTrue(mTrampoline.isBackupServiceActive(UserHandle.USER_SYSTEM));
@@ -349,6 +396,21 @@
     }
 
     @Test
+    public void setBackupServiceActive_forOneNonSystemUser_doesNotActivateForAllNonSystemUsers() {
+        mTrampoline.initializeService();
+        int otherUser = NON_USER_SYSTEM + 1;
+        File activateFile = new File(mTestDir, "activate-" + otherUser);
+        TrampolineTestable.sActivatedFiles.append(otherUser, activateFile);
+        mTrampoline.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+
+        mTrampoline.setBackupServiceActive(NON_USER_SYSTEM, true);
+
+        assertTrue(mTrampoline.isBackupServiceActive(NON_USER_SYSTEM));
+        assertFalse(mTrampoline.isBackupServiceActive(otherUser));
+        activateFile.delete();
+    }
+
+    @Test
     public void dataChanged_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.dataChanged(PACKAGE_NAME);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
@@ -1123,7 +1185,7 @@
     @Test
     public void requestBackup_forwardedToCallingUserId() throws Exception {
         TrampolineTestable.sCallingUserId = mUserId;
-        when(mBackupManagerServiceMock.requestBackup(NON_USER_SYSTEM, PACKAGE_NAMES,
+        when(mBackupManagerServiceMock.requestBackup(mUserId, PACKAGE_NAMES,
                 mBackupObserverMock, mBackupManagerMonitorMock, 123)).thenReturn(456);
         mTrampoline.initializeService();
 
@@ -1227,50 +1289,33 @@
         static int sCallingUserId = -1;
         static int sCallingUid = -1;
         static BackupManagerService sBackupManagerServiceMock = null;
+        static File sSuppressFile = null;
+        static SparseArray<File> sActivatedFiles = new SparseArray<>();
+        static UserManager sUserManagerMock = null;
         private int mCreateServiceCallsCount = 0;
-        private SparseArray<FakeFile> mSuppressFiles = new SparseArray<>();
-
-        private static class FakeFile extends File {
-            private boolean mExists;
-
-            FakeFile(String pathname) {
-                super(pathname);
-            }
-
-            @Override
-            public boolean exists() {
-                return mExists;
-            }
-
-            @Override
-            public boolean delete() {
-                mExists = false;
-                return true;
-            }
-
-            @Override
-            public boolean createNewFile() throws IOException {
-                mExists = true;
-                return true;
-            }
-        }
 
         TrampolineTestable(Context context) {
             super(context);
         }
 
         @Override
+        protected UserManager getUserManager() {
+            return sUserManagerMock;
+        }
+
+        @Override
         public boolean isBackupDisabled() {
             return sBackupDisabled;
         }
 
         @Override
-        public File getSuppressFileForUser(int userId) {
-            if (mSuppressFiles.get(userId) == null) {
-                FakeFile file = new FakeFile(Integer.toString(userId));
-                mSuppressFiles.append(userId, file);
-            }
-            return mSuppressFiles.get(userId);
+        protected File getSuppressFileForSystemUser() {
+            return sSuppressFile;
+        }
+
+        @Override
+        protected File getActivatedFileForNonSystemUser(int userId) {
+            return sActivatedFiles.get(userId);
         }
 
         protected int binderGetCallingUserId() {
@@ -1289,11 +1334,6 @@
         }
 
         @Override
-        protected void createBackupSuppressFileForUser(int userId) throws IOException {
-            getSuppressFileForUser(userId).createNewFile();
-        }
-
-        @Override
         protected void postToHandler(Runnable runnable) {
             runnable.run();
         }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 0813e6fa..535198b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5239,6 +5239,45 @@
         assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity());
     }
 
+    public void testCrossProfileCalendarPackages_initiallyEmpty() {
+        setAsProfileOwner(admin1);
+        final Set<String> packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());
+    }
+
+    public void testCrossProfileCalendarPackages_reopenDpms() {
+        setAsProfileOwner(admin1);
+        dpm.setCrossProfileCalendarPackages(admin1, null);
+        Set<String> packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertTrue(packages == null);
+        initializeDpms();
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertTrue(packages == null);
+
+        dpm.setCrossProfileCalendarPackages(admin1, Collections.emptySet());
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());
+        initializeDpms();
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, Collections.emptySet());
+
+        final String dummyPackageName = "test";
+        final Set<String> testPackages = new ArraySet<String>(Arrays.asList(dummyPackageName));
+        dpm.setCrossProfileCalendarPackages(admin1, testPackages);
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, testPackages);
+        initializeDpms();
+        packages = dpm.getCrossProfileCalendarPackages(admin1);
+        assertCrossProfileCalendarPackagesEqual(packages, testPackages);
+    }
+
+    private void assertCrossProfileCalendarPackagesEqual(Set<String> expected, Set<String> actual) {
+        assertTrue(expected != null);
+        assertTrue(actual != null);
+        assertTrue(expected.containsAll(actual));
+        assertTrue(actual.containsAll(expected));
+    }
+
     private void configureProfileOwnerForDeviceIdAccess(ComponentName who, int userId) {
         final long ident = mServiceContext.binder.clearCallingIdentity();
         mServiceContext.binder.callingUid =
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index e0ecd3e..ca39a7f 100644
--- a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -25,6 +25,7 @@
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.hardware.display.ColorDisplayManager;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -45,7 +46,9 @@
 import com.android.server.twilight.TwilightState;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
@@ -67,16 +70,23 @@
 
     private MockTwilightManager mTwilightManager;
 
-    private ColorDisplayController mColorDisplayController;
     private ColorDisplayService mColorDisplayService;
+    private ColorDisplayController mColorDisplayController;
+    private ColorDisplayService.BinderService mBinderService;
+
+    @BeforeClass
+    public static void setDtm() {
+        final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
+        LocalServices.addService(DisplayTransformManager.class, dtm);
+    }
 
     @Before
     public void setUp() {
         mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
-        mUserId = ActivityManager.getCurrentUser();
-
         doReturn(mContext).when(mContext).getApplicationContext();
 
+        mUserId = ActivityManager.getCurrentUser();
+
         final MockContentResolver cr = new MockContentResolver(mContext);
         cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         doReturn(cr).when(mContext).getContentResolver();
@@ -84,23 +94,19 @@
         final AlarmManager am = Mockito.mock(AlarmManager.class);
         doReturn(am).when(mContext).getSystemService(Context.ALARM_SERVICE);
 
-        final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
-        LocalServices.addService(DisplayTransformManager.class, dtm);
-
         mTwilightManager = new MockTwilightManager();
         LocalServices.addService(TwilightManager.class, mTwilightManager);
 
         mColorDisplayController = new ColorDisplayController(mContext, mUserId);
         mColorDisplayService = new ColorDisplayService(mContext);
+        mBinderService = mColorDisplayService.new BinderService();
     }
 
     @After
     public void tearDown() {
-        LocalServices.removeServiceForTest(DisplayTransformManager.class);
         LocalServices.removeServiceForTest(TwilightManager.class);
 
         mColorDisplayService = null;
-        mColorDisplayController = null;
 
         mTwilightManager = null;
 
@@ -108,6 +114,11 @@
         mContext = null;
     }
 
+    @AfterClass
+    public static void removeDtm() {
+        LocalServices.removeServiceForTest(DisplayTransformManager.class);
+    }
+
     @Test
     public void customSchedule_whenStartedAfterNight_ifOffAfterNight_turnsOff() {
         setAutoModeCustom(-120 /* startTimeOffset */, -60 /* endTimeOffset */);
@@ -981,7 +992,7 @@
      * @param endTimeOffset the offset relative to now to deactivate Night display (in minutes)
      */
     private void setAutoModeCustom(int startTimeOffset, int endTimeOffset) {
-        mColorDisplayController.setAutoMode(ColorDisplayController.AUTO_MODE_CUSTOM);
+        mColorDisplayController.setAutoMode(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
         mColorDisplayController.setCustomStartTime(getLocalTimeRelativeToNow(startTimeOffset));
         mColorDisplayController.setCustomEndTime(getLocalTimeRelativeToNow(endTimeOffset));
     }
@@ -993,7 +1004,7 @@
      * @param sunriseOffset the offset relative to now for sunrise (in minutes)
      */
     private void setAutoModeTwilight(int sunsetOffset, int sunriseOffset) {
-        mColorDisplayController.setAutoMode(ColorDisplayController.AUTO_MODE_TWILIGHT);
+        mColorDisplayController.setAutoMode(ColorDisplayManager.AUTO_MODE_TWILIGHT);
         mTwilightManager.setTwilightState(
                 getTwilightStateRelativeToNow(sunsetOffset, sunriseOffset));
     }
@@ -1006,7 +1017,7 @@
      * activated (in minutes)
      */
     private void setActivated(boolean activated, int lastActivatedTimeOffset) {
-        mColorDisplayController.setActivated(activated);
+        mBinderService.setNightDisplayActivated(activated);
         Secure.putStringForUser(mContext.getContentResolver(),
                 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
                 LocalDateTime.now().plusMinutes(lastActivatedTimeOffset).toString(),
@@ -1036,10 +1047,10 @@
     /**
      * Configures color mode via ColorDisplayController.
      *
-     * @param mode the color mode to set
+     * @param colorMode the color mode to set
      */
-    private void setColorMode(int mode) {
-        mColorDisplayController.setColorMode(mode);
+    private void setColorMode(int colorMode) {
+        mColorDisplayController.setColorMode(colorMode);
     }
 
     /**
@@ -1081,8 +1092,8 @@
      * @param activated the expected activated state of Night display
      */
     private void assertActivated(boolean activated) {
-        assertWithMessage("Invalid Night display activated state")
-                .that(mColorDisplayController.isActivated())
+        assertWithMessage("Incorrect Night display activated state")
+                .that(mBinderService.isNightDisplayActivated())
                 .isEqualTo(activated);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java b/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
index 01199a3..0219f22 100644
--- a/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/MaxJobCountsTest.java
@@ -17,15 +17,15 @@
 
 import android.util.KeyValueListParser;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.server.job.JobSchedulerService.MaxJobCounts;
 
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class MaxJobCountsTest {
@@ -43,13 +43,14 @@
 
         counts.parse(parser);
 
-        Assert.assertEquals(expectedTotal, counts.getTotalMax());
+        Assert.assertEquals(expectedTotal, counts.getMaxTotal());
         Assert.assertEquals(expectedMaxBg, counts.getMaxBg());
         Assert.assertEquals(expectedMinBg, counts.getMinBg());
     }
 
     @Test
     public void test() {
+        // Tests with various combinations.
         check("", /*default*/ 5, 1, 0, /*expected*/ 5, 1, 0);
         check("", /*default*/ 5, 0, 0, /*expected*/ 5, 1, 0);
         check("", /*default*/ 0, 0, 0, /*expected*/ 1, 1, 0);
@@ -58,7 +59,11 @@
         check("", /*default*/ 6, 5, 6, /*expected*/ 6, 5, 5);
         check("", /*default*/ 4, 5, 6, /*expected*/ 4, 4, 3);
         check("", /*default*/ 5, 1, 1, /*expected*/ 5, 1, 1);
+        check("", /*default*/ 15, 15, 15, /*expected*/ 15, 15, 14);
+        check("", /*default*/ 16, 16, 16, /*expected*/ 16, 16, 15);
+        check("", /*default*/ 20, 20, 20, /*expected*/ 16, 16, 15);
 
+        // Test for overriding with a setting string.
         check("total=5,maxbg=4,minbg=3", /*default*/ 9, 9, 9, /*expected*/ 5, 4, 3);
         check("total=5", /*default*/ 9, 9, 9, /*expected*/ 5, 5, 4);
         check("maxbg=4", /*default*/ 9, 9, 9, /*expected*/ 9, 4, 4);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index a381023..056568a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -549,8 +549,7 @@
         verify(mActivityMetricsLogger, times(1)).logActivityStart(any(), any(), any(),
                 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
                 eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), anyInt(),
-                eq(ActivityBuilder.getDefaultComponent().getPackageName()), anyInt(), anyBoolean(),
-                any(), eq(false));
+                any(), anyInt(), anyBoolean(), any(), eq(false));
     }
 
     /**
@@ -599,6 +598,10 @@
                 Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
                 false, false, false);
+        runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
+                Process.NFC_UID, false, PROCESS_STATE_TOP + 1,
+                UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+                false, false, false);
         runAndVerifyBackgroundActivityStartsSubtest(
                 "disallowed_callingUidHasVisibleWindow_notAborted", false,
                 UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index d0b7a5e8..50e4faa 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -61,6 +61,7 @@
 import android.os.UserHandle;
 import android.service.usb.UsbPortInfoProto;
 import android.service.usb.UsbPortManagerProto;
+import android.service.usb.UsbServiceProto;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
@@ -74,7 +75,6 @@
 import com.android.server.FgThread;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.NoSuchElementException;
 
 /**
@@ -141,7 +141,11 @@
 
     // Maintains the current connected status of the port.
     // Uploads logs only when the connection status is changes.
-    private final HashMap<String, Boolean> mConnected = new HashMap<>();
+    private final ArrayMap<String, Boolean> mConnected = new ArrayMap<>();
+
+    // Maintains the USB contaminant status that was previously logged.
+    // Logs get uploaded only when contaminant presence status changes.
+    private final ArrayMap<String, Integer> mContaminantStatus = new ArrayMap<>();
 
     private NotificationManager mNotificationManager;
 
@@ -959,6 +963,24 @@
         updateContaminantNotification();
     }
 
+    // Constants have to be converted between USB HAL V1.2 ContaminantDetectionStatus
+    // to usb.proto as proto guidelines recommends 0 to be UNKNOWN/UNSUPPORTTED
+    // whereas HAL policy is against a loosely defined constant.
+    private static int convertContaminantDetectionStatusToProto(int contaminantDetectionStatus) {
+        switch (contaminantDetectionStatus) {
+            case UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED:
+                return UsbServiceProto.CONTAMINANT_STATUS_NOT_SUPPORTED;
+            case UsbPortStatus.CONTAMINANT_DETECTION_DISABLED:
+                return UsbServiceProto.CONTAMINANT_STATUS_DISABLED;
+            case UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED:
+                return UsbServiceProto.CONTAMINANT_STATUS_NOT_DETECTED;
+            case UsbPortStatus.CONTAMINANT_DETECTION_DETECTED:
+                return UsbServiceProto.CONTAMINANT_STATUS_DETECTED;
+            default:
+                return UsbServiceProto.CONTAMINANT_STATUS_UNKNOWN;
+        }
+    }
+
     private void sendPortChangedBroadcastLocked(PortInfo portInfo) {
         final Intent intent = new Intent(UsbManager.ACTION_USB_PORT_CHANGED);
         intent.addFlags(
@@ -973,6 +995,33 @@
                 Manifest.permission.MANAGE_USB));
 
         // Log to statsd
+
+        // Port is removed
+        if (portInfo.mUsbPortStatus == null) {
+            if (mConnected.containsKey(portInfo.mUsbPort.getId())) {
+                //Previous logged a connected. Set it to disconnected.
+                if (mConnected.get(portInfo.mUsbPort.getId())) {
+                    StatsLog.write(StatsLog.USB_CONNECTOR_STATE_CHANGED,
+                            StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_DISCONNECTED,
+                            portInfo.mUsbPort.getId(), portInfo.mLastConnectDurationMillis);
+                }
+                mConnected.remove(portInfo.mUsbPort.getId());
+            }
+
+            if (mContaminantStatus.containsKey(portInfo.mUsbPort.getId())) {
+                //Previous logged a contaminant detected. Set it to not detected.
+                if ((mContaminantStatus.get(portInfo.mUsbPort.getId())
+                        == UsbPortStatus.CONTAMINANT_DETECTION_DETECTED)) {
+                    StatsLog.write(StatsLog.USB_CONTAMINANT_REPORTED,
+                            portInfo.mUsbPort.getId(),
+                            convertContaminantDetectionStatusToProto(
+                                    UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED));
+                }
+                mContaminantStatus.remove(portInfo.mUsbPort.getId());
+            }
+            return;
+        }
+
         if (!mConnected.containsKey(portInfo.mUsbPort.getId())
                 || (mConnected.get(portInfo.mUsbPort.getId())
                 != portInfo.mUsbPortStatus.isConnected())) {
@@ -983,6 +1032,17 @@
                     StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_DISCONNECTED,
                     portInfo.mUsbPort.getId(), portInfo.mLastConnectDurationMillis);
         }
+
+        if (!mContaminantStatus.containsKey(portInfo.mUsbPort.getId())
+                || (mContaminantStatus.get(portInfo.mUsbPort.getId())
+                != portInfo.mUsbPortStatus.getContaminantDetectionStatus())) {
+            mContaminantStatus.put(portInfo.mUsbPort.getId(),
+                    portInfo.mUsbPortStatus.getContaminantDetectionStatus());
+            StatsLog.write(StatsLog.USB_CONTAMINANT_REPORTED,
+                    portInfo.mUsbPort.getId(),
+                    convertContaminantDetectionStatusToProto(
+                            portInfo.mUsbPortStatus.getContaminantDetectionStatus()));
+        }
     }
 
     private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 8c82cc8..697469a 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -939,11 +939,7 @@
             runOrAddOperation(new Operation(
                     // always execute:
                     () -> {
-                        // Don't remove the callback if multiple triggers are allowed or
-                        // if this event was triggered by a getModelState request
-                        if (!mRecognitionConfig.allowMultipleTriggers
-                                && event.status
-                                    != SoundTrigger.RECOGNITION_STATUS_GET_STATE_RESPONSE) {
+                        if (!mRecognitionConfig.allowMultipleTriggers) {
                             // Unregister this remoteService once op is done
                             synchronized (mCallbacksLock) {
                                 mCallbacks.remove(mPuuid.getUuid());
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index bb01f04..718f2d3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -17,13 +17,18 @@
 package com.android.server.voiceinteraction;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -78,6 +83,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * SystemService that publishes an IVoiceInteractionManagerService.
@@ -200,6 +206,7 @@
 
         VoiceInteractionManagerServiceStub() {
             mEnableService = shouldEnableService(mContext);
+            new RoleObserver(mContext.getMainExecutor());
         }
 
         // TODO: VI Make sure the caller is the current user or profile
@@ -1268,6 +1275,106 @@
                     getActiveServiceComponentName());
         }
 
+        class RoleObserver implements OnRoleHoldersChangedListener {
+            private PackageManager mPm = mContext.getPackageManager();
+            private RoleManager mRm = mContext.getSystemService(RoleManager.class);
+
+            RoleObserver(@NonNull @CallbackExecutor Executor executor) {
+                mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL);
+            }
+
+            private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) {
+                ResolveInfo resolveInfo = mPm.resolveServiceAsUser(
+                        new Intent(RecognitionService.SERVICE_INTERFACE),
+                        PackageManager.GET_META_DATA, user.getIdentifier());
+
+                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+                    Log.w(TAG, "Unable to resolve default voice recognition service.");
+                    return "";
+                }
+
+                return new ComponentName(resolveInfo.serviceInfo.packageName,
+                        resolveInfo.serviceInfo.name).flattenToShortString();
+            }
+
+            /**
+             * Convert the assistant-role holder into settings. The rest of the system uses the
+             * settings.
+             *
+             * @param roleName the name of the role whose holders are changed
+             * @param user the user for this role holder change
+             */
+            @Override
+            public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
+                if (!roleName.equals(RoleManager.ROLE_ASSISTANT)) {
+                    return;
+                }
+
+                List<String> roleHolders = mRm.getRoleHoldersAsUser(roleName, user);
+
+                if (roleHolders.isEmpty()) {
+                    Settings.Secure.putString(getContext().getContentResolver(),
+                            Settings.Secure.ASSISTANT, "");
+                    Settings.Secure.putString(getContext().getContentResolver(),
+                            Settings.Secure.VOICE_INTERACTION_SERVICE, "");
+                    Settings.Secure.putString(getContext().getContentResolver(),
+                            Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user));
+                } else {
+                    // Assistant is singleton role
+                    String pkg = roleHolders.get(0);
+
+                    // Try to set role holder as VoiceInteractionService
+                    List<ResolveInfo> services = mPm.queryIntentServicesAsUser(
+                            new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg),
+                            PackageManager.GET_META_DATA, user.getIdentifier());
+
+                    for (ResolveInfo resolveInfo : services) {
+                        ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+
+                        VoiceInteractionServiceInfo voiceInteractionServiceInfo =
+                                new VoiceInteractionServiceInfo(mPm, serviceInfo);
+                        if (!voiceInteractionServiceInfo.getSupportsAssist()) {
+                            continue;
+                        }
+
+                        String serviceComponentName = serviceInfo.getComponentName()
+                                .flattenToShortString();
+
+                        String serviceRecognizerName = new ComponentName(pkg,
+                                voiceInteractionServiceInfo.getRecognitionService())
+                                .flattenToShortString();
+
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.ASSISTANT, serviceComponentName);
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName);
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName);
+
+                        return;
+                    }
+
+                    // If no service could be found try to set assist activity
+                    final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(
+                            new Intent(Intent.ACTION_ASSIST).setPackage(pkg),
+                            PackageManager.MATCH_DEFAULT_ONLY, user.getIdentifier());
+
+                    for (ResolveInfo resolveInfo : activities) {
+                        ActivityInfo activityInfo = resolveInfo.activityInfo;
+
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.ASSISTANT,
+                                activityInfo.getComponentName().flattenToShortString());
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_INTERACTION_SERVICE, "");
+                        Settings.Secure.putString(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_RECOGNITION_SERVICE,
+                                getDefaultRecognizer(user));
+                    }
+                }
+            }
+        }
+
         class SettingsObserver extends ContentObserver {
             SettingsObserver(Handler handler) {
                 super(handler);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a33b44c..349880d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -608,11 +608,41 @@
     public static final String KEY_CARRIER_PROMOTE_WFC_ON_CALL_FAIL_BOOL =
             "carrier_promote_wfc_on_call_fail_bool";
 
-    /** Flag specifying whether provisioning is required for VOLTE. */
+    /**
+     * Flag specifying whether provisioning is required for VoLTE, Video Telephony, and WiFi
+     * Calling.
+     */
     public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
             = "carrier_volte_provisioning_required_bool";
 
     /**
+     * Flag indicating whether or not the IMS MmTel UT capability requires carrier provisioning
+     * before it can be set as enabled.
+     *
+     * If true, the UT capability will be set to false for the newly loaded subscription
+     * and will require the carrier provisioning app to set the persistent provisioning result.
+     * If false, the platform will not wait for provisioning status updates for the UT capability
+     * and enable the UT over IMS capability for the subscription when the subscription is loaded.
+     *
+     * The default value for this key is {@code false}.
+     */
+    public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL =
+            "carrier_ut_provisioning_required_bool";
+
+    /**
+     * Flag indicating whether or not the carrier supports Supplementary Services over the UT
+     * interface for this subscription.
+     *
+     * If true, the device will use Supplementary Services over UT when provisioned (see
+     * {@link #KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL}). If false, this device will fallback to
+     * circuit switch for supplementary services and will disable this capability for IMS entirely.
+     *
+     * The default value for this key is {@code true}.
+     */
+    public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL =
+            "carrier_supports_ss_over_ut_bool";
+
+    /**
      * Flag specifying if WFC provisioning depends on VoLTE provisioning.
      *
      * {@code false}: default value; honor actual WFC provisioning state.
@@ -2575,6 +2605,8 @@
         sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT, 2);
         sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 9414abd..5b2e635 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -86,9 +86,7 @@
 
     /**
      * Prefer registering for IMS over IWLAN if possible if WiFi signal quality is high enough.
-     * @hide
      */
-    @SystemApi
     public static final int WIFI_MODE_WIFI_PREFERRED = 2;
 
     /**
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index d37198a..086a765 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -21,13 +21,17 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
 import android.content.Context;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.aidl.IImsConfigCallback;
+import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsConfigImplBase;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 
 import com.android.internal.telephony.ITelephony;
 
@@ -38,13 +42,68 @@
  * to changes in these configurations.
  *
  * Note: IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning
- * applications and may vary.
+ * applications and may vary. For compatibility purposes, the first 100 integer values used in
+ * {@link #setProvisioningIntValue(int, int)} have been reserved for existing provisioning keys
+ * previously defined in the Android framework. Some common constants have been defined in this
+ * class to make integrating with other system apps easier. USE WITH CARE!
+ *
+ * To avoid collisions, please use String based configurations when possible:
+ * {@link #setProvisioningStringValue(int, String)} and {@link #getProvisioningStringValue(int)}.
  * @hide
  */
 @SystemApi
 public class ProvisioningManager {
 
     /**
+     * The query from {@link #getProvisioningStringValue(int)} has resulted in an unspecified error.
+     */
+    public static final String STRING_QUERY_RESULT_ERROR_GENERIC =
+            "STRING_QUERY_RESULT_ERROR_GENERIC";
+
+    /**
+     * The query from {@link #getProvisioningStringValue(int)} has resulted in an error because the
+     * ImsService implementation was not ready for provisioning queries.
+     */
+    public static final String STRING_QUERY_RESULT_ERROR_NOT_READY =
+            "STRING_QUERY_RESULT_ERROR_NOT_READY";
+
+    /**
+     * The integer result of provisioning for the queried key is disabled.
+     */
+    public static final int PROVISIONING_VALUE_DISABLED = 0;
+
+    /**
+     * The integer result of provisioning for the queried key is enabled.
+     */
+    public static final int PROVISIONING_VALUE_ENABLED = 1;
+
+
+    /**
+     * Override the user-defined WiFi Roaming enabled setting for this subscription, defined in
+     * {@link SubscriptionManager#WFC_ROAMING_ENABLED_CONTENT_URI}, for the purposes of provisioning
+     * the subscription for WiFi Calling.
+     *
+     * @see #getProvisioningIntValue(int)
+     * @see #setProvisioningIntValue(int, int)
+     */
+    public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26;
+
+    /**
+     * Override the user-defined WiFi mode for this subscription, defined in
+     * {@link SubscriptionManager#WFC_MODE_CONTENT_URI}, for the purposes of provisioning
+     * this subscription for WiFi Calling.
+     *
+     * Valid values for this key are:
+     * {@link ImsMmTelManager#WIFI_MODE_WIFI_ONLY},
+     * {@link ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}, or
+     * {@link ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}.
+     *
+     * @see #getProvisioningIntValue(int)
+     * @see #setProvisioningIntValue(int, int)
+     */
+    public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27;
+
+    /**
      * Callback for IMS provisioning changes.
      */
     public static class Callback {
@@ -180,10 +239,15 @@
 
     /**
      * Query for the integer value associated with the provided key.
+     *
+     * This operation is blocking and should not be performed on the UI thread.
+     *
      * @param key An integer that represents the provisioning key, which is defined by the OEM.
-     * @return an integer value for the provided key.
+     * @return an integer value for the provided key, or
+     * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN} if the key doesn't exist.
      * @throws IllegalArgumentException if the key provided was invalid.
      */
+    @WorkerThread
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public int getProvisioningIntValue(int key) {
         try {
@@ -195,10 +259,16 @@
 
     /**
      * Query for the String value associated with the provided key.
-     * @param key An integer that represents the provisioning key, which is defined by the OEM.
-     * @return a String value for the provided key, or {@code null} if the key doesn't exist.
+     *
+     * This operation is blocking and should not be performed on the UI thread.
+     *
+     * @param key A String that represents the provisioning key, which is defined by the OEM.
+     * @return a String value for the provided key, {@code null} if the key doesn't exist, or one
+     * of the following error codes: {@link #STRING_QUERY_RESULT_ERROR_GENERIC},
+     * {@link #STRING_QUERY_RESULT_ERROR_NOT_READY}.
      * @throws IllegalArgumentException if the key provided was invalid.
      */
+    @WorkerThread
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getProvisioningStringValue(int key) {
         try {
@@ -210,10 +280,16 @@
 
     /**
      * Set the integer value associated with the provided key.
+     *
+     * This operation is blocking and should not be performed on the UI thread.
+     *
+     * Use {@link #setProvisioningStringValue(int, String)} with proper namespacing (to be defined
+     * per OEM or carrier) when possible instead to avoid key collision if needed.
      * @param key An integer that represents the provisioning key, which is defined by the OEM.
      * @param value a integer value for the provided key.
      * @return the result of setting the configuration value.
      */
+    @WorkerThread
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public @ImsConfigImplBase.SetConfigResult int setProvisioningIntValue(int key, int value) {
         try {
@@ -226,10 +302,14 @@
     /**
      * Set the String value associated with the provided key.
      *
-     * @param key An integer that represents the provisioning key, which is defined by the OEM.
+     * This operation is blocking and should not be performed on the UI thread.
+     *
+     * @param key A String that represents the provisioning key, which is defined by the OEM and
+     *     should be appropriately namespaced to avoid collision.
      * @param value a String value for the provided key.
      * @return the result of setting the configuration value.
      */
+    @WorkerThread
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public @ImsConfigImplBase.SetConfigResult int setProvisioningStringValue(int key,
             String value) {
@@ -240,6 +320,55 @@
         }
     }
 
+    /**
+     * Set the provisioning status for the IMS MmTel capability using the specified subscription.
+     *
+     * Provisioning may or may not be required, depending on the carrier configuration. If
+     * provisioning is not required for the carrier associated with this subscription or the device
+     * does not support the capability/technology combination specified, this operation will be a
+     * no-op.
+     *
+     * @see CarrierConfigManager#KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL
+     * @see CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+     * @param isProvisioned true if the device is provisioned for UT over IMS, false otherwise.
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void setProvisioningStatusForCapability(
+            @MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+            @ImsRegistrationImplBase.ImsRegistrationTech int tech,  boolean isProvisioned) {
+        try {
+            getITelephony().setImsProvisioningStatusForCapability(mSubId, capability, tech,
+                    isProvisioned);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Get the provisioning status for the IMS MmTel capability specified.
+     *
+     * If provisioning is not required for the queried
+     * {@link MmTelFeature.MmTelCapabilities.MmTelCapability} and
+     * {@link ImsRegistrationImplBase.ImsRegistrationTech} combination specified, this method will
+     * always return {@code true}.
+     *
+     * @see CarrierConfigManager#KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL
+     * @see CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+     * @return true if the device is provisioned for the capability or does not require
+     * provisioning, false if the capability does require provisioning and has not been
+     * provisioned yet.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean getProvisioningStatusForCapability(
+            @MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+            @ImsRegistrationImplBase.ImsRegistrationTech int tech) {
+        try {
+            return getITelephony().getImsProvisioningStatusForCapability(mSubId, capability, tech);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     private static SubscriptionManager getSubscriptionManager(Context context) {
         SubscriptionManager manager = context.getSystemService(SubscriptionManager.class);
         if (manager == null) {
diff --git a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
index 7c793a5..1ee8563 100644
--- a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
@@ -97,6 +97,13 @@
         public @ImsRegistrationImplBase.ImsRegistrationTech int getRadioTech() {
             return radioTech;
         }
+
+        @Override
+        public String toString() {
+            return "CapabilityPair{"
+                    + "mCapability=" + mCapability
+                    + ", radioTech=" + radioTech + '}';
+        }
     }
 
     // Pair contains <radio tech, mCapability>
@@ -212,6 +219,13 @@
         }
     }
 
+    @Override
+    public String toString() {
+        return "CapabilityChangeRequest{"
+                + "mCapabilitiesToEnable=" + mCapabilitiesToEnable
+                + ", mCapabilitiesToDisable=" + mCapabilitiesToDisable + '}';
+    }
+
     /**
      * @hide
      */
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 71a2174..4fc6a19 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -277,12 +277,14 @@
          * Wi-Fi calling roaming status.
          * Value is in Integer format. ON (1), OFF(0).
          */
-        public static final int VOICE_OVER_WIFI_ROAMING = 26;
+        public static final int VOICE_OVER_WIFI_ROAMING =
+                ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE;
         /**
          * Wi-Fi calling modem - WfcModeFeatureValueConstants.
          * Value is in Integer format.
          */
-        public static final int VOICE_OVER_WIFI_MODE = 27;
+        public static final int VOICE_OVER_WIFI_MODE =
+                ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE;
         /**
          * VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0).
          * Value is in Integer format.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9cc173c..8237d39 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1765,6 +1765,24 @@
     void unregisterImsProvisioningChangedCallback(int subId, IImsConfigCallback callback);
 
     /**
+     * Set the provisioning status for the IMS MmTel capability using the specified subscription.
+     */
+    void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
+            boolean isProvisioned);
+
+    /**
+     * Get the provisioning status for the IMS MmTel capability specified.
+     */
+    boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech);
+
+    /** Is the capability and tech flagged as provisioned in the cache */
+    boolean isMmTelCapabilityProvisionedInCache(int subId, int capability, int tech);
+
+    /** Set the provisioning for the capability and tech in the cache */
+    void cacheMmTelCapabilityProvisioning(int subId, int capability, int tech,
+            boolean isProvisioned);
+
+    /**
      * Return an integer containing the provisioning value for the specified provisioning key.
      */
     int getImsProvisioningInt(int subId, int key);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 0edc002..c76d153 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -284,10 +284,6 @@
      */
     private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
             int uid, String callingPackage, String message) {
-        // If the device identifier check is enabled then enforce the new access requirements for
-        // both 1P and 3P apps.
-        boolean enableDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 1;
         // Check if the application is a 3P app; if so then a separate setting is required to relax
         // the check to begin flagging problems with 3P apps early.
         boolean relax3PDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
@@ -300,6 +296,11 @@
                 context.getContentResolver(),
                 Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED, 0) == 1;
         boolean isNonPrivApp = false;
+        // Similar to above support relaxing the check for privileged apps while still enforcing it
+        // for non-privileged and 3P apps.
+        boolean relaxPrivDeviceIdentifierCheck = Settings.Global.getInt(
+                context.getContentResolver(),
+                Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED, 0) == 1;
         ApplicationInfo callingPackageInfo = null;
         try {
             callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
@@ -315,37 +316,28 @@
             Log.e(LOG_TAG, "Exception caught obtaining package info for package " + callingPackage,
                     e);
         }
-        Log.wtf(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
-                + ":is3PApp=" + is3PApp + ":isNonPrivApp=" + isNonPrivApp);
-        // The new Q restrictions for device identifier access will be enforced if any of the
-        // following are true:
-        // - The PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED setting has been set.
-        // - The app requesting a device identifier is not a preloaded app (3P), and the
-        //   PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED setting has not been set.
-        // - The app requesting a device identifier is a preloaded app but is not a privileged app,
-        //   and the PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED setting has not been set.
-        if (enableDeviceIdentifierCheck
+        // The new Q restrictions for device identifier access will be enforced for all apps with
+        // settings to individually disable the new restrictions for privileged, preloaded
+        // non-privileged, and 3P apps.
+        if ((!is3PApp && !isNonPrivApp && !relaxPrivDeviceIdentifierCheck)
                 || (is3PApp && !relax3PDeviceIdentifierCheck)
                 || (isNonPrivApp && !relaxNonPrivDeviceIdentifierCheck)) {
-            boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(),
-                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0;
-            if (callingPackage != null) {
-                // if the target SDK is pre-Q or the target Q behavior is disabled then check if
-                // the calling package would have previously had access to device identifiers.
-                if (callingPackageInfo != null && (
-                        callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q
-                                || targetQBehaviorDisabled)) {
-                    if (context.checkPermission(
-                            android.Manifest.permission.READ_PHONE_STATE,
-                            pid,
-                            uid) == PackageManager.PERMISSION_GRANTED) {
-                        return false;
-                    }
-                    if (SubscriptionManager.isValidSubscriptionId(subId)
-                            && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
-                            == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
-                        return false;
-                    }
+            Log.wtf(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
+                    + ":is3PApp=" + is3PApp + ":isNonPrivApp=" + isNonPrivApp);
+            // if the target SDK is pre-Q then check if the calling package would have previously
+            // had access to device identifiers.
+            if (callingPackageInfo != null && (
+                    callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
+                if (context.checkPermission(
+                        android.Manifest.permission.READ_PHONE_STATE,
+                        pid,
+                        uid) == PackageManager.PERMISSION_GRANTED) {
+                    return false;
+                }
+                if (SubscriptionManager.isValidSubscriptionId(subId)
+                        && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
+                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                    return false;
                 }
             }
             throw new SecurityException(message + ": The user " + uid
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index 34aa258..780bb24 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -36,6 +36,17 @@
 include $(BUILD_PACKAGE)
 ROLLBACK_TEST_APP_AV2 := $(LOCAL_INSTALLED_MODULE)
 
+# RollbackTestAppACrashingV2.apk
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, TestApp/src)
+LOCAL_MANIFEST_FILE := TestApp/ACrashingV2.xml
+LOCAL_PACKAGE_NAME := RollbackTestAppACrashingV2
+include $(BUILD_PACKAGE)
+ROLLBACK_TEST_APP_A_CRASHING_V2 := $(LOCAL_INSTALLED_MODULE)
+
 # RollbackTestAppBv1.apk
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := optional
@@ -68,6 +79,7 @@
 LOCAL_JAVA_RESOURCE_FILES := \
   $(ROLLBACK_TEST_APP_AV1) \
   $(ROLLBACK_TEST_APP_AV2) \
+  $(ROLLBACK_TEST_APP_A_CRASHING_V2) \
   $(ROLLBACK_TEST_APP_BV1) \
   $(ROLLBACK_TEST_APP_BV2)
 LOCAL_SDK_VERSION := system_current
@@ -77,5 +89,6 @@
 # Clean up local variables
 ROLLBACK_TEST_APP_AV1 :=
 ROLLBACK_TEST_APP_AV2 :=
+ROLLBACK_TEST_APP_A_CRASHING_V2 :=
 ROLLBACK_TEST_APP_BV1 :=
 ROLLBACK_TEST_APP_BV2 :=
diff --git a/tests/RollbackTest/TestApp/ACrashingV2.xml b/tests/RollbackTest/TestApp/ACrashingV2.xml
new file mode 100644
index 0000000..5708d23
--- /dev/null
+++ b/tests/RollbackTest/TestApp/ACrashingV2.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.rollback.testapp.A"
+    android:versionCode="2"
+    android:versionName="2.0" >
+
+
+    <uses-sdk android:minSdkVersion="19" />
+
+    <application android:label="Rollback Test App A v2">
+        <meta-data android:name="version" android:value="2" />
+        <receiver android:name="com.android.tests.rollback.testapp.ProcessUserData"
+                  android:exported="true" />
+        <activity android:name="com.android.tests.rollback.testapp.CrashingMainActivity">
+            <intent-filter>
+              <action android:name="android.intent.action.MAIN" />
+              <category android:name="android.intent.category.DEFAULT"/>
+              <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java
new file mode 100644
index 0000000..02a439b
--- /dev/null
+++ b/tests/RollbackTest/TestApp/src/com/android/tests/rollback/testapp/CrashingMainActivity.java
@@ -0,0 +1,33 @@
+/*
+ * 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.tests.rollback.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * A crashing test app for testing apk rollback support.
+ */
+public class CrashingMainActivity extends Activity {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        throw new RuntimeException("Intended force crash");
+    }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 9d67cea..13ac4f0 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -38,6 +38,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -57,6 +58,7 @@
 
     private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
     private static final String TEST_APP_B = "com.android.tests.rollback.testapp.B";
+    private static final String INSTRUMENTED_APP = "com.android.tests.rollback";
 
     /**
      * Test basic rollbacks.
@@ -663,4 +665,63 @@
         assertEquals(packageName, info.getVersionRolledBackTo().getPackageName());
         assertEquals(versionRolledBackTo, info.getVersionRolledBackTo().getLongVersionCode());
     }
+
+    // TODO(zezeozue): Stop ignoring after fixing race between rolling back and testing version
+    /**
+     * Test bad update automatic rollback.
+     */
+    @Ignore("Flaky")
+    @Test
+    public void testBadUpdateRollback() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+            // Prep installation of the test apps.
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppACrashingV2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            RollbackTestUtils.uninstall(TEST_APP_B);
+            RollbackTestUtils.install("RollbackTestAppBv1.apk", false);
+            RollbackTestUtils.install("RollbackTestAppBv2.apk", true);
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+
+            // Both test apps should now be available for rollback, and the
+            // targetPackage returned for rollback should be correct.
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // is made available.
+            Thread.sleep(1000);
+            RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
+            assertNotNull(rollbackA);
+            assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+
+            RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
+            assertNotNull(rollbackB);
+            assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+
+            // Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
+            for (int i = 0; i < 5; i++) {
+                RollbackTestUtils.launchPackage(TEST_APP_A);
+                Thread.sleep(1000);
+            }
+            Thread.sleep(1000);
+
+            // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+            // Instrumented app is still the package installer
+            Context context = InstrumentationRegistry.getContext();
+            String installer = context.getPackageManager().getInstallerPackageName(TEST_APP_A);
+            assertEquals(INSTRUMENTED_APP, installer);
+            // TEST_APP_B is untouched
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
 }
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index fbc3d8f..edb1355 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -135,6 +135,17 @@
         assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
     }
 
+    /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
+    static void launchPackage(String packageName)
+            throws InterruptedException, IOException {
+        Context context = InstrumentationRegistry.getContext();
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setPackage(packageName);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        context.startActivity(intent);
+    }
+
     /**
      * Installs the apks with the given resource names as an atomic set.
      *
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b5d5f61..923c7dd 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -123,6 +123,7 @@
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
 import android.net.NetworkUtils;
+import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.SocketKeepalive;
 import android.net.UidRange;
@@ -161,6 +162,7 @@
 import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.ProxyTracker;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.NetworkPinner;
@@ -1007,6 +1009,11 @@
         }
 
         @Override
+        protected ProxyTracker makeProxyTracker() {
+            return mock(ProxyTracker.class);
+        }
+
+        @Override
         protected int reserveNetId() {
             while (true) {
                 final int netId = super.reserveNetId();
@@ -1028,6 +1035,11 @@
             }
         }
 
+        @Override
+        protected boolean queryUserAccess(int uid, int netId) {
+            return true;
+        }
+
         public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
             return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
         }
@@ -5132,4 +5144,84 @@
         mCellNetworkAgent.sendLinkProperties(lp);
         verifyTcpBufferSizeChange(TEST_TCP_BUFFER_SIZES);
     }
+
+    @Test
+    public void testGetGlobalProxyForNetwork() {
+        final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
+        when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo);
+        assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
+    }
+
+    @Test
+    public void testGetProxyForActiveNetwork() {
+        final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        waitForIdle();
+        assertNull(mService.getProxyForNetwork(null));
+
+        final LinkProperties testLinkProperties = new LinkProperties();
+        testLinkProperties.setHttpProxy(testProxyInfo);
+
+        mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
+        waitForIdle();
+
+        assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
+    }
+
+    @Test
+    public void testGetProxyForVPN() {
+        final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+
+        // Set up a WiFi network with no proxy
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(true);
+        waitForIdle();
+        assertNull(mService.getProxyForNetwork(null));
+
+        // Set up a VPN network with a proxy
+        final int uid = Process.myUid();
+        final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+        final ArraySet<UidRange> ranges = new ArraySet<>();
+        ranges.add(new UidRange(uid, uid));
+        mMockVpn.setUids(ranges);
+        LinkProperties testLinkProperties = new LinkProperties();
+        testLinkProperties.setHttpProxy(testProxyInfo);
+        vpnNetworkAgent.sendLinkProperties(testLinkProperties);
+        waitForIdle();
+
+        // Connect to VPN with proxy
+        mMockVpn.setNetworkAgent(vpnNetworkAgent);
+        vpnNetworkAgent.connect(true);
+        mMockVpn.connect();
+        waitForIdle();
+
+        // Test that the VPN network returns a proxy, and the WiFi does not.
+        assertEquals(testProxyInfo, mService.getProxyForNetwork(vpnNetworkAgent.getNetwork()));
+        assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
+        assertNull(mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
+
+        // Test that the VPN network returns no proxy when it is set to null.
+        testLinkProperties.setHttpProxy(null);
+        vpnNetworkAgent.sendLinkProperties(testLinkProperties);
+        waitForIdle();
+        assertNull(mService.getProxyForNetwork(vpnNetworkAgent.getNetwork()));
+        assertNull(mService.getProxyForNetwork(null));
+
+        // Set WiFi proxy and check that the vpn proxy is still null.
+        testLinkProperties.setHttpProxy(testProxyInfo);
+        mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
+        waitForIdle();
+        assertNull(mService.getProxyForNetwork(null));
+
+        // Disconnect from VPN and check that the active network, which is now the WiFi, has the
+        // correct proxy setting.
+        vpnNetworkAgent.disconnect();
+        waitForIdle();
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+        assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
+        assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 0b74d87..5b17224 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -246,17 +246,17 @@
         assertFalse(vpn.getLockdown());
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
         assertTrue(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
         assertTrue(vpn.getAlwaysOn());
         assertTrue(vpn.getLockdown());
 
         // Remove always-on configuration.
-        assertTrue(vpn.setAlwaysOnPackage(null, false));
+        assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
         assertFalse(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
     }
@@ -270,11 +270,11 @@
         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
             new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -283,7 +283,7 @@
         assertUnblocked(vpn, user.start + PKG_UIDS[1]);
 
         // Switch to another app.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
         verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
             new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -297,6 +297,87 @@
     }
 
     @Test
+    public void testLockdownWhitelist() throws Exception {
+        final Vpn vpn = createVpn(primaryUser.id);
+        final UidRange user = UidRange.createForUser(primaryUser.id);
+
+        // Set always-on with lockdown and whitelist app PKGS[2] from lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2])));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
+                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+
+        // Change whitelisted app to PKGS[3].
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3])));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
+                new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
+
+        // Change the VPN app.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3])));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+                new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
+                new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
+
+        // Remove the whitelist.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
+                new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
+                user.start + PKG_UIDS[3]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[0]);
+
+        // Add the whitelist.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1])));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+                new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
+
+        // Try whitelisting a package with a comma, should be rejected.
+        assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d")));
+
+        // Pass a non-existent packages in the whitelist, they (and only they) should be ignored.
+        // Whitelisted package should change from PGKS[1] to PKGS[2].
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true,
+                Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+                new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
+                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        }));
+    }
+
+    @Test
     public void testLockdownAddingAProfile() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         setMockedUsers(primaryUser);
@@ -310,7 +391,7 @@
         final UidRange profile = UidRange.createForUser(tempProfile.id);
 
         // Set lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
             new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
@@ -436,7 +517,7 @@
                 .cancelAsUser(anyString(), anyInt(), eq(userHandle));
 
         // Start showing a notification for disconnected once always-on.
-        vpn.setAlwaysOnPackage(PKGS[0], false);
+        vpn.setAlwaysOnPackage(PKGS[0], false, null);
         order.verify(mNotificationManager)
                 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
 
@@ -450,7 +531,7 @@
                 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
 
         // Notification should be cleared after unsetting always-on package.
-        vpn.setAlwaysOnPackage(null, false);
+        vpn.setAlwaysOnPackage(null, false, null);
         order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
     }
 
@@ -583,7 +664,9 @@
             doAnswer(invocation -> {
                 final String appName = (String) invocation.getArguments()[0];
                 final int userId = (int) invocation.getArguments()[1];
-                return UserHandle.getUid(userId, packages.get(appName));
+                Integer appId = packages.get(appName);
+                if (appId == null) throw new PackageManager.NameNotFoundException(appName);
+                return UserHandle.getUid(userId, appId);
             }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
         } catch (Exception e) {
         }
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index 9b5df56..06ff05e 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -1,6 +1,8 @@
-java_library_host {
+java_plugin {
     name: "view-inspector-annotation-processor",
 
+    processor_class: "android.processor.view.inspector.PlatformInspectableProcessor",
+
     srcs: ["src/java/**/*.java"],
     java_resource_dirs: ["src/resources"],
 
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index a0ce9dd..d549799 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -214,4 +214,6 @@
         in IDppCallback callback);
 
     void stopDppSession();
+
+    void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec);
 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index d2d711f..96493de 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -787,6 +787,18 @@
     public boolean trusted;
 
     /**
+     * This Wifi configuration is created from a {@link WifiNetworkSuggestion}
+     * @hide
+     */
+    public boolean fromWifiNetworkSuggestion;
+
+    /**
+     * This Wifi configuration is created from a {@link WifiNetworkSpecifier}
+     * @hide
+     */
+    public boolean fromWifiNetworkSpecifier;
+
+    /**
      * Indicates if the creator of this configuration has expressed that it
      * should be considered metered.
      *
@@ -1668,6 +1680,8 @@
         ephemeral = false;
         osu = false;
         trusted = true; // Networks are considered trusted by default.
+        fromWifiNetworkSuggestion = false;
+        fromWifiNetworkSpecifier = false;
         meteredHint = false;
         meteredOverride = METERED_OVERRIDE_NONE;
         useExternalScores = false;
@@ -1779,10 +1793,13 @@
         if (this.ephemeral) sbuf.append(" ephemeral");
         if (this.osu) sbuf.append(" osu");
         if (this.trusted) sbuf.append(" trusted");
+        if (this.fromWifiNetworkSuggestion) sbuf.append(" fromWifiNetworkSuggestion");
+        if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier");
         if (this.meteredHint) sbuf.append(" meteredHint");
         if (this.useExternalScores) sbuf.append(" useExternalScores");
         if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
-                || this.ephemeral || this.trusted || this.meteredHint || this.useExternalScores) {
+                || this.ephemeral || this.trusted || this.fromWifiNetworkSuggestion
+                || this.fromWifiNetworkSpecifier || this.meteredHint || this.useExternalScores) {
             sbuf.append("\n");
         }
         if (this.meteredOverride != METERED_OVERRIDE_NONE) {
@@ -2270,6 +2287,8 @@
             ephemeral = source.ephemeral;
             osu = source.osu;
             trusted = source.trusted;
+            fromWifiNetworkSuggestion = source.fromWifiNetworkSuggestion;
+            fromWifiNetworkSpecifier = source.fromWifiNetworkSpecifier;
             meteredHint = source.meteredHint;
             meteredOverride = source.meteredOverride;
             useExternalScores = source.useExternalScores;
@@ -2347,6 +2366,8 @@
         dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
         dest.writeInt(ephemeral ? 1 : 0);
         dest.writeInt(trusted ? 1 : 0);
+        dest.writeInt(fromWifiNetworkSuggestion ? 1 : 0);
+        dest.writeInt(fromWifiNetworkSpecifier ? 1 : 0);
         dest.writeInt(meteredHint ? 1 : 0);
         dest.writeInt(meteredOverride);
         dest.writeInt(useExternalScores ? 1 : 0);
@@ -2418,6 +2439,8 @@
                 config.isLegacyPasspointConfig = in.readInt() != 0;
                 config.ephemeral = in.readInt() != 0;
                 config.trusted = in.readInt() != 0;
+                config.fromWifiNetworkSuggestion =  in.readInt() != 0;
+                config.fromWifiNetworkSpecifier =  in.readInt() != 0;
                 config.meteredHint = in.readInt() != 0;
                 config.meteredOverride = in.readInt();
                 config.useExternalScores = in.readInt() != 0;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 084bd09..40077e1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -4865,4 +4865,26 @@
             throw e.rethrowFromSystemServer();
         }
     }
-}
+
+    /**
+     * Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
+     * framework. The Wi-Fi usability score is derived from {@link WifiUsabilityStatsListener}
+     * where a score is matched to Wi-Fi usability statistics using the sequence number. The score
+     * is used to quantify whether Wi-Fi is usable in a future time.
+     *
+     * @param seqNum Sequence number of the Wi-Fi usability score.
+     * @param score The Wi-Fi usability score.
+     * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
+    public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
+        try {
+            mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
\ No newline at end of file
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 226c7c48..c236c7a 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -476,4 +476,9 @@
     public void removeWifiUsabilityStatsListener(int listenerIdentifier) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 7bff68a..449423f 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -60,6 +60,8 @@
         config.setPasspointManagementObjectTree(cookie);
         config.trusted = false;
         config.updateIdentifier = "1234";
+        config.fromWifiNetworkSpecifier = true;
+        config.fromWifiNetworkSuggestion = true;
         MacAddress macBeforeParcel = config.getOrCreateRandomizedMacAddress();
         Parcel parcelW = Parcel.obtain();
         config.writeToParcel(parcelW, 0);
@@ -76,6 +78,8 @@
         assertEquals(macBeforeParcel, reconfig.getOrCreateRandomizedMacAddress());
         assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
         assertFalse(reconfig.trusted);
+        assertTrue(config.fromWifiNetworkSpecifier);
+        assertTrue(config.fromWifiNetworkSuggestion);
 
         Parcel parcelWW = Parcel.obtain();
         reconfig.writeToParcel(parcelWW, 0);