Merge "Add intent to notify applications when the secure element state changed"
diff --git a/StubLibraries.bp b/StubLibraries.bp
index ed8781e..64ee09c 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -120,6 +120,20 @@
             new_since: ":android-non-updatable.api.public.latest",
         },
     },
+    dists: [
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/public/api",
+            dest: "android-non-updatable.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/public/api",
+            dest: "android-non-updatable-removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ],
 }
 
 priv_apps =
@@ -159,6 +173,20 @@
             baseline_file: "core/api/system-lint-baseline.txt",
         },
     },
+    dists: [
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/system/api",
+            dest: "android-non-updatable.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/system/api",
+            dest: "android-non-updatable-removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ],
 }
 
 droidstubs {
@@ -175,11 +203,32 @@
             baseline_file: "core/api/test-lint-baseline.txt",
         },
     },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/test/api",
-        dest: "android.txt",
-    },
+    dists: [
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/test/api",
+            dest: "android.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/test/api",
+            dest: "removed.txt",
+            tag: ".removed-api.txt",
+        },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/test/api",
+            dest: "android-non-updatable.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/test/api",
+            dest: "android-non-updatable-removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ],
 }
 
 droidstubs {
@@ -200,6 +249,20 @@
             new_since: ":android-non-updatable.api.module-lib.latest",
         },
     },
+    dists: [
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/module-lib/api",
+            dest: "android-non-updatable.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/module-lib/api",
+            dest: "android-non-updatable-removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ],
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS
index a060ad9..7e7feaf 100644
--- a/apct-tests/perftests/OWNERS
+++ b/apct-tests/perftests/OWNERS
@@ -1,2 +1,11 @@
-timmurray@google.com
+balejs@google.com
+carmenjackson@google.com
+cfijalkovich@google.com
+dualli@google.com
+edgararriaga@google.com
+jpakaravoor@google.com
+kevinjeon@google.com
 philipcuadra@google.com
+shombert@google.com
+timmurray@google.com
+wessam@google.com
diff --git a/apex/OWNERS b/apex/OWNERS
index 9760013..bde2bec 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1,7 +1,8 @@
-# Shared module build rule owners
-per-file *.bp=hansson@google.com
-per-file *.bp=jiyong@google.com
+# Mainline modularization team
 
-# This file, and all other OWNERS files
-per-file OWNERS=dariofreni@google.com
-per-file OWNERS=hansson@google.com
+andreionea@google.com
+dariofreni@google.com
+hansson@google.com
+mathewi@google.com
+pedroql@google.com
+satayev@google.com
diff --git a/api/Android.bp b/api/Android.bp
index 9a157b8..fdfef4c 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -50,10 +50,7 @@
             dest: "current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk", "win_sdk"],
             dir: "apistubs/android/public/api",
             dest: "android.txt",
         },
@@ -106,6 +103,11 @@
             dir: "api",
             dest: "removed.txt",
         },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/public/api",
+            dest: "removed.txt",
+        },
     ],
 }
 
@@ -131,10 +133,7 @@
             dest: "system-current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk", "win_sdk"],
             dir: "apistubs/android/system/api",
             dest: "android.txt",
         },
@@ -163,6 +162,11 @@
             dir: "api",
             dest: "system-removed.txt",
         },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/system/api",
+            dest: "removed.txt",
+        },
     ],
     visibility: ["//visibility:public"],
 }
@@ -189,10 +193,7 @@
             dest: "module-lib-current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk", "win_sdk"],
             dir: "apistubs/android/module-lib/api",
             dest: "android.txt",
         },
@@ -220,6 +221,11 @@
             dir: "api",
             dest: "module-lib-removed.txt",
         },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/module-lib/api",
+            dest: "removed.txt",
+        },
     ],
 }
 
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bdb8380..846a34e 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -174,10 +174,6 @@
                 instrument.noWindowAnimation = true;
             } else if (opt.equals("--no-hidden-api-checks")) {
                 instrument.disableHiddenApiChecks = true;
-            } else if (opt.equals("--no-test-api-checks")) {
-                // TODO(satayev): remove this option, only kept for backwards compatibility with
-                // cached tradefed instance
-                instrument.disableTestApiChecks = false;
             } else if (opt.equals("--no-test-api-access")) {
                 instrument.disableTestApiChecks = false;
             } else if (opt.equals("--no-isolated-storage")) {
@@ -198,7 +194,6 @@
         }
 
         instrument.componentNameArg = nextArgRequired();
-
         instrument.run();
     }
 }
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 07221f9..14ebb71 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -62,4 +62,13 @@
     // Create a symlink from app_process to app_process32 or 64
     // depending on the target configuration.
     symlink_preferred_arch: true,
+
+    // Enable ASYNC MTE in the zygote, in order to allow apps and the system
+    // server to use MTE. We use ASYNC because we don't expect the pre-fork
+    // zygote to have substantial memory corruption bugs (as it's primarily Java
+    // code), and we don't want to waste memory recording malloc/free stack
+    // traces (which happens in SYNC mode).
+    sanitize: {
+        memtag_heap: true,
+    },
 }
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index c2ee6dc..405d6f6 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -107,6 +107,8 @@
             runStartCheckpoint();
         } else if ("supports-checkpoint".equals(op)) {
             runSupportsCheckpoint();
+        } else if ("unmount-app-data-dirs".equals(op)) {
+            runDisableAppDataIsolation();
         } else {
             throw new IllegalArgumentException();
         }
@@ -253,6 +255,13 @@
         System.out.println(result.get());
     }
 
+    public void runDisableAppDataIsolation() throws RemoteException {
+        final String pkgName = nextArg();
+        final int pid = Integer.parseInt(nextArg());
+        final int userId = Integer.parseInt(nextArg());
+        mSm.disableAppDataIsolation(pkgName, pid, userId);
+    }
+
     public void runForget() throws RemoteException {
         final String fsUuid = nextArg();
         if ("all".equals(fsUuid)) {
@@ -373,6 +382,8 @@
         System.err.println("");
         System.err.println("       sm supports-checkpoint");
         System.err.println("");
+        System.err.println("       sm unmount-app-data-dirs PACKAGE_NAME PID USER_ID");
+        System.err.println("");
         return 1;
     }
 }
diff --git a/core/api/current.txt b/core/api/current.txt
index 60fe488..047761a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10145,6 +10145,7 @@
     method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public void sendStickyBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle);
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyOrderedBroadcast(@RequiresPermission android.content.Intent, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
@@ -10187,6 +10188,7 @@
     field public static final String BIOMETRIC_SERVICE = "biometric";
     field public static final String BLOB_STORE_SERVICE = "blob_store";
     field public static final String BLUETOOTH_SERVICE = "bluetooth";
+    field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CAMERA_SERVICE = "camera";
     field public static final String CAPTIONING_SERVICE = "captioning";
     field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
@@ -29596,6 +29598,24 @@
     method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
   }
 
+  public final class BugreportManager {
+    method public void cancelBugreport();
+    method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+  }
+
+  public abstract static class BugreportManager.BugreportCallback {
+    ctor public BugreportManager.BugreportCallback();
+    method public void onEarlyReportFinished();
+    method public void onError(int);
+    method public void onFinished();
+    method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
+    field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
+    field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
+    field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
+    field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
+    field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
+  }
+
   public class Build {
     ctor public Build();
     method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
@@ -33927,6 +33947,7 @@
     field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
     field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
     field public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
+    field public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
     field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
     field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
     field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
@@ -39229,6 +39250,7 @@
     field public static final int BAND_25 = 25; // 0x19
     field public static final int BAND_257 = 257; // 0x101
     field public static final int BAND_258 = 258; // 0x102
+    field public static final int BAND_26 = 26; // 0x1a
     field public static final int BAND_260 = 260; // 0x104
     field public static final int BAND_261 = 261; // 0x105
     field public static final int BAND_28 = 28; // 0x1c
@@ -39240,10 +39262,12 @@
     field public static final int BAND_39 = 39; // 0x27
     field public static final int BAND_40 = 40; // 0x28
     field public static final int BAND_41 = 41; // 0x29
+    field public static final int BAND_46 = 46; // 0x2e
     field public static final int BAND_48 = 48; // 0x30
     field public static final int BAND_5 = 5; // 0x5
     field public static final int BAND_50 = 50; // 0x32
     field public static final int BAND_51 = 51; // 0x33
+    field public static final int BAND_53 = 53; // 0x35
     field public static final int BAND_65 = 65; // 0x41
     field public static final int BAND_66 = 66; // 0x42
     field public static final int BAND_7 = 7; // 0x7
@@ -39269,6 +39293,7 @@
     field public static final int BAND_93 = 93; // 0x5d
     field public static final int BAND_94 = 94; // 0x5e
     field public static final int BAND_95 = 95; // 0x5f
+    field public static final int BAND_96 = 96; // 0x60
   }
 
   public static final class AccessNetworkConstants.UtranBand {
@@ -40706,17 +40731,27 @@
 
   public final class PhysicalChannelConfig implements android.os.Parcelable {
     method public int describeContents();
-    method public int getCellBandwidthDownlink();
-    method public int getChannelNumber();
+    method @IntRange(from=1, to=261) public int getBand();
+    method @IntRange(from=1) public int getCellBandwidthDownlinkKhz();
+    method @IntRange(from=1) public int getCellBandwidthUplinkKhz();
+    method @Deprecated public int getChannelNumber();
     method public int getConnectionStatus();
+    method @IntRange(from=0) public int getDownlinkChannelNumber();
+    method @IntRange(from=0) public int getDownlinkFrequencyKhz();
     method public int getNetworkType();
     method @IntRange(from=0, to=1007) public int getPhysicalCellId();
+    method @IntRange(from=0) public int getUplinkChannelNumber();
+    method @IntRange(from=0) public int getUplinkFrequencyKhz();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int BAND_UNKNOWN = 0; // 0x0
+    field public static final int CELL_BANDWIDTH_UNKNOWN = 0; // 0x0
     field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff
     field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1
     field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2
     field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR;
+    field public static final int FREQUENCY_UNKNOWN = -1; // 0xffffffff
+    field public static final int PHYSICAL_CELL_ID_MAXIMUM_VALUE = 1007; // 0x3ef
     field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff
   }
 
@@ -40799,8 +40834,26 @@
     field public static final int INVALID = 2147483647; // 0x7fffffff
   }
 
+  public final class SignalStrengthUpdateRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.os.IBinder getLiveToken();
+    method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos();
+    method public boolean isReportingRequestedWhileIdle();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrengthUpdateRequest> CREATOR;
+  }
+
+  public static final class SignalStrengthUpdateRequest.Builder {
+    ctor public SignalStrengthUpdateRequest.Builder();
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest build();
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setReportingRequestedWhileIdle(boolean);
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setSignalThresholdInfos(@NonNull java.util.Collection<android.telephony.SignalThresholdInfo>);
+  }
+
   public final class SignalThresholdInfo implements android.os.Parcelable {
     method public int describeContents();
+    method public static int getMaximumNumberOfThresholdsAllowed();
+    method public static int getMinimumNumberOfThresholdsAllowed();
     method public int getRadioAccessNetworkType();
     method public int getSignalMeasurementType();
     method @NonNull public int[] getThresholds();
@@ -41161,6 +41214,7 @@
 
   public class TelephonyManager {
     method public boolean canChangeDtmfToneLength();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void clearSignalStrengthUpdateRequest(@NonNull android.telephony.SignalStrengthUpdateRequest);
     method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
@@ -41239,7 +41293,7 @@
     method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
     method public boolean isConcurrentVoiceAndDataSupported();
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed();
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabled();
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
     method public boolean isEmergencyNumber(@NonNull String);
@@ -41273,6 +41327,7 @@
     method public boolean setOperatorBrandOverride(String);
     method public boolean setPreferredNetworkTypeToGlobal();
     method public void setPreferredOpportunisticDataSubscription(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSignalStrengthUpdateRequest(@NonNull android.telephony.SignalStrengthUpdateRequest);
     method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
     method public boolean setVoiceMailNumber(String, String);
     method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 9349770..c19dd4c 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -20,6 +20,22 @@
     field public final int sndWnd;
   }
 
+  public final class TestNetworkInterface implements android.os.Parcelable {
+    ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
+    method public int describeContents();
+    method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
+    method @NonNull public String getInterfaceName();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
+  }
+
+  public class TestNetworkManager {
+    method @NonNull public android.net.TestNetworkInterface createTapInterface();
+    method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
+    method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
+    method public void teardownTestNetwork(@NonNull android.net.Network);
+  }
+
 }
 
 package android.os {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e768ea6..21d8203 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -126,6 +126,7 @@
     field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
     field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
     field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
+    field public static final String MANAGE_TEST_NETWORKS = "android.permission.MANAGE_TEST_NETWORKS";
     field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
@@ -1412,8 +1413,14 @@
 package android.bluetooth {
 
   public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
+    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public android.bluetooth.BufferConstraints getBufferConstraints();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferMillis(int, int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+    field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
+    field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
+    field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0
     field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0
     field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0
     field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1
@@ -1595,6 +1602,25 @@
     field public static final int UUID_BYTES_32_BIT = 4; // 0x4
   }
 
+  public final class BufferConstraint implements android.os.Parcelable {
+    ctor public BufferConstraint(int, int, int);
+    method public int describeContents();
+    method public int getDefaultMillis();
+    method public int getMaxMillis();
+    method public int getMinMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraint> CREATOR;
+  }
+
+  public final class BufferConstraints implements android.os.Parcelable {
+    ctor public BufferConstraints(@NonNull java.util.List<android.bluetooth.BufferConstraint>);
+    method public int describeContents();
+    method @Nullable public android.bluetooth.BufferConstraint getCodec(int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int BUFFER_CODEC_MAX_NUM = 32; // 0x20
+    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR;
+  }
+
 }
 
 package android.bluetooth.le {
@@ -1684,7 +1710,6 @@
     field public static final String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final String BACKUP_SERVICE = "backup";
     field public static final String BATTERY_STATS_SERVICE = "batterystats";
-    field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
     field public static final String ETHERNET_SERVICE = "ethernet";
@@ -6505,157 +6530,157 @@
 
 package android.net.metrics {
 
-  public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
+  @Deprecated public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static final class ApfProgramEvent.Builder {
-    ctor public ApfProgramEvent.Builder();
-    method @NonNull public android.net.metrics.ApfProgramEvent build();
-    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
-    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
-    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
-    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
-    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
-    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
+  @Deprecated public static final class ApfProgramEvent.Builder {
+    ctor @Deprecated public ApfProgramEvent.Builder();
+    method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent build();
+    method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
+    method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
+    method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
+    method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
   }
 
-  public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
+  @Deprecated public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static final class ApfStats.Builder {
-    ctor public ApfStats.Builder();
-    method @NonNull public android.net.metrics.ApfStats build();
-    method @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
-    method @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
-    method @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
-    method @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
-    method @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
-    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
-    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
-    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
-    method @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
-    method @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
+  @Deprecated public static final class ApfStats.Builder {
+    ctor @Deprecated public ApfStats.Builder();
+    method @Deprecated @NonNull public android.net.metrics.ApfStats build();
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
+    method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
   }
 
-  public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
+  @Deprecated public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static final class DhcpClientEvent.Builder {
-    ctor public DhcpClientEvent.Builder();
-    method @NonNull public android.net.metrics.DhcpClientEvent build();
-    method @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
-    method @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
+  @Deprecated public static final class DhcpClientEvent.Builder {
+    ctor @Deprecated public DhcpClientEvent.Builder();
+    method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent build();
+    method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
+    method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
   }
 
-  public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
-    ctor public DhcpErrorEvent(int);
-    method public static int errorCodeWithOption(int, int);
-    field public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
-    field public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
-    field public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
-    field public static final int DHCP_ERROR = 4; // 0x4
-    field public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
-    field public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
-    field public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
-    field public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
-    field public static final int L2_ERROR = 1; // 0x1
-    field public static final int L2_TOO_SHORT = 16842752; // 0x1010000
-    field public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
-    field public static final int L3_ERROR = 2; // 0x2
-    field public static final int L3_INVALID_IP = 33751040; // 0x2030000
-    field public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
-    field public static final int L3_TOO_SHORT = 33619968; // 0x2010000
-    field public static final int L4_ERROR = 3; // 0x3
-    field public static final int L4_NOT_UDP = 50397184; // 0x3010000
-    field public static final int L4_WRONG_PORT = 50462720; // 0x3020000
-    field public static final int MISC_ERROR = 5; // 0x5
-    field public static final int PARSING_ERROR = 84082688; // 0x5030000
-    field public static final int RECEIVE_ERROR = 84017152; // 0x5020000
+  @Deprecated public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor @Deprecated public DhcpErrorEvent(int);
+    method @Deprecated public static int errorCodeWithOption(int, int);
+    field @Deprecated public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
+    field @Deprecated public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
+    field @Deprecated public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
+    field @Deprecated public static final int DHCP_ERROR = 4; // 0x4
+    field @Deprecated public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
+    field @Deprecated public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
+    field @Deprecated public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
+    field @Deprecated public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
+    field @Deprecated public static final int L2_ERROR = 1; // 0x1
+    field @Deprecated public static final int L2_TOO_SHORT = 16842752; // 0x1010000
+    field @Deprecated public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
+    field @Deprecated public static final int L3_ERROR = 2; // 0x2
+    field @Deprecated public static final int L3_INVALID_IP = 33751040; // 0x2030000
+    field @Deprecated public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
+    field @Deprecated public static final int L3_TOO_SHORT = 33619968; // 0x2010000
+    field @Deprecated public static final int L4_ERROR = 3; // 0x3
+    field @Deprecated public static final int L4_NOT_UDP = 50397184; // 0x3010000
+    field @Deprecated public static final int L4_WRONG_PORT = 50462720; // 0x3020000
+    field @Deprecated public static final int MISC_ERROR = 5; // 0x5
+    field @Deprecated public static final int PARSING_ERROR = 84082688; // 0x5030000
+    field @Deprecated public static final int RECEIVE_ERROR = 84017152; // 0x5020000
   }
 
-  public class IpConnectivityLog {
-    ctor public IpConnectivityLog();
-    method public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
+  @Deprecated public class IpConnectivityLog {
+    ctor @Deprecated public IpConnectivityLog();
+    method @Deprecated public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method @Deprecated public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method @Deprecated public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method @Deprecated public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method @Deprecated public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
   }
 
-  public static interface IpConnectivityLog.Event extends android.os.Parcelable {
+  @Deprecated public static interface IpConnectivityLog.Event extends android.os.Parcelable {
   }
 
-  public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event {
-    ctor public IpManagerEvent(int, long);
-    field public static final int COMPLETE_LIFECYCLE = 3; // 0x3
-    field public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8
-    field public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7
-    field public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6
-    field public static final int ERROR_STARTING_IPV4 = 4; // 0x4
-    field public static final int ERROR_STARTING_IPV6 = 5; // 0x5
-    field public static final int PROVISIONING_FAIL = 2; // 0x2
-    field public static final int PROVISIONING_OK = 1; // 0x1
+  @Deprecated public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor @Deprecated public IpManagerEvent(int, long);
+    field @Deprecated public static final int COMPLETE_LIFECYCLE = 3; // 0x3
+    field @Deprecated public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8
+    field @Deprecated public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7
+    field @Deprecated public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6
+    field @Deprecated public static final int ERROR_STARTING_IPV4 = 4; // 0x4
+    field @Deprecated public static final int ERROR_STARTING_IPV6 = 5; // 0x5
+    field @Deprecated public static final int PROVISIONING_FAIL = 2; // 0x2
+    field @Deprecated public static final int PROVISIONING_OK = 1; // 0x1
   }
 
-  public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event {
-    ctor public IpReachabilityEvent(int);
-    field public static final int NUD_FAILED = 512; // 0x200
-    field public static final int NUD_FAILED_ORGANIC = 1024; // 0x400
-    field public static final int PROBE = 256; // 0x100
-    field public static final int PROVISIONING_LOST = 768; // 0x300
-    field public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500
+  @Deprecated public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor @Deprecated public IpReachabilityEvent(int);
+    field @Deprecated public static final int NUD_FAILED = 512; // 0x200
+    field @Deprecated public static final int NUD_FAILED_ORGANIC = 1024; // 0x400
+    field @Deprecated public static final int PROBE = 256; // 0x100
+    field @Deprecated public static final int PROVISIONING_LOST = 768; // 0x300
+    field @Deprecated public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500
   }
 
-  public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event {
-    ctor public NetworkEvent(int, long);
-    ctor public NetworkEvent(int);
-    field public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
-    field public static final int NETWORK_CONNECTED = 1; // 0x1
-    field public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc
-    field public static final int NETWORK_DISCONNECTED = 7; // 0x7
-    field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
-    field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
-    field public static final int NETWORK_LINGER = 5; // 0x5
-    field public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd
-    field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
-    field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
-    field public static final int NETWORK_UNLINGER = 6; // 0x6
-    field public static final int NETWORK_VALIDATED = 2; // 0x2
-    field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
+  @Deprecated public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event {
+    ctor @Deprecated public NetworkEvent(int, long);
+    ctor @Deprecated public NetworkEvent(int);
+    field @Deprecated public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
+    field @Deprecated public static final int NETWORK_CONNECTED = 1; // 0x1
+    field @Deprecated public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc
+    field @Deprecated public static final int NETWORK_DISCONNECTED = 7; // 0x7
+    field @Deprecated public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
+    field @Deprecated public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
+    field @Deprecated public static final int NETWORK_LINGER = 5; // 0x5
+    field @Deprecated public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd
+    field @Deprecated public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
+    field @Deprecated public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
+    field @Deprecated public static final int NETWORK_UNLINGER = 6; // 0x6
+    field @Deprecated public static final int NETWORK_VALIDATED = 2; // 0x2
+    field @Deprecated public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
   }
 
-  public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
+  @Deprecated public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static final class RaEvent.Builder {
-    ctor public RaEvent.Builder();
-    method @NonNull public android.net.metrics.RaEvent build();
-    method @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
-    method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
-    method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
-    method @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
-    method @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
-    method @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
+  @Deprecated public static final class RaEvent.Builder {
+    ctor @Deprecated public RaEvent.Builder();
+    method @Deprecated @NonNull public android.net.metrics.RaEvent build();
+    method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
+    method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
+    method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
+    method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
+    method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
+    method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
   }
 
-  public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
-    method @NonNull public static String getProbeName(int);
-    field public static final int DNS_FAILURE = 0; // 0x0
-    field public static final int DNS_SUCCESS = 1; // 0x1
-    field public static final int PROBE_DNS = 0; // 0x0
-    field public static final int PROBE_FALLBACK = 4; // 0x4
-    field public static final int PROBE_HTTP = 1; // 0x1
-    field public static final int PROBE_HTTPS = 2; // 0x2
-    field public static final int PROBE_PAC = 3; // 0x3
-    field public static final int PROBE_PRIVDNS = 5; // 0x5
+  @Deprecated public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
+    method @Deprecated @NonNull public static String getProbeName(int);
+    field @Deprecated public static final int DNS_FAILURE = 0; // 0x0
+    field @Deprecated public static final int DNS_SUCCESS = 1; // 0x1
+    field @Deprecated public static final int PROBE_DNS = 0; // 0x0
+    field @Deprecated public static final int PROBE_FALLBACK = 4; // 0x4
+    field @Deprecated public static final int PROBE_HTTP = 1; // 0x1
+    field @Deprecated public static final int PROBE_HTTPS = 2; // 0x2
+    field @Deprecated public static final int PROBE_PAC = 3; // 0x3
+    field @Deprecated public static final int PROBE_PRIVDNS = 5; // 0x5
   }
 
-  public static final class ValidationProbeEvent.Builder {
-    ctor public ValidationProbeEvent.Builder();
-    method @NonNull public android.net.metrics.ValidationProbeEvent build();
-    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
-    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
-    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
+  @Deprecated public static final class ValidationProbeEvent.Builder {
+    ctor @Deprecated public ValidationProbeEvent.Builder();
+    method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent build();
+    method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
+    method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
+    method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
   }
 
 }
@@ -6926,7 +6951,10 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnEnabled();
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnSupported();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setAlwaysOn(boolean);
     method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
     field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
   }
@@ -7046,24 +7074,10 @@
   }
 
   public final class BugreportManager {
-    method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
     method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
     method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
   }
 
-  public abstract static class BugreportManager.BugreportCallback {
-    ctor public BugreportManager.BugreportCallback();
-    method public void onEarlyReportFinished();
-    method public void onError(int);
-    method public void onFinished();
-    method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
-    field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
-    field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
-    field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
-    field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
-    field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
-  }
-
   public final class BugreportParams {
     ctor public BugreportParams(int);
     method public int getMode();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9cf9ce4..715a099 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -981,7 +981,7 @@
 package android.net {
 
   public class ConnectivityManager {
-    method @RequiresPermission(anyOf={"android.permission.MANAGE_TEST_NETWORKS", android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
   }
 
   public class EthernetManager {
@@ -1001,22 +1001,6 @@
     method public static void setServiceForTest(@Nullable android.os.IBinder);
   }
 
-  public final class TestNetworkInterface implements android.os.Parcelable {
-    ctor public TestNetworkInterface(android.os.ParcelFileDescriptor, String);
-    method public int describeContents();
-    method public android.os.ParcelFileDescriptor getFileDescriptor();
-    method public String getInterfaceName();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
-  }
-
-  public class TestNetworkManager {
-    method public android.net.TestNetworkInterface createTapInterface();
-    method public android.net.TestNetworkInterface createTunInterface(@NonNull android.net.LinkAddress[]);
-    method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
-    method public void teardownTestNetwork(@NonNull android.net.Network);
-  }
-
   public class TrafficStats {
     method public static long getLoopbackRxBytes();
     method public static long getLoopbackRxPackets();
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
index c6f42f7..a31cfae 100644
--- a/core/java/android/accessibilityservice/OWNERS
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -1,4 +1,4 @@
 svetoslavganov@google.com
 pweaver@google.com
 rhedjao@google.com
-qasid@google.com
+ryanlwlin@google.com
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 602b835..12c9cd9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1428,6 +1428,45 @@
         }
     }
 
+    /**
+     * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+     * Intent you are sending stays around after the broadcast is complete,
+     * so that others can quickly retrieve that data through the return
+     * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}.  In
+     * all other ways, this behaves the same as
+     * {@link #sendBroadcast(Intent)}.
+     *
+     * @deprecated Sticky broadcasts should not be used.  They provide no security (anyone
+     * can access them), no protection (anyone can modify them), and many other problems.
+     * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+     * has changed, with another mechanism for apps to retrieve the current value whenever
+     * desired.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     * Intent will receive the broadcast, and the Intent will be held to
+     * be re-broadcast to future receivers.
+     * @param options (optional) Additional sending options, generated from a
+     * {@link android.app.BroadcastOptions}.
+     *
+     * @see #sendBroadcast(Intent)
+     * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+     */
+    @Override
+    @Deprecated
+    public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) {
+        warnIfCallingFromSystemProcess();
+        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        try {
+            intent.prepareToLeaveProcess(this);
+            ActivityManager.getService().broadcastIntentWithFeature(
+                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
+                    false, true, getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @Override
     @Deprecated
     public void sendStickyOrderedBroadcast(Intent intent,
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index be1681b..66a8325 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -223,7 +223,7 @@
      */
     IBinder requestStartActivityPermissionToken(in IBinder delegatorToken);
 
-    void releaseSomeActivities(in IApplicationThread app);
+    oneway void releaseSomeActivities(in IApplicationThread app);
     Bitmap getTaskDescriptionIcon(in String filename, int userId);
     void registerTaskStackListener(in ITaskStackListener listener);
     void unregisterTaskStackListener(in ITaskStackListener listener);
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 6d79e2d..60bfac5 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -42,8 +42,10 @@
 # Multiuser
 per-file *User* = file:/MULTIUSER_OWNERS
 
-# Notification
+# Notification, DND, Status bar
 per-file *Notification* = file:/packages/SystemUI/OWNERS
+per-file *Zen* = file:/packages/SystemUI/OWNERS
+per-file *StatusBar* = file:/packages/SystemUI/OWNERS
 
 # ResourcesManager
 per-file ResourcesManager = rtmitchell@google.com, toddke@google.com
diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS
new file mode 100644
index 0000000..439df4b
--- /dev/null
+++ b/core/java/android/appwidget/OWNERS
@@ -0,0 +1,3 @@
+pinyaoting@google.com
+suprabh@google.com
+sunnygoyal@google.com
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 15daf1c..cd91aa9 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -225,6 +225,39 @@
     @SystemApi
     public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
 
+    /** @hide */
+    @IntDef(prefix = "DYNAMIC_BUFFER_SUPPORT_", value = {
+            DYNAMIC_BUFFER_SUPPORT_NONE,
+            DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD,
+            DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Type {}
+
+    /**
+     * Indicates the supported type of Dynamic Audio Buffer is not supported.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0;
+
+    /**
+     * Indicates the supported type of Dynamic Audio Buffer is A2DP offload.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1;
+
+    /**
+     * Indicates the supported type of Dynamic Audio Buffer is A2DP software encoding.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2;
+
     private BluetoothAdapter mAdapter;
     private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector =
             new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp",
@@ -845,6 +878,87 @@
     }
 
     /**
+     * Get the supported type of the Dynamic Audio Buffer.
+     * <p>Possible return values are
+     * {@link #DYNAMIC_BUFFER_SUPPORT_NONE},
+     * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD},
+     * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}.
+     *
+     * @return supported type of Dynamic Audio Buffer feature
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public @Type int getDynamicBufferSupport() {
+        if (VDBG) log("getDynamicBufferSupport()");
+        try {
+            final IBluetoothA2dp service = getService();
+            if (service != null && isEnabled()) {
+                return service.getDynamicBufferSupport();
+            }
+            if (service == null) Log.w(TAG, "Proxy not attached to service");
+            return DYNAMIC_BUFFER_SUPPORT_NONE;
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to get getDynamicBufferSupport, error: ", e);
+            return DYNAMIC_BUFFER_SUPPORT_NONE;
+        }
+    }
+
+    /**
+     * Return the record of {@link BufferConstraints} object that
+     * has the default/maximum/minimum audio buffer. This can be used to inform what the controller
+     * has support for the audio buffer.
+     *
+     * @return a record with {@link BufferConstraints} or null if report is unavailable
+     * or unsupported
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public @Nullable BufferConstraints getBufferConstraints() {
+        if (VDBG) log("getBufferConstraints()");
+        try {
+            final IBluetoothA2dp service = getService();
+            if (service != null && isEnabled()) {
+                return service.getBufferConstraints();
+            }
+            if (service == null) Log.w(TAG, "Proxy not attached to service");
+            return null;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+            return null;
+        }
+    }
+
+    /**
+     * Set Dynamic Audio Buffer Size.
+     *
+     * @param codec audio codec
+     * @param value buffer millis
+     * @return true to indicate success, or false on immediate error
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean setBufferMillis(@BluetoothCodecConfig.SourceCodecType int codec, int value) {
+        if (VDBG) log("setBufferMillis(" + codec + ", " + value + ")");
+        try {
+            final IBluetoothA2dp service = getService();
+            if (service != null && isEnabled()) {
+                return service.setBufferMillis(codec, value);
+            }
+            if (service == null) Log.w(TAG, "Proxy not attached to service");
+            return false;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+            return false;
+        }
+    }
+
+    /**
      * Helper for converting a state to a string.
      *
      * For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/BufferConstraint.java b/core/java/android/bluetooth/BufferConstraint.java
new file mode 100644
index 0000000..cbffc78
--- /dev/null
+++ b/core/java/android/bluetooth/BufferConstraint.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 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.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Stores a codec's constraints on buffering length in milliseconds.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class BufferConstraint implements Parcelable {
+
+    private static final String TAG = "BufferConstraint";
+    private int mDefaultMillis;
+    private int mMaxMillis;
+    private int mMinMillis;
+
+    public BufferConstraint(int defaultMillis, int maxMillis,
+            int minMillis) {
+        mDefaultMillis = defaultMillis;
+        mMaxMillis = maxMillis;
+        mMinMillis = minMillis;
+    }
+
+    BufferConstraint(Parcel in) {
+        mDefaultMillis = in.readInt();
+        mMaxMillis = in.readInt();
+        mMinMillis = in.readInt();
+    }
+
+    public static final @NonNull Parcelable.Creator<BufferConstraint> CREATOR =
+            new Parcelable.Creator<BufferConstraint>() {
+                public BufferConstraint createFromParcel(Parcel in) {
+                    return new BufferConstraint(in);
+                }
+
+                public BufferConstraint[] newArray(int size) {
+                    return new BufferConstraint[size];
+                }
+            };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mDefaultMillis);
+        out.writeInt(mMaxMillis);
+        out.writeInt(mMinMillis);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Get the default buffer millis
+     *
+     * @return default buffer millis
+     * @hide
+     */
+    @SystemApi
+    public int getDefaultMillis() {
+        return mDefaultMillis;
+    }
+
+    /**
+     * Get the maximum buffer millis
+     *
+     * @return maximum buffer millis
+     * @hide
+     */
+    @SystemApi
+    public int getMaxMillis() {
+        return mMaxMillis;
+    }
+
+    /**
+     * Get the minimum buffer millis
+     *
+     * @return minimum buffer millis
+     * @hide
+     */
+    @SystemApi
+    public int getMinMillis() {
+        return mMinMillis;
+    }
+}
diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java
new file mode 100644
index 0000000..7e5ec1e
--- /dev/null
+++ b/core/java/android/bluetooth/BufferConstraints.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 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.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * A parcelable collection of buffer constraints by codec type.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class BufferConstraints implements Parcelable {
+    public static final int BUFFER_CODEC_MAX_NUM = 32;
+
+    private static final String TAG = "BufferConstraints";
+
+    private Map<Integer, BufferConstraint> mBufferConstraints;
+    private List<BufferConstraint> mBufferConstraintList;
+
+    public BufferConstraints(@NonNull List<BufferConstraint>
+            bufferConstraintList) {
+
+        mBufferConstraintList = new ArrayList<BufferConstraint>(bufferConstraintList);
+        mBufferConstraints = new HashMap<Integer, BufferConstraint>();
+        for (int i = 0; i < BUFFER_CODEC_MAX_NUM; i++) {
+            mBufferConstraints.put(i, bufferConstraintList.get(i));
+        }
+    }
+
+    BufferConstraints(Parcel in) {
+        mBufferConstraintList = new ArrayList<BufferConstraint>();
+        mBufferConstraints = new HashMap<Integer, BufferConstraint>();
+        in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader());
+        for (int i = 0; i < mBufferConstraintList.size(); i++) {
+            mBufferConstraints.put(i, mBufferConstraintList.get(i));
+        }
+    }
+
+    public static final @NonNull Parcelable.Creator<BufferConstraints> CREATOR =
+            new Parcelable.Creator<BufferConstraints>() {
+                public BufferConstraints createFromParcel(Parcel in) {
+                    return new BufferConstraints(in);
+                }
+
+                public BufferConstraints[] newArray(int size) {
+                    return new BufferConstraints[size];
+                }
+            };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeList(mBufferConstraintList);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Get the buffer constraints by codec type.
+     *
+     * @param codec Audio codec
+     * @return buffer constraints by codec type.
+     * @hide
+     */
+    @SystemApi
+    public @Nullable BufferConstraint getCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
+        return mBufferConstraints.get(codec);
+    }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 92ede1c..eecdb84 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2602,6 +2602,36 @@
     public abstract void sendStickyBroadcast(@RequiresPermission Intent intent);
 
     /**
+     * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+     * Intent you are sending stays around after the broadcast is complete,
+     * so that others can quickly retrieve that data through the return
+     * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}.  In
+     * all other ways, this behaves the same as
+     * {@link #sendBroadcast(Intent)}.
+     *
+     * @deprecated Sticky broadcasts should not be used.  They provide no security (anyone
+     * can access them), no protection (anyone can modify them), and many other problems.
+     * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+     * has changed, with another mechanism for apps to retrieve the current value whenever
+     * desired.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     * Intent will receive the broadcast, and the Intent will be held to
+     * be re-broadcast to future receivers.
+     * @param options (optional) Additional sending options, generated from a
+     * {@link android.app.BroadcastOptions}.
+     *
+     * @see #sendBroadcast(Intent)
+     * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+     */
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY)
+    public void sendStickyBroadcast(@RequiresPermission @NonNull Intent intent,
+            @Nullable Bundle options) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * <p>Version of {@link #sendStickyBroadcast} that allows you to
      * receive data back from the broadcast.  This is accomplished by
      * supplying your own BroadcastReceiver when calling, which will be
@@ -4999,9 +5029,7 @@
      * Service to capture a bugreport.
      * @see #getSystemService(String)
      * @see android.os.BugreportManager
-     * @hide
      */
-    @SystemApi
     public static final String BUGREPORT_SERVICE = "bugreport";
 
     /**
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 5bdd521..e351c244 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -617,6 +617,35 @@
         mBase.sendStickyBroadcast(intent);
     }
 
+    /**
+     * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+     * Intent you are sending stays around after the broadcast is complete,
+     * so that others can quickly retrieve that data through the return
+     * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}.  In
+     * all other ways, this behaves the same as
+     * {@link #sendBroadcast(Intent)}.
+     *
+     * @deprecated Sticky broadcasts should not be used.  They provide no security (anyone
+     * can access them), no protection (anyone can modify them), and many other problems.
+     * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+     * has changed, with another mechanism for apps to retrieve the current value whenever
+     * desired.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     * Intent will receive the broadcast, and the Intent will be held to
+     * be re-broadcast to future receivers.
+     * @param options (optional) Additional sending options, generated from a
+     * {@link android.app.BroadcastOptions}.
+     *
+     * @see #sendBroadcast(Intent)
+     * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+     */
+    @Override
+    @Deprecated
+    public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) {
+        mBase.sendStickyBroadcast(intent, options);
+    }
+
     @Override
     @Deprecated
     public void sendStickyOrderedBroadcast(
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index 44b5c44..0b950b4 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -17,6 +17,7 @@
 package android.content.om;
 
 import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
 
 /**
  * Api for getting information about overlay packages.
@@ -163,4 +164,18 @@
      * @param packageName The name of the overlay package whose idmap should be deleted.
      */
     void invalidateCachesForOverlay(in String packageName, in int userIs);
+
+    /**
+     * Perform a series of requests related to overlay packages. This is an
+     * atomic operation: either all requests were performed successfully and
+     * the changes were propagated to the rest of the system, or at least one
+     * request could not be performed successfully and nothing is changed and
+     * nothing is propagated to the rest of the system.
+     *
+     * @see OverlayManagerTransaction
+     *
+     * @param transaction the series of overlay related requests to perform
+     * @throws SecurityException if the transaction failed
+     */
+    void commit(in OverlayManagerTransaction transaction);
 }
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 217f637c..7c14c28 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -254,6 +254,29 @@
     }
 
     /**
+     * Perform a series of requests related to overlay packages. This is an
+     * atomic operation: either all requests were performed successfully and
+     * the changes were propagated to the rest of the system, or at least one
+     * request could not be performed successfully and nothing is changed and
+     * nothing is propagated to the rest of the system.
+     *
+     * @see OverlayManagerTransaction
+     *
+     * @param transaction the series of overlay related requests to perform
+     * @throws Exception if not all the requests could be successfully and
+     *         atomically executed
+     *
+     * @hide
+     */
+    public void commit(@NonNull final OverlayManagerTransaction transaction) {
+        try {
+            mService.commit(transaction);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Starting on R, actor enforcement and app visibility changes introduce additional failure
      * cases, but the SecurityException thrown with these checks is unexpected for existing
      * consumers of the API.
diff --git a/core/java/android/content/om/OverlayManagerTransaction.aidl b/core/java/android/content/om/OverlayManagerTransaction.aidl
new file mode 100644
index 0000000..6715c82
--- /dev/null
+++ b/core/java/android/content/om/OverlayManagerTransaction.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.content.om;
+
+parcelable OverlayManagerTransaction;
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
new file mode 100644
index 0000000..1fa8973
--- /dev/null
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -0,0 +1,216 @@
+/*
+ * 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.content.om;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Container for a batch of requests to the OverlayManagerService.
+ *
+ * Transactions are created using a builder interface. Example usage:
+ *
+ * final OverlayManager om = ctx.getSystemService(OverlayManager.class);
+ * final OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+ *     .setEnabled(...)
+ *     .setEnabled(...)
+ *     .build();
+ * om.commit(t);
+ *
+ * @hide
+ */
+public class OverlayManagerTransaction
+        implements Iterable<OverlayManagerTransaction.Request>, Parcelable {
+    // TODO: remove @hide from this class when OverlayManager is added to the
+    // SDK, but keep OverlayManagerTransaction.Request @hidden
+    private final List<Request> mRequests;
+
+    OverlayManagerTransaction(@NonNull final List<Request> requests) {
+        checkNotNull(requests);
+        if (requests.contains(null)) {
+            throw new IllegalArgumentException("null request");
+        }
+        mRequests = requests;
+    }
+
+    private OverlayManagerTransaction(@NonNull final Parcel source) {
+        final int size = source.readInt();
+        mRequests = new ArrayList<Request>(size);
+        for (int i = 0; i < size; i++) {
+            final int request = source.readInt();
+            final String packageName = source.readString();
+            final int userId = source.readInt();
+            mRequests.add(new Request(request, packageName, userId));
+        }
+    }
+
+    @Override
+    public Iterator<Request> iterator() {
+        return mRequests.iterator();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("OverlayManagerTransaction { mRequests = %s }", mRequests);
+    }
+
+    /**
+     * A single unit of the transaction, such as a request to enable an
+     * overlay, or to disable an overlay.
+     *
+     * @hide
+     */
+    public static class Request {
+        @IntDef(prefix = "TYPE_", value = {
+                TYPE_SET_ENABLED,
+                TYPE_SET_DISABLED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        @interface RequestType {}
+
+        public static final int TYPE_SET_ENABLED = 0;
+        public static final int TYPE_SET_DISABLED = 1;
+
+        @RequestType public final int type;
+        public final String packageName;
+        public final int userId;
+
+        public Request(@RequestType final int type, @NonNull final String packageName,
+                final int userId) {
+            this.type = type;
+            this.packageName = packageName;
+            this.userId = userId;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("Request{type=0x%02x (%s), packageName=%s, userId=%d}",
+                    type, typeToString(), packageName, userId);
+        }
+
+        /**
+         * Translate the request type into a human readable string. Only
+         * intended for debugging.
+         *
+         * @hide
+         */
+        public String typeToString() {
+            switch (type) {
+                case TYPE_SET_ENABLED: return "TYPE_SET_ENABLED";
+                case TYPE_SET_DISABLED: return "TYPE_SET_DISABLED";
+                default: return String.format("TYPE_UNKNOWN (0x%02x)", type);
+            }
+        }
+    }
+
+    /**
+     * Builder class for OverlayManagerTransaction objects.
+     *
+     * @hide
+     */
+    public static class Builder {
+        private final List<Request> mRequests = new ArrayList<>();
+
+        /**
+         * Request that an overlay package be enabled and change its loading
+         * order to the last package to be loaded, or disabled
+         *
+         * If the caller has the correct permissions, it is always possible to
+         * disable an overlay. Due to technical and security reasons it may not
+         * always be possible to enable an overlay, for instance if the overlay
+         * does not successfully overlay any target resources due to
+         * overlayable policy restrictions.
+         *
+         * An enabled overlay is a part of target package's resources, i.e. it will
+         * be part of any lookups performed via {@link android.content.res.Resources}
+         * and {@link android.content.res.AssetManager}. A disabled overlay will no
+         * longer affect the resources of the target package. If the target is
+         * currently running, its outdated resources will be replaced by new ones.
+         *
+         * @param packageName The name of the overlay package.
+         * @param enable true to enable the overlay, false to disable it.
+         * @return this Builder object, so you can chain additional requests
+         */
+        public Builder setEnabled(@NonNull String packageName, boolean enable) {
+            return setEnabled(packageName, enable, UserHandle.myUserId());
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setEnabled(@NonNull String packageName, boolean enable, int userId) {
+            checkNotNull(packageName);
+            @Request.RequestType final int type =
+                enable ? Request.TYPE_SET_ENABLED : Request.TYPE_SET_DISABLED;
+            mRequests.add(new Request(type, packageName, userId));
+            return this;
+        }
+
+        /**
+         * Create a new transaction out of the requests added so far. Execute
+         * the transaction by calling OverlayManager#commit.
+         *
+         * @see OverlayManager#commit
+         * @return a new transaction
+         */
+        public OverlayManagerTransaction build() {
+            return new OverlayManagerTransaction(mRequests);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        final int size = mRequests.size();
+        dest.writeInt(size);
+        for (int i = 0; i < size; i++) {
+            final Request req = mRequests.get(i);
+            dest.writeInt(req.type);
+            dest.writeString(req.packageName);
+            dest.writeInt(req.userId);
+        }
+    }
+
+    public static final Parcelable.Creator<OverlayManagerTransaction> CREATOR =
+            new Parcelable.Creator<OverlayManagerTransaction>() {
+
+        @Override
+        public OverlayManagerTransaction createFromParcel(Parcel source) {
+            return new OverlayManagerTransaction(source);
+        }
+
+        @Override
+        public OverlayManagerTransaction[] newArray(int size) {
+            return new OverlayManagerTransaction[size];
+        }
+    };
+}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 5e925b6..47c7a1a 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -206,11 +206,11 @@
     void startNattKeepalive(in Network network, int intervalSeconds,
             in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr);
 
-    void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
+    void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
             int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
             String dstAddr);
 
-    void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds,
+    void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
             in ISocketKeepaliveCallback cb);
 
     void stopKeepalive(in Network network, int slot);
diff --git a/core/java/android/net/NattSocketKeepalive.java b/core/java/android/net/NattSocketKeepalive.java
index b0ce0c7..a15d165 100644
--- a/core/java/android/net/NattSocketKeepalive.java
+++ b/core/java/android/net/NattSocketKeepalive.java
@@ -51,7 +51,7 @@
     void startImpl(int intervalSec) {
         mExecutor.execute(() -> {
             try {
-                mService.startNattKeepaliveWithFd(mNetwork, mPfd.getFileDescriptor(), mResourceId,
+                mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
                         intervalSec, mCallback,
                         mSource.getHostAddress(), mDestination.getHostAddress());
             } catch (RemoteException e) {
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 4f46736..83a7d16 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -227,12 +227,6 @@
      */
     public static final String REDIRECT_URL_KEY = "redirect URL";
 
-    /**
-     * Bundle key for the underlying networks in {@code EVENT_UNDERLYING_NETWORKS_CHANGED}.
-     * @hide
-     */
-    public static final String UNDERLYING_NETWORKS_KEY = "underlyingNetworks";
-
      /**
      * Sent by the NetworkAgent to ConnectivityService to indicate this network was
      * explicitly selected.  This should be sent before the NetworkInfo is marked
diff --git a/core/java/android/net/TcpSocketKeepalive.java b/core/java/android/net/TcpSocketKeepalive.java
index 436397e..d89814d 100644
--- a/core/java/android/net/TcpSocketKeepalive.java
+++ b/core/java/android/net/TcpSocketKeepalive.java
@@ -21,7 +21,6 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import java.io.FileDescriptor;
 import java.util.concurrent.Executor;
 
 /** @hide */
@@ -54,8 +53,7 @@
     void startImpl(int intervalSec) {
         mExecutor.execute(() -> {
             try {
-                final FileDescriptor fd = mPfd.getFileDescriptor();
-                mService.startTcpKeepalive(mNetwork, fd, intervalSec, mCallback);
+                mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback);
             } catch (RemoteException e) {
                 Log.e(TAG, "Error starting packet keepalive: ", e);
                 throw e.rethrowFromSystemServer();
diff --git a/core/java/android/net/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java
index 8455083..4449ff8 100644
--- a/core/java/android/net/TestNetworkInterface.java
+++ b/core/java/android/net/TestNetworkInterface.java
@@ -15,7 +15,8 @@
  */
 package android.net;
 
-import android.annotation.TestApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
@@ -25,9 +26,11 @@
  *
  * @hide
  */
-@TestApi
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public final class TestNetworkInterface implements Parcelable {
+    @NonNull
     private final ParcelFileDescriptor mFileDescriptor;
+    @NonNull
     private final String mInterfaceName;
 
     @Override
@@ -36,29 +39,32 @@
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
+    public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE);
         out.writeString(mInterfaceName);
     }
 
-    public TestNetworkInterface(ParcelFileDescriptor pfd, String intf) {
+    public TestNetworkInterface(@NonNull ParcelFileDescriptor pfd, @NonNull String intf) {
         mFileDescriptor = pfd;
         mInterfaceName = intf;
     }
 
-    private TestNetworkInterface(Parcel in) {
+    private TestNetworkInterface(@NonNull Parcel in) {
         mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
         mInterfaceName = in.readString();
     }
 
+    @NonNull
     public ParcelFileDescriptor getFileDescriptor() {
         return mFileDescriptor;
     }
 
+    @NonNull
     public String getInterfaceName() {
         return mInterfaceName;
     }
 
+    @NonNull
     public static final Parcelable.Creator<TestNetworkInterface> CREATOR =
             new Parcelable.Creator<TestNetworkInterface>() {
                 public TestNetworkInterface createFromParcel(Parcel in) {
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index a0a563b..4e89414 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -17,18 +17,21 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
 import android.os.IBinder;
 import android.os.RemoteException;
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Arrays;
+import java.util.Collection;
+
 /**
  * Class that allows creation and management of per-app, test-only networks
  *
  * @hide
  */
-@TestApi
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
 public class TestNetworkManager {
     /**
      * Prefix for tun interfaces created by this class.
@@ -57,7 +60,7 @@
      * @param network The test network that should be torn down
      * @hide
      */
-    @TestApi
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public void teardownTestNetwork(@NonNull Network network) {
         try {
             mService.teardownTestNetwork(network.netId);
@@ -102,7 +105,7 @@
      * @param binder A binder object guarding the lifecycle of this test network.
      * @hide
      */
-    @TestApi
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
         setupTestNetwork(iface, null, true, new int[0], binder);
     }
@@ -127,12 +130,29 @@
      * @param linkAddrs an array of LinkAddresses to assign to the TUN interface
      * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
      *     TUN interface.
+     * @deprecated Use {@link #createTunInterface(Collection)} instead.
      * @hide
      */
-    @TestApi
+    @Deprecated
+    @NonNull
     public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+        return createTunInterface(Arrays.asList(linkAddrs));
+    }
+
+    /**
+     * Create a tun interface for testing purposes
+     *
+     * @param linkAddrs an array of LinkAddresses to assign to the TUN interface
+     * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
+     *     TUN interface.
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @NonNull
+    public TestNetworkInterface createTunInterface(@NonNull Collection<LinkAddress> linkAddrs) {
         try {
-            return mService.createTunInterface(linkAddrs);
+            final LinkAddress[] arr = new LinkAddress[linkAddrs.size()];
+            return mService.createTunInterface(linkAddrs.toArray(arr));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -145,7 +165,8 @@
      *     TAP interface.
      * @hide
      */
-    @TestApi
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @NonNull
     public TestNetworkInterface createTapInterface() {
         try {
             return mService.createTapInterface();
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
index ab12cdd..3d79f28 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -39,7 +39,11 @@
  * An event logged when there is a change or event that requires updating the
  * the APF program in place with a new APF program.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class ApfProgramEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index fcafb7e..a32d3a6 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -27,7 +27,11 @@
 /**
  * An event logged for an interface with APF capabilities when its IpClient state machine exits.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class ApfStats implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index 8de427d..e175d58 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -28,7 +28,11 @@
 /**
  * An event recorded when a DhcpClient state machine transitions to a new state.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class DhcpClientEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index de3129d..7dd0696 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -27,7 +27,11 @@
 /**
  * Event class used to record error events when parsing DHCP response packets.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class DhcpErrorEvent implements IpConnectivityLog.Event {
     public static final int L2_ERROR   = 1;
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 58ea915..5cadb45 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -35,7 +35,11 @@
 /**
  * Class for logging IpConnectvity events with IpConnectivityMetrics
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public class IpConnectivityLog {
     private static final String TAG = IpConnectivityLog.class.getSimpleName();
@@ -137,7 +141,7 @@
      * @return true if the event was successfully logged.
      */
     public boolean log(@NonNull Network network, @NonNull int[] transports, @NonNull Event data) {
-        return log(network.netId, transports, data);
+        return log(network.getNetId(), transports, data);
     }
 
     /**
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index 4f7f326..3abcc05 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -33,7 +33,11 @@
  * An event recorded by IpClient when IP provisioning completes for a network or
  * when a network disconnects.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class IpManagerEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index d5003ba..0b65bbd 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -29,7 +29,11 @@
  * An event recorded when IpReachabilityMonitor sends a neighbor probe or receives
  * a neighbor probe result.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class IpReachabilityEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 8c28f7a..47eeeff 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -31,7 +31,11 @@
 
 /**
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class NetworkEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index b54874f..05a47e5 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -25,7 +25,11 @@
 /**
  * An event logged when the APF packet socket receives an RA packet.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class RaEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 7f4e4a7..8118fe0 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -32,7 +32,11 @@
 /**
  * An event recorded by NetworkMonitor when sending a probe for finding captive portals.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class ValidationProbeEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index 8dfd4e1..85e3fa3 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -29,7 +29,6 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionManager;
@@ -114,8 +113,8 @@
 
         final IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        mContext.registerReceiverAsUser(
-                mBroadcastReceiver, UserHandle.ALL, intentFilter, null, mHandler);
+        mContext.registerReceiverForAllUsers(mBroadcastReceiver, intentFilter,
+                null /* broadcastPermission */, mHandler);
 
         reevaluate();
     }
diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl
index 04b585c..80ac64b 100644
--- a/core/java/android/net/vcn/IVcnManagementService.aidl
+++ b/core/java/android/net/vcn/IVcnManagementService.aidl
@@ -16,6 +16,7 @@
 
 package android.net.vcn;
 
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
 import android.os.ParcelUuid;
 
@@ -25,4 +26,7 @@
 interface IVcnManagementService {
     void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName);
     void clearVcnConfig(in ParcelUuid subscriptionGroup);
+
+    void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
+    void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
 }
diff --git a/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
new file mode 100644
index 0000000..f8ae492
--- /dev/null
+++ b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 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.net.vcn;
+
+/** @hide */
+interface IVcnUnderlyingNetworkPolicyListener {
+    void onPolicyChanged();
+}
\ No newline at end of file
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 039360a..d531cdb 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -15,8 +15,6 @@
  */
 package android.net.vcn;
 
-import static android.net.NetworkCapabilities.NetCapability;
-
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
 
 import android.annotation.IntRange;
@@ -233,7 +231,7 @@
      *
      * @param capability the capability to check for
      */
-    public boolean hasExposedCapability(@NetCapability int capability) {
+    public boolean hasExposedCapability(int capability) {
         checkValidCapability(capability);
 
         return mExposedCapabilities.contains(capability);
@@ -254,7 +252,7 @@
      *
      * @param capability the capability to check for
      */
-    public boolean requiresUnderlyingCapability(@NetCapability int capability) {
+    public boolean requiresUnderlyingCapability(int capability) {
         checkValidCapability(capability);
 
         return mUnderlyingCapabilities.contains(capability);
@@ -341,7 +339,7 @@
          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
          *     Connection
          */
-        public Builder addExposedCapability(@NetCapability int exposedCapability) {
+        public Builder addExposedCapability(int exposedCapability) {
             checkValidCapability(exposedCapability);
 
             mExposedCapabilities.add(exposedCapability);
@@ -357,7 +355,7 @@
          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
          *     Connection
          */
-        public Builder removeExposedCapability(@NetCapability int exposedCapability) {
+        public Builder removeExposedCapability(int exposedCapability) {
             checkValidCapability(exposedCapability);
 
             mExposedCapabilities.remove(exposedCapability);
@@ -373,7 +371,7 @@
          * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
          *     networks
          */
-        public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+        public Builder addRequiredUnderlyingCapability(int underlyingCapability) {
             checkValidCapability(underlyingCapability);
 
             mUnderlyingCapabilities.add(underlyingCapability);
@@ -393,7 +391,7 @@
          * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
          *     networks
          */
-        public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+        public Builder removeRequiredUnderlyingCapability(int underlyingCapability) {
             checkValidCapability(underlyingCapability);
 
             mUnderlyingCapabilities.remove(underlyingCapability);
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index b881a339..2ccdc26 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -25,7 +25,12 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
 
 /**
  * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks.
@@ -60,6 +65,11 @@
 public final class VcnManager {
     @NonNull private static final String TAG = VcnManager.class.getSimpleName();
 
+    @VisibleForTesting
+    public static final Map<
+                    VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+            REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
+
     @NonNull private final Context mContext;
     @NonNull private final IVcnManagementService mService;
 
@@ -136,4 +146,101 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi
+    /**
+     * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components
+     * can register to receive updates for VCN-underlying Network policies from the System Server.
+     *
+     * @hide
+     */
+    public interface VcnUnderlyingNetworkPolicyListener {
+        /**
+         * Notifies the implementation that the VCN's underlying Network policy has changed.
+         *
+         * <p>After receiving this callback, implementations MUST poll VcnManager for the updated
+         * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy.
+         */
+        void onPolicyChanged();
+    }
+
+    /**
+     * Add a listener for VCN-underlying network policy updates.
+     *
+     * @param executor the Executor that will be used for invoking all calls to the specified
+     *     Listener
+     * @param listener the VcnUnderlyingNetworkPolicyListener to be added
+     * @throws SecurityException if the caller does not have permission NETWORK_FACTORY
+     * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is
+     *     already registered
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+    public void addVcnUnderlyingNetworkPolicyListener(
+            @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+        requireNonNull(executor, "executor must not be null");
+        requireNonNull(listener, "listener must not be null");
+
+        VcnUnderlyingNetworkPolicyListenerBinder binder =
+                new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener);
+        if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) {
+            throw new IllegalArgumentException(
+                    "Attempting to add a listener that is already in use");
+        }
+
+        try {
+            mService.addVcnUnderlyingNetworkPolicyListener(binder);
+        } catch (RemoteException e) {
+            REGISTERED_POLICY_LISTENERS.remove(listener);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager.
+     *
+     * <p>If the specified listener is not currently registered, this is a no-op.
+     *
+     * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed
+     * @hide
+     */
+    public void removeVcnUnderlyingNetworkPolicyListener(
+            @NonNull VcnUnderlyingNetworkPolicyListener listener) {
+        requireNonNull(listener, "listener must not be null");
+
+        VcnUnderlyingNetworkPolicyListenerBinder binder =
+                REGISTERED_POLICY_LISTENERS.remove(listener);
+        if (binder == null) {
+            return;
+        }
+
+        try {
+            mService.removeVcnUnderlyingNetworkPolicyListener(binder);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System
+     * Server.
+     *
+     * @hide
+     */
+    private static class VcnUnderlyingNetworkPolicyListenerBinder
+            extends IVcnUnderlyingNetworkPolicyListener.Stub {
+        @NonNull private final Executor mExecutor;
+        @NonNull private final VcnUnderlyingNetworkPolicyListener mListener;
+
+        private VcnUnderlyingNetworkPolicyListenerBinder(
+                Executor executor, VcnUnderlyingNetworkPolicyListener listener) {
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        @Override
+        public void onPolicyChanged() {
+            mExecutor.execute(() -> mListener.onPolicyChanged());
+        }
+    }
 }
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl
new file mode 100644
index 0000000..6cb6ee6
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 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.net.vcn;
+
+/** @hide */
+parcelable VcnUnderlyingNetworkPolicy;
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
new file mode 100644
index 0000000..dd7c86d8
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 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.net.vcn;
+
+import android.annotation.NonNull;
+import android.net.NetworkCapabilities;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * VcnUnderlyingNetworkPolicy represents the Network policy for a VCN-managed Network.
+ *
+ * <p>Transports that are bringing up networks capable of acting as a VCN's underlying network
+ * should query for policy state upon major capability changes (e.g. changing of TRUSTED bit), and
+ * when prompted by VcnManagementService via VcnUnderlyingNetworkPolicyListener.
+ *
+ * @hide
+ */
+public final class VcnUnderlyingNetworkPolicy implements Parcelable {
+    private final boolean mIsTearDownRequested;
+    private final NetworkCapabilities mMergedNetworkCapabilities;
+
+    /**
+     * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters.
+     *
+     * @hide
+     */
+    public VcnUnderlyingNetworkPolicy(
+            boolean isTearDownRequested, @NonNull NetworkCapabilities mergedNetworkCapabilities) {
+        Objects.requireNonNull(
+                mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull");
+
+        mIsTearDownRequested = isTearDownRequested;
+        mMergedNetworkCapabilities = mergedNetworkCapabilities;
+    }
+
+    /**
+     * Returns whether this Carrier VCN policy policy indicates that the underlying Network should
+     * be torn down.
+     */
+    public boolean isTeardownRequested() {
+        return mIsTearDownRequested;
+    }
+
+    /**
+     * Returns the NetworkCapabilities with Carrier VCN policy bits merged into the provided
+     * capabilities.
+     */
+    @NonNull
+    public NetworkCapabilities getMergedNetworkCapabilities() {
+        return mMergedNetworkCapabilities;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false;
+        final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o;
+
+        return mIsTearDownRequested == that.mIsTearDownRequested
+                && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBoolean(mIsTearDownRequested);
+        dest.writeParcelable(mMergedNetworkCapabilities, flags);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR =
+            new Creator<VcnUnderlyingNetworkPolicy>() {
+                public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) {
+                    return new VcnUnderlyingNetworkPolicy(
+                            in.readBoolean(), in.readParcelable(null));
+                }
+
+                public VcnUnderlyingNetworkPolicy[] newArray(int size) {
+                    return new VcnUnderlyingNetworkPolicy[size];
+                }
+            };
+}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 0b2cfdd..bc3d5c4 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -72,4 +72,7 @@
     boolean deviceSupportsNfcSecure();
     boolean setNfcSecure(boolean enable);
 
+    boolean setAlwaysOn(boolean value);
+    boolean isAlwaysOnEnabled();
+    boolean isAlwaysOnSupported();
 }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index a17a5370..e85eb93 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -350,6 +350,22 @@
             "android.nfc.extra.HANDOVER_TRANSFER_STATUS";
 
     /** @hide */
+    public static final String ACTION_ALWAYS_ON_STATE_CHANGED =
+            "android.nfc.action.ALWAYS_ON_STATE_CHANGED";
+
+    /**
+     * Used as an int extra field in {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
+     * intents to request the current power state. Possible values are:
+     * {@link #STATE_OFF},
+     * {@link #STATE_TURNING_ON},
+     * {@link #STATE_ON},
+     * {@link #STATE_TURNING_OFF},
+     * @hide
+     */
+    public static final String EXTRA_ALWAYS_ON_STATE =
+            "android.nfc.extra.ALWAYS_ON_STATE";
+
+    /** @hide */
     public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
     /** @hide */
     public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
@@ -358,6 +374,14 @@
     public static final String EXTRA_HANDOVER_TRANSFER_URI =
             "android.nfc.extra.HANDOVER_TRANSFER_URI";
 
+    /**
+     * Broadcast Action: Notify possible NFC transaction blocked because device is locked.
+     * <p>An external NFC field detected when device locked and SecureNfc enabled.
+     * @hide
+     */
+    public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC =
+            "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
+
     // Guarded by NfcAdapter.class
     static boolean sIsInitialized = false;
     static boolean sHasNfcFeature;
@@ -2211,4 +2235,106 @@
             return mContext.getApplicationInfo().targetSdkVersion;
         }
     }
+
+    /**
+     * Sets NFC controller always on feature.
+     * <p>This API is for the NFCC internal state management. It allows to discriminate
+     * the controller function from the NFC function by keeping the NFC Controller on without
+     * any NFC RF enabled if necessary.
+     * <p>This call is asynchronous. Listen for {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
+     * broadcasts to find out when the operation is complete.
+     * <p>If this returns true, then either NFCC is already on, or
+     * a {@link #ACTION_ALWAYS_ON_STATE_CHANGED} broadcast will be sent to indicate
+     * a state transition.
+     * If this returns false, then there is some problem that prevents an attempt to turn NFCC on.
+     * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
+     * disabled), if false the NFCC will follow completely the Nfc adapter state.
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @return void
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean setAlwaysOn(boolean value) {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.setAlwaysOn(value);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.setAlwaysOn(value);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Checks NFC controller always on feature is enabled.
+     *
+     * @return True if NFC controller always on is enabled, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @hide
+     */
+
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean isAlwaysOnEnabled() {
+        try {
+            return sService.isAlwaysOnEnabled();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.isAlwaysOnEnabled();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Checks if the device supports NFC controller always on functionality.
+     *
+     * @return True if device supports NFC controller always on, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @hide
+     */
+
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean isAlwaysOnSupported() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.isAlwaysOnSupported();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.isAlwaysOnSupported();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index fdccaae..2256365 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -112,7 +112,7 @@
     public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
     /** NFC Forum Tag Type 2 */
     public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
-    /** NFC Forum Tag Type 4 */
+    /** NFC Forum Tag Type 3 */
     public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
     /** NFC Forum Tag Type 4 */
     public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 46ad7b8..305c686 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -22,11 +22,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.ActivityManager;
 import android.content.Context;
-import android.os.Handler;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -41,12 +41,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
 
-/**
- * Class that provides a privileged API to capture and consume bugreports.
- *
- * @hide
- */
-@SystemApi
+/** Class that provides a privileged API to capture and consume bugreports. */
 @SystemService(Context.BUGREPORT_SERVICE)
 public final class BugreportManager {
 
@@ -61,28 +56,30 @@
         mBinder = binder;
     }
 
-    /**
-     * An interface describing the callback for bugreport progress and status.
-     */
+    /** An interface describing the callback for bugreport progress and status. */
     public abstract static class BugreportCallback {
-        /** @hide */
+        /**
+         * Possible error codes taking a bugreport can encounter.
+         *
+         * @hide
+         */
         @Retention(RetentionPolicy.SOURCE)
-        @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
-                BUGREPORT_ERROR_INVALID_INPUT,
-                BUGREPORT_ERROR_RUNTIME,
-                BUGREPORT_ERROR_USER_DENIED_CONSENT,
-                BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
-                BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
-        })
-
-        /** Possible error codes taking a bugreport can encounter */
+        @IntDef(
+                prefix = {"BUGREPORT_ERROR_"},
+                value = {
+                    BUGREPORT_ERROR_INVALID_INPUT,
+                    BUGREPORT_ERROR_RUNTIME,
+                    BUGREPORT_ERROR_USER_DENIED_CONSENT,
+                    BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
+                    BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
+                })
         public @interface BugreportErrorCode {}
 
         /** The input options were invalid */
         public static final int BUGREPORT_ERROR_INVALID_INPUT =
                 IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
 
-        /** A runtime error occured */
+        /** A runtime error occurred */
         public static final int BUGREPORT_ERROR_RUNTIME =
                 IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
 
@@ -100,6 +97,7 @@
 
         /**
          * Called when there is a progress update.
+         *
          * @param progress the progress in [0.0, 100.0]
          */
         public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {}
@@ -114,14 +112,12 @@
          * out, but the bugreport could be available in the internal directory of dumpstate for
          * manual retrieval.
          *
-         * <p> If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the
-         * caller should try later, as only one bugreport can be in progress at a time.
+         * <p>If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the caller
+         * should try later, as only one bugreport can be in progress at a time.
          */
         public void onError(@BugreportErrorCode int errorCode) {}
 
-        /**
-         * Called when taking bugreport finishes successfully.
-         */
+        /** Called when taking bugreport finishes successfully. */
         public void onFinished() {}
 
         /**
@@ -138,20 +134,23 @@
      * seconds to return in the worst case. {@code callback} will receive progress and status
      * updates.
      *
-     * <p>The bugreport artifacts will be copied over to the given file descriptors only if the
-     * user consents to sharing with the calling app.
+     * <p>The bugreport artifacts will be copied over to the given file descriptors only if the user
+     * consents to sharing with the calling app.
      *
      * <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}.
      *
-     * @param bugreportFd file to write the bugreport. This should be opened in write-only,
-     *     append mode.
-     * @param screenshotFd file to write the screenshot, if necessary. This should be opened
-     *     in write-only, append mode.
+     * @param bugreportFd file to write the bugreport. This should be opened in write-only, append
+     *     mode.
+     * @param screenshotFd file to write the screenshot, if necessary. This should be opened in
+     *     write-only, append mode.
      * @param params options that specify what kind of a bugreport should be taken
      * @param callback callback for progress and status updates
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd,
+    public void startBugreport(
+            @NonNull ParcelFileDescriptor bugreportFd,
             @Nullable ParcelFileDescriptor screenshotFd,
             @NonNull BugreportParams params,
             @NonNull @CallbackExecutor Executor executor,
@@ -165,17 +164,21 @@
             boolean isScreenshotRequested = screenshotFd != null;
             if (screenshotFd == null) {
                 // Binder needs a valid File Descriptor to be passed
-                screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"),
-                        ParcelFileDescriptor.MODE_READ_ONLY);
+                screenshotFd =
+                        ParcelFileDescriptor.open(
+                                new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY);
             }
-            DumpstateListener dsListener = new DumpstateListener(executor, callback,
-                    isScreenshotRequested);
+            DumpstateListener dsListener =
+                    new DumpstateListener(executor, callback, isScreenshotRequested);
             // Note: mBinder can get callingUid from the binder transaction.
-            mBinder.startBugreport(-1 /* callingUid */,
+            mBinder.startBugreport(
+                    -1 /* callingUid */,
                     mContext.getOpPackageName(),
                     bugreportFd.getFileDescriptor(),
                     screenshotFd.getFileDescriptor(),
-                    params.getMode(), dsListener, isScreenshotRequested);
+                    params.getMode(),
+                    dsListener,
+                    isScreenshotRequested);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (FileNotFoundException e) {
@@ -189,13 +192,64 @@
         }
     }
 
-    /*
-     * Cancels a currently running bugreport.
+    /**
+     * Starts a connectivity bugreport.
+     *
+     * <p>The connectivity bugreport is a specialized version of bugreport that only includes
+     * information specifically for debugging connectivity-related issues (e.g. telephony, wi-fi,
+     * and IP networking issues). It is intended primarily for use by OEMs and network providers
+     * such as mobile network operators. In addition to generally excluding information that isn't
+     * targeted to connectivity debugging, this type of bugreport excludes PII and sensitive
+     * information that isn't strictly necessary for connectivity debugging.
+     *
+     * <p>The calling app MUST have a context-specific reason for requesting a connectivity
+     * bugreport, such as detecting a connectivity-related issue. This API SHALL NOT be used to
+     * perform random sampling from a fleet of public end-user devices.
+     *
+     * <p>Calling this API will cause the system to ask the user for consent every single time. The
+     * bugreport artifacts will be copied over to the given file descriptors only if the user
+     * consents to sharing with the calling app.
+     *
+     * <p>This starts a bugreport in the background. However the call itself can take several
+     * seconds to return in the worst case. {@code callback} will receive progress and status
+     * updates.
+     *
+     * <p>Requires that the calling app has carrier privileges (see {@link
+     * android.telephony.TelephonyManager#hasCarrierPrivileges}) on any active subscription.
+     *
+     * @param bugreportFd file to write the bugreport. This should be opened in write-only, append
+     *     mode.
+     * @param callback callback for progress and status updates.
      */
-    @RequiresPermission(android.Manifest.permission.DUMP)
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    public void startConnectivityBugreport(
+            @NonNull ParcelFileDescriptor bugreportFd,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BugreportCallback callback) {
+        startBugreport(
+                bugreportFd,
+                null /* screenshotFd */,
+                new BugreportParams(BugreportParams.BUGREPORT_MODE_TELEPHONY),
+                executor,
+                callback);
+    }
+
+    /**
+     * Cancels the currently running bugreport.
+     *
+     * <p>Apps are only able to cancel their own bugreports. App A cannot cancel a bugreport started
+     * by app B.
+     *
+     * <p>Requires permission: {@link android.Manifest.permission#DUMP} or that the calling app has
+     * carrier privileges (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on
+     * any active subscription.
+     *
+     * @throws SecurityException if trying to cancel another app's bugreport in progress
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     public void cancelBugreport() {
         try {
-            mBinder.cancelBugreport();
+            mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -205,23 +259,26 @@
      * Requests a bugreport.
      *
      * <p>This requests the platform/system to take a bugreport and makes the final bugreport
-     * available to the user. The user may choose to share it with another app, but the bugreport
-     * is never given back directly to the app that requested it.
+     * available to the user. The user may choose to share it with another app, but the bugreport is
+     * never given back directly to the app that requested it.
      *
-     * @param params           {@link BugreportParams} that specify what kind of a bugreport should
-     *                         be taken, please note that not all kinds of bugreport allow for a
-     *                         progress notification
-     * @param shareTitle       title on the final share notification
+     * @param params {@link BugreportParams} that specify what kind of a bugreport should be taken,
+     *     please note that not all kinds of bugreport allow for a progress notification
+     * @param shareTitle title on the final share notification
      * @param shareDescription description on the final share notification
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle,
+    public void requestBugreport(
+            @NonNull BugreportParams params,
+            @Nullable CharSequence shareTitle,
             @Nullable CharSequence shareDescription) {
         try {
             String title = shareTitle == null ? null : shareTitle.toString();
             String description = shareDescription == null ? null : shareDescription.toString();
-            ActivityManager.getService().requestBugReportWithDescription(title, description,
-                    params.getMode());
+            ActivityManager.getService()
+                    .requestBugReportWithDescription(title, description, params.getMode());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -232,8 +289,8 @@
         private final BugreportCallback mCallback;
         private final boolean mIsScreenshotRequested;
 
-        DumpstateListener(Executor executor, BugreportCallback callback,
-                boolean isScreenshotRequested) {
+        DumpstateListener(
+                Executor executor, BugreportCallback callback, boolean isScreenshotRequested) {
             mExecutor = executor;
             mCallback = callback;
             mIsScreenshotRequested = isScreenshotRequested;
@@ -243,9 +300,7 @@
         public void onProgress(int progress) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onProgress(progress);
-                });
+                mExecutor.execute(() -> mCallback.onProgress(progress));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -255,9 +310,7 @@
         public void onError(int errorCode) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onError(errorCode);
-                });
+                mExecutor.execute(() -> mCallback.onError(errorCode));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -267,9 +320,7 @@
         public void onFinished() throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onFinished();
-                });
+                mExecutor.execute(() -> mCallback.onFinished());
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -284,20 +335,19 @@
             Handler mainThreadHandler = new Handler(Looper.getMainLooper());
             mainThreadHandler.post(
                     () -> {
-                        int message = success ? R.string.bugreport_screenshot_success_toast
-                                : R.string.bugreport_screenshot_failure_toast;
+                        int message =
+                                success
+                                        ? R.string.bugreport_screenshot_success_toast
+                                        : R.string.bugreport_screenshot_failure_toast;
                         Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
                     });
         }
 
         @Override
-        public void onUiIntensiveBugreportDumpsFinished()
-                throws RemoteException {
+        public void onUiIntensiveBugreportDumpsFinished() throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onEarlyReportFinished();
-                });
+                mExecutor.execute(() -> mCallback.onEarlyReportFinished());
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index df3c4d5..51856d8 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -50,6 +50,8 @@
     public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
     public static final int FLAG_SD = 1 << 2;
     public static final int FLAG_USB = 1 << 3;
+    /** The FLAG_STUB_VISIBLE is set from vold, which gets the flag from outside (e.g., ChromeOS) */
+    public static final int FLAG_STUB_VISIBLE = 1 << 6;
 
     public final String id;
     @UnsupportedAppUsage
@@ -152,6 +154,10 @@
         return (flags & FLAG_USB) != 0;
     }
 
+    public boolean isStubVisible() {
+        return (flags & FLAG_STUB_VISIBLE) != 0;
+    }
+
     @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 99bdfd1..4669b20 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -195,4 +195,5 @@
     void abortChanges(in String message, boolean retry) = 87;
     void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
     void fixupAppDir(in String path) = 89;
+    void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4086161..0f7365d 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -999,6 +999,20 @@
             "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
 
     /**
+     * Activity Action: Show settings to manage all SIM profiles.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS =
+            "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
+
+    /**
      * Activity Action: Show screen for controlling which apps can draw on top of other apps.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
diff --git a/core/java/android/se/OWNERS b/core/java/android/se/OWNERS
index f1539dc..5682fd3 100644
--- a/core/java/android/se/OWNERS
+++ b/core/java/android/se/OWNERS
@@ -1,4 +1,5 @@
 # Bug component: 456592
 
-cbrubaker@google.com
-vishwath@google.com
+zachoverflow@google.com
+alisher@google.com
+jackcwyu@google.com
diff --git a/core/java/android/se/omapi/OWNERS b/core/java/android/se/omapi/OWNERS
index f1539dc..5682fd3 100644
--- a/core/java/android/se/omapi/OWNERS
+++ b/core/java/android/se/omapi/OWNERS
@@ -1,4 +1,5 @@
 # Bug component: 456592
 
-cbrubaker@google.com
-vishwath@google.com
+zachoverflow@google.com
+alisher@google.com
+jackcwyu@google.com
diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS
index 10b8b76..0471e29 100644
--- a/core/java/android/service/textservice/OWNERS
+++ b/core/java/android/service/textservice/OWNERS
@@ -1,3 +1,3 @@
-# Bug component: 34867
+# Bug component: 816455
 
-include ../../inputmethodservice/OWNERS
\ No newline at end of file
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 17d3ae4..471f2c2 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -24,11 +24,12 @@
 import android.icu.text.MeasureFormat;
 import android.icu.util.Measure;
 import android.icu.util.MeasureUnit;
-import android.net.NetworkUtils;
 import android.text.BidiFormatter;
 import android.text.TextUtils;
 import android.view.View;
 
+import com.android.net.module.util.Inet4AddressUtils;
+
 import java.util.Locale;
 
 /**
@@ -207,7 +208,7 @@
      */
     @Deprecated
     public static String formatIpAddress(int ipv4Address) {
-        return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress();
+        return Inet4AddressUtils.intToInet4AddressHTL(ipv4Address).getHostAddress();
     }
 
     private static final int SECONDS_PER_MINUTE = 60;
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 93b5a2e..b1d3967 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -9,3 +9,4 @@
 ogunwale@google.com
 jjaggi@google.com
 pweaver@google.com
+ryanlwlin@google.com
diff --git a/core/java/android/view/textservice/OWNERS b/core/java/android/view/textservice/OWNERS
index 582be8d..0471e29 100644
--- a/core/java/android/view/textservice/OWNERS
+++ b/core/java/android/view/textservice/OWNERS
@@ -1,3 +1,3 @@
-# Bug component: 34867
+# Bug component: 816455
 
-include ../inputmethod/OWNERS
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index b9ff26b..6281ee9 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -39,6 +39,7 @@
 import android.view.inspector.InspectableProperty;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
@@ -776,17 +777,23 @@
 
     /**
      * Grows {@code r} from its center such that each dimension is at least {@code minimumSize}.
+     *
+     * The result will still have the same {@link Rect#centerX()} and {@link Rect#centerY()} as the
+     * input.
+     *
+     * @hide
      */
-    private void growRectTo(Rect r, int minimumSize) {
-        int dy = (minimumSize - r.height()) / 2;
+    @VisibleForTesting
+    public void growRectTo(Rect r, int minimumSize) {
+        int dy = minimumSize - r.height();
         if (dy > 0) {
-            r.top -= dy;
-            r.bottom += dy;
+            r.top -= (dy + 1) / 2;
+            r.bottom += dy / 2;
         }
-        int dx = (minimumSize - r.width()) / 2;
+        int dx = minimumSize - r.width();
         if (dx > 0) {
-            r.left -= dx;
-            r.right += dx;
+            r.left -= (dx + 1) / 2;
+            r.right += dx / 2;
         }
     }
 
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index cc266d6..a5eb5f6 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -22,17 +22,16 @@
 
 parcelable CompatibilityChangeConfig;
 parcelable CompatibilityChangeInfo;
-
 /**
  * Platform private API for talking with the PlatformCompat service.
  *
- * <p> Should be used for gating and logging from non-app processes.
- * For app processes please use android.compat.Compatibility API.
+ * <p>Should be used for gating and logging from non-app processes.
+ *
+ * <p>Note: for app processes please use {@code android.compat.Compatibility} API.
  *
  * {@hide}
  */
-interface IPlatformCompat
-{
+interface IPlatformCompat {
 
     /**
      * Reports that a compatibility change is affecting an app process now.
@@ -40,8 +39,9 @@
      * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
      * you do not need to call this API directly. The change will be reported for you.
      *
-     * @param changeId The ID of the compatibility change taking effect.
-     * @param appInfo  Representing the affected app.
+     * @param changeId the ID of the compatibility change taking effect
+     * @param appInfo  representing the affected app
+     * @throws SecurityException if logging is not allowed
      */
     void reportChange(long changeId, in ApplicationInfo appInfo);
 
@@ -51,11 +51,12 @@
      * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, String)},
      * you do not need to call this API directly. The change will be reported for you.
      *
-     * @param changeId    The ID of the compatibility change taking effect.
-     * @param userId      The ID of the user that the operation is done for.
-     * @param packageName The package name of the app in question.
+     * @param changeId    the ID of the compatibility change taking effect
+     * @param userId      the ID of the user that the operation is done for
+     * @param packageName the package name of the app in question
+     * @throws SecurityException if logging is not allowed
      */
-     void reportChangeByPackageName(long changeId, in String packageName, int userId);
+    void reportChangeByPackageName(long changeId, in String packageName, int userId);
 
     /**
      * Reports that a compatibility change is affecting an app process now.
@@ -63,13 +64,14 @@
      * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, int)},
      * you do not need to call this API directly. The change will be reported for you.
      *
-     * @param changeId The ID of the compatibility change taking effect.
-     * @param uid      The UID of the app in question.
+     * @param changeId the ID of the compatibility change taking effect
+     * @param uid      the UID of the app in question
+     * @throws SecurityException if logging is not allowed
      */
     void reportChangeByUid(long changeId, int uid);
 
     /**
-     * Query if a given compatibility change is enabled for an app process. This method should
+     * Queries if a given compatibility change is enabled for an app process. This method should
      * be called when implementing functionality on behalf of the affected app.
      *
      * <p>If this method returns {@code true}, the calling code should implement the compatibility
@@ -79,14 +81,15 @@
      * <p>It will also report the change as {@link #reportChange(long, ApplicationInfo)} would, so
      * there is no need to call that method directly.
      *
-     * @param changeId The ID of the compatibility change in question.
-     * @param appInfo  Representing the app in question.
-     * @return {@code true} if the change is enabled for the current app.
+     * @param changeId the ID of the compatibility change in question
+     * @param appInfo  representing the app in question
+     * @return {@code true} if the change is enabled for the current app
+     * @throws SecurityException if logging or reading compat confis is not allowed
      */
     boolean isChangeEnabled(long changeId, in ApplicationInfo appInfo);
 
     /**
-     * Query if a given compatibility change is enabled for an app process. This method should
+     * Queries if a given compatibility change is enabled for an app process. This method should
      * be called when implementing functionality on behalf of the affected app.
      *
      * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a package name
@@ -102,15 +105,16 @@
      * <p>It will also report the change as {@link #reportChange(long, String)} would, so there is
      * no need to call that method directly.
      *
-     * @param changeId    The ID of the compatibility change in question.
-     * @param packageName The package name of the app in question.
-     * @param userId      The ID of the user that the operation is done for.
-     * @return {@code true} if the change is enabled for the current app.
+     * @param changeId    the ID of the compatibility change in question
+     * @param packageName the package name of the app in question
+     * @param userId      the ID of the user that the operation is done for
+     * @return {@code true} if the change is enabled for the current app
+     * @throws SecurityException if logging or reading compat confis is not allowed
      */
     boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId);
 
     /**
-     * Query if a given compatibility change is enabled for an app process. This method should
+     * Queries if a given compatibility change is enabled for an app process. This method should
      * be called when implementing functionality on behalf of the affected app.
      *
      * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a uid
@@ -127,110 +131,132 @@
      * <p>It will also report the change as {@link #reportChange(long, int)} would, so there is
      * no need to call that method directly.
      *
-     * @param changeId The ID of the compatibility change in question.
-     * @param uid      The UID of the app in question.
-     * @return {@code true} if the change is enabled for the current app.
+     * @param changeId the ID of the compatibility change in question
+     * @param uid      the UID of the app in question
+     * @return {@code true} if the change is enabled for the current app
+     * @throws SecurityException if logging or reading compat confis is not allowed
      */
     boolean isChangeEnabledByUid(long changeId, int uid);
 
     /**
-     * Add overrides to compatibility changes. Kills the app to allow the changes to take effect.
+     * Adds overrides to compatibility changes.
      *
-     * @param overrides Parcelable containing the compat change overrides to be applied.
-     * @param packageName The package name of the app whose changes will be overridden.
+     * <p>Kills the app to allow the changes to take effect.
      *
+     * @param overrides   parcelable containing the compat change overrides to be applied
+     * @param packageName the package name of the app whose changes will be overridden
+     * @throws SecurityException if overriding changes is not permitted
      */
     void setOverrides(in CompatibilityChangeConfig overrides, in String packageName);
 
     /**
-     * Add overrides to compatibility changes. Doesn't kill the app, to be only used in tests.
+     * Adds overrides to compatibility changes.
      *
-     * @param overrides Parcelable containing the compat change overrides to be applied.
-     * @param packageName The package name of the app whose changes will be overridden.
+     * <p>Does not kill the app, to be only used in tests.
      *
+     * @param overrides   parcelable containing the compat change overrides to be applied
+     * @param packageName the package name of the app whose changes will be overridden
+     * @throws SecurityException if overriding changes is not permitted.
      */
     void setOverridesForTest(in CompatibilityChangeConfig overrides, in String packageName);
 
     /**
-     * Removes an override previously added via {@link #setOverrides(CompatibilityChangeConfig,
-     * String)}. This restores the default behaviour for the given change and app, once any app
-     * processes have been restarted.
-     * Kills the app to allow the changes to take effect.
+     * Restores the default behaviour for the given change and app.
      *
-     * @param changeId    The ID of the change that was overridden.
-     * @param packageName The app package name that was overridden.
-     * @return {@code true} if an override existed;
+     * <p>Kills the app to allow the changes to take effect.
+     *
+     * @param changeId    the ID of the change that was overridden
+     * @param packageName the app package name that was overridden
+     * @return {@code true} if an override existed
+     * @throws SecurityException if overriding changes is not permitted
      */
     boolean clearOverride(long changeId, String packageName);
 
     /**
-     * Enable all compatibility changes which have enabledSinceTargetSdk ==
-     * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
-     * changes to take effect.
+     * Restores the default behaviour for the given change and app.
      *
-     * @param packageName The package name of the app whose compatibility changes will be enabled.
+     * <p>Does not kill the app; to be only used in tests.
+     *
+     * @param changeId    the ID of the change that was overridden
+     * @param packageName the app package name that was overridden
+     * @throws SecurityException if overriding changes is not permitted
+     */
+    void clearOverrideForTest(long changeId, String packageName);
+
+    /**
+     * Enables all compatibility changes that have enabledSinceTargetSdk ==
+     * {@param targetSdkVersion} for an app, subject to the policy.
+     *
+     * <p>Kills the app to allow the changes to take effect.
+     *
+     * @param packageName      The package name of the app whose compatibility changes will be
+     *                         enabled.
      * @param targetSdkVersion The targetSdkVersion for filtering the changes to be enabled.
-     *
      * @return The number of changes that were enabled.
+     * @throws SecurityException if overriding changes is not permitted.
      */
     int enableTargetSdkChanges(in String packageName, int targetSdkVersion);
 
     /**
-     * Disable all compatibility changes which have enabledAfterTargetSdk ==
-     * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
-     * changes to take effect.
+     * Disables all compatibility changes that have enabledAfterTargetSdk ==
+     * {@param targetSdkVersion} for an app, subject to the policy.
      *
-     * @param packageName The package name of the app whose compatibility changes will be disabled.
-     * @param targetSdkVersion The targetSdkVersion for filtering the changes to be disabled.
+     * <p>Kills the app to allow the changes to take effect.
      *
-     * @return The number of changes that were disabled.
+     * @param packageName      the package name of the app whose compatibility changes will be
+     *                         disabled
+     * @param targetSdkVersion the targetSdkVersion for filtering the changes to be disabled
+     * @return the number of changes that were disabled
+     * @throws SecurityException if overriding changes is not permitted.
      */
     int disableTargetSdkChanges(in String packageName, int targetSdkVersion);
 
     /**
-     * Revert overrides to compatibility changes. Kills the app to allow the changes to take effect.
+     * Restores the default behaviour for the given app.
      *
-     * @param packageName The package name of the app whose overrides will be cleared.
+     * <p>Kills the app to allow the changes to take effect.
      *
+     * @param packageName the package name of the app whose overrides will be cleared
+     * @throws SecurityException if overriding changes is not permitted
      */
     void clearOverrides(in String packageName);
 
     /**
-     * Revert overrides to compatibility changes. Doesn't kill the app, to be only used in tests.
+     * Restores the default behaviour for the given app.
      *
-     * @param packageName The package name of the app whose overrides will be cleared.
+     * <p>Does not kill the app; to be only used in tests.
      *
+     * @param packageName the package name of the app whose overrides will be cleared
+     * @throws SecurityException if overriding changes is not permitted
      */
     void clearOverridesForTest(in String packageName);
 
-
     /**
      * Get configs for an application.
      *
-     * @param appInfo The application whose config will be returned.
-     *
-     * @return A {@link CompatibilityChangeConfig}, representing whether a change is enabled for
-     *         the given app or not.
+     * @param appInfo the application whose config will be returned
+     * @return a {@link CompatibilityChangeConfig}, representing whether a change is enabled for
+     * the given app or not
      */
     CompatibilityChangeConfig getAppConfig(in ApplicationInfo appInfo);
 
     /**
      * List all compatibility changes.
      *
-     * @return An array of {@link CompatChangeInfo} known to the service.
+     * @return an array of {@link CompatibilityChangeInfo} known to the service
      */
     CompatibilityChangeInfo[] listAllChanges();
 
     /**
-    * List the compatibility changes that should be present in the UI.
-    * Filters out certain changes like e.g. logging only.
-    *
-    * @return An array of {@link CompatChangeInfo}.
-    */
+     * List the compatibility changes that should be present in the UI.
+     * Filters out certain changes like e.g. logging only.
+     *
+     * @return an array of {@link CompatibilityChangeInfo}
+     */
     CompatibilityChangeInfo[] listUIChanges();
 
     /**
-     * Get an instance that can determine whether a changeid can be overridden for a package name.
+     * Gets an instance that can determine whether a changeid can be overridden for a package name.
      */
     IOverrideValidator getOverrideValidator();
 }
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 790d7f7..6860759e 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -69,15 +69,16 @@
         // Tell the Zygote what our actual PID is (since it only knows about the
         // wrapper that it directly forked).
         if (fdNum != 0) {
+            FileDescriptor fd = new FileDescriptor();
             try {
-                FileDescriptor fd = new FileDescriptor();
                 fd.setInt$(fdNum);
                 DataOutputStream os = new DataOutputStream(new FileOutputStream(fd));
                 os.writeInt(Process.myPid());
                 os.close();
-                IoUtils.closeQuietly(fd);
             } catch (IOException ex) {
                 Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex);
+            } finally {
+                IoUtils.closeQuietly(fd);
             }
         }
 
diff --git a/core/java/com/android/internal/textservice/OWNERS b/core/java/com/android/internal/textservice/OWNERS
new file mode 100644
index 0000000..0471e29
--- /dev/null
+++ b/core/java/com/android/internal/textservice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index 0fb2911..a9db91b 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -257,7 +257,17 @@
     // XXX Again cannot refer to gFields.constructID because InitClass may
     // not have been called yet.
 
-    return env->NewObject(clazz.get(), constructID, size);
+    // Cases:
+    // - this originates from another process (something so large should not fit
+    //   in the binder buffer, and it should be rejected by the binder driver)
+    // - if this is used in process, this code makes too many heap copies (in
+    //   order to retrofit HIDL's scatter-gather format to java types) to
+    //   justify passing such a large amount of data over this path. So the
+    //   alternative (updating the constructor and other code to accept other
+    //   types, should also probably not be taken in this case).
+    CHECK_LE(size, std::numeric_limits<jint>::max());
+
+    return env->NewObject(clazz.get(), constructID, static_cast<jint>(size));
 }
 
 }  // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index dc98aaf..b2e562c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1559,7 +1559,6 @@
     jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name,
     jstring managed_nice_name, fail_fn_t fail_fn) {
 
-  ensureInAppMountNamespace(fail_fn);
   std::vector<std::string> merged_data_info_list;
   insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list,
           process_name, managed_nice_name, fail_fn);
@@ -1706,10 +1705,11 @@
 
   MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);
 
-  // System services, isolated process, webview/app zygote, old target sdk app, should
-  // give a null in same_uid_pkgs and private_volumes so they don't need app data isolation.
-  // Isolated process / webview / app zygote should be gated by SELinux and file permission
-  // so they can't even traverse CE / DE directories.
+  // Make sure app is running in its own mount namespace before isolating its data directories.
+  ensureInAppMountNamespace(fail_fn);
+
+  // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
+  // mount all related packages separately.
   if (mount_data_dirs) {
     isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list,
             uid, process_name, managed_nice_name, fail_fn);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 60b3839..c6a1bdd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -313,8 +313,10 @@
     <protected-broadcast android:name="android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED" />
 
     <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+    <protected-broadcast android:name="android.nfc.action.ALWAYS_ON_STATE_CHANGED" />
     <protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
     <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+    <protected-broadcast android:name="android.nfc.action.REQUIRE_UNLOCK_FOR_NFC" />
     <protected-broadcast android:name="com.android.nfc.action.LLCP_UP" />
     <protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" />
     <protected-broadcast android:name="com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG" />
@@ -1625,7 +1627,7 @@
     <permission android:name="android.permission.MANAGE_IPSEC_TUNNELS"
         android:protectionLevel="signature|appop" />
 
-    <!-- @hide Allows apps to create and manage Test Networks.
+    <!-- @SystemApi @hide Allows apps to create and manage Test Networks.
          <p>Granted only to shell. CTS tests will use
          UiAutomation.AdoptShellPermissionIdentity() to gain access.
     -->
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index f9e3bc6..222471a 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -23,7 +23,10 @@
 import static org.junit.Assert.fail;
 
 import android.Manifest;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.BugreportManager;
 import android.os.BugreportManager.BugreportCallback;
 import android.os.BugreportParams;
@@ -31,7 +34,9 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.StrictMode;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -53,10 +58,11 @@
 import org.junit.runners.JUnit4;
 
 import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
-
 /**
  * Tests for BugreportManager API.
  */
@@ -67,8 +73,16 @@
 
     private static final String TAG = "BugreportManagerTest";
     private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10);
+    private static final long DUMPSTATE_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
     private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
 
+    // Sent by Shell when its bugreport finishes (contains final bugreport/screenshot file name
+    // associated with the bugreport).
+    private static final String INTENT_BUGREPORT_FINISHED =
+            "com.android.internal.intent.action.BUGREPORT_FINISHED";
+    private static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
+    private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+
     private Handler mHandler;
     private Executor mExecutor;
     private BugreportManager mBrm;
@@ -212,6 +226,48 @@
     }
 
     @Test
+    public void cancelBugreport_noReportStarted() throws Exception {
+        // Without the native DumpstateService running, we don't get a SecurityException.
+        mBrm.cancelBugreport();
+    }
+
+    @LargeTest
+    @Test
+    public void cancelBugreport_fromDifferentUid() throws Exception {
+        assertThat(Process.myUid()).isNotEqualTo(Process.SHELL_UID);
+
+        // Start a bugreport through ActivityManager's shell command - this starts a BR from the
+        // shell UID rather than our own.
+        BugreportBroadcastReceiver br = new BugreportBroadcastReceiver();
+        InstrumentationRegistry.getContext()
+                .registerReceiver(br, new IntentFilter(INTENT_BUGREPORT_FINISHED));
+        UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+                .executeShellCommand("am bug-report");
+
+        // The command triggers the report through a broadcast, so wait until dumpstate actually
+        // starts up, which may take a bit.
+        waitTillDumpstateRunningOrTimeout();
+
+        try {
+            mBrm.cancelBugreport();
+            fail("Expected cancelBugreport to throw SecurityException when report started by "
+                    + "different UID");
+        } catch (SecurityException expected) {
+        } finally {
+            // Do this in the finally block so that even if this test case fails, we don't break
+            // other test cases unexpectedly due to the still-running shell report.
+            try {
+                // The shell's BR is still running and should complete successfully.
+                br.waitForBugreportFinished();
+            } finally {
+                // The latch may fail for a number of reasons but we still need to unregister the
+                // BroadcastReceiver.
+                InstrumentationRegistry.getContext().unregisterReceiver(br);
+            }
+        }
+    }
+
+    @Test
     public void insufficientPermissions_throwsException() throws Exception {
         dropPermissions();
 
@@ -346,6 +402,28 @@
                 .adoptShellPermissionIdentity(Manifest.permission.DUMP);
     }
 
+    private static boolean isDumpstateRunning() {
+        String[] output;
+        try {
+            output =
+                    UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+                            .executeShellCommand("ps -A -o NAME | grep dumpstate")
+                            .trim()
+                            .split("\n");
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to check if dumpstate is running", e);
+            return false;
+        }
+        for (String line : output) {
+            // Check for an exact match since there may be other things that contain "dumpstate" as
+            // a substring (e.g. the dumpstate HAL).
+            if (TextUtils.equals("dumpstate", line)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static void assertFdIsClosed(ParcelFileDescriptor pfd) {
         try {
             int fd = pfd.getFd();
@@ -364,18 +442,25 @@
         return System.currentTimeMillis();
     }
 
-    private static boolean shouldTimeout(long startTimeMs) {
-        return now() - startTimeMs >= BUGREPORT_TIMEOUT_MS;
+    private static void waitTillDumpstateRunningOrTimeout() throws Exception {
+        long startTimeMs = now();
+        while (!isDumpstateRunning()) {
+            Thread.sleep(500 /* .5s */);
+            if (now() - startTimeMs >= DUMPSTATE_STARTUP_TIMEOUT_MS) {
+                break;
+            }
+            Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for dumpstate to start");
+        }
     }
 
     private static void waitTillDoneOrTimeout(BugreportCallbackImpl callback) throws Exception {
         long startTimeMs = now();
         while (!callback.isDone()) {
             Thread.sleep(1000 /* 1s */);
-            if (shouldTimeout(startTimeMs)) {
+            if (now() - startTimeMs >= BUGREPORT_TIMEOUT_MS) {
                 break;
             }
-            Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms");
+            Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for bugreport to finish");
         }
     }
 
@@ -450,6 +535,36 @@
         assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS));
     }
 
+    private class BugreportBroadcastReceiver extends BroadcastReceiver {
+        Intent mBugreportFinishedIntent = null;
+        final CountDownLatch mLatch;
+
+        BugreportBroadcastReceiver() {
+            mLatch = new CountDownLatch(1);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            setBugreportFinishedIntent(intent);
+            mLatch.countDown();
+        }
+
+        private void setBugreportFinishedIntent(Intent intent) {
+            mBugreportFinishedIntent = intent;
+        }
+
+        public Intent getBugreportFinishedIntent() {
+            return mBugreportFinishedIntent;
+        }
+
+        public void waitForBugreportFinished() throws Exception {
+            if (!mLatch.await(BUGREPORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                throw new Exception("Failed to receive BUGREPORT_FINISHED in "
+                        + BUGREPORT_TIMEOUT_MS + " ms.");
+            }
+        }
+    }
+
     /**
      * A rule to change strict mode vm policy temporarily till test method finished.
      *
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index 696aa11..912db1e 100644
--- a/core/tests/coretests/src/android/content/OWNERS
+++ b/core/tests/coretests/src/android/content/OWNERS
@@ -1,4 +1,3 @@
 per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
-per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
 per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS
new file mode 100644
index 0000000..711f5f0
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/OWNERS
@@ -0,0 +1,2 @@
+per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+
diff --git a/core/tests/coretests/src/android/view/textservice/OWNERS b/core/tests/coretests/src/android/view/textservice/OWNERS
new file mode 100644
index 0000000..0471e29
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textservice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
index 5371a0f..ccd873d 100644
--- a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
+++ b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
@@ -30,7 +30,6 @@
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.RectShape;
 import android.platform.test.annotations.Presubmit;
-import android.view.View;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -48,6 +47,7 @@
 @Presubmit
 public class AbsSeekBarTest {
 
+    public static final int PADDING = 10;
     private Context mContext;
     private AbsSeekBar mBar;
 
@@ -59,34 +59,42 @@
 
     @Test
     public void testExclusionForThumb_limitedTo48dp() {
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
         mBar.setProgress(50);
+
+        final int thumbOffset = mBar.getThumbOffset();
+
         measureAndLayout(dpToPxSize(200), dpToPxSize(100));
         List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
 
         assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
         assertEquals("exclusion should be centered on thumb",
-                center(mBar), center(exclusions.get(0)));
+                center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)),
+                center(exclusions.get(0)));
         assertEquals("exclusion should be 48dp high", dpToPxSize(48), exclusions.get(0).height());
         assertEquals("exclusion should be 48dp wide", dpToPxSize(48), exclusions.get(0).width());
     }
 
     @Test
     public void testExclusionForThumb_limitedToHeight() {
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
         mBar.setProgress(50);
+
+        final int thumbOffset = mBar.getThumbOffset();
+
         measureAndLayout(dpToPxSize(200), dpToPxSize(32));
         List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
 
         assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
         assertEquals("exclusion should be centered on thumb",
-                center(mBar), center(exclusions.get(0)));
+                center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)),
+                center(exclusions.get(0)));
         assertEquals("exclusion should be 32dp high", dpToPxSize(32), exclusions.get(0).height());
         assertEquals("exclusion should be 32dp wide", dpToPxSize(32), exclusions.get(0).width());
     }
@@ -95,7 +103,7 @@
     public void testExclusionForThumb_passesThroughUserExclusions() {
         mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(1, 2, 3, 4)));
 
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
@@ -110,12 +118,37 @@
         assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
     }
 
+    @Test
+    public void testGrowRectTo_evenInitialDifference() {
+        doGrowRectTest(new Rect(0, 0, 0, 0), 10, new Rect(-5, -5, 5, 5));
+    }
+
+    @Test
+    public void testGrowRectTo_unevenInitialDifference() {
+        doGrowRectTest(new Rect(0, 0, 1, 1), 10, new Rect(-5, -5, 5, 5));
+    }
+
+    @Test
+    public void testGrowRectTo_unevenInitialDifference_unevenSize() {
+        doGrowRectTest(new Rect(0, 0, 0, 0), 9, new Rect(-5, -5, 4, 4));
+    }
+
+    public void doGrowRectTest(Rect in, int minimumSize, Rect expected) {
+        Rect result = new Rect(in);
+        mBar.growRectTo(result, minimumSize);
+
+        assertEquals("grown rect", expected, result);
+        assertEquals("grown rect center point", center(expected), center(result));
+    }
+
     private Point center(Rect rect) {
         return new Point(rect.centerX(), rect.centerY());
     }
 
-    private Point center(View view) {
-        return center(new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+    private Rect offset(Rect rect, int dx, int dy) {
+        Rect result = new Rect(rect);
+        result.offset(dx, dy);
+        return result;
     }
 
     private ShapeDrawable newThumb(int size) {
diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp
index 12a2b08..f86ac9c 100644
--- a/core/tests/overlaytests/device/Android.bp
+++ b/core/tests/overlaytests/device/Android.bp
@@ -16,7 +16,11 @@
     name: "OverlayDeviceTests",
     srcs: ["src/**/*.java"],
     platform_apis: true,
-    static_libs: ["androidx.test.rules"],
+    certificate: "platform",
+    static_libs: [
+        "androidx.test.rules",
+        "testng",
+    ],
     test_suites: ["device-tests"],
     data: [
         ":OverlayDeviceTests_AppOverlayOne",
diff --git a/core/tests/overlaytests/device/AndroidManifest.xml b/core/tests/overlaytests/device/AndroidManifest.xml
index 4881636..a69911f 100644
--- a/core/tests/overlaytests/device/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/AndroidManifest.xml
@@ -19,6 +19,8 @@
 
     <uses-sdk android:minSdkVersion="21" />
 
+    <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" />
+
     <application>
         <uses-library android:name="android.test.runner"/>
     </application>
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
index 6507839..ebbdda5 100644
--- a/core/tests/overlaytests/device/AndroidTest.xml
+++ b/core/tests/overlaytests/device/AndroidTest.xml
@@ -19,9 +19,20 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-instrumentation" />
 
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="remount-system" value="true" />
+        <option name="push" value="OverlayDeviceTests.apk->/system/app/OverlayDeviceTests.apk" />
+    </target_preparer>
+
+    <!-- Reboot to have the test APK scanned by PM and reboot after to remove the test APK. -->
+    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer">
+      <option name="pre-reboot" value="true" />
+      <option name="post-reboot" value="true" />
+    </target_preparer>
+
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="OverlayDeviceTests.apk" />
         <option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" />
         <option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" />
         <option name="test-file-name" value="OverlayDeviceTests_FrameworkOverlay.apk" />
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
index 390bb76..76c01a7 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
@@ -18,60 +18,76 @@
 
 import static java.util.concurrent.TimeUnit.SECONDS;
 
-import android.app.UiAutomation;
-import android.content.res.Resources;
-import android.os.ParcelFileDescriptor;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.os.UserHandle;
 
 import androidx.test.InstrumentationRegistry;
 
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
 import java.util.concurrent.Executor;
 import java.util.concurrent.FutureTask;
 
 class LocalOverlayManager {
     private static final long TIMEOUT = 30;
 
-    public static void setEnabledAndWait(Executor executor, final String packageName,
-            boolean enable) throws Exception {
-        final String pattern = (enable ? "[x]" : "[ ]") + " " + packageName;
-        if (executeShellCommand("cmd overlay list").contains(pattern)) {
-            // nothing to do, overlay already in the requested state
-            return;
+    public static void toggleOverlaysAndWait(@NonNull final String[] overlaysToEnable,
+            @NonNull final String[] overlaysToDisable) throws Exception {
+        final int userId = UserHandle.myUserId();
+        OverlayManagerTransaction.Builder builder = new OverlayManagerTransaction.Builder();
+        for (String pkg : overlaysToEnable) {
+            builder.setEnabled(pkg, true, userId);
         }
+        for (String pkg : overlaysToDisable) {
+            builder.setEnabled(pkg, false, userId);
+        }
+        OverlayManagerTransaction transaction = builder.build();
 
-        final Resources res = InstrumentationRegistry.getContext().getResources();
-        final String[] oldApkPaths = res.getAssets().getApkPaths();
+        final Context ctx = InstrumentationRegistry.getTargetContext();
         FutureTask<Boolean> task = new FutureTask<>(() -> {
             while (true) {
-                if (!Arrays.equals(oldApkPaths, res.getAssets().getApkPaths())) {
+                final String[] paths = ctx.getResources().getAssets().getApkPaths();
+                if (arrayTailContains(paths, overlaysToEnable)
+                        && arrayDoesNotContain(paths, overlaysToDisable)) {
                     return true;
                 }
                 Thread.sleep(10);
             }
         });
+
+        OverlayManager om = ctx.getSystemService(OverlayManager.class);
+        om.commit(transaction);
+
+        Executor executor = (cmd) -> new Thread(cmd).start();
         executor.execute(task);
-        executeShellCommand("cmd overlay " + (enable ? "enable " : "disable ") + packageName);
         task.get(TIMEOUT, SECONDS);
     }
 
-    private static String executeShellCommand(final String command)
-            throws Exception {
-        final UiAutomation uiAutomation =
-                InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        final ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command);
-        try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
-            final BufferedReader reader = new BufferedReader(
-                    new InputStreamReader(in, StandardCharsets.UTF_8));
-            StringBuilder str = new StringBuilder();
-            String line;
-            while ((line = reader.readLine()) != null) {
-                str.append(line);
-            }
-            return str.toString();
+    private static boolean arrayTailContains(@NonNull final String[] array,
+            @NonNull final String[] substrings) {
+        if (array.length < substrings.length) {
+            return false;
         }
+        for (int i = 0; i < substrings.length; i++) {
+            String a = array[array.length - substrings.length + i];
+            String s = substrings[i];
+            if (!a.contains(s)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean arrayDoesNotContain(@NonNull final String[] array,
+            @NonNull final String[] substrings) {
+        for (String s : substrings) {
+            for (String a : array) {
+                if (a.contains(s)) {
+                    return false;
+                }
+            }
+        }
+        return true;
     }
 }
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java
new file mode 100644
index 0000000..0b4f5e2
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.overlaytest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.content.res.Resources;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.List;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class TransactionTest {
+    static final String APP_OVERLAY_ONE_PKG = "com.android.overlaytest.app_overlay_one";
+    static final String APP_OVERLAY_TWO_PKG = "com.android.overlaytest.app_overlay_two";
+
+    private Context mContext;
+    private Resources mResources;
+    private OverlayManager mOverlayManager;
+    private int mUserId;
+    private UserHandle mUserHandle;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        mResources = mContext.getResources();
+        mOverlayManager = mContext.getSystemService(OverlayManager.class);
+        mUserId = UserHandle.myUserId();
+        mUserHandle = UserHandle.of(mUserId);
+
+        LocalOverlayManager.toggleOverlaysAndWait(
+                new String[]{},
+                new String[]{APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG});
+    }
+
+    @Test
+    public void testValidTransaction() throws Exception {
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+
+        OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+                .setEnabled(APP_OVERLAY_ONE_PKG, true)
+                .setEnabled(APP_OVERLAY_TWO_PKG, true)
+                .build();
+        mOverlayManager.commit(t);
+
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId);
+        List<OverlayInfo> ois =
+                mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+        assertEquals(ois.size(), 2);
+        assertEquals(ois.get(0).packageName, APP_OVERLAY_ONE_PKG);
+        assertEquals(ois.get(1).packageName, APP_OVERLAY_TWO_PKG);
+
+        OverlayManagerTransaction t2 = new OverlayManagerTransaction.Builder()
+                .setEnabled(APP_OVERLAY_TWO_PKG, true)
+                .setEnabled(APP_OVERLAY_ONE_PKG, true)
+                .build();
+        mOverlayManager.commit(t2);
+
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId);
+        List<OverlayInfo> ois2 =
+                mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+        assertEquals(ois2.size(), 2);
+        assertEquals(ois2.get(0).packageName, APP_OVERLAY_TWO_PKG);
+        assertEquals(ois2.get(1).packageName, APP_OVERLAY_ONE_PKG);
+
+        OverlayManagerTransaction t3 = new OverlayManagerTransaction.Builder()
+                .setEnabled(APP_OVERLAY_TWO_PKG, false)
+                .build();
+        mOverlayManager.commit(t3);
+
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+        List<OverlayInfo> ois3 =
+                mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+        assertEquals(ois3.size(), 2);
+        assertEquals(ois3.get(0).packageName, APP_OVERLAY_TWO_PKG);
+        assertEquals(ois3.get(1).packageName, APP_OVERLAY_ONE_PKG);
+    }
+
+    @Test
+    public void testInvalidRequestHasNoEffect() {
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+
+        OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+                .setEnabled(APP_OVERLAY_ONE_PKG, true)
+                .setEnabled("does-not-exist", true)
+                .setEnabled(APP_OVERLAY_TWO_PKG, true)
+                .build();
+        assertThrows(SecurityException.class, () -> mOverlayManager.commit(t));
+
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+    }
+
+    private void assertOverlayIsEnabled(final String packageName, boolean enabled, int userId) {
+        final OverlayInfo oi = mOverlayManager.getOverlayInfo(packageName, UserHandle.of(userId));
+        assertNotNull(oi);
+        assertEquals(oi.isEnabled(), enabled);
+    }
+}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
index d28c47d..420f755 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -22,8 +22,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.concurrent.Executor;
-
 @RunWith(JUnit4.class)
 @MediumTest
 public class WithMultipleOverlaysTest extends OverlayBaseTest {
@@ -33,9 +31,8 @@
 
     @BeforeClass
     public static void enableOverlay() throws Exception {
-        Executor executor = (cmd) -> new Thread(cmd).start();
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, true);
-        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
+        LocalOverlayManager.toggleOverlaysAndWait(
+                new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG},
+                new String[]{});
     }
 }
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
index 6566ad3..a86255e 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
@@ -22,8 +22,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.concurrent.Executor;
-
 @RunWith(JUnit4.class)
 @MediumTest
 public class WithOverlayTest extends OverlayBaseTest {
@@ -32,10 +30,9 @@
     }
 
     @BeforeClass
-    public static void enableOverlay() throws Exception {
-        Executor executor = (cmd) -> new Thread(cmd).start();
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
-        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
+    public static void enableOverlays() throws Exception {
+        LocalOverlayManager.toggleOverlaysAndWait(
+                new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG},
+                new String[]{APP_OVERLAY_TWO_PKG});
     }
 }
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
index 48cfeab..51c4118 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -22,8 +22,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.concurrent.Executor;
-
 @RunWith(JUnit4.class)
 @MediumTest
 public class WithoutOverlayTest extends OverlayBaseTest {
@@ -33,9 +31,8 @@
 
     @BeforeClass
     public static void disableOverlays() throws Exception {
-        Executor executor = (cmd) -> new Thread(cmd).start();
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, false);
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
-        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, false);
+        LocalOverlayManager.toggleOverlaysAndWait(
+                new String[]{},
+                new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG});
     }
 }
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
index da3aa00..847b491 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
@@ -15,6 +15,6 @@
 android_test {
     name: "OverlayDeviceTests_AppOverlayOne",
     sdk_version: "current",
-
+    certificate: "platform",
     aaptflags: ["--no-resource-removal"],
 }
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
index 215b66da3..7d5f82a 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
@@ -15,6 +15,6 @@
 android_test {
     name: "OverlayDeviceTests_AppOverlayTwo",
     sdk_version: "current",
-
+    certificate: "platform",
     aaptflags: ["--no-resource-removal"],
 }
diff --git a/keystore/java/android/security/AuthTokenUtils.java b/keystore/java/android/security/AuthTokenUtils.java
index 14d6626..e637600 100644
--- a/keystore/java/android/security/AuthTokenUtils.java
+++ b/keystore/java/android/security/AuthTokenUtils.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.hardware.security.keymint.HardwareAuthToken;
-import android.hardware.security.keymint.Timestamp;
+import android.hardware.security.secureclock.Timestamp;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
index 2b76f25..fcc518c 100644
--- a/keystore/java/android/security/Authorization.java
+++ b/keystore/java/android/security/Authorization.java
@@ -17,11 +17,13 @@
 package android.security;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.security.keymint.HardwareAuthToken;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.security.authorization.IKeystoreAuthorization;
+import android.security.authorization.LockScreenEvent;
 import android.system.keystore2.ResponseCode;
 import android.util.Log;
 
@@ -42,7 +44,7 @@
     private static synchronized IKeystoreAuthorization getService() {
         if (sIKeystoreAuthorization == null) {
             sIKeystoreAuthorization = IKeystoreAuthorization.Stub.asInterface(
-                    ServiceManager.getService("android.security.authorization"));
+                    ServiceManager.checkService("android.security.authorization"));
         }
         return sIKeystoreAuthorization;
     }
@@ -75,4 +77,31 @@
         return addAuthToken(AuthTokenUtils.toHardwareAuthToken(authToken));
     }
 
+    /**
+     * Informs keystore2 about lock screen event.
+     *
+     * @param locked            - whether it is a lock (true) or unlock (false) event
+     * @param syntheticPassword - if it is an unlock event with the password, pass the synthetic
+     *                          password provided by the LockSettingService
+     *
+     * @return 0 if successful or a {@code ResponseCode}.
+     */
+    public int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
+            @Nullable byte[] syntheticPassword) {
+        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+        try {
+            if (locked) {
+                getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null);
+            } else {
+                getService().onLockScreenEvent(LockScreenEvent.UNLOCK, userId, syntheticPassword);
+            }
+            return 0;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        } catch (ServiceSpecificException e) {
+            return e.errorCode;
+        }
+    }
+
 }
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 158c349..2edd48c 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -102,12 +102,12 @@
     bool hasBackwardProjectedNodesSubtree = false;
 
     for (auto& child : mChildNodes) {
-        hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
         RenderNode* childNode = child.getRenderNode();
         Matrix4 mat4(child.getRecordedMatrix());
         info.damageAccumulator->pushTransform(&mat4);
         info.hasBackwardProjectedNodes = false;
         childFn(childNode, observer, info, functorsNeedLayer);
+        hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
         hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes;
         info.damageAccumulator->popTransform();
     }
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 068f968..4b8a8ad 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -73,6 +73,8 @@
     void unregisterManager(IMediaRouter2Manager manager);
     void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
             in MediaRoute2Info route, int volume);
+    void startScan(IMediaRouter2Manager manager);
+    void stopScan(IMediaRouter2Manager manager);
 
     void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId,
             in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route);
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 4b09a5f..68237de 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -147,6 +147,36 @@
     }
 
     /**
+     * Starts scanning remote routes.
+     * @see #stopScan(String)
+     */
+    public void startScan() {
+        Client client = getOrCreateClient();
+        if (client != null) {
+            try {
+                mMediaRouterService.startScan(client);
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+            }
+        }
+    }
+
+    /**
+     * Stops scanning remote routes to reduce resource consumption.
+     * @see #startScan(String)
+     */
+    public void stopScan() {
+        Client client = getOrCreateClient();
+        if (client != null) {
+            try {
+                mMediaRouterService.stopScan(client);
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Unable to get sessions. Service probably died.", ex);
+            }
+        }
+    }
+
+    /**
      * Gets a {@link android.media.session.MediaController} associated with the
      * given routing session.
      * If there is no matching media session, {@code null} is returned.
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 68f2964..2f95247 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -153,6 +153,7 @@
             return false;
         }
         RouteDiscoveryPreference other = (RouteDiscoveryPreference) o;
+        //TODO: Make this order-free
         return Objects.equals(mPreferredFeatures, other.mPreferredFeatures)
                 && mShouldPerformActiveScan == other.mShouldPerformActiveScan;
     }
diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java
index 1249e0d..0bedbd3 100644
--- a/media/java/android/media/tv/TvInputHardwareInfo.java
+++ b/media/java/android/media/tv/TvInputHardwareInfo.java
@@ -190,13 +190,16 @@
 
     /** @hide */
     public Builder toBuilder() {
-        return new Builder()
+        Builder newBuilder = new Builder()
             .deviceId(mDeviceId)
             .type(mType)
             .audioType(mAudioType)
             .audioAddress(mAudioAddress)
-            .hdmiPortId(mHdmiPortId)
             .cableConnectionStatus(mCableConnectionStatus);
+        if (mType == TV_INPUT_TYPE_HDMI) {
+            newBuilder.hdmiPortId(mHdmiPortId);
+        }
+        return newBuilder;
     }
 
     public static final class Builder {
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 8871167..c4b622d 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -47,6 +47,7 @@
     private static int sInstantId = 0;
     private int mSegmentId = 0;
     private int mOverflow;
+    private Boolean mIsStopped = null;
 
     private native int nativeAttachFilter(Filter filter);
     private native int nativeDetachFilter(Filter filter);
@@ -135,7 +136,13 @@
                 .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
-        return nativeStartDvr();
+        synchronized (mIsStopped) {
+            int result = nativeStartDvr();
+            if (result == Tuner.RESULT_SUCCESS) {
+                mIsStopped = false;
+            }
+            return result;
+        }
     }
 
     /**
@@ -152,7 +159,13 @@
                 .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow);
-        return nativeStopDvr();
+        synchronized (mIsStopped) {
+            int result = nativeStopDvr();
+            if (result == Tuner.RESULT_SUCCESS) {
+                mIsStopped = true;
+            }
+            return result;
+        }
     }
 
     /**
@@ -164,7 +177,13 @@
      */
     @Result
     public int flush() {
-        return nativeFlushDvr();
+        synchronized (mIsStopped) {
+            if (mIsStopped) {
+                return nativeFlushDvr();
+            }
+            Log.w(TAG, "Cannot flush non-stopped Record DVR.");
+            return Tuner.RESULT_INVALID_STATE;
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 5a7c5c9..f65f97a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -271,7 +271,7 @@
         float contentStart = getPaddingStart();
         int childCount = getChildCount();
         // Underflow === don't show content until that index
-        if (DEBUG) android.util.Log.d(TAG, "calculateIconTranslations: start=" + translationX
+        if (DEBUG) Log.d(TAG, "calculateIconTranslations: start=" + translationX
                 + " width=" + width + " underflow=" + mNeedsUnderflow);
 
         // Collect all of the states which want to be visible
diff --git a/services/Android.bp b/services/Android.bp
index ef52c2a..785ca35 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -147,11 +147,20 @@
             baseline_file: "api/lint-baseline.txt",
         },
     },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/system-server/api",
-        dest: "android.txt",
-    },
+    dists: [
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/system-server/api",
+            dest: "android.txt",
+            tag: ".api.txt"
+        },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/system-server/api",
+            dest: "removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ]
 }
 
 java_library {
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index c6f42f7..a31cfae 100644
--- a/services/accessibility/OWNERS
+++ b/services/accessibility/OWNERS
@@ -1,4 +1,4 @@
 svetoslavganov@google.com
 pweaver@google.com
 rhedjao@google.com
-qasid@google.com
+ryanlwlin@google.com
diff --git a/services/appwidget/java/com/android/server/appwidget/OWNERS b/services/appwidget/java/com/android/server/appwidget/OWNERS
new file mode 100644
index 0000000..d724cac
--- /dev/null
+++ b/services/appwidget/java/com/android/server/appwidget/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/appwidget/OWNERS
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 307d344..adebcc7 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -112,6 +112,9 @@
         "time_zone_distro",
         "time_zone_distro_installer",
         "android.hardware.authsecret-V1.0-java",
+        "android.hardware.boot-V1.0-java",
+        "android.hardware.boot-V1.1-java",
+        "android.hardware.boot-V1.2-java",
         "android.hardware.broadcastradio-V2.0-java",
         "android.hardware.health-V1.0-java",
         "android.hardware.health-V2.0-java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3ad4c5b..b07e98f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -888,6 +888,13 @@
         }
 
         /**
+         * Get a reference to the system keystore.
+         */
+        public KeyStore getKeyStore() {
+            return KeyStore.getInstance();
+        }
+
+        /**
          * @see ProxyTracker
          */
         public ProxyTracker makeProxyTracker(@NonNull Context context,
@@ -981,7 +988,7 @@
         mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
         mNetd = netd;
-        mKeyStore = KeyStore.getInstance();
+        mKeyStore = mDeps.getKeyStore();
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mLocationPermissionChecker = new LocationPermissionChecker(mContext);
@@ -1108,11 +1115,7 @@
         userAllContext.registerReceiver(
                 mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
 
-        try {
-            mNMS.registerObserver(mDataActivityObserver);
-        } catch (RemoteException e) {
-            loge("Error registering observer :" + e);
-        }
+        mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS);
 
         mSettingsObserver = new SettingsObserver(mContext, mHandler);
         registerSettingsCallbacks();
@@ -1644,7 +1647,6 @@
     private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
         if (nai == null) return null;
         synchronized (nai) {
-            if (nai.networkCapabilities == null) return null;
             return networkCapabilitiesRestrictedForCallerPermissions(
                     nai.networkCapabilities, Binder.getCallingPid(), mDeps.getCallingUid());
         }
@@ -1796,30 +1798,6 @@
         }
     }
 
-    private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
-        @Override
-        public void interfaceClassDataActivityChanged(int transportType, boolean active,
-                long tsNanos, int uid) {
-            sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos);
-        }
-    };
-
-    // This is deprecated and only to support legacy use cases.
-    private int transportTypeToLegacyType(int type) {
-        switch (type) {
-            case NetworkCapabilities.TRANSPORT_CELLULAR:
-                return ConnectivityManager.TYPE_MOBILE;
-            case NetworkCapabilities.TRANSPORT_WIFI:
-                return ConnectivityManager.TYPE_WIFI;
-            case NetworkCapabilities.TRANSPORT_BLUETOOTH:
-                return ConnectivityManager.TYPE_BLUETOOTH;
-            case NetworkCapabilities.TRANSPORT_ETHERNET:
-                return ConnectivityManager.TYPE_ETHERNET;
-            default:
-                loge("Unexpected transport in transportTypeToLegacyType: " + type);
-        }
-        return ConnectivityManager.TYPE_NONE;
-    }
     /**
      * Ensures that the system cannot call a particular method.
      */
@@ -2268,20 +2246,6 @@
         sendStickyBroadcast(makeGeneralIntent(info, bcastType));
     }
 
-    private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
-        Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
-        intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
-        intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
-        intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
-                    RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void sendStickyBroadcast(Intent intent) {
         synchronized (this) {
             if (!mSystemReady
@@ -2387,74 +2351,6 @@
     }
 
     /**
-     * Setup data activity tracking for the given network.
-     *
-     * Every {@code setupDataActivityTracking} should be paired with a
-     * {@link #removeDataActivityTracking} for cleanup.
-     */
-    private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
-        final String iface = networkAgent.linkProperties.getInterfaceName();
-
-        final int timeout;
-        final int type;
-
-        if (networkAgent.networkCapabilities.hasTransport(
-                NetworkCapabilities.TRANSPORT_CELLULAR)) {
-            timeout = Settings.Global.getInt(mContext.getContentResolver(),
-                                             Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
-                                             10);
-            type = NetworkCapabilities.TRANSPORT_CELLULAR;
-        } else if (networkAgent.networkCapabilities.hasTransport(
-                NetworkCapabilities.TRANSPORT_WIFI)) {
-            timeout = Settings.Global.getInt(mContext.getContentResolver(),
-                                             Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
-                                             15);
-            type = NetworkCapabilities.TRANSPORT_WIFI;
-        } else {
-            return; // do not track any other networks
-        }
-
-        if (timeout > 0 && iface != null) {
-            try {
-                mNMS.addIdleTimer(iface, timeout, type);
-            } catch (Exception e) {
-                // You shall not crash!
-                loge("Exception in setupDataActivityTracking " + e);
-            }
-        }
-    }
-
-    /**
-     * Remove data activity tracking when network disconnects.
-     */
-    private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
-        final String iface = networkAgent.linkProperties.getInterfaceName();
-        final NetworkCapabilities caps = networkAgent.networkCapabilities;
-
-        if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
-                              caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
-            try {
-                // the call fails silently if no idle timer setup for this interface
-                mNMS.removeIdleTimer(iface);
-            } catch (Exception e) {
-                loge("Exception in removeDataActivityTracking " + e);
-            }
-        }
-    }
-
-    /**
-     * Update data activity tracking when network state is updated.
-     */
-    private void updateDataActivityTracking(NetworkAgentInfo newNetwork,
-            NetworkAgentInfo oldNetwork) {
-        if (newNetwork != null) {
-            setupDataActivityTracking(newNetwork);
-        }
-        if (oldNetwork != null) {
-            removeDataActivityTracking(oldNetwork);
-        }
-    }
-    /**
      * Reads the network specific MTU size from resources.
      * and set it on it's iface.
      */
@@ -2768,7 +2664,6 @@
     }
 
     private boolean isLiveNetworkAgent(NetworkAgentInfo nai, int what) {
-        if (nai.network == null) return false;
         final NetworkAgentInfo officialNai = getNetworkAgentInfoForNetwork(nai.network);
         if (officialNai != null && officialNai.equals(nai)) return true;
         if (officialNai != null || VDBG) {
@@ -2869,13 +2764,7 @@
                         Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
                         break;
                     }
-                    final ArrayList<Network> underlying;
-                    try {
-                        underlying = ((Bundle) arg.second).getParcelableArrayList(
-                                NetworkAgent.UNDERLYING_NETWORKS_KEY);
-                    } catch (NullPointerException | ClassCastException e) {
-                        break;
-                    }
+                    final List<Network> underlying = (List<Network>) arg.second;
                     final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
                     nai.declaredUnderlyingNetworks = (underlying != null)
                             ? underlying.toArray(new Network[0]) : null;
@@ -3461,6 +3350,7 @@
             // available until we've told netd to delete it below.
             mNetworkForNetId.remove(nai.network.getNetId());
         }
+        propagateUnderlyingNetworkCapabilities(nai.network);
         // Remove all previously satisfied requests.
         for (int i = 0; i < nai.numNetworkRequests(); i++) {
             NetworkRequest request = nai.requestAt(i);
@@ -3473,10 +3363,12 @@
             }
         }
         nai.clearLingerState();
-        propagateUnderlyingNetworkCapabilities(nai.network);
+        // TODO: this loop, and the mLegacyTypeTracker.remove just below it, seem redundant given
+        // there's a full rematch right after. Currently, deleting it breaks tests that check for
+        // the default network disconnecting. Find out why, fix the rematch code, and delete this.
         if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
             mDefaultNetworkNai = null;
-            updateDataActivityTracking(null /* newNetwork */, nai);
+            mNetworkActivityTracker.updateDataActivityTracking(null /* newNetwork */, nai);
             notifyLockdownVpn(nai);
             ensureNetworkTransitionWakelock(nai.toShortString());
         }
@@ -4984,16 +4876,23 @@
         mVpnBlockedUidRanges = newVpnBlockedUidRanges;
     }
 
+    private boolean isLockdownVpnEnabled() {
+        return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
+    }
+
     @Override
     public boolean updateLockdownVpn() {
-        if (mDeps.getCallingUid() != Process.SYSTEM_UID) {
-            logw("Lockdown VPN only available to AID_SYSTEM");
+        // Allow the system UID for the system server and for Settings.
+        // Also, for unit tests, allow the process that ConnectivityService is running in.
+        if (mDeps.getCallingUid() != Process.SYSTEM_UID
+                && Binder.getCallingPid() != Process.myPid()) {
+            logw("Lockdown VPN only available to system process or AID_SYSTEM");
             return false;
         }
 
         synchronized (mVpns) {
             // Tear down existing lockdown if profile was removed
-            mLockdownEnabled = LockdownVpnTracker.isEnabled();
+            mLockdownEnabled = isLockdownVpnEnabled();
             if (mLockdownEnabled) {
                 byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
                 if (profileTag == null) {
@@ -5014,7 +4913,8 @@
                     logw("VPN for user " + user + " not ready yet. Skipping lockdown");
                     return false;
                 }
-                setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
+                setLockdownTracker(
+                        new LockdownVpnTracker(mContext, this, mHandler, mKeyStore, vpn,  profile));
             } else {
                 setLockdownTracker(null);
             }
@@ -5102,7 +5002,7 @@
 
         synchronized (mVpns) {
             // Can't set always-on VPN if legacy VPN is already in lockdown mode.
-            if (LockdownVpnTracker.isEnabled()) {
+            if (isLockdownVpnEnabled()) {
                 return false;
             }
 
@@ -5208,7 +5108,7 @@
             }
             userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
             mVpns.put(userId, userVpn);
-            if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
             }
         }
@@ -5292,7 +5192,7 @@
     private void onUserUnlocked(int userId) {
         synchronized (mVpns) {
             // User present may be sent because of an unlock, which might mean an unlocked keystore.
-            if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
             } else {
                 startAlwaysOnVpn(userId);
@@ -6059,6 +5959,10 @@
     public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
+        Objects.requireNonNull(networkInfo, "networkInfo must not be null");
+        Objects.requireNonNull(linkProperties, "linkProperties must not be null");
+        Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+        Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null");
         if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
             enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
         } else {
@@ -6597,7 +6501,7 @@
         }
 
         // Don't modify caller's NetworkCapabilities.
-        NetworkCapabilities newNc = new NetworkCapabilities(nc);
+        final NetworkCapabilities newNc = new NetworkCapabilities(nc);
         if (nai.lastValidated) {
             newNc.addCapability(NET_CAPABILITY_VALIDATED);
         } else {
@@ -6685,26 +6589,21 @@
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
-        // TODO : static analysis indicates that prevNc can't be null here (getAndSetNetworkCaps
-        // never returns null), so mark the relevant members and functions in nai as @NonNull and
-        // remove this test
-        if (prevNc != null) {
-            final boolean oldMetered = prevNc.isMetered();
-            final boolean newMetered = newNc.isMetered();
-            final boolean meteredChanged = oldMetered != newMetered;
+        final boolean oldMetered = prevNc.isMetered();
+        final boolean newMetered = newNc.isMetered();
+        final boolean meteredChanged = oldMetered != newMetered;
 
-            if (meteredChanged) {
-                maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
-                        mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
-            }
+        if (meteredChanged) {
+            maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
+                    mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
+        }
 
-            final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
-                    newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+        final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
+                != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
 
-            // Report changes that are interesting for network statistics tracking.
-            if (meteredChanged || roamingChanged) {
-                notifyIfacesChangedForNetworkStats();
-            }
+        // Report changes that are interesting for network statistics tracking.
+        if (meteredChanged || roamingChanged) {
+            notifyIfacesChangedForNetworkStats();
         }
 
         // This network might have been underlying another network. Propagate its capabilities.
@@ -7299,7 +7198,8 @@
             if (oldDefaultNetwork != null) {
                 mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
             }
-            updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+            mNetworkActivityTracker.updateDataActivityTracking(
+                    newDefaultNetwork, oldDefaultNetwork);
             // Notify system services of the new default.
             makeDefault(newDefaultNetwork);
 
@@ -7579,10 +7479,6 @@
         if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
             networkAgent.everConnected = true;
 
-            if (networkAgent.linkProperties == null) {
-                Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
-            }
-
             // NetworkCapabilities need to be set before sending the private DNS config to
             // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
             networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities);
@@ -7901,10 +7797,11 @@
     }
 
     @Override
-    public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId,
+    public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId,
             int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
             String dstAddr) {
         try {
+            final FileDescriptor fd = pfd.getFileDescriptor();
             mKeepaliveTracker.startNattKeepalive(
                     getNetworkAgentInfoForNetwork(network), fd, resourceId,
                     intervalSeconds, cb,
@@ -7912,24 +7809,25 @@
         } finally {
             // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
             // startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately.
-            if (fd != null && Binder.getCallingPid() != Process.myPid()) {
-                IoUtils.closeQuietly(fd);
+            if (pfd != null && Binder.getCallingPid() != Process.myPid()) {
+                IoUtils.closeQuietly(pfd);
             }
         }
     }
 
     @Override
-    public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds,
+    public void startTcpKeepalive(Network network, ParcelFileDescriptor pfd, int intervalSeconds,
             ISocketKeepaliveCallback cb) {
         try {
             enforceKeepalivePermission();
+            final FileDescriptor fd = pfd.getFileDescriptor();
             mKeepaliveTracker.startTcpKeepalive(
                     getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb);
         } finally {
             // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
             // startTcpKeepalive calls Os.dup(fd) before returning, so we can close immediately.
-            if (fd != null && Binder.getCallingPid() != Process.myPid()) {
-                IoUtils.closeQuietly(fd);
+            if (pfd != null && Binder.getCallingPid() != Process.myPid()) {
+                IoUtils.closeQuietly(pfd);
             }
         }
     }
@@ -8655,4 +8553,145 @@
 
         notifyDataStallSuspected(p, network.getNetId());
     }
+
+    private final LegacyNetworkActivityTracker mNetworkActivityTracker;
+
+    /**
+     * Class used for updating network activity tracking with netd and notify network activity
+     * changes.
+     */
+    private static final class LegacyNetworkActivityTracker {
+        private final Context mContext;
+        private final INetworkManagementService mNMS;
+
+        LegacyNetworkActivityTracker(@NonNull Context context,
+                        @NonNull INetworkManagementService nms) {
+            mContext = context;
+            mNMS = nms;
+            try {
+                mNMS.registerObserver(mDataActivityObserver);
+            } catch (RemoteException e) {
+                loge("Error registering observer :" + e);
+            }
+        }
+
+        // TODO: Migrate away the dependency with INetworkManagementEventObserver.
+        private final INetworkManagementEventObserver mDataActivityObserver =
+                new BaseNetworkObserver() {
+                    @Override
+                    public void interfaceClassDataActivityChanged(int transportType, boolean active,
+                            long tsNanos, int uid) {
+                        sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active,
+                                tsNanos);
+                    }
+        };
+
+        // This is deprecated and only to support legacy use cases.
+        private int transportTypeToLegacyType(int type) {
+            switch (type) {
+                case NetworkCapabilities.TRANSPORT_CELLULAR:
+                    return ConnectivityManager.TYPE_MOBILE;
+                case NetworkCapabilities.TRANSPORT_WIFI:
+                    return ConnectivityManager.TYPE_WIFI;
+                case NetworkCapabilities.TRANSPORT_BLUETOOTH:
+                    return ConnectivityManager.TYPE_BLUETOOTH;
+                case NetworkCapabilities.TRANSPORT_ETHERNET:
+                    return ConnectivityManager.TYPE_ETHERNET;
+                default:
+                    loge("Unexpected transport in transportTypeToLegacyType: " + type);
+            }
+            return ConnectivityManager.TYPE_NONE;
+        }
+
+        public void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
+            final Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
+            intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
+            intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
+            intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
+                        RECEIVE_DATA_ACTIVITY_CHANGE,
+                        null /* resultReceiver */,
+                        null /* scheduler */,
+                        0 /* initialCode */,
+                        null /* initialData */,
+                        null /* initialExtra */);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Setup data activity tracking for the given network.
+         *
+         * Every {@code setupDataActivityTracking} should be paired with a
+         * {@link #removeDataActivityTracking} for cleanup.
+         */
+        private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
+            final String iface = networkAgent.linkProperties.getInterfaceName();
+
+            final int timeout;
+            final int type;
+
+            if (networkAgent.networkCapabilities.hasTransport(
+                    NetworkCapabilities.TRANSPORT_CELLULAR)) {
+                timeout = Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
+                        10);
+                type = NetworkCapabilities.TRANSPORT_CELLULAR;
+            } else if (networkAgent.networkCapabilities.hasTransport(
+                    NetworkCapabilities.TRANSPORT_WIFI)) {
+                timeout = Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+                        15);
+                type = NetworkCapabilities.TRANSPORT_WIFI;
+            } else {
+                return; // do not track any other networks
+            }
+
+            if (timeout > 0 && iface != null) {
+                try {
+                    // TODO: Access INetd directly instead of NMS
+                    mNMS.addIdleTimer(iface, timeout, type);
+                } catch (Exception e) {
+                    // You shall not crash!
+                    loge("Exception in setupDataActivityTracking " + e);
+                }
+            }
+        }
+
+        /**
+         * Remove data activity tracking when network disconnects.
+         */
+        private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
+            final String iface = networkAgent.linkProperties.getInterfaceName();
+            final NetworkCapabilities caps = networkAgent.networkCapabilities;
+
+            if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+                    || caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
+                try {
+                    // the call fails silently if no idle timer setup for this interface
+                    // TODO: Access INetd directly instead of NMS
+                    mNMS.removeIdleTimer(iface);
+                } catch (Exception e) {
+                    // You shall not crash!
+                    loge("Exception in removeDataActivityTracking " + e);
+                }
+            }
+        }
+
+        /**
+         * Update data activity tracking when network state is updated.
+         */
+        public void updateDataActivityTracking(NetworkAgentInfo newNetwork,
+                NetworkAgentInfo oldNetwork) {
+            if (newNetwork != null) {
+                setupDataActivityTracking(newNetwork);
+            }
+            if (oldNetwork != null) {
+                removeDataActivityTracking(oldNetwork);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1ea4a89..d30a640 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -405,6 +405,9 @@
             if (mLastPowerStateFromRadio != powerState) {
                 mLastPowerStateFromRadio = powerState;
                 try {
+                    // TODO: The interface changes that comes from netd are handled by BSS itself.
+                    // There are still events caused by setting or removing idle timer, so keep
+                    // reporting from here until setting idler timer moved to CS.
                     getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
                 } catch (RemoteException e) {
                 }
@@ -415,6 +418,9 @@
             if (mLastPowerStateFromWifi != powerState) {
                 mLastPowerStateFromWifi = powerState;
                 try {
+                    // TODO: The interface changes that comes from netd are handled by BSS itself.
+                    // There are still events caused by setting or removing idle timer, so keep
+                    // reporting from here until setting idler timer moved to CS.
                     getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
                 } catch (RemoteException e) {
                 }
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index f6b72d6..222c96f 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -6,10 +6,10 @@
 per-file VibratorService.java, DisplayThread.java = ogunwale@google.com
 
 # Zram writeback
-per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com
+per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com
 
 # Userspace reboot
-per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com
+per-file UserspaceRebootLogger.java = ioffe@google.com, dvander@google.com
 
 # Sensor Privacy
 per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
@@ -31,6 +31,7 @@
 per-file MmsServiceBroker.java = file:/telephony/OWNERS
 per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS
 per-file PackageWatchdog.java = file:/services/core/java/com/android/server/rollback/OWNERS
+per-file PinnerService.java = file:/apct-tests/perftests/OWNERS
 per-file TelephonyRegistry.java = file:/telephony/OWNERS
 per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS
 per-file VcnManagementService.java = file:/services/core/java/com/android/server/vcn/OWNERS
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c8d457d..5c34584 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1537,6 +1537,9 @@
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
 
         } else if (vol.type == VolumeInfo.TYPE_STUB) {
+            if (vol.disk.isStubVisible()) {
+                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+            }
             vol.mountUserId = mCurrentUserId;
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
         } else {
@@ -1606,7 +1609,6 @@
         }
     }
 
-
     private void onVolumeStateChangedAsync(VolumeInfo vol, int oldState, int newState) {
         synchronized (mLock) {
             // Remember that we saw this volume so we're ready to accept user
@@ -3427,6 +3429,27 @@
         }
     }
 
+    /*
+     * Disable storage's app data isolation for testing.
+     */
+    @Override
+    public void disableAppDataIsolation(String pkgName, int pid, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
+            throw new SecurityException("no permission to enable app visibility");
+        }
+        final String[] sharedPackages =
+                mPmInternal.getSharedUserPackagesForPackage(pkgName, userId);
+        final int uid = mPmInternal.getPackageUid(pkgName, 0, userId);
+        final String[] packages =
+                sharedPackages.length != 0 ? sharedPackages : new String[]{pkgName};
+        try {
+            mVold.unmountAppStorageDirs(uid, pid, packages);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     /** Not thread safe */
     class AppFuseMountScope extends AppFuseBridge.MountScope {
         private boolean mMounted = false;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 5560f81..81d2b83 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -52,7 +52,6 @@
 import android.telephony.CallQuality;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
-import android.telephony.CellLocation;
 import android.telephony.CellSignalStrength;
 import android.telephony.CellSignalStrengthCdma;
 import android.telephony.CellSignalStrengthGsm;
@@ -584,8 +583,6 @@
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public TelephonyRegistry(Context context, ConfigurationProvider configurationProvider) {
-        CellLocation  location = CellLocation.getEmpty();
-
         mContext = context;
         mConfigurationProvider = configurationProvider;
         mBatteryStats = BatteryStatsService.getService();
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index c191a78..2fdc796 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.vcn.IVcnManagementService;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
 import android.os.Binder;
 import android.os.Handler;
@@ -495,4 +496,20 @@
             return Collections.unmodifiableMap(mVcns);
         }
     }
+
+    /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
+    @Override
+    public void addVcnUnderlyingNetworkPolicyListener(
+            IVcnUnderlyingNetworkPolicyListener listener) {
+        // TODO(b/175739863): implement policy listener registration
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
+    @Override
+    public void removeVcnUnderlyingNetworkPolicyListener(
+            IVcnUnderlyingNetworkPolicyListener listener) {
+        // TODO(b/175739863): implement policy listener unregistration
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 928ddab..686adbb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -190,6 +190,7 @@
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
+import android.compat.Compatibility;
 import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
@@ -318,6 +319,7 @@
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.SystemUserHomeActivity;
 import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.compat.CompatibilityChangeConfig;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
@@ -16944,6 +16946,8 @@
             if (disableHiddenApiChecks || disableTestApiChecks) {
                 enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
                         "disable hidden API checks");
+
+                enableTestApiAccess(ii.packageName);
             }
 
             // TODO(b/158750470): remove
@@ -17083,6 +17087,25 @@
 
         forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
                 "finished inst");
+
+        disableTestApiAccess(app.info.packageName);
+    }
+
+    private void enableTestApiAccess(String packageName) {
+        if (mPlatformCompat != null) {
+            Compatibility.ChangeConfig config = new Compatibility.ChangeConfig(
+                    Collections.singleton(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */),
+                    Collections.emptySet());
+            CompatibilityChangeConfig override = new CompatibilityChangeConfig(config);
+            mPlatformCompat.setOverridesForTest(override, packageName);
+        }
+    }
+
+    private void disableTestApiAccess(String packageName) {
+        if (mPlatformCompat != null) {
+            mPlatformCompat.clearOverrideForTest(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */,
+                    packageName);
+        }
     }
 
     public void finishInstrumentation(IApplicationThread target,
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 1ade8e7..3c53880 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,11 +21,14 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.net.INetworkManagementEventObserver;
+import android.net.NetworkCapabilities;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.INetworkManagementService;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelFormatException;
@@ -33,6 +36,7 @@
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -52,6 +56,7 @@
 import android.telephony.TelephonyManager;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BatteryStatsImpl;
@@ -62,6 +67,7 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ParseUtils;
 import com.android.server.LocalServices;
+import com.android.server.net.BaseNetworkObserver;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -108,6 +114,39 @@
     private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
     private static final int MAX_LOW_POWER_STATS_SIZE = 4096;
 
+    @GuardedBy("mStats")
+    private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+    @GuardedBy("mStats")
+    private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+    private final INetworkManagementEventObserver mActivityChangeObserver =
+            new BaseNetworkObserver() {
+                @Override
+                public void interfaceClassDataActivityChanged(int transportType, boolean active,
+                        long tsNanos, int uid) {
+                    final int powerState = active
+                            ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+                            : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+                    final long timestampNanos;
+                    if (tsNanos <= 0) {
+                        timestampNanos = SystemClock.elapsedRealtimeNanos();
+                    } else {
+                        timestampNanos = tsNanos;
+                    }
+
+                    switch (transportType) {
+                        case NetworkCapabilities.TRANSPORT_CELLULAR:
+                            noteMobileRadioPowerState(powerState, timestampNanos, uid);
+                            break;
+                        case NetworkCapabilities.TRANSPORT_WIFI:
+                            noteWifiRadioPowerState(powerState, timestampNanos, uid);
+                            break;
+                        default:
+                            Slog.d(TAG, "Received unexpected transport in "
+                                    + "interfaceClassDataActivityChanged unexpected type: "
+                                    + transportType);
+                    }
+                }
+            };
     /**
      * Replaces the information in the given rpmStats with up-to-date information.
      */
@@ -203,6 +242,13 @@
     }
 
     public void systemServicesReady() {
+        final INetworkManagementService nms = INetworkManagementService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+        try {
+            nms.registerObserver(mActivityChangeObserver);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Could not register INetworkManagement event observer " + e);
+        }
         mStats.systemServicesReady(mContext);
     }
 
@@ -680,8 +726,13 @@
 
     public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) {
         enforceCallingPermission();
+
         final boolean update;
         synchronized (mStats) {
+            // Ignore if no power state change.
+            if (mLastPowerStateFromRadio == powerState) return;
+
+            mLastPowerStateFromRadio = powerState;
             update = mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid);
         }
 
@@ -863,6 +914,10 @@
         // There was a change in WiFi power state.
         // Collect data now for the past activity.
         synchronized (mStats) {
+            // Ignore if no power state change.
+            if (mLastPowerStateFromWifi == powerState) return;
+
+            mLastPowerStateFromWifi = powerState;
             if (mStats.isOnBattery()) {
                 final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH ||
                         powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active"
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 88b0c3b..b6e632d 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -110,7 +110,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.RuntimeInit;
 import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
@@ -349,12 +348,23 @@
     private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
 
     /**
-     * Enable memory tag checks in non-system apps. This flag will only have an effect on
-     * hardware supporting the ARM Memory Tagging Extension (MTE).
+     * Enable asynchronous (ASYNC) memory tag checking in this process. This
+     * flag will only have an effect on hardware supporting the ARM Memory
+     * Tagging Extension (MTE).
      */
     @ChangeId
     @Disabled
-    private static final long NATIVE_MEMORY_TAGGING = 135772972; // This is a bug id.
+    private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id.
+
+    /**
+     * Enable synchronous (SYNC) memory tag checking in this process. This flag
+     * will only have an effect on hardware supporting the ARM Memory Tagging
+     * Extension (MTE). If both NATIVE_MEMTAG_ASYNC and this option is selected,
+     * this option takes preference and MTE is enabled in SYNC mode.
+     */
+    @ChangeId
+    @Disabled
+    private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id.
 
     /**
      * Enable sampled memory bug detection in the app.
@@ -1677,23 +1687,23 @@
         return gidArray;
     }
 
-    private boolean shouldEnableMemoryTagging(ProcessRecord app) {
+    // Returns the memory tagging level to be enabled. If memory tagging isn't
+    // requested, returns zero.
+    private int getMemtagLevel(ProcessRecord app) {
         // Ensure the hardware + kernel actually supports MTE.
         if (!Zygote.nativeSupportsMemoryTagging()) {
-            return false;
+            return 0;
         }
 
-        // Enable MTE for system apps if supported.
-        if ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-            return true;
+        if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_SYNC, app.info)) {
+            return Zygote.MEMORY_TAG_LEVEL_SYNC;
         }
 
-        // Enable MTE if the compat feature is enabled.
-        if (mPlatformCompat.isChangeEnabled(NATIVE_MEMORY_TAGGING, app.info)) {
-            return true;
+        if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_ASYNC, app.info)) {
+            return Zygote.MEMORY_TAG_LEVEL_ASYNC;
         }
 
-        return false;
+        return 0;
     }
 
     private boolean shouldEnableTaggedPointers(ProcessRecord app) {
@@ -1717,8 +1727,9 @@
 
     private int decideTaggingLevel(ProcessRecord app) {
         // Check MTE support first, as it should take precedence over TBI.
-        if (shouldEnableMemoryTagging(app)) {
-            return Zygote.MEMORY_TAG_LEVEL_ASYNC;
+        int memtagLevel = getMemtagLevel(app);
+        if (memtagLevel != 0) {
+            return memtagLevel;
         }
 
         if (shouldEnableTaggedPointers(app)) {
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 9376e8d..69686a2 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.os.Environment;
-import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.LongArray;
 import android.util.LongSparseArray;
@@ -53,7 +52,7 @@
 import javax.xml.datatype.DatatypeConfigurationException;
 
 /**
- * This class maintains state relating to platform compatibility changes.
+ * CompatConfig maintains state related to the platform compatibility changes.
  *
  * <p>It stores the default configuration for each change, and any per-package overrides that have
  * been configured.
@@ -65,18 +64,38 @@
     @GuardedBy("mChanges")
     private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
 
-    private OverrideValidatorImpl mOverrideValidator;
+    private final OverrideValidatorImpl mOverrideValidator;
 
     @VisibleForTesting
     CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
         mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
     }
 
+    static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
+        CompatConfig config = new CompatConfig(androidBuildClassifier, context);
+        config.initConfigFromLib(Environment.buildPath(
+                Environment.getRootDirectory(), "etc", "compatconfig"));
+        config.initConfigFromLib(Environment.buildPath(
+                Environment.getRootDirectory(), "system_ext", "etc", "compatconfig"));
+
+        List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos();
+        for (ApexManager.ActiveApexInfo apex : apexes) {
+            config.initConfigFromLib(Environment.buildPath(
+                    apex.apexDirectory, "etc", "compatconfig"));
+        }
+        config.invalidateCache();
+        return config;
+    }
+
     /**
-     * Add a change. This is intended to be used by code that reads change config from the
-     * filesystem. This should be done at system startup time.
+     * Adds a change.
      *
-     * @param change The change to add. Any change with the same ID will be overwritten.
+     * <p>This is intended to be used by code that reads change config from the filesystem. This
+     * should be done at system startup time.
+     *
+     * <p>Any change with the same ID will be overwritten.
+     *
+     * @param change the change to add
      */
     void addChange(CompatChange change) {
         synchronized (mChanges) {
@@ -86,13 +105,15 @@
     }
 
     /**
-     * Retrieves the set of disabled changes for a given app. Any change ID not in the returned
-     * array is by default enabled for the app.
+     * Retrieves the set of disabled changes for a given app.
      *
-     * @param app The app in question
-     * @return A sorted long array of change IDs. We use a primitive array to minimize memory
-     * footprint: Every app process will store this array statically so we aim to reduce
-     * overhead as much as possible.
+     * <p>Any change ID not in the returned array is by default enabled for the app.
+     *
+     * <p>We use a primitive array to minimize memory footprint: every app process will store this
+     * array statically so we aim to reduce overhead as much as possible.
+     *
+     * @param app the app in question
+     * @return a sorted long array of change IDs
      */
     long[] getDisabledChanges(ApplicationInfo app) {
         LongArray disabled = new LongArray();
@@ -110,10 +131,10 @@
     }
 
     /**
-     * Look up a change ID by name.
+     * Looks up a change ID by name.
      *
-     * @param name Name of the change to look up
-     * @return The change ID, or {@code -1} if no change with that name exists.
+     * @param name name of the change to look up
+     * @return the change ID, or {@code -1} if no change with that name exists
      */
     long lookupChangeId(String name) {
         synchronized (mChanges) {
@@ -127,10 +148,10 @@
     }
 
     /**
-     * Find if a given change is enabled for a given application.
+     * Checks if a given change is enabled for a given application.
      *
-     * @param changeId The ID of the change in question
-     * @param app      App to check for
+     * @param changeId the ID of the change in question
+     * @param app      app to check for
      * @return {@code true} if the change is enabled for this app. Also returns {@code true} if the
      * change ID is not known, as unknown changes are enabled by default.
      */
@@ -146,10 +167,10 @@
     }
 
     /**
-     * Find if a given change will be enabled for a given package name, prior to installation.
+     * Checks if a given change will be enabled for a given package name after the installation.
      *
-     * @param changeId    The ID of the change in question
-     * @param packageName Package name to check for
+     * @param changeId    the ID of the change in question
+     * @param packageName package name to check for
      * @return {@code true} if the change would be enabled for this package name. Also returns
      * {@code true} if the change ID is not known, as unknown changes are enabled by default.
      */
@@ -165,22 +186,22 @@
     }
 
     /**
-     * Overrides the enabled state for a given change and app. This method is intended to be used
-     * *only* for debugging purposes, ultimately invoked either by an adb command, or from some
-     * developer settings UI.
+     * Overrides the enabled state for a given change and app.
      *
-     * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+     * <p>This method is intended to be used *only* for debugging purposes, ultimately invoked
+     * either by an adb command, or from some developer settings UI.
      *
-     * @param changeId    The ID of the change to be overridden. Note, this call will succeed even
-     *                    if
-     *                    this change is not known; it will only have any effect if any code in the
-     *                    platform is gated on the ID given.
-     * @param packageName The app package name to override the change for.
-     * @param enabled     If the change should be enabled or disabled.
-     * @return {@code true} if the change existed before adding the override.
+     * <p>Note: package overrides are not persistent and will be lost on system or runtime restart.
+     *
+     * @param changeId    the ID of the change to be overridden. Note, this call will succeed even
+     *                    if this change is not known; it will only have any effect if any code in
+     *                    the platform is gated on the ID given.
+     * @param packageName the app package name to override the change for
+     * @param enabled     if the change should be enabled or disabled
+     * @return {@code true} if the change existed before adding the override
+     * @throws IllegalStateException if overriding is not allowed
      */
-    boolean addOverride(long changeId, String packageName, boolean enabled)
-            throws SecurityException {
+    boolean addOverride(long changeId, String packageName, boolean enabled) {
         boolean alreadyKnown = true;
         OverrideAllowedState allowedState =
                 mOverrideValidator.getOverrideAllowedState(changeId, packageName);
@@ -201,18 +222,14 @@
                     break;
                 default:
                     throw new IllegalStateException("Should only be able to override changes that "
-                                                    + "are allowed or can be deferred.");
+                            + "are allowed or can be deferred.");
             }
             invalidateCache();
         }
         return alreadyKnown;
     }
 
-    /**
-     * Check whether the change is known to the compat config.
-     *
-     * @return {@code true} if the change is known.
-     */
+    /** Checks whether the change is known to the compat config. */
     boolean isKnownChangeId(long changeId) {
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
@@ -221,16 +238,13 @@
     }
 
     /**
-     * Returns the maximum sdk version for which this change can be opted in (or -1 if it is not
-     * target sdk gated).
+     * Returns the maximum SDK version for which this change can be opted in (or -1 if it is not
+     * target SDK gated).
      */
     int maxTargetSdkForChangeIdOptIn(long changeId) {
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
-            if (c == null) {
-                return -1;
-            }
-            if (c.getEnableSinceTargetSdk() != -1) {
+            if (c != null && c.getEnableSinceTargetSdk() != -1) {
                 return c.getEnableSinceTargetSdk() - 1;
             }
             return -1;
@@ -243,10 +257,7 @@
     boolean isLoggingOnly(long changeId) {
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
-            if (c == null) {
-                return false;
-            }
-            return c.getLoggingOnly();
+            return c != null && c.getLoggingOnly();
         }
     }
 
@@ -256,24 +267,21 @@
     boolean isDisabled(long changeId) {
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
-            if (c == null) {
-                return false;
-            }
-            return c.getDisabled();
+            return c != null && c.getDisabled();
         }
     }
 
     /**
-     * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
-     * restores the default behaviour for the given change and app, once any app processes have been
-     * restarted.
+     * Removes an override previously added via {@link #addOverride(long, String, boolean)}.
      *
-     * @param changeId    The ID of the change that was overridden.
-     * @param packageName The app package name that was overridden.
+     * <p>This restores the default behaviour for the given change and app, once any app processes
+     * have been restarted.
+     *
+     * @param changeId    the ID of the change that was overridden
+     * @param packageName the app package name that was overridden
      * @return {@code true} if an override existed;
      */
-    boolean removeOverride(long changeId, String packageName)
-            throws SecurityException {
+    boolean removeOverride(long changeId, String packageName) {
         boolean overrideExists = false;
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
@@ -299,13 +307,12 @@
     /**
      * Overrides the enabled state for a given change and app.
      *
-     * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+     * <p>Note: package overrides are not persistent and will be lost on system or runtime restart.
      *
-     * @param overrides   list of overrides to default changes config.
-     * @param packageName app for which the overrides will be applied.
+     * @param overrides   list of overrides to default changes config
+     * @param packageName app for which the overrides will be applied
      */
-    void addOverrides(CompatibilityChangeConfig overrides, String packageName)
-            throws RemoteException, SecurityException {
+    void addOverrides(CompatibilityChangeConfig overrides, String packageName) {
         synchronized (mChanges) {
             for (Long changeId : overrides.enabledChanges()) {
                 addOverride(changeId, packageName, true);
@@ -324,9 +331,9 @@
      *
      * <p>This restores the default behaviour for the given app.
      *
-     * @param packageName The package for which the overrides should be purged.
+     * @param packageName the package for which the overrides should be purged
      */
-    void removePackageOverrides(String packageName) throws SecurityException {
+    void removePackageOverrides(String packageName) {
         synchronized (mChanges) {
             for (int i = 0; i < mChanges.size(); ++i) {
                 CompatChange change = mChanges.valueAt(i);
@@ -337,8 +344,7 @@
     }
 
     private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName,
-                                                             int targetSdkVersion)
-                    throws RemoteException {
+            int targetSdkVersion) {
         LongArray allowed = new LongArray();
         synchronized (mChanges) {
             for (int i = 0; i < mChanges.size(); ++i) {
@@ -348,7 +354,7 @@
                 }
                 OverrideAllowedState allowedState =
                         mOverrideValidator.getOverrideAllowedState(change.getId(),
-                                                                    packageName);
+                                packageName);
                 if (allowedState.state == OverrideAllowedState.ALLOWED) {
                     allowed.add(change.getId());
                 }
@@ -361,10 +367,9 @@
      * Enables all changes with enabledSinceTargetSdk == {@param targetSdkVersion} for
      * {@param packageName}.
      *
-     * @return The number of changes that were toggled.
+     * @return the number of changes that were toggled
      */
-    int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
-            throws RemoteException {
+    int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
         long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
         for (long changeId : changes) {
             addOverride(changeId, packageName, true);
@@ -372,15 +377,13 @@
         return changes.length;
     }
 
-
     /**
      * Disables all changes with enabledSinceTargetSdk == {@param targetSdkVersion} for
      * {@param packageName}.
      *
-     * @return The number of changes that were toggled.
+     * @return the number of changes that were toggled
      */
-    int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
-            throws RemoteException {
+    int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
         long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
         for (long changeId : changes) {
             addOverride(changeId, packageName, false);
@@ -425,7 +428,7 @@
     /**
      * Dumps the current list of compatibility config information.
      *
-     * @param pw The {@link PrintWriter} instance to which the information will be dumped.
+     * @param pw {@link PrintWriter} instance to which the information will be dumped
      */
     void dumpConfig(PrintWriter pw) {
         synchronized (mChanges) {
@@ -441,13 +444,10 @@
     }
 
     /**
-     * Get the config for a given app.
+     * Returns config for a given app.
      *
-     * @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped.
-     * @return A {@link CompatibilityChangeConfig} which contains the compat config info for the
-     * given app.
+     * @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped
      */
-
     CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) {
         Set<Long> enabled = new HashSet<>();
         Set<Long> disabled = new HashSet<>();
@@ -467,7 +467,7 @@
     /**
      * Dumps all the compatibility change information.
      *
-     * @return An array of {@link CompatibilityChangeInfo} with the current changes.
+     * @return an array of {@link CompatibilityChangeInfo} with the current changes
      */
     CompatibilityChangeInfo[] dumpChanges() {
         synchronized (mChanges) {
@@ -480,22 +480,6 @@
         }
     }
 
-    static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
-        CompatConfig config = new CompatConfig(androidBuildClassifier, context);
-        config.initConfigFromLib(Environment.buildPath(
-                Environment.getRootDirectory(), "etc", "compatconfig"));
-        config.initConfigFromLib(Environment.buildPath(
-                Environment.getRootDirectory(), "system_ext", "etc", "compatconfig"));
-
-        List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos();
-        for (ApexManager.ActiveApexInfo apex : apexes) {
-            config.initConfigFromLib(Environment.buildPath(
-                    apex.apexDirectory, "etc", "compatconfig"));
-        }
-        config.invalidateCache();
-        return config;
-    }
-
     void initConfigFromLib(File libraryDir) {
         if (!libraryDir.exists() || !libraryDir.isDirectory()) {
             Slog.d(TAG, "No directory " + libraryDir + ", skipping");
@@ -526,6 +510,7 @@
     private void invalidateCache() {
         ChangeIdStateCache.invalidate();
     }
+
     /**
      * Rechecks all the existing overrides for a package.
      */
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 1ea468c..6b2a1c9 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -63,45 +63,43 @@
     private final ChangeReporter mChangeReporter;
     private final CompatConfig mCompatConfig;
 
-    private static int sMinTargetSdk = Build.VERSION_CODES.Q;
-
     public PlatformCompat(Context context) {
         mContext = context;
-        mChangeReporter = new ChangeReporter(
-                ChangeReporter.SOURCE_SYSTEM_SERVER);
+        mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
         mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
     }
 
     @VisibleForTesting
     PlatformCompat(Context context, CompatConfig compatConfig) {
         mContext = context;
-        mChangeReporter = new ChangeReporter(
-                ChangeReporter.SOURCE_SYSTEM_SERVER);
+        mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER);
         mCompatConfig = compatConfig;
+
         registerPackageReceiver(context);
     }
 
     @Override
     public void reportChange(long changeId, ApplicationInfo appInfo) {
-        checkCompatChangeLogPermission();
-        reportChange(changeId, appInfo.uid,
-                ChangeReporter.STATE_LOGGED);
+        reportChangeByUid(changeId, appInfo.uid);
     }
 
     @Override
-    public void reportChangeByPackageName(long changeId, String packageName, int userId) {
-        checkCompatChangeLogPermission();
+    public void reportChangeByPackageName(long changeId, String packageName,
+            @UserIdInt int userId) {
         ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
-        if (appInfo == null) {
-            return;
+        if (appInfo != null) {
+            reportChangeByUid(changeId, appInfo.uid);
         }
-        reportChange(changeId, appInfo);
     }
 
     @Override
     public void reportChangeByUid(long changeId, int uid) {
         checkCompatChangeLogPermission();
-        reportChange(changeId, uid, ChangeReporter.STATE_LOGGED);
+        reportChangeInternal(changeId, uid, ChangeReporter.STATE_LOGGED);
+    }
+
+    private void reportChangeInternal(long changeId, int uid, int state) {
+        mChangeReporter.reportChange(uid, changeId, state);
     }
 
     @Override
@@ -110,28 +108,6 @@
         return isChangeEnabledInternal(changeId, appInfo);
     }
 
-    /**
-     * Internal version of the above method, without logging. Does not perform costly permission
-     * check.
-     * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property.
-     */
-    public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) {
-        return mCompatConfig.isChangeEnabled(changeId, appInfo);
-    }
-
-    /**
-     * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. Does not perform costly
-     * permission check.
-     */
-    public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
-        boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo);
-        if (appInfo != null) {
-            reportChange(changeId, appInfo.uid,
-                    enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
-        }
-        return enabled;
-    }
-
     @Override
     public boolean isChangeEnabledByPackageName(long changeId, String packageName,
             @UserIdInt int userId) {
@@ -140,7 +116,7 @@
         if (appInfo == null) {
             return mCompatConfig.willChangeBeEnabled(changeId, packageName);
         }
-        return isChangeEnabled(changeId, appInfo);
+        return isChangeEnabledInternal(changeId, appInfo);
     }
 
     @Override
@@ -152,81 +128,82 @@
         }
         boolean enabled = true;
         for (String packageName : packages) {
-            enabled = enabled && isChangeEnabledByPackageName(changeId, packageName,
+            enabled &= isChangeEnabledByPackageName(changeId, packageName,
                     UserHandle.getUserId(uid));
         }
         return enabled;
     }
 
     /**
-     * Register a listener for change state overrides. Only one listener per change is allowed.
+     * Internal version of the above method, without logging.
      *
-     * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
-     * packageName before the app is killed upon an override change. The state of a change is not
-     * guaranteed to change when {@code listener.onCompatChange(String)} is called.
-     *
-     * @param changeId to get updates for
-     * @param listener the listener that will be called upon a potential change for package.
-     * @throws IllegalStateException if a listener was already registered for changeId
-     * @returns {@code true} if a change with changeId was already known, or (@code false}
-     * otherwise.
+     * <p>Does not perform costly permission check.
+     * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property.
      */
-    public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
-        return mCompatConfig.registerListener(changeId, listener);
+    public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) {
+        return mCompatConfig.isChangeEnabled(changeId, appInfo);
+    }
+
+    /**
+     * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}.
+     *
+     * <p>Does not perform costly permission check.
+     */
+    public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
+        boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo);
+        if (appInfo != null) {
+            reportChangeInternal(changeId, appInfo.uid,
+                    enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
+        }
+        return enabled;
     }
 
     @Override
-    public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
-            throws RemoteException, SecurityException {
+    public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
         checkCompatChangeOverridePermission();
         mCompatConfig.addOverrides(overrides, packageName);
         killPackage(packageName);
     }
 
     @Override
-    public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
-            throws RemoteException, SecurityException {
+    public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
         checkCompatChangeOverridePermission();
         mCompatConfig.addOverrides(overrides, packageName);
     }
 
     @Override
-    public int enableTargetSdkChanges(String packageName, int targetSdkVersion)
-            throws RemoteException, SecurityException {
+    public int enableTargetSdkChanges(String packageName, int targetSdkVersion) {
         checkCompatChangeOverridePermission();
-        int numChanges = mCompatConfig.enableTargetSdkChangesForPackage(packageName,
-                                                                        targetSdkVersion);
+        int numChanges =
+                mCompatConfig.enableTargetSdkChangesForPackage(packageName, targetSdkVersion);
         killPackage(packageName);
         return numChanges;
     }
 
     @Override
-    public int disableTargetSdkChanges(String packageName, int targetSdkVersion)
-            throws RemoteException, SecurityException {
+    public int disableTargetSdkChanges(String packageName, int targetSdkVersion) {
         checkCompatChangeOverridePermission();
-        int numChanges = mCompatConfig.disableTargetSdkChangesForPackage(packageName,
-                                                                         targetSdkVersion);
+        int numChanges =
+                mCompatConfig.disableTargetSdkChangesForPackage(packageName, targetSdkVersion);
         killPackage(packageName);
         return numChanges;
     }
 
     @Override
-    public void clearOverrides(String packageName) throws RemoteException, SecurityException {
+    public void clearOverrides(String packageName) {
         checkCompatChangeOverridePermission();
         mCompatConfig.removePackageOverrides(packageName);
         killPackage(packageName);
     }
 
     @Override
-    public void clearOverridesForTest(String packageName)
-            throws RemoteException, SecurityException {
+    public void clearOverridesForTest(String packageName) {
         checkCompatChangeOverridePermission();
         mCompatConfig.removePackageOverrides(packageName);
     }
 
     @Override
-    public boolean clearOverride(long changeId, String packageName)
-            throws RemoteException, SecurityException {
+    public boolean clearOverride(long changeId, String packageName) {
         checkCompatChangeOverridePermission();
         boolean existed = mCompatConfig.removeOverride(changeId, packageName);
         killPackage(packageName);
@@ -234,6 +211,12 @@
     }
 
     @Override
+    public void clearOverrideForTest(long changeId, String packageName) {
+        checkCompatChangeOverridePermission();
+        mCompatConfig.removeOverride(changeId, packageName);
+    }
+
+    @Override
     public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
         checkCompatChangeReadAndLogPermission();
         return mCompatConfig.getAppConfig(appInfo);
@@ -247,18 +230,13 @@
 
     @Override
     public CompatibilityChangeInfo[] listUIChanges() {
-        return Arrays.stream(listAllChanges()).filter(
-                x -> isShownInUI(x)).toArray(CompatibilityChangeInfo[]::new);
+        return Arrays.stream(listAllChanges()).filter(this::isShownInUI).toArray(
+                CompatibilityChangeInfo[]::new);
     }
 
-    /**
-     * Check whether the change is known to the compat config.
-     *
-     * @return {@code true} if the change is known.
-     */
+    /** Checks whether the change is known to the compat config. */
     public boolean isKnownChangeId(long changeId) {
         return mCompatConfig.isKnownChangeId(changeId);
-
     }
 
     /**
@@ -286,7 +264,9 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
+        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) {
+            return;
+        }
         checkCompatChangeReadAndLogPermission();
         mCompatConfig.dumpConfig(pw);
     }
@@ -298,7 +278,8 @@
 
     /**
      * Clears information stored about events reported on behalf of an app.
-     * To be called once upon app start or end. A second call would be a no-op.
+     *
+     * <p>To be called once upon app start or end. A second call would be a no-op.
      *
      * @param appInfo the app to reset
      */
@@ -311,13 +292,9 @@
                 packageName, 0, userId, userId);
     }
 
-    private void reportChange(long changeId, int uid, int state) {
-        mChangeReporter.reportChange(uid, changeId, state);
-    }
-
     private void killPackage(String packageName) {
         int uid = LocalServices.getService(PackageManagerInternal.class).getPackageUid(packageName,
-                    0, UserHandle.myUserId());
+                0, UserHandle.myUserId());
 
         if (uid < 0) {
             Slog.w(TAG, "Didn't find package " + packageName + " on device.");
@@ -325,21 +302,18 @@
         }
 
         Slog.d(TAG, "Killing package " + packageName + " (UID " + uid + ").");
-        killUid(UserHandle.getAppId(uid),
-                UserHandle.USER_ALL, "PlatformCompat overrides");
+        killUid(UserHandle.getAppId(uid));
     }
 
-    private void killUid(int appId, int userId, String reason) {
+    private void killUid(int appId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             IActivityManager am = ActivityManager.getService();
             if (am != null) {
-                try {
-                    am.killUid(appId, userId, reason);
-                } catch (RemoteException e) {
-                    /* ignore - same process */
-                }
+                am.killUid(appId, UserHandle.USER_ALL, "PlatformCompat overrides");
             }
+        } catch (RemoteException e) {
+            /* ignore - same process */
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -350,13 +324,12 @@
         if (Binder.getCallingUid() == SYSTEM_UID) {
             return;
         }
-        if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE)
-                != PERMISSION_GRANTED) {
+        if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE) != PERMISSION_GRANTED) {
             throw new SecurityException("Cannot log compat change usage");
         }
     }
 
-    private void checkCompatChangeReadPermission() throws SecurityException {
+    private void checkCompatChangeReadPermission() {
         // Don't check for permissions within the system process
         if (Binder.getCallingUid() == SYSTEM_UID) {
             return;
@@ -367,7 +340,7 @@
         }
     }
 
-    private void checkCompatChangeOverridePermission() throws SecurityException {
+    private void checkCompatChangeOverridePermission() {
         // Don't check for permissions within the system process
         if (Binder.getCallingUid() == SYSTEM_UID) {
             return;
@@ -378,7 +351,7 @@
         }
     }
 
-    private void checkCompatChangeReadAndLogPermission() throws SecurityException {
+    private void checkCompatChangeReadAndLogPermission() {
         checkCompatChangeReadPermission();
         checkCompatChangeLogPermission();
     }
@@ -391,16 +364,34 @@
             return false;
         }
         if (change.getEnableSinceTargetSdk() > 0) {
-            if (change.getEnableSinceTargetSdk() < sMinTargetSdk) {
-                return false;
-            }
+            return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q;
         }
         return true;
     }
 
     /**
+     * Registers a listener for change state overrides.
+     *
+     * <p>Only one listener per change is allowed.
+     *
+     * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
+     * packageName before the app is killed upon an override change. The state of a change is not
+     * guaranteed to change when {@code listener.onCompatChange(String)} is called.
+     *
+     * @param changeId to get updates for
+     * @param listener the listener that will be called upon a potential change for package
+     * @return {@code true} if a change with changeId was already known, or (@code false}
+     * otherwise
+     * @throws IllegalStateException if a listener was already registered for changeId
+     */
+    public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
+        return mCompatConfig.registerListener(changeId, listener);
+    }
+
+    /**
      * Registers a broadcast receiver that listens for package install, replace or remove.
-     * @param context the context where the receiver should be registered.
+     *
+     * @param context the context where the receiver should be registered
      */
     public void registerPackageReceiver(Context context) {
         final BroadcastReceiver receiver = new BroadcastReceiver() {
@@ -429,8 +420,8 @@
     }
 
     /**
-     * Register the observer for
-     * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT}
+     * Registers the observer for
+     * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT}.
      */
     public void registerContentObserver() {
         mCompatConfig.registerContentObserver();
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 1024556..26244e6 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -368,6 +368,7 @@
 
         @Override
         public void logDefaultNetworkValidity(boolean valid) {
+            NetworkStack.checkNetworkStackPermission(getContext());
             mDefaultNetworkMetrics.logDefaultNetworkValidity(SystemClock.elapsedRealtime(), valid);
         }
 
@@ -375,6 +376,7 @@
         public void logDefaultNetworkEvent(Network defaultNetwork, int score, boolean validated,
                 LinkProperties lp, NetworkCapabilities nc, Network previousDefaultNetwork,
                 int previousScore, LinkProperties previousLp, NetworkCapabilities previousNc) {
+            NetworkStack.checkNetworkStackPermission(getContext());
             final long timeMs = SystemClock.elapsedRealtime();
             mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, defaultNetwork, score, validated,
                     lp, nc,  previousDefaultNetwork, previousScore, previousLp, previousNc);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index c1b1b6a..952193b 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -246,11 +246,6 @@
             return;
         }
 
-        if (mNetwork.linkProperties == null) {
-            Log.e(TAG, "startClat: Can't start clat with null LinkProperties");
-            return;
-        }
-
         String baseIface = mNetwork.linkProperties.getInterfaceName();
         if (baseIface == null) {
             Log.e(TAG, "startClat: Can't start clat on null interface");
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index b0a73f1..e3663ba 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -37,7 +37,6 @@
 import android.net.NetworkRequest;
 import android.net.NetworkState;
 import android.net.TcpKeepalivePacketData;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
@@ -53,7 +52,6 @@
 import com.android.server.ConnectivityService;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
@@ -136,12 +134,12 @@
     // This Network object should always be used if possible, so as to encourage reuse of the
     // enclosed socket factory and connection pool.  Avoid creating other Network objects.
     // This Network object is always valid.
-    public final Network network;
-    public LinkProperties linkProperties;
+    @NonNull public final Network network;
+    @NonNull public LinkProperties linkProperties;
     // This should only be modified by ConnectivityService, via setNetworkCapabilities().
     // TODO: make this private with a getter.
-    public NetworkCapabilities networkCapabilities;
-    public final NetworkAgentConfig networkAgentConfig;
+    @NonNull public NetworkCapabilities networkCapabilities;
+    @NonNull public final NetworkAgentConfig networkAgentConfig;
 
     // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
     // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
@@ -329,6 +327,12 @@
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
             IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
             int creatorUid) {
+        Objects.requireNonNull(net);
+        Objects.requireNonNull(info);
+        Objects.requireNonNull(lp);
+        Objects.requireNonNull(nc);
+        Objects.requireNonNull(context);
+        Objects.requireNonNull(config);
         networkAgent = na;
         network = net;
         networkInfo = info;
@@ -536,19 +540,22 @@
         }
 
         @Override
-        public void sendNetworkCapabilities(NetworkCapabilities nc) {
+        public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) {
+            Objects.requireNonNull(nc);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget();
         }
 
         @Override
-        public void sendLinkProperties(LinkProperties lp) {
+        public void sendLinkProperties(@NonNull LinkProperties lp) {
+            Objects.requireNonNull(lp);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget();
         }
 
         @Override
-        public void sendNetworkInfo(NetworkInfo info) {
+        public void sendNetworkInfo(@NonNull NetworkInfo info) {
+            Objects.requireNonNull(info);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, info)).sendToTarget();
         }
@@ -574,16 +581,8 @@
 
         @Override
         public void sendUnderlyingNetworks(@Nullable List<Network> networks) {
-            final Bundle args = new Bundle();
-            if (networks instanceof ArrayList<?>) {
-                args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY,
-                        (ArrayList<Network>) networks);
-            } else {
-                args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY,
-                        networks == null ? null : new ArrayList<>(networks));
-            }
             mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED,
-                    new Pair<>(NetworkAgentInfo.this, args)).sendToTarget();
+                    new Pair<>(NetworkAgentInfo.this, networks)).sendToTarget();
         }
     }
 
@@ -603,7 +602,7 @@
      *
      * @return the old capabilities of this network.
      */
-    public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
+    @NonNull public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
             @NonNull final NetworkCapabilities nc) {
         final NetworkCapabilities oldNc = networkCapabilities;
         networkCapabilities = nc;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a65f809..fb1e819 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -439,6 +439,11 @@
         mEnableTeardown = enableTeardown;
     }
 
+    @VisibleForTesting
+    public boolean getEnableTeardown() {
+        return mEnableTeardown;
+    }
+
     /**
      * Update current state, dispatching event to listeners.
      */
@@ -2146,6 +2151,11 @@
 
         // Start a new LegacyVpnRunner and we are done!
         mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile);
+        startLegacyVpnRunner();
+    }
+
+    @VisibleForTesting
+    protected void startLegacyVpnRunner() {
         mVpnRunner.start();
     }
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index d003b89..c005af4 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -89,6 +89,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
+import android.security.Authorization;
 import android.security.KeyStore;
 import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyProperties;
@@ -1272,6 +1273,7 @@
 
     private void unlockKeystore(byte[] password, int userHandle) {
         if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
+        new Authorization().onLockScreenEvent(false, userHandle, password);
         // TODO(b/120484642): Update keystore to accept byte[] passwords
         String passwordString = password == null ? null : new String(password);
         final KeyStore ks = KeyStore.getInstance();
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index f882c57..edc9d7c 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -77,7 +77,7 @@
     @NonNull
     public List<RoutingSessionInfo> getSessionInfos() {
         synchronized (mLock) {
-            return mSessionInfos;
+            return new ArrayList<>(mSessionInfos);
         }
     }
 
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 85af346..ab38dca 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -108,8 +108,8 @@
         mLastDiscoveryPreference = discoveryPreference;
         if (mConnectionReady) {
             mActiveConnection.updateDiscoveryPreference(discoveryPreference);
-            updateBinding();
         }
+        updateBinding();
     }
 
     @Override
@@ -205,9 +205,11 @@
     }
 
     private boolean shouldBind() {
-        //TODO: Binding could be delayed until it's necessary.
         if (mRunning) {
-            return true;
+            // Bind when there is a discovery preference or an active route session.
+            return (mLastDiscoveryPreference != null
+                    && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty())
+                    || !getSessionInfos().isEmpty();
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 1114fe0..31edf43 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.media;
 
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
 import static android.media.MediaRouter2Utils.getOriginalId;
 import static android.media.MediaRouter2Utils.getProviderId;
@@ -73,10 +74,12 @@
     // TODO: (In Android S or later) if we add callback methods for generic failures
     //       in MediaRouter2, remove this constant and replace the usages with the real request IDs.
     private static final long DUMMY_REQUEST_ID = -1;
+    private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND;
 
     private final Context mContext;
     private final Object mLock = new Object();
     final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
+    final ActivityManager mActivityManager;
 
     @GuardedBy("mLock")
     private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
@@ -87,8 +90,21 @@
     @GuardedBy("mLock")
     private int mCurrentUserId = -1;
 
+    private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
+            (uid, importance) -> {
+                synchronized (mLock) {
+                    final int count = mUserRecords.size();
+                    for (int i = 0; i < count; i++) {
+                        mUserRecords.valueAt(i).mHandler.maybeUpdateDiscoveryPreferenceForUid(uid);
+                    }
+                }
+            };
+
     MediaRouter2ServiceImpl(Context context) {
         mContext = context;
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
+        mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener,
+                PACKAGE_IMPORTANCE_FOR_DISCOVERY);
     }
 
     ////////////////////////////////////////////////////////////////
@@ -388,6 +404,30 @@
         }
     }
 
+    public void startScan(IMediaRouter2Manager manager) {
+        Objects.requireNonNull(manager, "manager must not be null");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                startScanLocked(manager);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    public void stopScan(IMediaRouter2Manager manager) {
+        Objects.requireNonNull(manager, "manager must not be null");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                stopScanLocked(manager);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
             MediaRoute2Info route, int volume) {
         Objects.requireNonNull(manager, "manager must not be null");
@@ -839,6 +879,24 @@
         disposeUserIfNeededLocked(userRecord); // since manager removed from user
     }
 
+    private void startScanLocked(@NonNull IMediaRouter2Manager manager) {
+        final IBinder binder = manager.asBinder();
+        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+        if (managerRecord == null) {
+            return;
+        }
+        managerRecord.startScan();
+    }
+
+    private void stopScanLocked(@NonNull IMediaRouter2Manager manager) {
+        final IBinder binder = manager.asBinder();
+        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+        if (managerRecord == null) {
+            return;
+        }
+        managerRecord.stopScan();
+    }
+
     private void setRouteVolumeWithManagerLocked(int requestId,
             @NonNull IMediaRouter2Manager manager,
             @NonNull MediaRoute2Info route, int volume) {
@@ -1122,6 +1180,7 @@
         public final String mPackageName;
         public final int mManagerId;
         public SessionCreationRequest mLastSessionCreationRequest;
+        public boolean mIsScanning;
 
         ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
                 int uid, int pid, String packageName) {
@@ -1146,6 +1205,24 @@
             pw.println(prefix + this);
         }
 
+        public void startScan() {
+            if (mIsScanning) {
+                return;
+            }
+            mIsScanning = true;
+            mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage(
+                    UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
+        }
+
+        public void stopScan() {
+            if (!mIsScanning) {
+                return;
+            }
+            mIsScanning = false;
+            mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage(
+                    UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
+        }
+
         @Override
         public String toString() {
             return "Manager " + mPackageName + " (pid " + mPid + ")";
@@ -1262,6 +1339,24 @@
             return null;
         }
 
+        public void maybeUpdateDiscoveryPreferenceForUid(int uid) {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return;
+            }
+            boolean isUidRelevant;
+            synchronized (service.mLock) {
+                isUidRelevant = mUserRecord.mRouterRecords.stream().anyMatch(
+                        router -> router.mUid == uid)
+                        | mUserRecord.mManagerRecords.stream().anyMatch(
+                            manager -> manager.mUid == uid);
+            }
+            if (isUidRelevant) {
+                sendMessage(PooledLambda.obtainMessage(
+                        UserHandler::updateDiscoveryPreferenceOnHandler, this));
+            }
+        }
+
         private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
             int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
             MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
@@ -1767,6 +1862,16 @@
             return managers;
         }
 
+        private List<RouterRecord> getRouterRecords() {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return Collections.emptyList();
+            }
+            synchronized (service.mLock) {
+                return new ArrayList<>(mUserRecord.mRouterRecords);
+            }
+        }
+
         private List<ManagerRecord> getManagerRecords() {
             MediaRouter2ServiceImpl service = mServiceRef.get();
             if (service == null) {
@@ -2001,13 +2106,28 @@
                 return;
             }
             List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>();
-            synchronized (service.mLock) {
-                for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
+            List<RouterRecord> routerRecords = getRouterRecords();
+            List<ManagerRecord> managerRecords = getManagerRecords();
+            boolean isAnyManagerScanning =
+                    managerRecords.stream().anyMatch(manager -> manager.mIsScanning
+                    && service.mActivityManager.getPackageImportance(manager.mPackageName)
+                    <= PACKAGE_IMPORTANCE_FOR_DISCOVERY);
+
+            for (RouterRecord routerRecord : routerRecords) {
+                if (isAnyManagerScanning
+                        || service.mActivityManager.getPackageImportance(routerRecord.mPackageName)
+                        <= PACKAGE_IMPORTANCE_FOR_DISCOVERY) {
                     discoveryPreferences.add(routerRecord.mDiscoveryPreference);
                 }
-                mUserRecord.mCompositeDiscoveryPreference =
-                        new RouteDiscoveryPreference.Builder(discoveryPreferences)
-                                .build();
+            }
+
+            synchronized (service.mLock) {
+                RouteDiscoveryPreference newPreference =
+                        new RouteDiscoveryPreference.Builder(discoveryPreferences).build();
+                if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) {
+                    return;
+                }
+                mUserRecord.mCompositeDiscoveryPreference = newPreference;
             }
             for (MediaRoute2Provider provider : mRouteProviders) {
                 provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 0e52a67..b6d6cc4 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -544,6 +544,18 @@
 
     // Binder call
     @Override
+    public void startScan(IMediaRouter2Manager manager) {
+        mService2.startScan(manager);
+    }
+
+    // Binder call
+    @Override
+    public void stopScan(IMediaRouter2Manager manager) {
+        mService2.stopScan(manager);
+    }
+
+    // Binder call
+    @Override
     public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
             MediaRoute2Info route, int volume) {
         mService2.setRouteVolumeWithManager(manager, requestId, route, volume);
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index ea1d8da..ea2788c 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -34,7 +34,6 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
 import android.os.Handler;
-import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
@@ -70,6 +69,7 @@
     @NonNull private final Handler mHandler;
     @NonNull private final Vpn mVpn;
     @NonNull private final VpnProfile mProfile;
+    @NonNull private final KeyStore mKeyStore;
 
     @NonNull private final Object mStateLock = new Object();
 
@@ -81,13 +81,10 @@
 
     private int mErrorCount;
 
-    public static boolean isEnabled() {
-        return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN);
-    }
-
     public LockdownVpnTracker(@NonNull Context context,
             @NonNull ConnectivityService connService,
             @NonNull Handler handler,
+            @NonNull KeyStore keyStore,
             @NonNull Vpn vpn,
             @NonNull VpnProfile profile) {
         mContext = Objects.requireNonNull(context);
@@ -95,6 +92,7 @@
         mHandler = Objects.requireNonNull(handler);
         mVpn = Objects.requireNonNull(vpn);
         mProfile = Objects.requireNonNull(profile);
+        mKeyStore = Objects.requireNonNull(keyStore);
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
 
         final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
@@ -157,7 +155,7 @@
                 try {
                     // Use the privileged method because Lockdown VPN is initiated by the system, so
                     // no additional permission checks are necessary.
-                    mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp);
+                    mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, egressProp);
                 } catch (IllegalStateException e) {
                     mAcceptedEgressIface = null;
                     Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 0f8c9c7..fc56541 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -24,11 +24,15 @@
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_REASON;
+import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_DISABLED;
+import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_ENABLED;
 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
 import static android.os.Trace.TRACE_TAG_RRO;
 import static android.os.Trace.traceBegin;
 import static android.os.Trace.traceEnd;
 
+import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -39,6 +43,7 @@
 import android.content.IntentFilter;
 import android.content.om.IOverlayManager;
 import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
 import android.content.om.OverlayableInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
@@ -48,6 +53,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -64,7 +70,6 @@
 
 import com.android.internal.content.om.OverlayConfig;
 import com.android.server.FgThread;
-import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
@@ -82,12 +87,15 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
 
 /**
  * Service to manage asset overlays.
@@ -236,7 +244,14 @@
 
     private final OverlayActorEnforcer mActorEnforcer;
 
-    private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
+    private final Consumer<PackageAndUser> mPropagateOverlayChange = (pair) -> {
+        persistSettings();
+        FgThread.getHandler().post(() -> {
+            List<String> affectedTargets = updatePackageManager(pair.packageName, pair.userId);
+            updateActivityManager(affectedTargets, pair.userId);
+            broadcastActionOverlayChanged(pair.packageName, pair.userId);
+        });
+    };
 
     public OverlayManagerService(@NonNull final Context context) {
         super(context);
@@ -249,17 +264,19 @@
             IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager);
             mSettings = new OverlayManagerSettings();
             mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
-                    OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
-                    new OverlayChangeListener());
+                    OverlayConfig.getSystemInstance(), getDefaultOverlayPackages());
             mActorEnforcer = new OverlayActorEnforcer(mPackageManager);
 
+            HandlerThread packageReceiverThread = new HandlerThread(TAG);
+            packageReceiverThread.start();
+
             final IntentFilter packageFilter = new IntentFilter();
             packageFilter.addAction(ACTION_PACKAGE_ADDED);
             packageFilter.addAction(ACTION_PACKAGE_CHANGED);
             packageFilter.addAction(ACTION_PACKAGE_REMOVED);
             packageFilter.addDataScheme("package");
             getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
-                    packageFilter, null, null);
+                    packageFilter, null, packageReceiverThread.getThreadHandler());
 
             final IntentFilter userFilter = new IntentFilter();
             userFilter.addAction(ACTION_USER_ADDED);
@@ -292,11 +309,11 @@
             for (int i = 0; i < userCount; i++) {
                 final UserInfo userInfo = users.get(i);
                 if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
-                    // Initialize any users that can't be switched to, as there state would
+                    // Initialize any users that can't be switched to, as their state would
                     // never be setup in onSwitchUser(). We will switch to the system user right
                     // after this, and its state will be setup there.
                     final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
-                    updateOverlayPaths(users.get(i).id, targets);
+                    updatePackageManager(targets, users.get(i).id);
                 }
             }
         }
@@ -310,9 +327,10 @@
             // any asset changes to the rest of the system
             synchronized (mLock) {
                 final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
-                updateAssets(newUserId, targets);
+                final List<String> affectedTargets = updatePackageManager(targets, newUserId);
+                updateActivityManager(affectedTargets, newUserId);
             }
-            schedulePersistSettings();
+            persistSettings();
         } finally {
             traceEnd(TRACE_TAG_RRO);
         }
@@ -396,10 +414,17 @@
                                 false);
                         if (pi != null && !pi.applicationInfo.isInstantApp()) {
                             mPackageManager.cachePackageInfo(packageName, userId, pi);
-                            if (pi.isOverlayPackage()) {
-                                mImpl.onOverlayPackageAdded(packageName, userId);
-                            } else {
-                                mImpl.onTargetPackageAdded(packageName, userId);
+
+                            try {
+                                if (pi.isOverlayPackage()) {
+                                    mImpl.onOverlayPackageAdded(packageName, userId)
+                                        .ifPresent(mPropagateOverlayChange);
+                                } else {
+                                    mImpl.onTargetPackageAdded(packageName, userId)
+                                        .ifPresent(mPropagateOverlayChange);
+                                }
+                            } catch (OperationFailedException e) {
+                                Slog.e(TAG, "onPackageAdded internal error", e);
                             }
                         }
                     }
@@ -419,10 +444,17 @@
                                 false);
                         if (pi != null && pi.applicationInfo.isInstantApp()) {
                             mPackageManager.cachePackageInfo(packageName, userId, pi);
-                            if (pi.isOverlayPackage()) {
-                                mImpl.onOverlayPackageChanged(packageName, userId);
-                            }  else {
-                                mImpl.onTargetPackageChanged(packageName, userId);
+
+                            try {
+                                if (pi.isOverlayPackage()) {
+                                    mImpl.onOverlayPackageChanged(packageName, userId)
+                                        .ifPresent(mPropagateOverlayChange);
+                                }  else {
+                                    mImpl.onTargetPackageChanged(packageName, userId)
+                                        .ifPresent(mPropagateOverlayChange);
+                                }
+                            } catch (OperationFailedException e) {
+                                Slog.e(TAG, "onPackageChanged internal error", e);
                             }
                         }
                     }
@@ -441,7 +473,12 @@
                         mPackageManager.forgetPackageInfo(packageName, userId);
                         final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
                         if (oi != null) {
-                            mImpl.onOverlayPackageReplacing(packageName, userId);
+                            try {
+                                mImpl.onOverlayPackageReplacing(packageName, userId)
+                                    .ifPresent(mPropagateOverlayChange);
+                            } catch (OperationFailedException e) {
+                                Slog.e(TAG, "onPackageReplacing internal error", e);
+                            }
                         }
                     }
                 }
@@ -460,10 +497,16 @@
                                 false);
                         if (pi != null && !pi.applicationInfo.isInstantApp()) {
                             mPackageManager.cachePackageInfo(packageName, userId, pi);
-                            if (pi.isOverlayPackage()) {
-                                mImpl.onOverlayPackageReplaced(packageName, userId);
-                            } else {
-                                mImpl.onTargetPackageReplaced(packageName, userId);
+                            try {
+                                if (pi.isOverlayPackage()) {
+                                    mImpl.onOverlayPackageReplaced(packageName, userId)
+                                        .ifPresent(mPropagateOverlayChange);
+                                } else {
+                                    mImpl.onTargetPackageReplaced(packageName, userId)
+                                        .ifPresent(mPropagateOverlayChange);
+                                }
+                            } catch (OperationFailedException e) {
+                                Slog.e(TAG, "onPackageReplaced internal error", e);
                             }
                         }
                     }
@@ -481,10 +524,17 @@
                     synchronized (mLock) {
                         mPackageManager.forgetPackageInfo(packageName, userId);
                         final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
-                        if (oi != null) {
-                            mImpl.onOverlayPackageRemoved(packageName, userId);
-                        } else {
-                            mImpl.onTargetPackageRemoved(packageName, userId);
+
+                        try {
+                            if (oi != null) {
+                                mImpl.onOverlayPackageRemoved(packageName, userId)
+                                    .ifPresent(mPropagateOverlayChange);
+                            } else {
+                                mImpl.onTargetPackageRemoved(packageName, userId)
+                                    .ifPresent(mPropagateOverlayChange);
+                            }
+                        } catch (OperationFailedException e) {
+                            Slog.e(TAG, "onPackageRemoved internal error", e);
                         }
                     }
                 }
@@ -507,7 +557,7 @@
                             synchronized (mLock) {
                                 targets = mImpl.updateOverlaysForUser(userId);
                             }
-                            updateOverlayPaths(userId, targets);
+                            updatePackageManager(targets, userId);
                         } finally {
                             traceEnd(TRACE_TAG_RRO);
                         }
@@ -602,7 +652,13 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setEnabled(packageName, enable, realUserId);
+                        try {
+                            mImpl.setEnabled(packageName, enable, realUserId)
+                                .ifPresent(mPropagateOverlayChange);
+                            return true;
+                        } catch (OperationFailedException e) {
+                            return false;
+                        }
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -627,8 +683,14 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
-                                realUserId);
+                        try {
+                            mImpl.setEnabledExclusive(packageName,
+                                    false /* withinCategory */, realUserId)
+                                .ifPresent(mPropagateOverlayChange);
+                            return true;
+                        } catch (OperationFailedException e) {
+                            return false;
+                        }
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -654,8 +716,14 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
-                                realUserId);
+                        try {
+                            mImpl.setEnabledExclusive(packageName,
+                                    true /* withinCategory */, realUserId)
+                                .ifPresent(mPropagateOverlayChange);
+                            return true;
+                        } catch (OperationFailedException e) {
+                            return false;
+                        }
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -681,7 +749,13 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setPriority(packageName, parentPackageName, realUserId);
+                        try {
+                            mImpl.setPriority(packageName, parentPackageName, realUserId)
+                                .ifPresent(mPropagateOverlayChange);
+                            return true;
+                        } catch (OperationFailedException e) {
+                            return false;
+                        }
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -705,7 +779,13 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setHighestPriority(packageName, realUserId);
+                        try {
+                            mImpl.setHighestPriority(packageName, realUserId)
+                                .ifPresent(mPropagateOverlayChange);
+                            return true;
+                        } catch (OperationFailedException e) {
+                            return false;
+                        }
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -729,7 +809,13 @@
                 final long ident = Binder.clearCallingIdentity();
                 try {
                     synchronized (mLock) {
-                        return mImpl.setLowestPriority(packageName, realUserId);
+                        try {
+                            mImpl.setLowestPriority(packageName, realUserId)
+                                .ifPresent(mPropagateOverlayChange);
+                            return true;
+                        } catch (OperationFailedException e) {
+                            return false;
+                        }
                     }
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -778,6 +864,129 @@
         }
 
         @Override
+        public void commit(@NonNull final OverlayManagerTransaction transaction)
+                throws RemoteException {
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#commit " + transaction);
+                try {
+                    executeAllRequests(transaction);
+                } catch (Exception e) {
+                    final long ident = Binder.clearCallingIdentity();
+                    try {
+                        restoreSettings();
+                    } finally {
+                        Binder.restoreCallingIdentity(ident);
+                    }
+                    Slog.d(TAG, "commit failed: " + e.getMessage(), e);
+                    throw new SecurityException("commit failed"
+                            + (DEBUG ? ": " + e.getMessage() : ""));
+                }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
+            }
+        }
+
+        private Optional<PackageAndUser> executeRequest(
+                @NonNull final OverlayManagerTransaction.Request request) throws Exception {
+            final int realUserId = handleIncomingUser(request.userId, request.typeToString());
+            enforceActor(request.packageName, request.typeToString(), realUserId);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                switch (request.type) {
+                    case TYPE_SET_ENABLED:
+                        Optional<PackageAndUser> opt1 =
+                                mImpl.setEnabled(request.packageName, true, request.userId);
+                        Optional<PackageAndUser> opt2 =
+                                mImpl.setHighestPriority(request.packageName, request.userId);
+                        // Both setEnabled and setHighestPriority affected the same
+                        // target package and user: if both return non-empty
+                        // Optionals, they are identical
+                        return opt1.isPresent() ? opt1 : opt2;
+                    case TYPE_SET_DISABLED:
+                        return mImpl.setEnabled(request.packageName, false, request.userId);
+                    default:
+                        throw new IllegalArgumentException("unsupported request: " + request);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        private void executeAllRequests(@NonNull final OverlayManagerTransaction transaction)
+                throws Exception {
+            if (DEBUG) {
+                Slog.d(TAG, "commit " + transaction);
+            }
+            if (transaction == null) {
+                throw new IllegalArgumentException("null transaction");
+            }
+
+            // map: userId -> set<package-name>: target packages of overlays in
+            // this transaction
+            SparseArray<Set<String>> transactionTargets = new SparseArray<>();
+
+            // map: userId -> set<package-name>: packages that need to reload
+            // their resources due to changes to the overlays in this
+            // transaction
+            SparseArray<List<String>> affectedPackagesToUpdate = new SparseArray<>();
+
+            synchronized (mLock) {
+
+                // execute the requests (as calling user)
+                for (final OverlayManagerTransaction.Request request : transaction) {
+                    executeRequest(request).ifPresent(target -> {
+                        Set<String> userTargets = transactionTargets.get(target.userId);
+                        if (userTargets == null) {
+                            userTargets = new ArraySet<String>();
+                            transactionTargets.put(target.userId, userTargets);
+                        }
+                        userTargets.add(target.packageName);
+                    });
+                }
+
+                // past the point of no return: the entire transaction has been
+                // processed successfully, we can no longer fail: continue as
+                // system_server
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    persistSettings();
+
+                    // inform the package manager about the new paths
+                    for (int index = 0; index < transactionTargets.size(); index++) {
+                        final int userId = transactionTargets.keyAt(index);
+                        final List<String> affectedTargets =
+                                updatePackageManager(transactionTargets.valueAt(index), userId);
+                        affectedPackagesToUpdate.put(userId, affectedTargets);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            } // synchronized (mLock)
+
+            FgThread.getHandler().post(() -> {
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    // schedule apps to refresh
+                    for (int index = 0; index < affectedPackagesToUpdate.size(); index++) {
+                        final int userId = affectedPackagesToUpdate.keyAt(index);
+                        updateActivityManager(affectedPackagesToUpdate.valueAt(index), userId);
+                    }
+
+                    // broadcast the ACTION_OVERLAY_CHANGED intents
+                    for (int index = 0; index < transactionTargets.size(); index++) {
+                        final int userId = transactionTargets.keyAt(index);
+                        for (String pkg: transactionTargets.valueAt(index)) {
+                            broadcastActionOverlayChanged(pkg, userId);
+                        }
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            });
+        }
+
+        @Override
         public void onShellCommand(@NonNull final FileDescriptor in,
                 @NonNull final FileDescriptor out, @NonNull final FileDescriptor err,
                 @NonNull final String[] args, @NonNull final ShellCallback callback,
@@ -898,162 +1107,7 @@
         }
     };
 
-    private final class OverlayChangeListener
-            implements OverlayManagerServiceImpl.OverlayChangeListener {
-        @Override
-        public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
-            schedulePersistSettings();
-            FgThread.getHandler().post(() -> {
-                updateAssets(userId, targetPackageName);
-
-                final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
-                        Uri.fromParts("package", targetPackageName, null));
-                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-
-                if (DEBUG) {
-                    Slog.d(TAG, "send broadcast " + intent);
-                }
-
-                try {
-                    ActivityManager.getService().broadcastIntentWithFeature(null, null, intent,
-                            null, null, 0, null, null, null, android.app.AppOpsManager.OP_NONE,
-                            null, false, false, userId);
-                } catch (RemoteException e) {
-                    // Intentionally left empty.
-                }
-            });
-        }
-    }
-
-    /**
-     * Updates the target packages' set of enabled overlays in PackageManager.
-     */
-    private ArrayList<String> updateOverlayPaths(int userId, List<String> targetPackageNames) {
-        try {
-            traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames);
-            if (DEBUG) {
-                Slog.d(TAG, "Updating overlay assets");
-            }
-            final PackageManagerInternal pm =
-                    LocalServices.getService(PackageManagerInternal.class);
-            final boolean updateFrameworkRes = targetPackageNames.contains("android");
-            if (updateFrameworkRes) {
-                targetPackageNames = pm.getTargetPackageNames(userId);
-            }
-
-            final Map<String, List<String>> pendingChanges =
-                    new ArrayMap<>(targetPackageNames.size());
-            synchronized (mLock) {
-                final List<String> frameworkOverlays =
-                        mImpl.getEnabledOverlayPackageNames("android", userId);
-                final int n = targetPackageNames.size();
-                for (int i = 0; i < n; i++) {
-                    final String targetPackageName = targetPackageNames.get(i);
-                    List<String> list = new ArrayList<>();
-                    if (!"android".equals(targetPackageName)) {
-                        list.addAll(frameworkOverlays);
-                    }
-                    list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
-                    pendingChanges.put(targetPackageName, list);
-                }
-            }
-
-            final HashSet<String> updatedPackages = new HashSet<>();
-            final int n = targetPackageNames.size();
-            for (int i = 0; i < n; i++) {
-                final String targetPackageName = targetPackageNames.get(i);
-                if (DEBUG) {
-                    Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
-                            + TextUtils.join(",", pendingChanges.get(targetPackageName))
-                            + "] userId=" + userId);
-                }
-
-                if (!pm.setEnabledOverlayPackages(
-                        userId, targetPackageName, pendingChanges.get(targetPackageName),
-                        updatedPackages)) {
-                    Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
-                            targetPackageName, userId));
-                }
-            }
-            return new ArrayList<>(updatedPackages);
-        } finally {
-            traceEnd(TRACE_TAG_RRO);
-        }
-    }
-
-    private void updateAssets(final int userId, final String targetPackageName) {
-        updateAssets(userId, Collections.singletonList(targetPackageName));
-    }
-
-    private void updateAssets(final int userId, List<String> targetPackageNames) {
-        final IActivityManager am = ActivityManager.getService();
-        try {
-            final ArrayList<String> updatedPaths = updateOverlayPaths(userId, targetPackageNames);
-            am.scheduleApplicationInfoChanged(updatedPaths, userId);
-        } catch (RemoteException e) {
-            // Intentionally left empty.
-        }
-    }
-
-    private void schedulePersistSettings() {
-        if (mPersistSettingsScheduled.getAndSet(true)) {
-            return;
-        }
-        IoThread.getHandler().post(() -> {
-            mPersistSettingsScheduled.set(false);
-            if (DEBUG) {
-                Slog.d(TAG, "Writing overlay settings");
-            }
-            synchronized (mLock) {
-                FileOutputStream stream = null;
-                try {
-                    stream = mSettingsFile.startWrite();
-                    mSettings.persist(stream);
-                    mSettingsFile.finishWrite(stream);
-                } catch (IOException | XmlPullParserException e) {
-                    mSettingsFile.failWrite(stream);
-                    Slog.e(TAG, "failed to persist overlay state", e);
-                }
-            }
-        });
-    }
-
-    private void restoreSettings() {
-        try {
-            traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
-            synchronized (mLock) {
-                if (!mSettingsFile.getBaseFile().exists()) {
-                    return;
-                }
-                try (FileInputStream stream = mSettingsFile.openRead()) {
-                    mSettings.restore(stream);
-
-                    // We might have data for dying users if the device was
-                    // restarted before we received USER_REMOVED. Remove data for
-                    // users that will not exist after the system is ready.
-
-                    final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
-                    final int[] liveUserIds = new int[liveUsers.size()];
-                    for (int i = 0; i < liveUsers.size(); i++) {
-                        liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
-                    }
-                    Arrays.sort(liveUserIds);
-
-                    for (int userId : mSettings.getUsers()) {
-                        if (Arrays.binarySearch(liveUserIds, userId) < 0) {
-                            mSettings.removeUser(userId);
-                        }
-                    }
-                } catch (IOException | XmlPullParserException e) {
-                    Slog.e(TAG, "failed to restore overlay state", e);
-                }
-            }
-        } finally {
-            traceEnd(TRACE_TAG_RRO);
-        }
-    }
-
-    private static final class PackageManagerHelperImpl implements PackageManagerHelper  {
+    private static final class PackageManagerHelperImpl implements PackageManagerHelper {
 
         private final Context mContext;
         private final IPackageManager mPackageManager;
@@ -1263,4 +1317,144 @@
             }
         }
     }
+
+    // Helper methods to update other parts of the system or read/write
+    // settings: these methods should never call into each other!
+
+    private void broadcastActionOverlayChanged(@NonNull final String targetPackageName,
+            final int userId) {
+        final Intent intent = new Intent(ACTION_OVERLAY_CHANGED,
+                Uri.fromParts("package", targetPackageName, null));
+        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        try {
+            ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null, null,
+                    null, android.app.AppOpsManager.OP_NONE, null, false, false, userId);
+        } catch (RemoteException e) {
+            // Intentionally left empty.
+        }
+    }
+
+    /**
+     * Tell the activity manager to tell a set of packages to reload their
+     * resources.
+     */
+    private void updateActivityManager(List<String> targetPackageNames, final int userId) {
+        final IActivityManager am = ActivityManager.getService();
+        try {
+            am.scheduleApplicationInfoChanged(targetPackageNames, userId);
+        } catch (RemoteException e) {
+            // Intentionally left empty.
+        }
+    }
+
+    private ArrayList<String> updatePackageManager(String targetPackageNames, final int userId) {
+        return updatePackageManager(Collections.singletonList(targetPackageNames), userId);
+    }
+
+    /**
+     * Updates the target packages' set of enabled overlays in PackageManager.
+     * @return the package names of affected targets (a superset of
+     *         targetPackageNames: the target themserlves and shared libraries)
+     */
+    private ArrayList<String> updatePackageManager(@NonNull Collection<String> targetPackageNames,
+            final int userId) {
+        try {
+            traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManager " + targetPackageNames);
+            if (DEBUG) {
+                Slog.d(TAG, "Update package manager about changed overlays");
+            }
+            final PackageManagerInternal pm =
+                    LocalServices.getService(PackageManagerInternal.class);
+            final boolean updateFrameworkRes = targetPackageNames.contains("android");
+            if (updateFrameworkRes) {
+                targetPackageNames = pm.getTargetPackageNames(userId);
+            }
+
+            final Map<String, List<String>> pendingChanges =
+                    new ArrayMap<>(targetPackageNames.size());
+            synchronized (mLock) {
+                final List<String> frameworkOverlays =
+                        mImpl.getEnabledOverlayPackageNames("android", userId);
+                for (final String targetPackageName : targetPackageNames) {
+                    List<String> list = new ArrayList<>();
+                    if (!"android".equals(targetPackageName)) {
+                        list.addAll(frameworkOverlays);
+                    }
+                    list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+                    pendingChanges.put(targetPackageName, list);
+                }
+            }
+
+            final HashSet<String> updatedPackages = new HashSet<>();
+            for (final String targetPackageName : targetPackageNames) {
+                if (DEBUG) {
+                    Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
+                            + TextUtils.join(",", pendingChanges.get(targetPackageName))
+                            + "] userId=" + userId);
+                }
+
+                if (!pm.setEnabledOverlayPackages(
+                        userId, targetPackageName, pendingChanges.get(targetPackageName),
+                        updatedPackages)) {
+                    Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
+                            targetPackageName, userId));
+                }
+            }
+            return new ArrayList<>(updatedPackages);
+        } finally {
+            traceEnd(TRACE_TAG_RRO);
+        }
+    }
+
+    private void persistSettings() {
+        if (DEBUG) {
+            Slog.d(TAG, "Writing overlay settings");
+        }
+        synchronized (mLock) {
+            FileOutputStream stream = null;
+            try {
+                stream = mSettingsFile.startWrite();
+                mSettings.persist(stream);
+                mSettingsFile.finishWrite(stream);
+            } catch (IOException | XmlPullParserException e) {
+                mSettingsFile.failWrite(stream);
+                Slog.e(TAG, "failed to persist overlay state", e);
+            }
+        }
+    }
+
+    private void restoreSettings() {
+        try {
+            traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
+            synchronized (mLock) {
+                if (!mSettingsFile.getBaseFile().exists()) {
+                    return;
+                }
+                try (FileInputStream stream = mSettingsFile.openRead()) {
+                    mSettings.restore(stream);
+
+                    // We might have data for dying users if the device was
+                    // restarted before we received USER_REMOVED. Remove data for
+                    // users that will not exist after the system is ready.
+
+                    final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
+                    final int[] liveUserIds = new int[liveUsers.size()];
+                    for (int i = 0; i < liveUsers.size(); i++) {
+                        liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
+                    }
+                    Arrays.sort(liveUserIds);
+
+                    for (int userId : mSettings.getUsers()) {
+                        if (Arrays.binarySearch(liveUserIds, userId) < 0) {
+                            mSettings.removeUser(userId);
+                        }
+                    }
+                } catch (IOException | XmlPullParserException e) {
+                    Slog.e(TAG, "failed to restore overlay state", e);
+                }
+            }
+        } finally {
+            traceEnd(TRACE_TAG_RRO);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 05a4a38..e60411bb 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -45,6 +45,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 
 /**
@@ -71,7 +72,6 @@
     private final OverlayManagerSettings mSettings;
     private final OverlayConfig mOverlayConfig;
     private final String[] mDefaultOverlays;
-    private final OverlayChangeListener mListener;
 
     /**
      * Helper method to merge the overlay manager's (as read from overlays.xml)
@@ -114,14 +114,12 @@
             @NonNull final IdmapManager idmapManager,
             @NonNull final OverlayManagerSettings settings,
             @NonNull final OverlayConfig overlayConfig,
-            @NonNull final String[] defaultOverlays,
-            @NonNull final OverlayChangeListener listener) {
+            @NonNull final String[] defaultOverlays) {
         mPackageManager = packageManager;
         mIdmapManager = idmapManager;
         mSettings = settings;
         mOverlayConfig = overlayConfig;
         mDefaultOverlays = defaultOverlays;
-        mListener = listener;
     }
 
     /**
@@ -259,52 +257,58 @@
         mSettings.removeUser(userId);
     }
 
-    void onTargetPackageAdded(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onTargetPackageAdded(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
         }
 
-        updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+        return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
     }
 
-    void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onTargetPackageChanged(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
         }
 
-        updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+        return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
     }
 
-    void onTargetPackageReplacing(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onTargetPackageReplacing(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onTargetPackageReplacing packageName=" + packageName + " userId="
                     + userId);
         }
 
-        updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+        return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
     }
 
-    void onTargetPackageReplaced(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onTargetPackageReplaced(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onTargetPackageReplaced packageName=" + packageName + " userId=" + userId);
         }
 
-        updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+        return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
     }
 
-    void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onTargetPackageRemoved(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
         }
 
-        updateAndRefreshOverlaysForTarget(packageName, userId, 0);
+        return updateAndRefreshOverlaysForTarget(packageName, userId, 0);
     }
 
     /**
      * Update the state of any overlays for this target.
      */
-    private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName,
-            final int userId, final int flags) {
+    private Optional<PackageAndUser> updateAndRefreshOverlaysForTarget(
+            @NonNull final String targetPackageName, final int userId, final int flags)
+            throws OperationFailedException {
         final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName,
                 userId);
 
@@ -364,11 +368,13 @@
         }
 
         if (modified) {
-            mListener.onOverlaysChanged(targetPackageName, userId);
+            return Optional.of(new PackageAndUser(targetPackageName, userId));
         }
+        return Optional.empty();
     }
 
-    void onOverlayPackageAdded(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onOverlayPackageAdded(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onOverlayPackageAdded packageName=" + packageName + " userId=" + userId);
         }
@@ -376,8 +382,7 @@
         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
         if (overlayPackage == null) {
             Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found");
-            onOverlayPackageRemoved(packageName, userId);
-            return;
+            return onOverlayPackageRemoved(packageName, userId);
         }
 
         mSettings.init(packageName, userId, overlayPackage.overlayTarget,
@@ -389,15 +394,17 @@
                 overlayPackage.overlayCategory);
         try {
             if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
-                mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+                return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
             }
+            return Optional.empty();
         } catch (OverlayManagerSettings.BadKeyException e) {
-            Slog.e(TAG, "failed to update settings", e);
             mSettings.remove(packageName, userId);
+            throw new OperationFailedException("failed to update settings", e);
         }
     }
 
-    void onOverlayPackageChanged(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onOverlayPackageChanged(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId);
         }
@@ -405,14 +412,16 @@
         try {
             final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
             if (updateState(oi.targetPackageName, packageName, userId, 0)) {
-                mListener.onOverlaysChanged(oi.targetPackageName, userId);
+                return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
             }
+            return Optional.empty();
         } catch (OverlayManagerSettings.BadKeyException e) {
-            Slog.e(TAG, "failed to update settings", e);
+            throw new OperationFailedException("failed to update settings", e);
         }
     }
 
-    void onOverlayPackageReplacing(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onOverlayPackageReplacing(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onOverlayPackageReplacing packageName=" + packageName + " userId="
                     + userId);
@@ -423,14 +432,16 @@
             if (updateState(oi.targetPackageName, packageName, userId,
                         FLAG_OVERLAY_IS_BEING_REPLACED)) {
                 removeIdmapIfPossible(oi);
-                mListener.onOverlaysChanged(oi.targetPackageName, userId);
+                return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
             }
+            return Optional.empty();
         } catch (OverlayManagerSettings.BadKeyException e) {
-            Slog.e(TAG, "failed to update settings", e);
+            throw new OperationFailedException("failed to update settings", e);
         }
     }
 
-    void onOverlayPackageReplaced(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onOverlayPackageReplaced(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "onOverlayPackageReplaced packageName=" + packageName + " userId="
                     + userId);
@@ -439,16 +450,12 @@
         final PackageInfo pkg = mPackageManager.getPackageInfo(packageName, userId);
         if (pkg == null) {
             Slog.w(TAG, "overlay package " + packageName + " was replaced, but couldn't be found");
-            onOverlayPackageRemoved(packageName, userId);
-            return;
+            return onOverlayPackageRemoved(packageName, userId);
         }
 
         try {
             final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
             if (mustReinitializeOverlay(pkg, oldOi)) {
-                if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) {
-                    mListener.onOverlaysChanged(pkg.overlayTarget, userId);
-                }
                 mSettings.init(packageName, userId, pkg.overlayTarget, pkg.targetOverlayableName,
                         pkg.applicationInfo.getBaseCodePath(),
                         isPackageConfiguredMutable(pkg.packageName),
@@ -457,22 +464,25 @@
             }
 
             if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
-                mListener.onOverlaysChanged(pkg.overlayTarget, userId);
+                return Optional.of(new PackageAndUser(pkg.overlayTarget, userId));
             }
+            return Optional.empty();
         } catch (OverlayManagerSettings.BadKeyException e) {
-            Slog.e(TAG, "failed to update settings", e);
+            throw new OperationFailedException("failed to update settings", e);
         }
     }
 
-    void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> onOverlayPackageRemoved(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         try {
             final OverlayInfo overlayInfo = mSettings.getOverlayInfo(packageName, userId);
             if (mSettings.remove(packageName, userId)) {
                 removeIdmapIfPossible(overlayInfo);
-                mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId);
+                return Optional.of(new PackageAndUser(overlayInfo.targetPackageName, userId));
             }
+            return Optional.empty();
         } catch (OverlayManagerSettings.BadKeyException e) {
-            Slog.e(TAG, "failed to remove overlay", e);
+            throw new OperationFailedException("failed to remove overlay", e);
         }
     }
 
@@ -493,8 +503,8 @@
         return mSettings.getOverlaysForUser(userId);
     }
 
-    boolean setEnabled(@NonNull final String packageName, final boolean enable,
-            final int userId) {
+    Optional<PackageAndUser> setEnabled(@NonNull final String packageName, final boolean enable,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, String.format("setEnabled packageName=%s enable=%s userId=%d",
                         packageName, enable, userId));
@@ -502,30 +512,33 @@
 
         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
         if (overlayPackage == null) {
-            return false;
+            throw new OperationFailedException(
+                    String.format("failed to find overlay package %s for user %d",
+                        packageName, userId));
         }
 
         try {
             final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
             if (!oi.isMutable) {
                 // Ignore immutable overlays.
-                return false;
+                throw new OperationFailedException(
+                        "cannot enable immutable overlay packages in runtime");
             }
 
             boolean modified = mSettings.setEnabled(packageName, userId, enable);
             modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
 
             if (modified) {
-                mListener.onOverlaysChanged(oi.targetPackageName, userId);
+                return Optional.of(new PackageAndUser(oi.targetPackageName, userId));
             }
-            return true;
+            return Optional.empty();
         } catch (OverlayManagerSettings.BadKeyException e) {
-            return false;
+            throw new OperationFailedException("failed to update settings", e);
         }
     }
 
-    boolean setEnabledExclusive(@NonNull final String packageName, boolean withinCategory,
-            final int userId) {
+    Optional<PackageAndUser> setEnabledExclusive(@NonNull final String packageName,
+            boolean withinCategory, final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, String.format("setEnabledExclusive packageName=%s"
                     + " withinCategory=%s userId=%d", packageName, withinCategory, userId));
@@ -533,7 +546,8 @@
 
         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
         if (overlayPackage == null) {
-            return false;
+            throw new OperationFailedException(String.format(
+                        "failed to find overlay package %s for user %d", packageName, userId));
         }
 
         try {
@@ -576,11 +590,11 @@
             modified |= updateState(targetPackageName, packageName, userId, 0);
 
             if (modified) {
-                mListener.onOverlaysChanged(targetPackageName, userId);
+                return Optional.of(new PackageAndUser(targetPackageName, userId));
             }
-            return true;
+            return Optional.empty();
         } catch (OverlayManagerSettings.BadKeyException e) {
-            return false;
+            throw new OperationFailedException("failed to update settings", e);
         }
     }
 
@@ -596,66 +610,75 @@
         return mOverlayConfig.isEnabled(packageName);
     }
 
-    boolean setPriority(@NonNull final String packageName,
-            @NonNull final String newParentPackageName, final int userId) {
+    Optional<PackageAndUser> setPriority(@NonNull final String packageName,
+            @NonNull final String newParentPackageName, final int userId)
+            throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "setPriority packageName=" + packageName + " newParentPackageName="
                     + newParentPackageName + " userId=" + userId);
         }
 
         if (!isPackageConfiguredMutable(packageName)) {
-            return false;
+            throw new OperationFailedException(String.format(
+                        "overlay package %s user %d is not updatable", packageName, userId));
         }
 
         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
         if (overlayPackage == null) {
-            return false;
+            throw new OperationFailedException(String.format(
+                        "failed to find overlay package %s for user %d", packageName, userId));
         }
 
         if (mSettings.setPriority(packageName, newParentPackageName, userId)) {
-            mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+            return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
         }
-        return true;
+        return Optional.empty();
     }
 
-    boolean setHighestPriority(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> setHighestPriority(@NonNull final String packageName,
+            final int userId) throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "setHighestPriority packageName=" + packageName + " userId=" + userId);
         }
 
         if (!isPackageConfiguredMutable(packageName)) {
-            return false;
+            throw new OperationFailedException(String.format(
+                        "overlay package %s user %d is not updatable", packageName, userId));
         }
 
         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
         if (overlayPackage == null) {
-            return false;
+            throw new OperationFailedException(String.format(
+                        "failed to find overlay package %s for user %d", packageName, userId));
         }
 
         if (mSettings.setHighestPriority(packageName, userId)) {
-            mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+            return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
         }
-        return true;
+        return Optional.empty();
     }
 
-    boolean setLowestPriority(@NonNull final String packageName, final int userId) {
+    Optional<PackageAndUser> setLowestPriority(@NonNull final String packageName, final int userId)
+            throws OperationFailedException {
         if (DEBUG) {
             Slog.d(TAG, "setLowestPriority packageName=" + packageName + " userId=" + userId);
         }
 
         if (!isPackageConfiguredMutable(packageName)) {
-            return false;
+            throw new OperationFailedException(String.format(
+                        "overlay package %s user %d is not updatable", packageName, userId));
         }
 
         final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
         if (overlayPackage == null) {
-            return false;
+            throw new OperationFailedException(String.format(
+                        "failed to find overlay package %s for user %d", packageName, userId));
         }
 
         if (mSettings.setLowestPriority(packageName, userId)) {
-            mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
+            return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId));
         }
-        return true;
+        return Optional.empty();
     }
 
     void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
@@ -797,12 +820,13 @@
         mIdmapManager.removeIdmap(oi, oi.userId);
     }
 
-    interface OverlayChangeListener {
+    static final class OperationFailedException extends Exception {
+        OperationFailedException(@NonNull final String message) {
+            super(message);
+        }
 
-        /**
-         * An event triggered by changes made to overlay state or settings as well as changes that
-         * add or remove target packages of overlays.
-         **/
-        void onOverlaysChanged(@NonNull String targetPackage, int userId);
+        OperationFailedException(@NonNull final String message, @NonNull Throwable cause) {
+            super(message, cause);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/om/PackageAndUser.java b/services/core/java/com/android/server/om/PackageAndUser.java
new file mode 100644
index 0000000..5c38ba7
--- /dev/null
+++ b/services/core/java/com/android/server/om/PackageAndUser.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 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.om;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+
+final class PackageAndUser {
+    public final @NonNull String packageName;
+    public final @UserIdInt int userId;
+
+    PackageAndUser(@NonNull String packageName, @UserIdInt int userId) {
+        this.packageName = packageName;
+        this.userId = userId;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof PackageAndUser)) {
+            return false;
+        }
+        PackageAndUser other = (PackageAndUser) obj;
+        return packageName.equals(other.packageName) && userId == other.userId;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + packageName.hashCode();
+        result = prime * result + userId;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("PackageAndUser{packageName=%s, userId=%d}", packageName, userId);
+    }
+}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index dd507a3..ef0f0ee 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.BugreportParams;
@@ -31,6 +32,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserManager;
+import android.telephony.TelephonyManager;
 import android.util.ArraySet;
 import android.util.Slog;
 
@@ -53,11 +55,13 @@
     private final Object mLock = new Object();
     private final Context mContext;
     private final AppOpsManager mAppOps;
+    private final TelephonyManager mTelephonyManager;
     private final ArraySet<String> mBugreportWhitelistedPackages;
 
     BugreportManagerServiceImpl(Context context) {
         mContext = context;
-        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOps = context.getSystemService(AppOpsManager.class);
+        mTelephonyManager = context.getSystemService(TelephonyManager.class);
         mBugreportWhitelistedPackages =
                 SystemConfig.getInstance().getBugreportWhitelistedPackages();
     }
@@ -67,11 +71,14 @@
     public void startBugreport(int callingUidUnused, String callingPackage,
             FileDescriptor bugreportFd, FileDescriptor screenshotFd,
             int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
         Objects.requireNonNull(callingPackage);
         Objects.requireNonNull(bugreportFd);
         Objects.requireNonNull(listener);
         validateBugreportMode(bugreportMode);
+
+        int callingUid = Binder.getCallingUid();
+        enforcePermission(callingPackage, callingUid, bugreportMode
+                == BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */);
         final long identity = Binder.clearCallingIdentity();
         try {
             ensureIsPrimaryUser();
@@ -79,13 +86,6 @@
             Binder.restoreCallingIdentity(identity);
         }
 
-        int callingUid = Binder.getCallingUid();
-        mAppOps.checkPackage(callingUid, callingPackage);
-
-        if (!mBugreportWhitelistedPackages.contains(callingPackage)) {
-            throw new SecurityException(
-                    callingPackage + " is not whitelisted to use Bugreport API");
-        }
         synchronized (mLock) {
             startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
                     bugreportMode, listener, isScreenshotRequested);
@@ -93,10 +93,11 @@
     }
 
     @Override
-    @RequiresPermission(android.Manifest.permission.DUMP)
-    public void cancelBugreport() {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
-                "cancelBugreport");
+    @RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges
+    public void cancelBugreport(int callingUidUnused, String callingPackage) {
+        int callingUid = Binder.getCallingUid();
+        enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */);
+
         synchronized (mLock) {
             IDumpstate ds = getDumpstateBinderServiceLocked();
             if (ds == null) {
@@ -104,7 +105,11 @@
                 return;
             }
             try {
-                ds.cancelBugreport();
+                // Note: this may throw SecurityException back out to the caller if they aren't
+                // allowed to cancel the report, in which case we should NOT be setting ctl.stop,
+                // since that would unintentionally kill some other app's bugreport, which we
+                // specifically disallow.
+                ds.cancelBugreport(callingUid, callingPackage);
             } catch (RemoteException e) {
                 Slog.e(TAG, "RemoteException in cancelBugreport", e);
             }
@@ -127,6 +132,34 @@
         }
     }
 
+    private void enforcePermission(
+            String callingPackage, int callingUid, boolean checkCarrierPrivileges) {
+        mAppOps.checkPackage(callingUid, callingPackage);
+
+        // To gain access through the DUMP permission, the OEM has to allow this package explicitly
+        // via sysconfig and privileged permissions.
+        if (mBugreportWhitelistedPackages.contains(callingPackage)
+                && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                        == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+        // For carrier privileges, this can include user-installed apps. This is essentially a
+        // function of the current active SIM(s) in the device to let carrier apps through.
+        if (checkCarrierPrivileges
+                && mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
+                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+            return;
+        }
+
+        String message =
+                callingPackage
+                        + " does not hold the DUMP permission or is not bugreport-whitelisted "
+                        + (checkCarrierPrivileges ? "and does not have carrier privileges " : "")
+                        + "to request a bugreport";
+        Slog.w(TAG, message);
+        throw new SecurityException(message);
+    }
+
     /**
      * Validates that the current user is the primary user.
      *
@@ -182,7 +215,7 @@
             // lifecycle correctly. If we don't subsequent callers will get
             // BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS error.
             // Note that listener will be notified by the death recipient below.
-            cancelBugreport();
+            cancelBugreport(callingUid, callingPackage);
         }
     }
 
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 5c01e43..fd2d8e1 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
+import android.hardware.boot.V1_0.IBootControl;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.Binder;
@@ -73,6 +74,8 @@
     static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
     @VisibleForTesting
     static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
+    @VisibleForTesting
+    static final String AB_UPDATE = "ro.build.ab_update";
 
     private static final Object sRequestLock = new Object();
 
@@ -177,6 +180,25 @@
             return socket;
         }
 
+        /**
+         * Throws remote exception if there's an error getting the boot control HAL.
+         * Returns null if the boot control HAL's version is older than V1_2.
+         */
+        public android.hardware.boot.V1_2.IBootControl getBootControl() throws RemoteException {
+            IBootControl bootControlV10 = IBootControl.getService(true);
+            if (bootControlV10 == null) {
+                throw new RemoteException("Failed to get boot control HAL V1_0.");
+            }
+
+            android.hardware.boot.V1_2.IBootControl bootControlV12 =
+                    android.hardware.boot.V1_2.IBootControl.castFrom(bootControlV10);
+            if (bootControlV12 == null) {
+                Slog.w(TAG, "Device doesn't implement boot control HAL V1_2.");
+                return null;
+            }
+            return bootControlV12;
+        }
+
         public void threadSleep(long millis) throws InterruptedException {
             Thread.sleep(millis);
         }
@@ -476,6 +498,56 @@
         return needClear ? ROR_REQUESTED_NEED_CLEAR : ROR_REQUESTED_SKIP_CLEAR;
     }
 
+    private boolean isAbDevice() {
+        return "true".equalsIgnoreCase(mInjector.systemPropertiesGet(AB_UPDATE));
+    }
+
+    private boolean verifySlotForNextBoot(boolean slotSwitch) {
+        if (!isAbDevice()) {
+            Slog.w(TAG, "Device isn't a/b, skipping slot verification.");
+            return true;
+        }
+
+        android.hardware.boot.V1_2.IBootControl bootControl;
+        try {
+            bootControl = mInjector.getBootControl();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to get the boot control HAL " + e);
+            return false;
+        }
+
+        // TODO(xunchang) enforce boot control V1_2 HAL on devices using multi client RoR
+        if (bootControl == null) {
+            Slog.w(TAG, "Cannot get the boot control HAL, skipping slot verification.");
+            return true;
+        }
+
+        int current_slot;
+        int next_active_slot;
+        try {
+            current_slot = bootControl.getCurrentSlot();
+            if (current_slot != 0 && current_slot != 1) {
+                throw new IllegalStateException("Current boot slot should be 0 or 1, got "
+                        + current_slot);
+            }
+            next_active_slot = bootControl.getActiveBootSlot();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to query the active slots", e);
+            return false;
+        }
+
+        int expected_active_slot = current_slot;
+        if (slotSwitch) {
+            expected_active_slot = current_slot == 0 ? 1 : 0;
+        }
+        if (next_active_slot != expected_active_slot) {
+            Slog.w(TAG, "The next active boot slot doesn't match the expected value, "
+                    + "expected " + expected_active_slot + ", got " + next_active_slot);
+            return false;
+        }
+        return true;
+    }
+
     private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
         if (packageName == null) {
             Slog.w(TAG, "Missing packageName when rebooting with lskf.");
@@ -485,7 +557,10 @@
             return false;
         }
 
-        // TODO(xunchang) check the slot to boot into, and fail the reboot upon slot mismatch.
+        if (!verifySlotForNextBoot(slotSwitch)) {
+            return false;
+        }
+
         // TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot.
         if (!mInjector.getLockSettingsService().armRebootEscrow()) {
             Slog.w(TAG, "Failure to escrow key for reboot");
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
index f20d80d..ae71c1a 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
@@ -76,7 +76,7 @@
     private int rebootAndApply() throws RemoteException {
         String packageName = getNextArgRequired();
         String rebootReason = getNextArgRequired();
-        boolean success = mService.rebootWithLskf(packageName, rebootReason, true);
+        boolean success = mService.rebootWithLskf(packageName, rebootReason, false);
         PrintWriter pw = getOutPrintWriter();
         // Keep the old message for cts test.
         pw.printf("%s Reboot and apply status: %s\n", packageName,
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 0d059ae..8345424 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -361,7 +361,11 @@
         }
     }
 
+    private static boolean isSupportedVolume(VolumeInfo vol) {
+        return isEmulatedOrPublic(vol) || vol.type == VolumeInfo.TYPE_STUB;
+    }
+
     private boolean shouldHandle(@Nullable VolumeInfo vol) {
-        return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
+        return mIsFuseEnabled && !mIsResetting && (vol == null || isSupportedVolume(vol));
     }
 }
diff --git a/services/core/java/com/android/server/textservices/OWNERS b/services/core/java/com/android/server/textservices/OWNERS
new file mode 100644
index 0000000..9fa9b29
--- /dev/null
+++ b/services/core/java/com/android/server/textservices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 25cd641..75277d1 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,6 +53,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.security.Authorization;
 import android.security.KeyStore;
 import android.service.trust.TrustAgentService;
 import android.text.TextUtils;
@@ -185,6 +186,8 @@
     private boolean mTrustAgentsCanRun = false;
     private int mCurrentUser = UserHandle.USER_SYSTEM;
 
+    private Authorization mAuthorizationService;
+
     public TrustManagerService(Context context) {
         super(context);
         mContext = context;
@@ -194,6 +197,7 @@
         mStrongAuthTracker = new StrongAuthTracker(context);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mSettingsObserver = new SettingsObserver(mHandler);
+        mAuthorizationService = new Authorization();
     }
 
     @Override
@@ -696,11 +700,13 @@
         if (changed) {
             dispatchDeviceLocked(userId, locked);
 
+            mAuthorizationService.onLockScreenEvent(locked, userId, null);
             KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
             // Also update the user's profiles who have unified challenge, since they
             // share the same unlocked state (see {@link #isDeviceLocked(int)})
             for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
                 if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
+                    mAuthorizationService.onLockScreenEvent(locked, profileHandle, null);
                     KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
                 }
             }
@@ -1252,6 +1258,7 @@
                         mDeviceLockedForUser.put(userId, locked);
                     }
 
+                    mAuthorizationService.onLockScreenEvent(locked, userId, null);
                     KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
 
                     if (locked) {
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 7024e67..4e0c0c5 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -123,7 +123,7 @@
     private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST =
             "Underlying Network lost";
     private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
-    private static final int TOKEN_ANY = Integer.MIN_VALUE;
+    private static final int TOKEN_ALL = Integer.MIN_VALUE;
 
     private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30;
     private static final int TEARDOWN_TIMEOUT_SECONDS = 5;
@@ -139,7 +139,7 @@
      *
      * <p>In the Connected state, this MAY indicate a mobility even occurred.
      *
-     * @param arg1 The "any" token; this event is always applicable.
+     * @param arg1 The "all" token; this event is always applicable.
      * @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data.
      */
     private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1;
@@ -175,7 +175,7 @@
      * <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout
      * state to the Connecting state.
      *
-     * @param arg1 The "any" token; no sessions are active in the RetryTimeoutState.
+     * @param arg1 The "all" token; no sessions are active in the RetryTimeoutState.
      */
     private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2;
 
@@ -318,7 +318,7 @@
      * <p>Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel
      * any pending work items, and move to the Disconnected state.
      *
-     * @param arg1 The "any" token; this signal is always honored.
+     * @param arg1 The "all" token; this signal is always honored.
      * @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data.
      */
     private static final int EVENT_DISCONNECT_REQUESTED = 7;
@@ -504,16 +504,9 @@
      * <p>Once torn down, this VcnTunnel CANNOT be started again.
      */
     public void teardownAsynchronously() {
-        mUnderlyingNetworkTracker.teardown();
-
-        // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
-        if (mTunnelIface != null) {
-            mTunnelIface.close();
-        }
-
         sendMessage(
                 EVENT_DISCONNECT_REQUESTED,
-                TOKEN_ANY,
+                TOKEN_ALL,
                 new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
         quit();
 
@@ -521,6 +514,16 @@
         // is also called asynchronously when a NetworkAgent becomes unwanted
     }
 
+    @Override
+    protected void onQuitting() {
+        // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
+        if (mTunnelIface != null) {
+            mTunnelIface.close();
+        }
+
+        mUnderlyingNetworkTracker.teardown();
+    }
+
     private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
         @Override
         public void onSelectedUnderlyingNetworkChanged(
@@ -530,26 +533,24 @@
             if (underlying == null) {
                 sendMessageDelayed(
                         EVENT_DISCONNECT_REQUESTED,
-                        TOKEN_ANY,
+                        TOKEN_ALL,
                         new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST),
                         TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS));
-                return;
-            }
+            } else if (getHandler() != null) {
+                // Cancel any existing disconnect due to loss of underlying network
+                // getHandler() can return null if the state machine has already quit. Since this is
+                // called from other classes, this condition must be verified.
 
-            // Cancel any existing disconnect due to loss of underlying network
-            // getHandler() can return null if the state machine has already quit. Since this is
-            // called
-            // from other classes, this condition must be verified.
-            if (getHandler() != null) {
                 getHandler()
                         .removeEqualMessages(
                                 EVENT_DISCONNECT_REQUESTED,
                                 new EventDisconnectRequestedInfo(
                                         DISCONNECT_REASON_UNDERLYING_NETWORK_LOST));
             }
+
             sendMessage(
                     EVENT_UNDERLYING_NETWORK_CHANGED,
-                    TOKEN_ANY,
+                    TOKEN_ALL,
                     new EventUnderlyingNetworkChangedInfo(underlying));
         }
     }
@@ -594,10 +595,101 @@
     }
 
     private abstract class BaseState extends State {
+        @Override
+        public void enter() {
+            try {
+                enterState();
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Uncaught exception", e);
+                sendMessage(
+                        EVENT_DISCONNECT_REQUESTED,
+                        TOKEN_ALL,
+                        new EventDisconnectRequestedInfo(
+                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+            }
+        }
+
         protected void enterState() throws Exception {}
 
+        /**
+         * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng
+         * builds.
+         */
+        @Override
+        public boolean processMessage(Message msg) {
+            try {
+                processStateMsg(msg);
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Uncaught exception", e);
+                sendMessage(
+                        EVENT_DISCONNECT_REQUESTED,
+                        TOKEN_ALL,
+                        new EventDisconnectRequestedInfo(
+                                DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
+            }
+
+            return HANDLED;
+        }
+
         protected abstract void processStateMsg(Message msg) throws Exception;
+
+        protected void logUnhandledMessage(Message msg) {
+            // Log as unexpected all known messages, and log all else as unknown.
+            switch (msg.what) {
+                case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough
+                case EVENT_RETRY_TIMEOUT_EXPIRED: // Fallthrough
+                case EVENT_SESSION_LOST: // Fallthrough
+                case EVENT_SESSION_CLOSED: // Fallthrough
+                case EVENT_TRANSFORM_CREATED: // Fallthrough
+                case EVENT_SETUP_COMPLETED: // Fallthrough
+                case EVENT_DISCONNECT_REQUESTED: // Fallthrough
+                case EVENT_TEARDOWN_TIMEOUT_EXPIRED:
+                    logUnexpectedEvent(msg.what);
+                    break;
+                default:
+                    logWtfUnknownEvent(msg.what);
+                    break;
+            }
+        }
+
+        protected void teardownNetwork() {
+            if (mNetworkAgent != null) {
+                mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */));
+                mNetworkAgent = null;
+            }
+        }
+
+        protected void teardownIke() {
+            if (mIkeSession != null) {
+                mIkeSession.close();
+            }
+        }
+
+        protected void handleDisconnectRequested(String msg) {
+            Slog.v(TAG, "Tearing down. Cause: " + msg);
+            teardownNetwork();
+            teardownIke();
+
+            if (mIkeSession == null) {
+                // Already disconnected, go straight to DisconnectedState
+                transitionTo(mDisconnectedState);
+            } else {
+                // Still need to wait for full closure
+                transitionTo(mDisconnectingState);
+            }
+        }
+
+        protected void logUnexpectedEvent(int what) {
+            Slog.d(TAG, String.format(
+                    "Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
+        }
+
+        protected void logWtfUnknownEvent(int what) {
+            Slog.wtf(TAG, String.format(
+                    "Unknown event code %d in state %s", what, this.getClass().getSimpleName()));
+        }
     }
+
     /**
      * State representing the a disconnected VCN tunnel.
      *
@@ -608,7 +700,29 @@
         protected void processStateMsg(Message msg) {}
     }
 
-    private abstract class ActiveBaseState extends BaseState {}
+    private abstract class ActiveBaseState extends BaseState {
+        /**
+         * Handles all incoming messages, discarding messages for previous networks.
+         *
+         * <p>States that handle mobility events may need to override this method to receive
+         * messages for all underlying networks.
+         */
+        @Override
+        public boolean processMessage(Message msg) {
+            final int token = msg.arg1;
+            // Only process if a valid token is presented.
+            if (isValidToken(token)) {
+                return super.processMessage(msg);
+            }
+
+            Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what);
+            return HANDLED;
+        }
+
+        protected boolean isValidToken(int token) {
+            return (token == TOKEN_ALL || token == mCurrentToken);
+        }
+    }
 
     /**
      * Transitive state representing a VCN that is tearing down an IKE session.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0542ef9..783037f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3306,9 +3306,8 @@
                 }
 
                 final ActivityStack stack = r.getRootTask();
-                final Task task = stack.getDisplayArea().createStack(stack.getWindowingMode(),
-                        stack.getActivityType(), !ON_TOP, ainfo, intent,
-                        false /* createdByOrganizer */);
+                final Task task = new ActivityStack(this, stack.getDisplayArea().getNextStackId(),
+                        stack.getActivityType(), ainfo, intent, false /* createdByOrganizer */);
 
                 if (!mRecentTasks.addToBottom(task)) {
                     // The app has too many tasks already and we can't add any more
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
index 391611b..5468fba 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java
@@ -78,7 +78,7 @@
     }
 
     @Test
-    public void testImmutableEnabledChange() {
+    public void testImmutableEnabledChange() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
         installNewPackage(target(TARGET), USER);
         installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -106,7 +106,7 @@
     }
 
     @Test
-    public void testMutableEnabledChangeHasNoEffect() {
+    public void testMutableEnabledChangeHasNoEffect() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
         installNewPackage(target(TARGET), USER);
         installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -134,7 +134,7 @@
     }
 
     @Test
-    public void testMutableEnabledToImmutableEnabled() {
+    public void testMutableEnabledToImmutableEnabled() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
         installNewPackage(target(TARGET), USER);
         installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -178,7 +178,7 @@
     }
 
     @Test
-    public void testMutablePriorityChange() {
+    public void testMutablePriorityChange() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
         installNewPackage(target(TARGET), USER);
         installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -218,7 +218,7 @@
     }
 
     @Test
-    public void testImmutablePriorityChange() {
+    public void testImmutablePriorityChange() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
         installNewPackage(target(TARGET), USER);
         installNewPackage(overlay(OVERLAY, TARGET), USER);
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index 4f882ce..33dbcc0 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -22,11 +22,14 @@
 import static android.os.OverlayablePolicy.CONFIG_SIGNATURE;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertThrows;
 
 import android.content.om.OverlayInfo;
+import android.util.Pair;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -35,6 +38,7 @@
 
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 @RunWith(AndroidJUnit4.class)
 public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase {
@@ -55,7 +59,7 @@
     private static final String CERT_CONFIG_NOK = "config_certificate_nok";
 
     @Test
-    public void testGetOverlayInfo() {
+    public void testGetOverlayInfo() throws Exception {
         installNewPackage(overlay(OVERLAY, TARGET), USER);
 
         final OverlayManagerServiceImpl impl = getImpl();
@@ -67,7 +71,7 @@
     }
 
     @Test
-    public void testGetOverlayInfosForTarget() {
+    public void testGetOverlayInfosForTarget() throws Exception {
         installNewPackage(overlay(OVERLAY, TARGET), USER);
         installNewPackage(overlay(OVERLAY2, TARGET), USER);
         installNewPackage(overlay(OVERLAY3, TARGET), USER2);
@@ -92,7 +96,7 @@
     }
 
     @Test
-    public void testGetOverlayInfosForUser() {
+    public void testGetOverlayInfosForUser() throws Exception {
         installNewPackage(target(TARGET), USER);
         installNewPackage(overlay(OVERLAY, TARGET), USER);
         installNewPackage(overlay(OVERLAY2, TARGET), USER);
@@ -119,7 +123,7 @@
     }
 
     @Test
-    public void testPriority() {
+    public void testPriority() throws Exception {
         installNewPackage(overlay(OVERLAY, TARGET), USER);
         installNewPackage(overlay(OVERLAY2, TARGET), USER);
         installNewPackage(overlay(OVERLAY3, TARGET), USER);
@@ -131,18 +135,21 @@
 
         assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
 
-        assertTrue(impl.setLowestPriority(OVERLAY3, USER));
+        assertEquals(impl.setLowestPriority(OVERLAY3, USER),
+                Optional.of(new PackageAndUser(TARGET, USER)));
         assertOverlayInfoForTarget(TARGET, USER, o3, o1, o2);
 
-        assertTrue(impl.setHighestPriority(OVERLAY3, USER));
+        assertEquals(impl.setHighestPriority(OVERLAY3, USER),
+                Optional.of(new PackageAndUser(TARGET, USER)));
         assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);
 
-        assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER));
+        assertEquals(impl.setPriority(OVERLAY, OVERLAY2, USER),
+                Optional.of(new PackageAndUser(TARGET, USER)));
         assertOverlayInfoForTarget(TARGET, USER, o2, o1, o3);
     }
 
     @Test
-    public void testOverlayInfoStateTransitions() {
+    public void testOverlayInfoStateTransitions() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
         assertNull(impl.getOverlayInfo(OVERLAY, USER));
 
@@ -153,7 +160,8 @@
         installNewPackage(target, USER);
         assertState(STATE_DISABLED, OVERLAY, USER);
 
-        impl.setEnabled(OVERLAY, true, USER);
+        assertEquals(impl.setEnabled(OVERLAY, true, USER),
+                Optional.of(new PackageAndUser(TARGET, USER)));
         assertState(STATE_ENABLED, OVERLAY, USER);
 
         // target upgrades do not change the state of the overlay
@@ -168,50 +176,40 @@
     }
 
     @Test
-    public void testOnOverlayPackageUpgraded() {
-        final FakeListener listener = getListener();
+    public void testOnOverlayPackageUpgraded() throws Exception {
         final FakeDeviceState.PackageBuilder target = target(TARGET);
         final FakeDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
         installNewPackage(target, USER);
         installNewPackage(overlay, USER);
-        listener.count = 0;
         upgradePackage(overlay, USER);
-        assertEquals(2, listener.count);
 
         // upgrade to a version where the overlay has changed its target
-        // expect once for the old target package, once for the new target package
-        listener.count = 0;
         final FakeDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
-        upgradePackage(overlay2, USER);
-        assertEquals(3, listener.count);
-
-        listener.count = 0;
-        upgradePackage(overlay2, USER);
-        assertEquals(2, listener.count);
+        final Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> pair =
+                upgradePackage(overlay2, USER);
+        assertEquals(pair.first, Optional.of(new PackageAndUser(TARGET, USER)));
+        assertEquals(pair.second, Optional.of(new PackageAndUser("some.other.target", USER)));
     }
 
     @Test
-    public void testListener() {
+    public void testSetEnabledAtVariousConditions() throws Exception {
         final OverlayManagerServiceImpl impl = getImpl();
-        final FakeListener listener = getListener();
-        installNewPackage(overlay(OVERLAY, TARGET), USER);
-        assertEquals(1, listener.count);
-        listener.count = 0;
+        assertThrows(OverlayManagerServiceImpl.OperationFailedException.class,
+                () -> impl.setEnabled(OVERLAY, true, USER));
 
+        // request succeeded, and there was a change that needs to be
+        // propagated to the rest of the system
         installNewPackage(target(TARGET), USER);
-        assertEquals(1, listener.count);
-        listener.count = 0;
+        installNewPackage(overlay(OVERLAY, TARGET), USER);
+        assertEquals(impl.setEnabled(OVERLAY, true, USER),
+                Optional.of(new PackageAndUser(TARGET, USER)));
 
-        impl.setEnabled(OVERLAY, true, USER);
-        assertEquals(1, listener.count);
-        listener.count = 0;
-
-        impl.setEnabled(OVERLAY, true, USER);
-        assertEquals(0, listener.count);
+        // request succeeded, but nothing changed
+        assertFalse(impl.setEnabled(OVERLAY, true, USER).isPresent());
     }
 
     @Test
-    public void testConfigSignaturePolicyOk() {
+    public void testConfigSignaturePolicyOk() throws Exception {
         setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
         reinitializeImpl();
 
@@ -229,7 +227,7 @@
     }
 
     @Test
-    public void testConfigSignaturePolicyCertNok() {
+    public void testConfigSignaturePolicyCertNok() throws Exception {
         setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
         reinitializeImpl();
 
@@ -247,7 +245,7 @@
     }
 
     @Test
-    public void testConfigSignaturePolicyNoConfig() {
+    public void testConfigSignaturePolicyNoConfig() throws Exception {
         addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
         installNewPackage(target(TARGET), USER);
         installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
@@ -262,7 +260,7 @@
     }
 
     @Test
-    public void testConfigSignaturePolicyNoRefPkg() {
+    public void testConfigSignaturePolicyNoRefPkg() throws Exception {
         installNewPackage(target(TARGET), USER);
         installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
 
@@ -276,7 +274,7 @@
     }
 
     @Test
-    public void testConfigSignaturePolicyRefPkgNotSystem() {
+    public void testConfigSignaturePolicyRefPkgNotSystem() throws Exception {
         setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
         reinitializeImpl();
 
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 006dda0..2c477c8 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -16,6 +16,8 @@
 
 package com.android.server.om;
 
+import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
@@ -30,6 +32,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Pair;
 
 import androidx.annotation.Nullable;
 
@@ -43,13 +46,13 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 /** Base class for creating {@link OverlayManagerServiceImplTests} tests. */
 class OverlayManagerServiceImplTestsBase {
     private OverlayManagerServiceImpl mImpl;
     private FakeDeviceState mState;
-    private FakeListener mListener;
     private FakePackageManagerHelper mPackageManager;
     private FakeIdmapDaemon mIdmapDaemon;
     private OverlayConfig mOverlayConfig;
@@ -58,7 +61,6 @@
     @Before
     public void setUp() {
         mState = new FakeDeviceState();
-        mListener = new FakeListener();
         mPackageManager = new FakePackageManagerHelper(mState);
         mIdmapDaemon = new FakeIdmapDaemon(mState);
         mOverlayConfig = mock(OverlayConfig.class);
@@ -73,18 +75,13 @@
                 new IdmapManager(mIdmapDaemon, mPackageManager),
                 new OverlayManagerSettings(),
                 mOverlayConfig,
-                new String[0],
-                mListener);
+                new String[0]);
     }
 
     OverlayManagerServiceImpl getImpl() {
         return mImpl;
     }
 
-    FakeListener getListener() {
-        return mListener;
-    }
-
     FakeIdmapDaemon getIdmapd() {
         return mIdmapDaemon;
     }
@@ -155,7 +152,8 @@
      *
      * @throws IllegalStateException if the package is currently installed
      */
-    void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId) {
+    void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId)
+            throws OperationFailedException {
         if (mState.select(pkg.packageName, userId) != null) {
             throw new IllegalStateException("package " + pkg.packageName + " already installed");
         }
@@ -176,23 +174,30 @@
      * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
      * {@link android.content.Intent#EXTRA_REPLACING} extra.
      *
+     * @return the two Optional<PackageAndUser> objects from starting and finishing the upgrade
+     *
      * @throws IllegalStateException if the package is not currently installed
      */
-    void upgradePackage(FakeDeviceState.PackageBuilder pkg, int userId) {
+    Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> upgradePackage(
+            FakeDeviceState.PackageBuilder pkg, int userId) throws OperationFailedException {
         final FakeDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
         if (replacedPackage == null) {
             throw new IllegalStateException("package " + pkg.packageName + " not installed");
         }
+        Optional<PackageAndUser> opt1 = Optional.empty();
         if (replacedPackage.targetPackageName != null) {
-            mImpl.onOverlayPackageReplacing(pkg.packageName, userId);
+            opt1 = mImpl.onOverlayPackageReplacing(pkg.packageName, userId);
         }
 
         mState.add(pkg, userId);
+        Optional<PackageAndUser> opt2;
         if (pkg.targetPackage == null) {
-            mImpl.onTargetPackageReplaced(pkg.packageName, userId);
+            opt2 = mImpl.onTargetPackageReplaced(pkg.packageName, userId);
         } else {
-            mImpl.onOverlayPackageReplaced(pkg.packageName, userId);
+            opt2 = mImpl.onOverlayPackageReplaced(pkg.packageName, userId);
         }
+
+        return Pair.create(opt1, opt2);
     }
 
     /**
@@ -203,7 +208,7 @@
      *
      * @throws IllegalStateException if the package is not currently installed
      */
-    void uninstallPackage(String packageName, int userId) {
+    void uninstallPackage(String packageName, int userId) throws OperationFailedException {
         final FakeDeviceState.Package pkg = mState.select(packageName, userId);
         if (pkg == null) {
             throw new IllegalStateException("package " + packageName+ " not installed");
@@ -485,12 +490,4 @@
             }
         }
     }
-
-    static class FakeListener implements OverlayManagerServiceImpl.OverlayChangeListener {
-        public int count;
-
-        public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
-            count++;
-        }
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
index b07b8fa..9b8a2a8 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -35,6 +35,7 @@
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
+import android.hardware.boot.V1_2.IBootControl;
 import android.os.Handler;
 import android.os.IPowerManager;
 import android.os.IRecoverySystemProgressListener;
@@ -68,12 +69,13 @@
     private IThermalService mIThermalService;
     private FileWriter mUncryptUpdateFileWriter;
     private LockSettingsInternal mLockSettingsInternal;
+    private IBootControl mIBootControl;
 
     private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package";
     private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package";
 
     @Before
-    public void setup() {
+    public void setup() throws Exception {
         mContext = mock(Context.class);
         mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties();
         mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class);
@@ -88,8 +90,13 @@
         PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
                 mIThermalService, new Handler(looper));
 
+        mIBootControl = mock(IBootControl.class);
+        when(mIBootControl.getCurrentSlot()).thenReturn(0);
+        when(mIBootControl.getActiveBootSlot()).thenReturn(1);
+
         mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
-                powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal);
+                powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal,
+                mIBootControl);
     }
 
     @Test
@@ -332,6 +339,15 @@
         verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
     }
 
+
+    @Test
+    public void rebootWithLskf_slotMismatch_Failure() throws Exception {
+        assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
+        mRecoverySystemService.onPreparedForReboot(true);
+        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", false),
+                is(false));
+    }
+
     @Test
     public void rebootWithLskf_withoutPrepare_Failure() throws Exception {
         assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
index 131e4f3..0727e5a 100644
--- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
@@ -17,6 +17,7 @@
 package com.android.server.recoverysystem;
 
 import android.content.Context;
+import android.hardware.boot.V1_2.IBootControl;
 import android.os.PowerManager;
 
 import com.android.internal.widget.LockSettingsInternal;
@@ -30,16 +31,19 @@
         private final FileWriter mUncryptPackageFileWriter;
         private final UncryptSocket mUncryptSocket;
         private final LockSettingsInternal mLockSettingsInternal;
+        private final IBootControl mIBootControl;
 
         MockInjector(Context context, FakeSystemProperties systemProperties,
                 PowerManager powerManager, FileWriter uncryptPackageFileWriter,
-                UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) {
+                UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
+                IBootControl bootControl) {
             super(context);
             mSystemProperties = systemProperties;
             mPowerManager = powerManager;
             mUncryptPackageFileWriter = uncryptPackageFileWriter;
             mUncryptSocket = uncryptSocket;
             mLockSettingsInternal = lockSettingsInternal;
+            mIBootControl = bootControl;
         }
 
         @Override
@@ -85,13 +89,19 @@
         public LockSettingsInternal getLockSettingsService() {
             return mLockSettingsInternal;
         }
+
+        @Override
+        public IBootControl getBootControl() {
+            return mIBootControl;
+        }
     }
 
     RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
             PowerManager powerManager, FileWriter uncryptPackageFileWriter,
-            UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) {
+            UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
+            IBootControl bootControl) {
         super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
-                uncryptSocket, lockSettingsInternal));
+                uncryptSocket, lockSettingsInternal, bootControl));
     }
 
     public static class FakeSystemProperties {
@@ -102,6 +112,8 @@
                     || RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key)
                     || RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) {
                 return null;
+            } else if (RecoverySystemService.AB_UPDATE.equals(key)) {
+                return "true";
             } else {
                 throw new IllegalArgumentException("unexpected test key: " + key);
             }
diff --git a/services/tests/servicestests/src/com/android/server/textservices/OWNERS b/services/tests/servicestests/src/com/android/server/textservices/OWNERS
new file mode 100644
index 0000000..0471e29
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/textservices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index d012971..f6d18fc 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -18,10 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
-import android.hardware.radio.V1_1.GeranBands;
 import android.hardware.radio.V1_5.AccessNetwork;
-import android.hardware.radio.V1_5.EutranBands;
-import android.hardware.radio.V1_5.UtranBands;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -117,52 +114,120 @@
      * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
      */
     public static final class GeranBand {
-        public static final int BAND_T380 = GeranBands.BAND_T380;
-        public static final int BAND_T410 = GeranBands.BAND_T410;
-        public static final int BAND_450 = GeranBands.BAND_450;
-        public static final int BAND_480 = GeranBands.BAND_480;
-        public static final int BAND_710 = GeranBands.BAND_710;
-        public static final int BAND_750 = GeranBands.BAND_750;
-        public static final int BAND_T810 = GeranBands.BAND_T810;
-        public static final int BAND_850 = GeranBands.BAND_850;
-        public static final int BAND_P900 = GeranBands.BAND_P900;
-        public static final int BAND_E900 = GeranBands.BAND_E900;
-        public static final int BAND_R900 = GeranBands.BAND_R900;
-        public static final int BAND_DCS1800 = GeranBands.BAND_DCS1800;
-        public static final int BAND_PCS1900 = GeranBands.BAND_PCS1900;
-        public static final int BAND_ER900 = GeranBands.BAND_ER900;
+        public static final int BAND_T380 = android.hardware.radio.V1_1.GeranBands.BAND_T380;
+        public static final int BAND_T410 = android.hardware.radio.V1_1.GeranBands.BAND_T410;
+        public static final int BAND_450 = android.hardware.radio.V1_1.GeranBands.BAND_450;
+        public static final int BAND_480 = android.hardware.radio.V1_1.GeranBands.BAND_480;
+        public static final int BAND_710 = android.hardware.radio.V1_1.GeranBands.BAND_710;
+        public static final int BAND_750 = android.hardware.radio.V1_1.GeranBands.BAND_750;
+        public static final int BAND_T810 = android.hardware.radio.V1_1.GeranBands.BAND_T810;
+        public static final int BAND_850 = android.hardware.radio.V1_1.GeranBands.BAND_850;
+        public static final int BAND_P900 = android.hardware.radio.V1_1.GeranBands.BAND_P900;
+        public static final int BAND_E900 = android.hardware.radio.V1_1.GeranBands.BAND_E900;
+        public static final int BAND_R900 = android.hardware.radio.V1_1.GeranBands.BAND_R900;
+        public static final int BAND_DCS1800 = android.hardware.radio.V1_1.GeranBands.BAND_DCS1800;
+        public static final int BAND_PCS1900 = android.hardware.radio.V1_1.GeranBands.BAND_PCS1900;
+        public static final int BAND_ER900 = android.hardware.radio.V1_1.GeranBands.BAND_ER900;
+
+        /**
+         * GeranBand
+         *
+         * @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = {"BAND_"},
+                value = {BAND_T380,
+                        BAND_T410,
+                        BAND_450,
+                        BAND_480,
+                        BAND_710,
+                        BAND_750,
+                        BAND_T810,
+                        BAND_850,
+                        BAND_P900,
+                        BAND_E900,
+                        BAND_R900,
+                        BAND_DCS1800,
+                        BAND_PCS1900,
+                        BAND_ER900})
+
+        public @interface GeranBands {}
 
         /** @hide */
         private GeranBand() {}
     }
 
     /**
+     * 3GPP TS 45.005 Table 2-1 Dynamically mapped ARFCN.
+     * 3GPP TS 45.005 Table 2-2 Fixed designation of ARFCN.
+     * @hide
+     */
+    enum GeranBandArfcnFrequency {
+
+        // Dynamically mapped ARFCN
+//        GERAN_ARFCN_FREQUENCY_BAND_T380(GeranBand.BAND_T380, 380.2, 0),
+//        GERAN_ARFCN_FREQUENCY_BAND_T410(GeranBand.BAND_T410, 410.2, 0),
+//        GERAN_ARFCN_FREQUENCY_BAND_710(GeranBand.BAND_710, 698, 0),
+//        GERAN_ARFCN_FREQUENCY_BAND_750(GeranBand.BAND_750, 747, 438, 30),
+//        GERAN_ARFCN_FREQUENCY_BAND_T810(GeranBand.BAND_T810, 806, 350),
+        // Fixed designation of ARFCN
+        GERAN_ARFCN_FREQUENCY_BAND_450(GeranBand.BAND_450, 450600, 259, 259, 293, 10),
+        GERAN_ARFCN_FREQUENCY_BAND_480(GeranBand.BAND_480, 479000, 306, 306, 340, 10),
+        GERAN_ARFCN_FREQUENCY_BAND_850(GeranBand.BAND_850, 824200, 128, 128, 251, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_DCS1800(GeranBand.BAND_DCS1800, 1710200, 512, 512, 885, 95),
+        GERAN_ARFCN_FREQUENCY_BAND_PCS1900(GeranBand.BAND_PCS1900, 1850200, 512, 512, 810, 80),
+        GERAN_ARFCN_FREQUENCY_BAND_E900_1(GeranBand.BAND_E900, 890000, 0, 0, 124, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_E900_2(GeranBand.BAND_E900, 890000, 1024, 975, 1023, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_R900_1(GeranBand.BAND_R900, 890000, 0, 0, 124, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_R900_2(GeranBand.BAND_R900, 890000, 1024, 955, 1023, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_P900(GeranBand.BAND_P900, 890000, 0, 1, 124, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_ER900_1(GeranBand.BAND_ER900, 890000, 0, 0, 124, 45),
+        GERAN_ARFCN_FREQUENCY_BAND_ER900_2(GeranBand.BAND_ER900, 890000, 1024, 940, 1023, 1024);
+
+        GeranBandArfcnFrequency(int band, int uplinkFrequencyFirstKhz, int arfcnOffset,
+                                int arfcnRangeFirst, int arfcnRangeLast, int downlinkOffset) {
+            this.band = band;
+            this.uplinkFrequencyFirst = uplinkFrequencyFirstKhz;
+            this.arfcnOffset = arfcnOffset;
+            this.arfcnRangeFirst = arfcnRangeFirst;
+            this.arfcnRangeLast = arfcnRangeLast;
+            this.downlinkOffset = downlinkOffset;
+        }
+
+        int band;
+        int uplinkFrequencyFirst;
+        int arfcnOffset;
+        int arfcnRangeFirst;
+        int arfcnRangeLast;
+        int downlinkOffset;
+    }
+
+    /**
      * Frequency bands for UTRAN.
      * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
      */
     public static final class UtranBand {
-        public static final int BAND_1 = UtranBands.BAND_1;
-        public static final int BAND_2 = UtranBands.BAND_2;
-        public static final int BAND_3 = UtranBands.BAND_3;
-        public static final int BAND_4 = UtranBands.BAND_4;
-        public static final int BAND_5 = UtranBands.BAND_5;
-        public static final int BAND_6 = UtranBands.BAND_6;
-        public static final int BAND_7 = UtranBands.BAND_7;
-        public static final int BAND_8 = UtranBands.BAND_8;
-        public static final int BAND_9 = UtranBands.BAND_9;
-        public static final int BAND_10 = UtranBands.BAND_10;
-        public static final int BAND_11 = UtranBands.BAND_11;
-        public static final int BAND_12 = UtranBands.BAND_12;
-        public static final int BAND_13 = UtranBands.BAND_13;
-        public static final int BAND_14 = UtranBands.BAND_14;
+        public static final int BAND_1 = android.hardware.radio.V1_5.UtranBands.BAND_1;
+        public static final int BAND_2 = android.hardware.radio.V1_5.UtranBands.BAND_2;
+        public static final int BAND_3 = android.hardware.radio.V1_5.UtranBands.BAND_3;
+        public static final int BAND_4 = android.hardware.radio.V1_5.UtranBands.BAND_4;
+        public static final int BAND_5 = android.hardware.radio.V1_5.UtranBands.BAND_5;
+        public static final int BAND_6 = android.hardware.radio.V1_5.UtranBands.BAND_6;
+        public static final int BAND_7 = android.hardware.radio.V1_5.UtranBands.BAND_7;
+        public static final int BAND_8 = android.hardware.radio.V1_5.UtranBands.BAND_8;
+        public static final int BAND_9 = android.hardware.radio.V1_5.UtranBands.BAND_9;
+        public static final int BAND_10 = android.hardware.radio.V1_5.UtranBands.BAND_10;
+        public static final int BAND_11 = android.hardware.radio.V1_5.UtranBands.BAND_11;
+        public static final int BAND_12 = android.hardware.radio.V1_5.UtranBands.BAND_12;
+        public static final int BAND_13 = android.hardware.radio.V1_5.UtranBands.BAND_13;
+        public static final int BAND_14 = android.hardware.radio.V1_5.UtranBands.BAND_14;
         // band 15, 16, 17, 18 are reserved
-        public static final int BAND_19 = UtranBands.BAND_19;
-        public static final int BAND_20 = UtranBands.BAND_20;
-        public static final int BAND_21 = UtranBands.BAND_21;
-        public static final int BAND_22 = UtranBands.BAND_22;
+        public static final int BAND_19 = android.hardware.radio.V1_5.UtranBands.BAND_19;
+        public static final int BAND_20 = android.hardware.radio.V1_5.UtranBands.BAND_20;
+        public static final int BAND_21 = android.hardware.radio.V1_5.UtranBands.BAND_21;
+        public static final int BAND_22 = android.hardware.radio.V1_5.UtranBands.BAND_22;
         // band 23, 24 are reserved
-        public static final int BAND_25 = UtranBands.BAND_25;
-        public static final int BAND_26 = UtranBands.BAND_26;
+        public static final int BAND_25 = android.hardware.radio.V1_5.UtranBands.BAND_25;
+        public static final int BAND_26 = android.hardware.radio.V1_5.UtranBands.BAND_26;
 
         // Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2.
 
@@ -171,115 +236,423 @@
          * 1900 - 1920 MHz: Uplink and downlink transmission
          * 2010 - 2025 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_A = UtranBands.BAND_A;
+        public static final int BAND_A = android.hardware.radio.V1_5.UtranBands.BAND_A;
 
         /**
          * Band B
          * 1850 - 1910 MHz: Uplink and downlink transmission
          * 1930 - 1990 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_B = UtranBands.BAND_B;
+        public static final int BAND_B = android.hardware.radio.V1_5.UtranBands.BAND_B;
 
         /**
          * Band C
          * 1910 - 1930 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_C = UtranBands.BAND_C;
+        public static final int BAND_C = android.hardware.radio.V1_5.UtranBands.BAND_C;
 
         /**
          * Band D
          * 2570 - 2620 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_D = UtranBands.BAND_D;
+        public static final int BAND_D = android.hardware.radio.V1_5.UtranBands.BAND_D;
 
         /**
          * Band E
          * 2300—2400 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_E = UtranBands.BAND_E;
+        public static final int BAND_E = android.hardware.radio.V1_5.UtranBands.BAND_E;
 
         /**
          * Band F
          * 1880 - 1920 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_F = UtranBands.BAND_F;
+        public static final int BAND_F = android.hardware.radio.V1_5.UtranBands.BAND_F;
+
+        /**
+         * UtranBand
+         *
+         * @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = {"BAND_"},
+                value = {BAND_1,
+                        BAND_2,
+                        BAND_3,
+                        BAND_4,
+                        BAND_5,
+                        BAND_6,
+                        BAND_7,
+                        BAND_8,
+                        BAND_9,
+                        BAND_10,
+                        BAND_11,
+                        BAND_12,
+                        BAND_13,
+                        BAND_14,
+                        BAND_19,
+                        BAND_20,
+                        BAND_21,
+                        BAND_22,
+                        BAND_25,
+                        BAND_26,
+                        BAND_A,
+                        BAND_B,
+                        BAND_C,
+                        BAND_D,
+                        BAND_E,
+                        BAND_F})
+
+        public @interface UtranBands {}
 
         /** @hide */
         private UtranBand() {}
     }
 
     /**
+     * 3GPP TS 25.101, Table 5.1 UARFCN definition (general)
+     * 3GPP TS 25.102, Table 5.2 UTRA Absolute Radio Frequency Channel Number 1.28 Mcps TDD Option.
+     *
+     * @hide
+     */
+    enum UtranBandArfcnFrequency {
+
+        UTRAN_ARFCN_FREQUENCY_BAND_1(UtranBand.BAND_1, 0, 10562, 10838, 0, 9612, 9888),
+        UTRAN_ARFCN_FREQUENCY_BAND_2(UtranBand.BAND_2, 0, 9662, 9938, 0, 9262, 9538),
+        UTRAN_ARFCN_FREQUENCY_BAND_3(UtranBand.BAND_3, 1575000, 1162, 1513, 1525000, 937, 1288),
+        UTRAN_ARFCN_FREQUENCY_BAND_4(UtranBand.BAND_4, 1805000, 1537, 1738, 1450000, 1312, 1513),
+        UTRAN_ARFCN_FREQUENCY_BAND_5(UtranBand.BAND_5, 0, 4357, 4458, 0, 4132, 4233),
+        UTRAN_ARFCN_FREQUENCY_BAND_6(UtranBand.BAND_6, 0, 4387, 4413, 0, 4162, 4188),
+        UTRAN_ARFCN_FREQUENCY_BAND_7(UtranBand.BAND_7, 2175000, 2237, 2563, 2100000, 2012, 2338),
+        UTRAN_ARFCN_FREQUENCY_BAND_8(UtranBand.BAND_8, 340000, 2937, 3088, 340000, 2712, 2863),
+        UTRAN_ARFCN_FREQUENCY_BAND_9(UtranBand.BAND_9, 0, 9327, 9837, 0, 8762, 8912),
+        UTRAN_ARFCN_FREQUENCY_BAND_10(UtranBand.BAND_10, 1490000, 3112, 3388, 1135000, 2887, 3163),
+        UTRAN_ARFCN_FREQUENCY_BAND_11(UtranBand.BAND_11, 736000, 3712, 3787, 733000, 3487, 3562),
+        UTRAN_ARFCN_FREQUENCY_BAND_12(UtranBand.BAND_12, -37000, 3842, 3903, -22000, 3617, 3678),
+        UTRAN_ARFCN_FREQUENCY_BAND_13(UtranBand.BAND_13, -55000, 4017, 4043, 21000, 3792, 3818),
+        UTRAN_ARFCN_FREQUENCY_BAND_14(UtranBand.BAND_14, -63000, 4117, 4143, 12000, 3892, 3918),
+        UTRAN_ARFCN_FREQUENCY_BAND_19(UtranBand.BAND_19, 735000, 712, 763, 770000, 312, 363),
+        UTRAN_ARFCN_FREQUENCY_BAND_20(UtranBand.BAND_20, -109000, 4512, 4638, -23000, 4287, 4413),
+        UTRAN_ARFCN_FREQUENCY_BAND_21(UtranBand.BAND_21, 1326000, 862, 912, 1358000, 462, 512),
+        UTRAN_ARFCN_FREQUENCY_BAND_22(UtranBand.BAND_22, 2580000, 4662, 5038, 2525000, 4437, 4813),
+        UTRAN_ARFCN_FREQUENCY_BAND_25(UtranBand.BAND_25, 910000, 5112, 5413, 875000, 4887, 5188),
+        UTRAN_ARFCN_FREQUENCY_BAND_A(UtranBand.BAND_A, 0, 10054, 10121, 0, 9504, 9596),
+        UTRAN_ARFCN_FREQUENCY_BAND_B(UtranBand.BAND_B, 0, 9654, 9946, 0, 9254, 9546),
+        UTRAN_ARFCN_FREQUENCY_BAND_C(UtranBand.BAND_C, 0, 0, 0, 0, 9554, 9646),
+        UTRAN_ARFCN_FREQUENCY_BAND_D(UtranBand.BAND_D, 0, 0, 0, 0, 12854, 13096),
+        UTRAN_ARFCN_FREQUENCY_BAND_E(UtranBand.BAND_E, 0, 0, 0, 0, 11504, 11996),
+        UTRAN_ARFCN_FREQUENCY_BAND_F(UtranBand.BAND_F, 0, 0, 0, 0, 9404, 9596);
+
+        UtranBandArfcnFrequency(int band, int downlinkOffsetKhz, int downlinkRangeFirst,
+                                int downlinkRangeLast, int uplinkOffsetKhz, int uplinkRangeFirst,
+                                int uplinkRangeLast) {
+            this.band = band;
+            this.downlinkOffset = downlinkOffsetKhz;
+            this.downlinkRangeFirst = downlinkRangeFirst;
+            this.downlinkRangeLast = downlinkRangeLast;
+            this.uplinkOffset = uplinkOffsetKhz;
+            this.uplinkRangeFirst = uplinkRangeFirst;
+            this.uplinkRangeLast = uplinkRangeLast;
+        }
+
+        int band;
+        int downlinkOffset;
+        int downlinkRangeFirst;
+        int downlinkRangeLast;
+        int uplinkOffset;
+        int uplinkRangeFirst;
+        int uplinkRangeLast;
+    }
+
+    /**
      * Frequency bands for EUTRAN.
      * 3GPP TS 36.101, Version 16.4.0, Table 5.5: Operating bands
      * https://www.etsi.org/deliver/etsi_ts/136100_136199/136101/15.09.00_60/ts_136101v150900p.pdf
      */
     public static final class EutranBand {
-        public static final int BAND_1 = EutranBands.BAND_1;
-        public static final int BAND_2 = EutranBands.BAND_2;
-        public static final int BAND_3 = EutranBands.BAND_3;
-        public static final int BAND_4 = EutranBands.BAND_4;
-        public static final int BAND_5 = EutranBands.BAND_5;
-        public static final int BAND_6 = EutranBands.BAND_6;
-        public static final int BAND_7 = EutranBands.BAND_7;
-        public static final int BAND_8 = EutranBands.BAND_8;
-        public static final int BAND_9 = EutranBands.BAND_9;
-        public static final int BAND_10 = EutranBands.BAND_10;
-        public static final int BAND_11 = EutranBands.BAND_11;
-        public static final int BAND_12 = EutranBands.BAND_12;
-        public static final int BAND_13 = EutranBands.BAND_13;
-        public static final int BAND_14 = EutranBands.BAND_14;
-        public static final int BAND_17 = EutranBands.BAND_17;
-        public static final int BAND_18 = EutranBands.BAND_18;
-        public static final int BAND_19 = EutranBands.BAND_19;
-        public static final int BAND_20 = EutranBands.BAND_20;
-        public static final int BAND_21 = EutranBands.BAND_21;
-        public static final int BAND_22 = EutranBands.BAND_22;
-        public static final int BAND_23 = EutranBands.BAND_23;
-        public static final int BAND_24 = EutranBands.BAND_24;
-        public static final int BAND_25 = EutranBands.BAND_25;
-        public static final int BAND_26 = EutranBands.BAND_26;
-        public static final int BAND_27 = EutranBands.BAND_27;
-        public static final int BAND_28 = EutranBands.BAND_28;
-        public static final int BAND_30 = EutranBands.BAND_30;
-        public static final int BAND_31 = EutranBands.BAND_31;
-        public static final int BAND_33 = EutranBands.BAND_33;
-        public static final int BAND_34 = EutranBands.BAND_34;
-        public static final int BAND_35 = EutranBands.BAND_35;
-        public static final int BAND_36 = EutranBands.BAND_36;
-        public static final int BAND_37 = EutranBands.BAND_37;
-        public static final int BAND_38 = EutranBands.BAND_38;
-        public static final int BAND_39 = EutranBands.BAND_39;
-        public static final int BAND_40 = EutranBands.BAND_40;
-        public static final int BAND_41 = EutranBands.BAND_41;
-        public static final int BAND_42 = EutranBands.BAND_42;
-        public static final int BAND_43 = EutranBands.BAND_43;
-        public static final int BAND_44 = EutranBands.BAND_44;
-        public static final int BAND_45 = EutranBands.BAND_45;
-        public static final int BAND_46 = EutranBands.BAND_46;
-        public static final int BAND_47 = EutranBands.BAND_47;
-        public static final int BAND_48 = EutranBands.BAND_48;
-        public static final int BAND_49 = EutranBands.BAND_49;
-        public static final int BAND_50 = EutranBands.BAND_50;
-        public static final int BAND_51 = EutranBands.BAND_51;
-        public static final int BAND_52 = EutranBands.BAND_52;
-        public static final int BAND_53 = EutranBands.BAND_53;
-        public static final int BAND_65 = EutranBands.BAND_65;
-        public static final int BAND_66 = EutranBands.BAND_66;
-        public static final int BAND_68 = EutranBands.BAND_68;
-        public static final int BAND_70 = EutranBands.BAND_70;
-        public static final int BAND_71 = EutranBands.BAND_71;
-        public static final int BAND_72 = EutranBands.BAND_72;
-        public static final int BAND_73 = EutranBands.BAND_73;
-        public static final int BAND_74 = EutranBands.BAND_74;
-        public static final int BAND_85 = EutranBands.BAND_85;
-        public static final int BAND_87 = EutranBands.BAND_87;
-        public static final int BAND_88 = EutranBands.BAND_88;
+        public static final int BAND_1 = android.hardware.radio.V1_5.EutranBands.BAND_1;
+        public static final int BAND_2 = android.hardware.radio.V1_5.EutranBands.BAND_2;
+        public static final int BAND_3 = android.hardware.radio.V1_5.EutranBands.BAND_3;
+        public static final int BAND_4 = android.hardware.radio.V1_5.EutranBands.BAND_4;
+        public static final int BAND_5 = android.hardware.radio.V1_5.EutranBands.BAND_5;
+        public static final int BAND_6 = android.hardware.radio.V1_5.EutranBands.BAND_6;
+        public static final int BAND_7 = android.hardware.radio.V1_5.EutranBands.BAND_7;
+        public static final int BAND_8 = android.hardware.radio.V1_5.EutranBands.BAND_8;
+        public static final int BAND_9 = android.hardware.radio.V1_5.EutranBands.BAND_9;
+        public static final int BAND_10 = android.hardware.radio.V1_5.EutranBands.BAND_10;
+        public static final int BAND_11 = android.hardware.radio.V1_5.EutranBands.BAND_11;
+        public static final int BAND_12 = android.hardware.radio.V1_5.EutranBands.BAND_12;
+        public static final int BAND_13 = android.hardware.radio.V1_5.EutranBands.BAND_13;
+        public static final int BAND_14 = android.hardware.radio.V1_5.EutranBands.BAND_14;
+        public static final int BAND_17 = android.hardware.radio.V1_5.EutranBands.BAND_17;
+        public static final int BAND_18 = android.hardware.radio.V1_5.EutranBands.BAND_18;
+        public static final int BAND_19 = android.hardware.radio.V1_5.EutranBands.BAND_19;
+        public static final int BAND_20 = android.hardware.radio.V1_5.EutranBands.BAND_20;
+        public static final int BAND_21 = android.hardware.radio.V1_5.EutranBands.BAND_21;
+        public static final int BAND_22 = android.hardware.radio.V1_5.EutranBands.BAND_22;
+        public static final int BAND_23 = android.hardware.radio.V1_5.EutranBands.BAND_23;
+        public static final int BAND_24 = android.hardware.radio.V1_5.EutranBands.BAND_24;
+        public static final int BAND_25 = android.hardware.radio.V1_5.EutranBands.BAND_25;
+        public static final int BAND_26 = android.hardware.radio.V1_5.EutranBands.BAND_26;
+        public static final int BAND_27 = android.hardware.radio.V1_5.EutranBands.BAND_27;
+        public static final int BAND_28 = android.hardware.radio.V1_5.EutranBands.BAND_28;
+        public static final int BAND_30 = android.hardware.radio.V1_5.EutranBands.BAND_30;
+        public static final int BAND_31 = android.hardware.radio.V1_5.EutranBands.BAND_31;
+        public static final int BAND_33 = android.hardware.radio.V1_5.EutranBands.BAND_33;
+        public static final int BAND_34 = android.hardware.radio.V1_5.EutranBands.BAND_34;
+        public static final int BAND_35 = android.hardware.radio.V1_5.EutranBands.BAND_35;
+        public static final int BAND_36 = android.hardware.radio.V1_5.EutranBands.BAND_36;
+        public static final int BAND_37 = android.hardware.radio.V1_5.EutranBands.BAND_37;
+        public static final int BAND_38 = android.hardware.radio.V1_5.EutranBands.BAND_38;
+        public static final int BAND_39 = android.hardware.radio.V1_5.EutranBands.BAND_39;
+        public static final int BAND_40 = android.hardware.radio.V1_5.EutranBands.BAND_40;
+        public static final int BAND_41 = android.hardware.radio.V1_5.EutranBands.BAND_41;
+        public static final int BAND_42 = android.hardware.radio.V1_5.EutranBands.BAND_42;
+        public static final int BAND_43 = android.hardware.radio.V1_5.EutranBands.BAND_43;
+        public static final int BAND_44 = android.hardware.radio.V1_5.EutranBands.BAND_44;
+        public static final int BAND_45 = android.hardware.radio.V1_5.EutranBands.BAND_45;
+        public static final int BAND_46 = android.hardware.radio.V1_5.EutranBands.BAND_46;
+        public static final int BAND_47 = android.hardware.radio.V1_5.EutranBands.BAND_47;
+        public static final int BAND_48 = android.hardware.radio.V1_5.EutranBands.BAND_48;
+        public static final int BAND_49 = android.hardware.radio.V1_5.EutranBands.BAND_49;
+        public static final int BAND_50 = android.hardware.radio.V1_5.EutranBands.BAND_50;
+        public static final int BAND_51 = android.hardware.radio.V1_5.EutranBands.BAND_51;
+        public static final int BAND_52 = android.hardware.radio.V1_5.EutranBands.BAND_52;
+        public static final int BAND_53 = android.hardware.radio.V1_5.EutranBands.BAND_53;
+        public static final int BAND_65 = android.hardware.radio.V1_5.EutranBands.BAND_65;
+        public static final int BAND_66 = android.hardware.radio.V1_5.EutranBands.BAND_66;
+        public static final int BAND_68 = android.hardware.radio.V1_5.EutranBands.BAND_68;
+        public static final int BAND_70 = android.hardware.radio.V1_5.EutranBands.BAND_70;
+        public static final int BAND_71 = android.hardware.radio.V1_5.EutranBands.BAND_71;
+        public static final int BAND_72 = android.hardware.radio.V1_5.EutranBands.BAND_72;
+        public static final int BAND_73 = android.hardware.radio.V1_5.EutranBands.BAND_73;
+        public static final int BAND_74 = android.hardware.radio.V1_5.EutranBands.BAND_74;
+        public static final int BAND_85 = android.hardware.radio.V1_5.EutranBands.BAND_85;
+        public static final int BAND_87 = android.hardware.radio.V1_5.EutranBands.BAND_87;
+        public static final int BAND_88 = android.hardware.radio.V1_5.EutranBands.BAND_88;
+
+        /**
+         * EutranBands
+         *
+         * @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(prefix = {"BAND_"},
+                value = {BAND_1,
+                        BAND_2,
+                        BAND_3,
+                        BAND_4,
+                        BAND_5,
+                        BAND_6,
+                        BAND_7,
+                        BAND_8,
+                        BAND_9,
+                        BAND_10,
+                        BAND_11,
+                        BAND_12,
+                        BAND_13,
+                        BAND_14,
+                        BAND_17,
+                        BAND_18,
+                        BAND_19,
+                        BAND_20,
+                        BAND_21,
+                        BAND_22,
+                        BAND_23,
+                        BAND_24,
+                        BAND_25,
+                        BAND_26,
+                        BAND_27,
+                        BAND_28,
+                        BAND_30,
+                        BAND_31,
+                        BAND_33,
+                        BAND_34,
+                        BAND_35,
+                        BAND_36,
+                        BAND_37,
+                        BAND_38,
+                        BAND_39,
+                        BAND_40,
+                        BAND_41,
+                        BAND_42,
+                        BAND_43,
+                        BAND_44,
+                        BAND_45,
+                        BAND_46,
+                        BAND_47,
+                        BAND_48,
+                        BAND_49,
+                        BAND_50,
+                        BAND_51,
+                        BAND_52,
+                        BAND_53,
+                        BAND_65,
+                        BAND_66,
+                        BAND_68,
+                        BAND_70,
+                        BAND_71,
+                        BAND_72,
+                        BAND_73,
+                        BAND_74,
+                        BAND_85,
+                        BAND_87,
+                        BAND_88})
+
+        public @interface EutranBands {}
 
         /** @hide */
         private EutranBand() {};
     }
 
     /**
+     * 3GPP TS 36.101 Table 5.7.3-1 E-UTRA channel numbers.
+     *
+     * @hide
+     */
+    enum EutranBandArfcnFrequency {
+
+        EUTRAN_ARFCN_FREQUENCY_BAND_1(
+                EutranBand.BAND_1, 2110000, 0, 599, 1920000, 18800, 18599),
+        EUTRAN_ARFCN_FREQUENCY_BAND_2(
+                EutranBand.BAND_2, 1930000, 600, 1199, 1850000, 18600, 19199),
+        EUTRAN_ARFCN_FREQUENCY_BAND_3(
+                EutranBand.BAND_3, 1805000, 1200, 1949, 1710000, 19200, 19949),
+        EUTRAN_ARFCN_FREQUENCY_BAND_4(
+                EutranBand.BAND_4, 2110000, 1950, 2399, 1710000, 19950, 20399),
+        EUTRAN_ARFCN_FREQUENCY_BAND_5(
+                EutranBand.BAND_5, 869000, 2400, 2649, 824000, 20400, 20649),
+        EUTRAN_ARFCN_FREQUENCY_BAND_6(
+                EutranBand.BAND_6, 875000, 2650, 2749, 830000, 20650, 20749),
+        EUTRAN_ARFCN_FREQUENCY_BAND_7(
+                EutranBand.BAND_7, 2620000, 2750, 3449, 2500000, 20750, 21449),
+        EUTRAN_ARFCN_FREQUENCY_BAND_8(
+                EutranBand.BAND_8, 925000, 3450, 3799, 880000, 21450, 21799),
+        EUTRAN_ARFCN_FREQUENCY_BAND_9(
+                EutranBand.BAND_9, 1844900, 3800, 4149, 1749900, 21800, 22149),
+        EUTRAN_ARFCN_FREQUENCY_BAND_10(
+                EutranBand.BAND_10, 2110000, 4150, 4749, 1710000, 22150, 22749),
+        EUTRAN_ARFCN_FREQUENCY_BAND_11(
+                EutranBand.BAND_11, 1475900, 4750, 4949, 1427900, 22750, 22949),
+        EUTRAN_ARFCN_FREQUENCY_BAND_12(
+                EutranBand.BAND_12, 729000, 5010, 5179, 699000, 23010, 23179),
+        EUTRAN_ARFCN_FREQUENCY_BAND_13(
+                EutranBand.BAND_13, 746000, 5180, 5279, 777000, 23180, 23279),
+        EUTRAN_ARFCN_FREQUENCY_BAND_14(
+                EutranBand.BAND_14, 758000, 5280, 5379, 788000, 23230, 23379),
+        EUTRAN_ARFCN_FREQUENCY_BAND_17(
+                EutranBand.BAND_17, 734000, 5730, 5849, 704000, 23730, 23849),
+        EUTRAN_ARFCN_FREQUENCY_BAND_18(
+                EutranBand.BAND_18, 860000, 5850, 5999, 815000, 23850, 23999),
+        EUTRAN_ARFCN_FREQUENCY_BAND_19(
+                EutranBand.BAND_19, 875000, 6000, 6149, 830000, 24000, 24149),
+        EUTRAN_ARFCN_FREQUENCY_BAND_20(
+                EutranBand.BAND_20, 791000, 6150, 6449, 832000, 24150, 24449),
+        EUTRAN_ARFCN_FREQUENCY_BAND_21(
+                EutranBand.BAND_21, 1495900, 6450, 6599, 1447900, 24450, 24599),
+        EUTRAN_ARFCN_FREQUENCY_BAND_22(
+                EutranBand.BAND_22, 3510000, 6600, 7399, 3410000, 24600, 25399),
+        EUTRAN_ARFCN_FREQUENCY_BAND_23(
+                EutranBand.BAND_23, 2180000, 7500, 7699, 2000000, 25500, 25699),
+        EUTRAN_ARFCN_FREQUENCY_BAND_24(
+                EutranBand.BAND_24, 1525000, 7700, 8039, 1626500, 25700, 26039),
+        EUTRAN_ARFCN_FREQUENCY_BAND_25(
+                EutranBand.BAND_25, 1930000, 8040, 8689, 1850000, 26040, 26689),
+        EUTRAN_ARFCN_FREQUENCY_BAND_26(
+                EutranBand.BAND_26, 859000, 8690, 9039, 814000, 26690, 27039),
+        EUTRAN_ARFCN_FREQUENCY_BAND_27(
+                EutranBand.BAND_27, 852000, 9040, 9209, 807000, 27040, 27209),
+        EUTRAN_ARFCN_FREQUENCY_BAND_28(
+                EutranBand.BAND_28, 758000, 9210, 9659, 703000, 27210, 27659),
+        EUTRAN_ARFCN_FREQUENCY_BAND_30(
+                EutranBand.BAND_30, 2350000, 9770, 9869, 2305000, 27660, 27759),
+        EUTRAN_ARFCN_FREQUENCY_BAND_31(
+                EutranBand.BAND_31, 462500, 9870, 9919, 452500, 27760, 27809),
+        EUTRAN_ARFCN_FREQUENCY_BAND_33(
+                EutranBand.BAND_33, 1900000, 36000, 36199, 1900000, 36000, 36199),
+        EUTRAN_ARFCN_FREQUENCY_BAND_34(
+                EutranBand.BAND_34, 2010000, 36200, 36349, 2010000, 36200, 36349),
+        EUTRAN_ARFCN_FREQUENCY_BAND_35(
+                EutranBand.BAND_35, 1850000, 36350, 36949, 1850000, 36350, 36949),
+        EUTRAN_ARFCN_FREQUENCY_BAND_36(
+                EutranBand.BAND_36, 1930000, 36950, 37549, 1930000, 36950, 37549),
+        EUTRAN_ARFCN_FREQUENCY_BAND_37(
+                EutranBand.BAND_37, 1910000, 37550, 37749, 1910000, 37550, 37749),
+        EUTRAN_ARFCN_FREQUENCY_BAND_38(
+                EutranBand.BAND_38, 2570000, 37750, 38249, 2570000, 37750, 38249),
+        EUTRAN_ARFCN_FREQUENCY_BAND_39(
+                EutranBand.BAND_39, 1880000, 38250, 38649, 1880000, 38250, 38649),
+        EUTRAN_ARFCN_FREQUENCY_BAND_40(
+                EutranBand.BAND_40, 2300000, 38650, 39649, 2300000, 38650, 39649),
+        EUTRAN_ARFCN_FREQUENCY_BAND_41(
+                EutranBand.BAND_41, 2496000, 39650, 41589, 2496000, 39650, 41589),
+        EUTRAN_ARFCN_FREQUENCY_BAND_42(
+                EutranBand.BAND_42, 3400000, 41950, 43589, 3400000, 41950, 43589),
+        EUTRAN_ARFCN_FREQUENCY_BAND_43(
+                EutranBand.BAND_43, 3600000, 43950, 45589, 3600000, 43950, 45589),
+        EUTRAN_ARFCN_FREQUENCY_BAND_44(
+                EutranBand.BAND_44, 703000, 45590, 46589, 703000, 45590, 46589),
+        EUTRAN_ARFCN_FREQUENCY_BAND_45(
+                EutranBand.BAND_45, 1447000, 46590, 46789, 1447000, 46590, 46789),
+        EUTRAN_ARFCN_FREQUENCY_BAND_46(
+                EutranBand.BAND_46, 5150000, 46790, 54539, 5150000, 46790, 54539),
+        EUTRAN_ARFCN_FREQUENCY_BAND_47(
+                EutranBand.BAND_47, 5855000, 54540, 55239, 5855000, 54540, 55239),
+        EUTRAN_ARFCN_FREQUENCY_BAND_48(
+                EutranBand.BAND_48, 3550000, 55240, 56739, 3550000, 55240, 56739),
+        EUTRAN_ARFCN_FREQUENCY_BAND_49(
+                EutranBand.BAND_49, 3550000, 56740, 58239, 3550000, 56740, 58239),
+        EUTRAN_ARFCN_FREQUENCY_BAND_50(
+                EutranBand.BAND_50, 1432000, 58240, 59089, 1432000, 58240, 59089),
+        EUTRAN_ARFCN_FREQUENCY_BAND_51(
+                EutranBand.BAND_51, 1427000, 59090, 59139, 1427000, 59090, 59139),
+        EUTRAN_ARFCN_FREQUENCY_BAND_52(
+                EutranBand.BAND_52, 3300000, 59140, 60139, 3300000, 59140, 60139),
+        EUTRAN_ARFCN_FREQUENCY_BAND_53(
+                EutranBand.BAND_53, 2483500, 60140, 60254, 2483500, 60140, 60254),
+        EUTRAN_ARFCN_FREQUENCY_BAND_65(
+                EutranBand.BAND_65, 2110000, 65536, 66435, 1920000, 131072, 131971),
+        EUTRAN_ARFCN_FREQUENCY_BAND_66(
+                EutranBand.BAND_66, 2110000, 66436, 67335, 1710000, 131972, 132671),
+        EUTRAN_ARFCN_FREQUENCY_BAND_68(
+                EutranBand.BAND_68, 753000, 67536, 67835, 698000, 132672, 132971),
+        EUTRAN_ARFCN_FREQUENCY_BAND_70(
+                EutranBand.BAND_70, 1995000, 68336, 68585, 1695000, 132972, 133121),
+        EUTRAN_ARFCN_FREQUENCY_BAND_71(
+                EutranBand.BAND_71, 617000, 68586, 68935, 663000, 133122, 133471),
+        EUTRAN_ARFCN_FREQUENCY_BAND_72(
+                EutranBand.BAND_72, 461000, 68936, 68985, 451000, 133472, 133521),
+        EUTRAN_ARFCN_FREQUENCY_BAND_73(
+                EutranBand.BAND_73, 460000, 68986, 69035, 450000, 133522, 133571),
+        EUTRAN_ARFCN_FREQUENCY_BAND_74(
+                EutranBand.BAND_74, 1475000, 69036, 69465, 1427000, 133572, 134001),
+        EUTRAN_ARFCN_FREQUENCY_BAND_85(
+                EutranBand.BAND_85, 728000, 70366, 70545, 698000, 134002, 134181),
+        EUTRAN_ARFCN_FREQUENCY_BAND_87(
+                EutranBand.BAND_87, 420000, 70546, 70595, 410000, 134182, 134231),
+        EUTRAN_ARFCN_FREQUENCY_BAND_88(
+                EutranBand.BAND_88, 422000, 70596, 70645, 412000, 134231, 134280);
+
+        EutranBandArfcnFrequency(int band, int downlinkLowKhz, int downlinkOffset,
+                                 int downlinkRange, int uplinkLowKhz, int uplinkOffset,
+                                 int uplinkRange) {
+            this.band = band;
+            this.downlinkLowKhz = downlinkLowKhz;
+            this.downlinkOffset = downlinkOffset;
+            this.uplinkLowKhz = uplinkLowKhz;
+            this.uplinkOffset = uplinkOffset;
+            this.downlinkRange = downlinkRange;
+            this.uplinkRange = uplinkRange;
+        }
+
+        int band;
+        int downlinkLowKhz;
+        int downlinkOffset;
+        int uplinkLowKhz;
+        int uplinkOffset;
+        int downlinkRange;
+        int uplinkRange;
+    }
+
+    /**
      * Frequency bands for CDMA2000.
      * http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf
      * @hide
@@ -320,7 +693,7 @@
      * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810102/15.08.00_60/ts_13810102v150800p.pdf
      */
     public static final class NgranBands {
-        /** 3GPP TS 38.101-1, Version 16.2.0, Table 5.2-1: FR1 bands */
+        /** 3GPP TS 38.101-1, Version 16.5.0, Table 5.2-1: FR1 bands */
         public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1;
         public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2;
         public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3;
@@ -332,6 +705,7 @@
         public static final int BAND_18 = android.hardware.radio.V1_5.NgranBands.BAND_18;
         public static final int BAND_20 = android.hardware.radio.V1_5.NgranBands.BAND_20;
         public static final int BAND_25 = android.hardware.radio.V1_5.NgranBands.BAND_25;
+        public static final int BAND_26 = android.hardware.radio.V1_6.NgranBands.BAND_26;
         public static final int BAND_28 = android.hardware.radio.V1_5.NgranBands.BAND_28;
         public static final int BAND_29 = android.hardware.radio.V1_5.NgranBands.BAND_29;
         public static final int BAND_30 = android.hardware.radio.V1_5.NgranBands.BAND_30;
@@ -340,9 +714,11 @@
         public static final int BAND_39 = android.hardware.radio.V1_5.NgranBands.BAND_39;
         public static final int BAND_40 = android.hardware.radio.V1_5.NgranBands.BAND_40;
         public static final int BAND_41 = android.hardware.radio.V1_5.NgranBands.BAND_41;
+        public static final int BAND_46 = android.hardware.radio.V1_6.NgranBands.BAND_46;
         public static final int BAND_48 = android.hardware.radio.V1_5.NgranBands.BAND_48;
         public static final int BAND_50 = android.hardware.radio.V1_5.NgranBands.BAND_50;
         public static final int BAND_51 = android.hardware.radio.V1_5.NgranBands.BAND_51;
+        public static final int BAND_53 = android.hardware.radio.V1_6.NgranBands.BAND_53;
         public static final int BAND_65 = android.hardware.radio.V1_5.NgranBands.BAND_65;
         public static final int BAND_66 = android.hardware.radio.V1_5.NgranBands.BAND_66;
         public static final int BAND_70 = android.hardware.radio.V1_5.NgranBands.BAND_70;
@@ -366,6 +742,7 @@
         public static final int BAND_93 = android.hardware.radio.V1_5.NgranBands.BAND_93;
         public static final int BAND_94 = android.hardware.radio.V1_5.NgranBands.BAND_94;
         public static final int BAND_95 = android.hardware.radio.V1_5.NgranBands.BAND_95;
+        public static final int BAND_96 = android.hardware.radio.V1_6.NgranBands.BAND_96;
 
         /** 3GPP TS 38.101-2, Version 16.2.0, Table 5.2-1: FR2 bands */
         public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257;
@@ -390,6 +767,7 @@
                         BAND_18,
                         BAND_20,
                         BAND_25,
+                        BAND_26,
                         BAND_28,
                         BAND_29,
                         BAND_30,
@@ -398,9 +776,11 @@
                         BAND_39,
                         BAND_40,
                         BAND_41,
+                        BAND_46,
                         BAND_48,
                         BAND_50,
                         BAND_51,
+                        BAND_53,
                         BAND_65,
                         BAND_66,
                         BAND_70,
@@ -424,6 +804,7 @@
                         BAND_93,
                         BAND_94,
                         BAND_95,
+                        BAND_96,
                         BAND_257,
                         BAND_258,
                         BAND_260,
@@ -464,7 +845,8 @@
                 value = {
                         FREQUENCY_RANGE_GROUP_UNKNOWN,
                         FREQUENCY_RANGE_GROUP_1,
-                        FREQUENCY_RANGE_GROUP_2})
+                        FREQUENCY_RANGE_GROUP_2
+                })
         public @interface FrequencyRangeGroup {}
 
         /**
@@ -489,6 +871,7 @@
                 case BAND_18:
                 case BAND_20:
                 case BAND_25:
+                case BAND_26:
                 case BAND_28:
                 case BAND_29:
                 case BAND_30:
@@ -497,9 +880,11 @@
                 case BAND_39:
                 case BAND_40:
                 case BAND_41:
+                case BAND_46:
                 case BAND_48:
                 case BAND_50:
                 case BAND_51:
+                case BAND_53:
                 case BAND_65:
                 case BAND_66:
                 case BAND_70:
@@ -523,6 +908,7 @@
                 case BAND_93:
                 case BAND_94:
                 case BAND_95:
+                case BAND_96:
                     return FREQUENCY_RANGE_GROUP_1;
                 case BAND_257:
                 case BAND_258:
@@ -538,6 +924,33 @@
         private NgranBands() {}
     }
 
+    /**
+     * 3GPP TS 38.104 Table 5.4.2.1-1 NR-ARFCN parameters for the global frequency raster.
+     *
+     * @hide
+     */
+    enum NgranArfcnFrequency {
+
+        NGRAN_ARFCN_FREQUENCY_RANGE_1(5, 0, 0, 0, 599999),
+        NGRAN_ARFCN_FREQUENCY_RANGE_2(15, 3000000, 600000, 600000, 2016666),
+        NGRAN_ARFCN_FREQUENCY_RANGE_3(60, 24250080, 2016667, 2016667, 3279165);
+
+        NgranArfcnFrequency(int globalKhz, int rangeOffset, int arfcnOffset,
+                            int rangeFirst, int rangeLast) {
+            this.globalKhz = globalKhz;
+            this.rangeOffset = rangeOffset;
+            this.arfcnOffset = arfcnOffset;
+            this.rangeFirst = rangeFirst;
+            this.rangeLast = rangeLast;
+        }
+
+        int globalKhz;
+        int rangeOffset;
+        int arfcnOffset;
+        int rangeFirst;
+        int rangeLast;
+    }
+
     /** @hide */
     private AccessNetworkConstants() {};
 }
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 7661a32..f29f3bd 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -4,12 +4,20 @@
 import static android.telephony.ServiceState.DUPLEX_MODE_TDD;
 import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN;
 
+import android.telephony.AccessNetworkConstants.EutranBandArfcnFrequency;
 import android.telephony.AccessNetworkConstants.EutranBand;
 import android.telephony.AccessNetworkConstants.GeranBand;
+import android.telephony.AccessNetworkConstants.GeranBandArfcnFrequency;
+import android.telephony.AccessNetworkConstants.NgranArfcnFrequency;
+import android.telephony.AccessNetworkConstants.NgranBands;
 import android.telephony.AccessNetworkConstants.UtranBand;
+import android.telephony.AccessNetworkConstants.UtranBandArfcnFrequency;
 import android.telephony.ServiceState.DuplexMode;
+import android.util.Log;
 
 import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * Utilities to map between radio constants.
@@ -22,9 +30,27 @@
     private AccessNetworkUtils() {}
 
     public static final int INVALID_BAND = -1;
+    public static final int INVALID_FREQUENCY = -1;
 
     /** ISO country code of Japan. */
     private static final String JAPAN_ISO_COUNTRY_CODE = "jp";
+    private static final String TAG = "AccessNetworkUtils";
+
+    private static final int FREQUENCY_KHZ = 1000;
+    private static final int FREQUENCY_RANGE_LOW_KHZ = 1000000;
+    private static final int FREQUENCY_RANGE_MID_KHZ = 3000000;
+    private static final int FREQUENCY_RANGE_HIGH_KHZ = 6000000;
+
+    private static final Set<Integer> UARFCN_NOT_GENERAL_BAND;
+    static {
+        UARFCN_NOT_GENERAL_BAND = new HashSet<Integer>();
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_A);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_B);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_C);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_D);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_E);
+        UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_F);
+    }
 
     /**
      * Gets the duplex mode for the given EUTRAN operating band.
@@ -325,4 +351,403 @@
         }
         return INVALID_BAND;
     }
+
+    /**
+     * Get geran bands from {@link PhysicalChannelConfig#getBand()}
+     */
+    public static int getFrequencyRangeGroupFromGeranBand(@GeranBand.GeranBands int band) {
+        switch (band) {
+            case GeranBand.BAND_T380:
+            case GeranBand.BAND_T410:
+            case GeranBand.BAND_450:
+            case GeranBand.BAND_480:
+            case GeranBand.BAND_710:
+            case GeranBand.BAND_750:
+            case GeranBand.BAND_T810:
+            case GeranBand.BAND_850:
+            case GeranBand.BAND_P900:
+            case GeranBand.BAND_E900:
+            case GeranBand.BAND_R900:
+            case GeranBand.BAND_ER900:
+                return ServiceState.FREQUENCY_RANGE_LOW;
+            case GeranBand.BAND_DCS1800:
+            case GeranBand.BAND_PCS1900:
+                return ServiceState.FREQUENCY_RANGE_MID;
+            default:
+                return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        }
+    }
+
+    /**
+     * Get utran bands from {@link PhysicalChannelConfig#getBand()}
+     */
+    public static int getFrequencyRangeGroupFromUtranBand(@UtranBand.UtranBands int band) {
+        switch (band) {
+            case UtranBand.BAND_5:
+            case UtranBand.BAND_6:
+            case UtranBand.BAND_8:
+            case UtranBand.BAND_12:
+            case UtranBand.BAND_13:
+            case UtranBand.BAND_14:
+            case UtranBand.BAND_19:
+            case UtranBand.BAND_20:
+            case UtranBand.BAND_26:
+                return ServiceState.FREQUENCY_RANGE_LOW;
+            case UtranBand.BAND_1:
+            case UtranBand.BAND_2:
+            case UtranBand.BAND_3:
+            case UtranBand.BAND_4:
+            case UtranBand.BAND_7:
+            case UtranBand.BAND_9:
+            case UtranBand.BAND_10:
+            case UtranBand.BAND_11:
+            case UtranBand.BAND_21:
+            case UtranBand.BAND_25:
+            case UtranBand.BAND_A:
+            case UtranBand.BAND_B:
+            case UtranBand.BAND_C:
+            case UtranBand.BAND_D:
+            case UtranBand.BAND_E:
+            case UtranBand.BAND_F:
+                return ServiceState.FREQUENCY_RANGE_MID;
+            case UtranBand.BAND_22:
+                return ServiceState.FREQUENCY_RANGE_HIGH;
+            default:
+                return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        }
+    }
+
+    /**
+     * Get eutran bands from {@link PhysicalChannelConfig#getBand()}
+     * 3GPP TS 36.101 Table 5.5 EUTRA operating bands
+     */
+    public static int getFrequencyRangeGroupFromEutranBand(@EutranBand.EutranBands int band) {
+        switch (band) {
+            case EutranBand.BAND_5:
+            case EutranBand.BAND_6:
+            case EutranBand.BAND_8:
+            case EutranBand.BAND_12:
+            case EutranBand.BAND_13:
+            case EutranBand.BAND_14:
+            case EutranBand.BAND_17:
+            case EutranBand.BAND_18:
+            case EutranBand.BAND_19:
+            case EutranBand.BAND_20:
+            case EutranBand.BAND_26:
+            case EutranBand.BAND_27:
+            case EutranBand.BAND_28:
+            case EutranBand.BAND_31:
+            case EutranBand.BAND_44:
+            case EutranBand.BAND_50:
+            case EutranBand.BAND_51:
+            case EutranBand.BAND_68:
+            case EutranBand.BAND_71:
+            case EutranBand.BAND_72:
+            case EutranBand.BAND_73:
+            case EutranBand.BAND_85:
+            case EutranBand.BAND_87:
+            case EutranBand.BAND_88:
+                return ServiceState.FREQUENCY_RANGE_LOW;
+            case EutranBand.BAND_1:
+            case EutranBand.BAND_2:
+            case EutranBand.BAND_3:
+            case EutranBand.BAND_4:
+            case EutranBand.BAND_7:
+            case EutranBand.BAND_9:
+            case EutranBand.BAND_10:
+            case EutranBand.BAND_11:
+            case EutranBand.BAND_21:
+            case EutranBand.BAND_23:
+            case EutranBand.BAND_24:
+            case EutranBand.BAND_25:
+            case EutranBand.BAND_30:
+            case EutranBand.BAND_33:
+            case EutranBand.BAND_34:
+            case EutranBand.BAND_35:
+            case EutranBand.BAND_36:
+            case EutranBand.BAND_37:
+            case EutranBand.BAND_38:
+            case EutranBand.BAND_39:
+            case EutranBand.BAND_40:
+            case EutranBand.BAND_41:
+            case EutranBand.BAND_45:
+            case EutranBand.BAND_53:
+            case EutranBand.BAND_65:
+            case EutranBand.BAND_66:
+            case EutranBand.BAND_70:
+            case EutranBand.BAND_74:
+                return ServiceState.FREQUENCY_RANGE_MID;
+            case EutranBand.BAND_22:
+            case EutranBand.BAND_42:
+            case EutranBand.BAND_43:
+            case EutranBand.BAND_46:
+            case EutranBand.BAND_47:
+            case EutranBand.BAND_48:
+            case EutranBand.BAND_49:
+            case EutranBand.BAND_52:
+                return ServiceState.FREQUENCY_RANGE_HIGH;
+            default:
+                return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        }
+    }
+
+    /**
+     * Get ngran band from {@link PhysicalChannelConfig#getBand()}
+     * 3GPP TS 38.104 Table 5.2-1 NR operating bands in FR1
+     * 3GPP TS 38.104 Table 5.2-2 NR operating bands in FR2
+     */
+    public static int getFrequencyRangeGroupFromNrBand(@NgranBands.NgranBand int band) {
+        switch (band) {
+            case NgranBands.BAND_5:
+            case NgranBands.BAND_8:
+            case NgranBands.BAND_12:
+            case NgranBands.BAND_14:
+            case NgranBands.BAND_18:
+            case NgranBands.BAND_20:
+            case NgranBands.BAND_26:
+            case NgranBands.BAND_28:
+            case NgranBands.BAND_29:
+            case NgranBands.BAND_71:
+            case NgranBands.BAND_81:
+            case NgranBands.BAND_82:
+            case NgranBands.BAND_83:
+            case NgranBands.BAND_89:
+                return ServiceState.FREQUENCY_RANGE_LOW;
+            case NgranBands.BAND_1:
+            case NgranBands.BAND_2:
+            case NgranBands.BAND_3:
+            case NgranBands.BAND_7:
+            case NgranBands.BAND_25:
+            case NgranBands.BAND_30:
+            case NgranBands.BAND_34:
+            case NgranBands.BAND_38:
+            case NgranBands.BAND_39:
+            case NgranBands.BAND_40:
+            case NgranBands.BAND_41:
+            case NgranBands.BAND_50:
+            case NgranBands.BAND_51:
+            case NgranBands.BAND_53:
+            case NgranBands.BAND_65:
+            case NgranBands.BAND_66:
+            case NgranBands.BAND_70:
+            case NgranBands.BAND_74:
+            case NgranBands.BAND_75:
+            case NgranBands.BAND_76:
+            case NgranBands.BAND_80:
+            case NgranBands.BAND_84:
+            case NgranBands.BAND_86:
+            case NgranBands.BAND_90:
+            case NgranBands.BAND_91:
+            case NgranBands.BAND_92:
+            case NgranBands.BAND_93:
+            case NgranBands.BAND_94:
+            case NgranBands.BAND_95:
+                return ServiceState.FREQUENCY_RANGE_MID;
+            case NgranBands.BAND_46:
+            case NgranBands.BAND_48:
+            case NgranBands.BAND_77:
+            case NgranBands.BAND_78:
+            case NgranBands.BAND_79:
+                return ServiceState.FREQUENCY_RANGE_HIGH;
+            case NgranBands.BAND_96:
+            case NgranBands.BAND_257:
+            case NgranBands.BAND_258:
+            case NgranBands.BAND_260:
+            case NgranBands.BAND_261:
+                return ServiceState.FREQUENCY_RANGE_MMWAVE;
+            default:
+                return ServiceState.FREQUENCY_RANGE_UNKNOWN;
+        }
+    }
+
+    /**
+     * 3GPP TS 38.104 Table 5.4.2.1-1 NR-ARFCN parameters for the global frequency raster.
+     * Formula of NR-ARFCN convert to actual frequency:
+     * Actual frequency(kHz) = (RANGE_OFFSET + GLOBAL_KHZ * (ARFCN - ARFCN_OFFSET))
+     */
+    public static int getFrequencyFromNrArfcn(int nrArfcn) {
+
+        int globalKhz = 0;
+        int rangeOffset = 0;
+        int arfcnOffset = 0;
+        for (NgranArfcnFrequency nrArfcnFrequency : AccessNetworkConstants.
+                NgranArfcnFrequency.values()) {
+            if (nrArfcn >= nrArfcnFrequency.rangeFirst
+                    && nrArfcn <= nrArfcnFrequency.rangeLast) {
+                globalKhz = nrArfcnFrequency.globalKhz;
+                rangeOffset = nrArfcnFrequency.rangeOffset;
+                arfcnOffset = nrArfcnFrequency.arfcnOffset;
+                break;
+            }
+        }
+        return rangeOffset + globalKhz * (nrArfcn - arfcnOffset);
+    }
+
+    /**
+     * Get actual frequency from E-UTRA ARFCN.
+     */
+    public static int getFrequencyFromEarfcn(int band, int earfcn, boolean isUplink) {
+
+        int low = 0;
+        int offset = 0;
+        for (EutranBandArfcnFrequency earfcnFrequency : EutranBandArfcnFrequency.values()) {
+            if (band == earfcnFrequency.band) {
+                if (isInEarfcnRange(earfcn, earfcnFrequency, isUplink)) {
+                    low = isUplink ? earfcnFrequency.uplinkLowKhz : earfcnFrequency.downlinkLowKhz;
+                    offset = isUplink ? earfcnFrequency.uplinkOffset
+                            : earfcnFrequency.downlinkOffset;
+                    break;
+                } else {
+                    Log.e(TAG, "Band and the range of EARFCN are not consistent.");
+                    return INVALID_FREQUENCY;
+                }
+            }
+        }
+        return convertEarfcnToFrequency(low, earfcn, offset);
+    }
+
+    /**
+     * 3GPP TS 36.101 Table 5.7.3-1 E-UTRA channel numbers.
+     * Formula of E-UTRA ARFCN convert to actual frequency:
+     * Actual frequency(kHz) = (DOWNLINK_LOW + 0.1 * (ARFCN - DOWNLINK_OFFSET)) * FREQUENCY_KHZ
+     * Actual frequency(kHz) = (UPLINK_LOW + 0.1 * (ARFCN - UPLINK_OFFSET)) * FREQUENCY_KHZ
+     */
+    private static int convertEarfcnToFrequency(int low, int earfcn, int offset) {
+        return low + 100 * (earfcn - offset);
+    }
+
+    private static boolean isInEarfcnRange(int earfcn, EutranBandArfcnFrequency earfcnFrequency,
+                                           boolean isUplink) {
+        if (isUplink) {
+            return earfcn >= earfcnFrequency.uplinkOffset && earfcn <= earfcnFrequency.uplinkRange;
+        } else {
+            return earfcn >= earfcnFrequency.downlinkOffset
+                    && earfcn <= earfcnFrequency.downlinkRange;
+        }
+    }
+
+    /**
+     * Get actual frequency from UTRA ARFCN.
+     */
+    public static int getFrequencyFromUarfcn(int band, int uarfcn, boolean isUplink) {
+
+        int offsetKhz = 0;
+        for (UtranBandArfcnFrequency uarfcnFrequency : AccessNetworkConstants.
+                UtranBandArfcnFrequency.values()) {
+            if (band == uarfcnFrequency.band) {
+                if (isInUarfcnRange(uarfcn, uarfcnFrequency, isUplink)) {
+                    offsetKhz = isUplink ? uarfcnFrequency.uplinkOffset
+                            : uarfcnFrequency.downlinkOffset;
+                    break;
+                } else {
+                    Log.e(TAG, "Band and the range of UARFCN are not consistent.");
+                    return INVALID_FREQUENCY;
+                }
+            }
+        }
+
+        if (!UARFCN_NOT_GENERAL_BAND.contains(band)) {
+            return convertUarfcnToFrequency(offsetKhz, uarfcn);
+        } else {
+            return convertUarfcnTddToFrequency(band, uarfcn);
+        }
+    }
+
+    /**
+     * 3GPP TS 25.101, Table 5.1 UARFCN definition (general).
+     * Formula of UTRA ARFCN convert to actual frequency:
+     * For general bands:
+     * Downlink actual frequency(kHz) = (DOWNLINK_OFFSET + 0.2 * ARFCN) * FREQUENCY_KHZ
+     * Uplink actual frequency(kHz) = (UPLINK_OFFSET + 0.2 * ARFCN) * FREQUENCY_KHZ
+     */
+    private static int convertUarfcnToFrequency(int offsetKhz, int uarfcn) {
+        return offsetKhz + (200 * uarfcn);
+    }
+
+    /**
+     * 3GPP TS 25.102, Table 5.2 UTRA Absolute Radio Frequency Channel Number 1.28 Mcps TDD Option.
+     * For FDD bands A, B, C, E, F:
+     * Actual frequency(kHz) =  5 * ARFCN * FREQUENCY_KHZ
+     * For TDD bands D:
+     * Actual frequency(kHz) =  (5 * (ARFCN - 2150.1MHz)) * FREQUENCY_KHZ
+     */
+    private static int convertUarfcnTddToFrequency(int band, int uarfcn) {
+        if (band != UtranBand.BAND_D) {
+            return 5 * uarfcn * FREQUENCY_KHZ;
+        } else {
+            return 5 * ((FREQUENCY_KHZ * uarfcn) - 2150100);
+        }
+    }
+
+    private static boolean isInUarfcnRange(int uarfcn, UtranBandArfcnFrequency uarfcnFrequency,
+                                           boolean isUplink) {
+        if (isUplink) {
+            return uarfcn >= uarfcnFrequency.uplinkRangeFirst
+                    && uarfcn <= uarfcnFrequency.uplinkRangeLast;
+        } else {
+            if (uarfcnFrequency.downlinkRangeFirst != 0 && uarfcnFrequency.downlinkRangeLast != 0) {
+                return uarfcn >= uarfcnFrequency.downlinkRangeFirst
+                        && uarfcn <= uarfcnFrequency.downlinkRangeLast;
+            } else {
+                // BAND_C, BAND_D, BAND_E and BAND_F do not have the downlink range.
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Get actual frequency from GERAN ARFCN.
+     */
+    public static int getFrequencyFromArfcn(int band, int arfcn, boolean isUplink) {
+
+        int uplinkFrequencyFirst = 0;
+        int arfcnOffset = 0;
+        int downlinkOffset = 0;
+        int frequency = 0;
+        for (GeranBandArfcnFrequency arfcnFrequency : AccessNetworkConstants.
+                GeranBandArfcnFrequency.values()) {
+            if (band == arfcnFrequency.band) {
+                if (arfcn >= arfcnFrequency.arfcnRangeFirst
+                        && arfcn <= arfcnFrequency.arfcnRangeLast) {
+                    uplinkFrequencyFirst = arfcnFrequency.uplinkFrequencyFirst;
+                    downlinkOffset = arfcnFrequency.downlinkOffset;
+                    arfcnOffset = arfcnFrequency.arfcnOffset;
+                    frequency = convertArfcnToFrequency(arfcn, uplinkFrequencyFirst,
+                            arfcnOffset);
+                    break;
+                } else {
+                    Log.e(TAG, "Band and the range of ARFCN are not consistent.");
+                    return INVALID_FREQUENCY;
+                }
+            }
+        }
+
+        return isUplink ? frequency : frequency + downlinkOffset;
+    }
+
+    /**
+     * 3GPP TS 45.005 Table 2-1 Dynamically mapped ARFCN
+     * Formula of Geran ARFCN convert to actual frequency:
+     * Uplink actual frequency(kHz) =
+     *      (UPLINK_FREQUENCY_FIRST + 0.2 * (ARFCN - ARFCN_RANGE_FIRST)) * FREQUENCY_KHZ
+     * Downlink actual frequency(kHz) = Uplink actual frequency + 10
+     */
+    private static int convertArfcnToFrequency(int arfcn, int uplinkFrequencyFirstKhz,
+                                               int arfcnOffset) {
+        return uplinkFrequencyFirstKhz + 200 * (arfcn - arfcnOffset);
+    }
+
+    public static int getFrequencyRangeFromArfcn(int frequency) {
+        if (frequency < FREQUENCY_RANGE_LOW_KHZ) {
+            return ServiceState.FREQUENCY_RANGE_LOW;
+        } else if (frequency < FREQUENCY_RANGE_MID_KHZ
+                && frequency >= FREQUENCY_RANGE_LOW_KHZ) {
+            return ServiceState.FREQUENCY_RANGE_MID;
+        } else if (frequency < FREQUENCY_RANGE_HIGH_KHZ
+                && frequency >= FREQUENCY_RANGE_MID_KHZ) {
+            return ServiceState.FREQUENCY_RANGE_HIGH;
+        } else {
+            return ServiceState.FREQUENCY_RANGE_MMWAVE;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 74b2aad..e3eb0b5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4077,6 +4077,18 @@
             "use_lower_mtu_value_if_both_received";
 
     /**
+     * Determines the default RTT mode.
+     *
+     * Upon first boot, when the user has not yet set a value for their preferred RTT mode,
+     * the value of this config will be sent to the IMS stack. Valid values are the same as for
+     * {@link Settings.Secure#RTT_CALLING_MODE}.
+     *
+     * @hide
+     */
+    public static final String KEY_DEFAULT_RTT_MODE_INT =
+            "default_rtt_mode_int";
+
+    /**
      * Indicates if auto-configuration server is used for the RCS config
      * Reference: GSMA RCC.14
      */
@@ -4628,6 +4640,7 @@
         sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
         sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
         sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false);
+        sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0);
     }
 
     /**
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 327d631..9fb098e 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -55,6 +55,18 @@
     /** Physical Cell Id is unknown. */
     public static final int PHYSICAL_CELL_ID_UNKNOWN = -1;
 
+    /** Physical Cell Id's maximum value is 1007. */
+    public static final int PHYSICAL_CELL_ID_MAXIMUM_VALUE = 1007;
+
+    /** Cell bandwidth is unknown. */
+    public static final int CELL_BANDWIDTH_UNKNOWN = 0;
+
+    /** The frequency is unknown. */
+    public static final int FREQUENCY_UNKNOWN = -1;
+
+    /** The band is unknown. */
+    public static final int BAND_UNKNOWN = 0;
+
     /**
      * Connection status of the cell.
      *
@@ -64,15 +76,20 @@
     private int mCellConnectionStatus;
 
     /**
-     * Cell bandwidth, in kHz.
+     * Downlink cell bandwidth, in kHz.
      */
     private int mCellBandwidthDownlinkKhz;
 
     /**
+     * Uplink cell bandwidth, in kHz.
+     */
+    private int mCellBandwidthUplinkKhz;
+
+    /**
      * The radio technology for this physical channel.
      */
     @NetworkType
-    private int mRat;
+    private int mNetworkType;
 
     /**
      * The rough frequency range for this physical channel.
@@ -81,9 +98,24 @@
     private int mFrequencyRange;
 
     /**
-     * The absolute radio frequency channel number, {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
+     * The frequency of Downlink.
      */
-    private int mChannelNumber;
+    private int mDownlinkFrequency;
+
+    /**
+     * The frequency of Uplink.
+     */
+    private int mUplinkFrequency;
+
+    /**
+     * Downlink Absolute Radio Frequency Channel Number
+     */
+    private int mDownlinkChannelNumber;
+
+    /**
+     * Uplink Absolute Radio Frequency Channel Number
+     */
+    private int mUplinkChannelNumber;
 
     /**
      * A list of data calls mapped to this physical channel. An empty list means the physical
@@ -96,6 +128,11 @@
      */
     private int mPhysicalCellId;
 
+    /**
+     * This is the band which is being used.
+     */
+    private int mBand;
+
     @Override
     public int describeContents() {
         return 0;
@@ -105,27 +142,39 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mCellConnectionStatus);
         dest.writeInt(mCellBandwidthDownlinkKhz);
-        dest.writeInt(mRat);
-        dest.writeInt(mChannelNumber);
+        dest.writeInt(mCellBandwidthUplinkKhz);
+        dest.writeInt(mNetworkType);
+        dest.writeInt(mDownlinkChannelNumber);
+        dest.writeInt(mUplinkChannelNumber);
         dest.writeInt(mFrequencyRange);
         dest.writeIntArray(mContextIds);
         dest.writeInt(mPhysicalCellId);
+        dest.writeInt(mBand);
     }
 
     /**
-     * @return Cell bandwidth, in kHz
+     * @return Downlink cell bandwidth in kHz, {@link #CELL_BANDWIDTH_UNKNOWN} if unknown.
      */
-    public int getCellBandwidthDownlink() {
+    @IntRange(from = 1)
+    public int getCellBandwidthDownlinkKhz() {
         return mCellBandwidthDownlinkKhz;
     }
 
     /**
+     * @return Uplink cell bandwidth in kHz, {@link #CELL_BANDWIDTH_UNKNOWN} if unknown.
+     */
+    @IntRange(from = 1)
+    public int getCellBandwidthUplinkKhz() {
+        return mCellBandwidthUplinkKhz;
+    }
+
+    /**
      * Get the list of data call ids mapped to this physical channel. This list is sorted into
      * ascending numerical order. Each id in this list must match the id in
      * {@link com.android.internal.telephony.dataconnection.DataConnection}. An empty list means the
      * physical channel has no data call mapped to it.
      *
-     * @return an integer list indicates the data call ids.
+     * @return an integer list indicates the data call ids,
      * @hide
      */
     public int[] getContextIds() {
@@ -133,7 +182,18 @@
     }
 
     /**
-     * @return the rough frequency range for this physical channel.
+     * @return the absolute radio frequency channel number for this physical channel,
+     * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
+     * @deprecated Use {@link #getDownlinkChannelNumber()} to get the channel number.
+     */
+    @Deprecated
+    public int getChannelNumber() {
+        return getDownlinkChannelNumber();
+    }
+
+    /**
+     * @return the rough frequency range for this physical channel,
+     * {@link ServiceState#FREQUENCY_RANGE_UNKNOWN} if unknown.
      * @see {@link ServiceState#FREQUENCY_RANGE_LOW}
      * @see {@link ServiceState#FREQUENCY_RANGE_MID}
      * @see {@link ServiceState#FREQUENCY_RANGE_HIGH}
@@ -146,11 +206,48 @@
     }
 
     /**
-     * @return the absolute radio frequency channel number for this physical channel,
+     * @return Downlink Absolute Radio Frequency Channel Number,
      * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
      */
-    public int getChannelNumber() {
-        return mChannelNumber;
+    @IntRange(from = 0)
+    public int getDownlinkChannelNumber() {
+        return mDownlinkChannelNumber;
+    }
+
+    /**
+     * @return Uplink Absolute Radio Frequency Channel Number,
+     * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
+     */
+    @IntRange(from = 0)
+    public int getUplinkChannelNumber() {
+        return mUplinkChannelNumber;
+    }
+
+    /**
+     * The valid bands are {@link AccessNetworkConstants.GeranBand},
+     * {@link AccessNetworkConstants.UtranBand}, {@link AccessNetworkConstants.EutranBand} and
+     * {@link AccessNetworkConstants.NgranBands}.
+     *
+     * @return the frequency band, {@link #BAND_UNKNOWN} if unknown. */
+    @IntRange(from = 1, to = 261)
+    public int getBand() {
+        return mBand;
+    }
+
+    /**
+     * @return The downlink frequency in kHz, {@link #FREQUENCY_UNKNOWN} if unknown.
+     */
+    @IntRange(from = 0)
+    public int getDownlinkFrequencyKhz() {
+        return mDownlinkFrequency;
+    }
+
+    /**
+     * @return The uplink frequency in kHz, {@link #FREQUENCY_UNKNOWN} if unknown.
+     */
+    @IntRange(from = 0)
+    public int getUplinkFrequencyKhz() {
+        return mUplinkFrequency;
     }
 
     /**
@@ -171,10 +268,13 @@
         return mPhysicalCellId;
     }
 
-    /**The radio technology for this physical channel. */
+    /**
+     * @return The network type for this physical channel,
+     * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if unknown.
+     */
     @NetworkType
     public int getNetworkType() {
-        return mRat;
+        return mNetworkType;
     }
 
     /**
@@ -184,7 +284,7 @@
      * @see #CONNECTION_SECONDARY_SERVING
      * @see #CONNECTION_UNKNOWN
      *
-     * @return Connection status of the cell
+     * @return Connection status of the cell, {@link #CONNECTION_UNKNOWN} if unknown.
      */
     @ConnectionStatus
     public int getConnectionStatus() {
@@ -208,6 +308,97 @@
         }
     }
 
+    private void setDownlinkFrequency() {
+        switch (mNetworkType) {
+            case TelephonyManager.NETWORK_TYPE_NR:
+                mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromNrArfcn(
+                        mDownlinkChannelNumber);
+                break;
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn(
+                        mBand, mDownlinkChannelNumber, false);
+                break;
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+                mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromUarfcn(
+                        mBand, mDownlinkChannelNumber, false);
+                break;
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_GSM:
+                mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromArfcn(
+                        mBand, mDownlinkChannelNumber, false);
+                break;
+        }
+    }
+
+    private void setUplinkFrequency() {
+        switch (mNetworkType){
+            case TelephonyManager.NETWORK_TYPE_NR:
+                mUplinkFrequency = mDownlinkFrequency;
+                break;
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                mUplinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn(
+                        mBand, mUplinkChannelNumber, true);
+                break;
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+                mUplinkFrequency = AccessNetworkUtils.getFrequencyFromUarfcn(
+                        mBand, mUplinkChannelNumber, true);
+                break;
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_GSM:
+                mUplinkFrequency = AccessNetworkUtils.getFrequencyFromArfcn(
+                        mBand, mUplinkChannelNumber, true);
+                break;
+        }
+    }
+
+    private void setFrequencyRange() {
+        if (mFrequencyRange != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+            return;
+        }
+
+        switch (mNetworkType) {
+            case TelephonyManager.NETWORK_TYPE_NR:
+                mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromNrBand(mBand);
+                break;
+            case TelephonyManager.NETWORK_TYPE_LTE:
+                mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromEutranBand(mBand);
+                break;
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+                mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromUtranBand(mBand);
+                break;
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_GSM:
+                mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromGeranBand(mBand);
+                break;
+            default:
+                mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
+                break;
+        }
+
+        if (mFrequencyRange == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+            mFrequencyRange = AccessNetworkUtils.getFrequencyRangeFromArfcn(
+                    mDownlinkFrequency);
+        }
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -221,30 +412,37 @@
         PhysicalChannelConfig config = (PhysicalChannelConfig) o;
         return mCellConnectionStatus == config.mCellConnectionStatus
                 && mCellBandwidthDownlinkKhz == config.mCellBandwidthDownlinkKhz
-                && mRat == config.mRat
+                && mCellBandwidthUplinkKhz == config.mCellBandwidthUplinkKhz
+                && mNetworkType == config.mNetworkType
                 && mFrequencyRange == config.mFrequencyRange
-                && mChannelNumber == config.mChannelNumber
+                && mDownlinkChannelNumber == config.mDownlinkChannelNumber
+                && mUplinkChannelNumber == config.mUplinkChannelNumber
                 && mPhysicalCellId == config.mPhysicalCellId
-                && Arrays.equals(mContextIds, config.mContextIds);
+                && Arrays.equals(mContextIds, config.mContextIds)
+                && mBand == config.mBand
+                && mDownlinkFrequency == config.mDownlinkFrequency
+                && mUplinkFrequency == config.mUplinkFrequency;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(
-                mCellConnectionStatus, mCellBandwidthDownlinkKhz, mRat, mFrequencyRange,
-                mChannelNumber, mPhysicalCellId, mContextIds);
+                mCellConnectionStatus, mCellBandwidthDownlinkKhz, mCellBandwidthUplinkKhz,
+                mNetworkType, mFrequencyRange, mDownlinkChannelNumber, mUplinkChannelNumber,
+                mContextIds, mPhysicalCellId, mBand, mDownlinkFrequency, mUplinkFrequency);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<PhysicalChannelConfig> CREATOR =
-        new Parcelable.Creator<PhysicalChannelConfig>() {
-            public PhysicalChannelConfig createFromParcel(Parcel in) {
-                return new PhysicalChannelConfig(in);
-            }
+    public static final
+    @android.annotation.NonNull Parcelable.Creator<PhysicalChannelConfig> CREATOR =
+            new Parcelable.Creator<PhysicalChannelConfig>() {
+                public PhysicalChannelConfig createFromParcel(Parcel in) {
+                    return new PhysicalChannelConfig(in);
+                }
 
-            public PhysicalChannelConfig[] newArray(int size) {
-                return new PhysicalChannelConfig[size];
-            }
-        };
+                public PhysicalChannelConfig[] newArray(int size) {
+                    return new PhysicalChannelConfig[size];
+                }
+            };
 
     @Override
     public String toString() {
@@ -253,16 +451,26 @@
                 .append(getConnectionStatusString())
                 .append(",mCellBandwidthDownlinkKhz=")
                 .append(mCellBandwidthDownlinkKhz)
-                .append(",mRat=")
-                .append(TelephonyManager.getNetworkTypeName(mRat))
+                .append(",mCellBandwidthUplinkKhz=")
+                .append(mCellBandwidthUplinkKhz)
+                .append(",mNetworkType=")
+                .append(TelephonyManager.getNetworkTypeName(mNetworkType))
                 .append(",mFrequencyRange=")
                 .append(ServiceState.frequencyRangeToString(mFrequencyRange))
-                .append(",mChannelNumber=")
-                .append(mChannelNumber)
+                .append(",mDownlinkChannelNumber=")
+                .append(mDownlinkChannelNumber)
+                .append(",mUplinkChannelNumber=")
+                .append(mUplinkChannelNumber)
                 .append(",mContextIds=")
                 .append(Arrays.toString(mContextIds))
                 .append(",mPhysicalCellId=")
                 .append(mPhysicalCellId)
+                .append(",mBand=")
+                .append(mBand)
+                .append(",mDownlinkFrequency=")
+                .append(mDownlinkFrequency)
+                .append(",mUplinkFrequency=")
+                .append(mUplinkFrequency)
                 .append("}")
                 .toString();
     }
@@ -270,21 +478,37 @@
     private PhysicalChannelConfig(Parcel in) {
         mCellConnectionStatus = in.readInt();
         mCellBandwidthDownlinkKhz = in.readInt();
-        mRat = in.readInt();
-        mChannelNumber = in.readInt();
+        mCellBandwidthUplinkKhz = in.readInt();
+        mNetworkType = in.readInt();
+        mDownlinkChannelNumber = in.readInt();
+        mUplinkChannelNumber = in.readInt();
         mFrequencyRange = in.readInt();
         mContextIds = in.createIntArray();
         mPhysicalCellId = in.readInt();
+        mBand = in.readInt();
+        if (mBand > BAND_UNKNOWN) {
+            setDownlinkFrequency();
+            setUplinkFrequency();
+            setFrequencyRange();
+        }
     }
 
     private PhysicalChannelConfig(Builder builder) {
         mCellConnectionStatus = builder.mCellConnectionStatus;
         mCellBandwidthDownlinkKhz = builder.mCellBandwidthDownlinkKhz;
-        mRat = builder.mRat;
-        mChannelNumber = builder.mChannelNumber;
+        mCellBandwidthUplinkKhz = builder.mCellBandwidthUplinkKhz;
+        mNetworkType = builder.mNetworkType;
+        mDownlinkChannelNumber = builder.mDownlinkChannelNumber;
+        mUplinkChannelNumber = builder.mUplinkChannelNumber;
         mFrequencyRange = builder.mFrequencyRange;
         mContextIds = builder.mContextIds;
         mPhysicalCellId = builder.mPhysicalCellId;
+        mBand = builder.mBand;
+        if (mBand > BAND_UNKNOWN) {
+            setDownlinkFrequency();
+            setUplinkFrequency();
+            setFrequencyRange();
+        }
     }
 
     /**
@@ -292,61 +516,105 @@
      * @hide
      */
     public static final class Builder {
-        private int mRat;
+        private int mNetworkType;
         private int mFrequencyRange;
-        private int mChannelNumber;
+        private int mDownlinkChannelNumber;
+        private int mUplinkChannelNumber;
         private int mCellBandwidthDownlinkKhz;
+        private int mCellBandwidthUplinkKhz;
         private int mCellConnectionStatus;
         private int[] mContextIds;
         private int mPhysicalCellId;
+        private int mBand;
 
         public Builder() {
-            mRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+            mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
             mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
-            mChannelNumber = CHANNEL_NUMBER_UNKNOWN;
-            mCellBandwidthDownlinkKhz = 0;
+            mDownlinkChannelNumber = CHANNEL_NUMBER_UNKNOWN;
+            mUplinkChannelNumber = CHANNEL_NUMBER_UNKNOWN;
+            mCellBandwidthDownlinkKhz = CELL_BANDWIDTH_UNKNOWN;
+            mCellBandwidthUplinkKhz = CELL_BANDWIDTH_UNKNOWN;
             mCellConnectionStatus = CONNECTION_UNKNOWN;
             mContextIds = new int[0];
             mPhysicalCellId = PHYSICAL_CELL_ID_UNKNOWN;
+            mBand = BAND_UNKNOWN;
         }
 
         public PhysicalChannelConfig build() {
             return new PhysicalChannelConfig(this);
         }
 
-        public Builder setRat(int rat) {
-            this.mRat = rat;
+        public @NonNull Builder setNetworkType(@NetworkType int networkType) {
+            if (!TelephonyManager.isNetworkTypeValid(networkType)) {
+                throw new IllegalArgumentException("Network type: " + networkType + " is invalid.");
+            }
+            mNetworkType = networkType;
             return this;
         }
 
-        public Builder setFrequencyRange(int frequencyRange) {
-            this.mFrequencyRange = frequencyRange;
+        public @NonNull Builder setFrequencyRange(int frequencyRange) {
+            if (!ServiceState.isFrequencyRangeValid(frequencyRange)) {
+                throw new IllegalArgumentException("Frequency range: " + frequencyRange +
+                        " is invalid.");
+            }
+            mFrequencyRange = frequencyRange;
             return this;
         }
 
-        public Builder setChannelNumber(int channelNumber) {
-            this.mChannelNumber = channelNumber;
+        public @NonNull Builder setDownlinkChannelNumber(int downlinkChannelNumber) {
+            mDownlinkChannelNumber = downlinkChannelNumber;
             return this;
         }
 
-        public Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) {
-            this.mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
+        public @NonNull Builder setUplinkChannelNumber(int uplinkChannelNumber) {
+            mUplinkChannelNumber = uplinkChannelNumber;
             return this;
         }
 
-        public Builder setCellConnectionStatus(int connectionStatus) {
-            this.mCellConnectionStatus = connectionStatus;
+        public @NonNull Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) {
+            if (cellBandwidthDownlinkKhz < CELL_BANDWIDTH_UNKNOWN) {
+                throw new IllegalArgumentException("Cell downlink bandwidth(kHz): " +
+                        cellBandwidthDownlinkKhz + " is invalid.");
+            }
+            mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
             return this;
         }
 
-        public Builder setContextIds(int[] contextIds) {
+        public @NonNull Builder setCellBandwidthUplinkKhz(int cellBandwidthUplinkKhz) {
+            if (cellBandwidthUplinkKhz < CELL_BANDWIDTH_UNKNOWN) {
+                throw new IllegalArgumentException("Cell uplink bandwidth(kHz): "+
+                        cellBandwidthUplinkKhz +" is invalid.");
+            }
+            mCellBandwidthUplinkKhz = cellBandwidthUplinkKhz;
+            return this;
+        }
+
+        public @NonNull Builder setCellConnectionStatus(int connectionStatus) {
+            mCellConnectionStatus = connectionStatus;
+            return this;
+        }
+
+        public @NonNull Builder setContextIds(int[] contextIds) {
             if (contextIds != null) Arrays.sort(contextIds);
-            this.mContextIds = contextIds;
+            mContextIds = contextIds;
             return this;
         }
 
-        public Builder setPhysicalCellId(int physicalCellId) {
-            this.mPhysicalCellId = physicalCellId;
+        public @NonNull Builder setPhysicalCellId(int physicalCellId) {
+            if (physicalCellId > PHYSICAL_CELL_ID_MAXIMUM_VALUE) {
+                throw new IllegalArgumentException("Physical cell Id: " + physicalCellId +
+                        " is over limit.");
+            }
+            mPhysicalCellId = physicalCellId;
+            return this;
+        }
+
+        public @NonNull Builder setBand(int band) {
+            if (band <= BAND_UNKNOWN) {
+                throw new IllegalArgumentException("Band: " + band +
+                        " is invalid.");
+            }
+            mBand = band;
             return this;
         }
     }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index dedb1af..f110dae 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -2111,4 +2111,23 @@
         }
         return false;
     }
+
+    /**
+     * The frequency range is valid or not.
+     *
+     * @param frequencyRange The frequency range {@link FrequencyRange}.
+     * @return {@code true} if valid, {@code false} otherwise.
+     *
+     * @hide
+     */
+    public static boolean isFrequencyRangeValid(int frequencyRange) {
+        if (frequencyRange == FREQUENCY_RANGE_LOW
+                || frequencyRange == FREQUENCY_RANGE_MID
+                || frequencyRange == FREQUENCY_RANGE_HIGH
+                || frequencyRange == FREQUENCY_RANGE_MMWAVE) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl b/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl
new file mode 100644
index 0000000..a45de2e
--- /dev/null
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2020 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.telephony;
+
+parcelable SignalStrengthUpdateRequest;
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
new file mode 100644
index 0000000..af67ed2
--- /dev/null
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2020 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.telephony;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Request used to register {@link SignalThresholdInfo} to be notified when the signal strength
+ * breach the specified thresholds.
+ */
+public final class SignalStrengthUpdateRequest implements Parcelable {
+    /**
+     * List of SignalThresholdInfo for the request.
+     */
+    private final List<SignalThresholdInfo> mSignalThresholdInfos;
+
+    /**
+     * Whether the reporting is required for thresholds in the request while device is idle.
+     */
+    private final boolean mIsReportingRequestedWhileIdle;
+
+    /**
+     * Whether the reporting requested for system thresholds while device is idle.
+     *
+     * System signal thresholds are loaded from carrier config items and mainly used for UI
+     * displaying. By default, they are ignored when device is idle. When setting the value to true,
+     * modem will continue reporting signal strength changes over the system signal thresholds even
+     * device is idle.
+     *
+     * This should only set to true by the system caller.
+     */
+    private final boolean mIsSystemThresholdReportingRequestedWhileIdle;
+
+    /**
+     * A IBinder object as a token for server side to check if the request client is still living.
+     */
+    private final IBinder mLiveToken;
+
+    private SignalStrengthUpdateRequest(
+            @NonNull List<SignalThresholdInfo> signalThresholdInfos,
+            boolean isReportingRequestedWhileIdle,
+            boolean isSystemThresholdReportingRequestedWhileIdle) {
+        validate(signalThresholdInfos);
+
+        mSignalThresholdInfos = signalThresholdInfos;
+        mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
+        mIsSystemThresholdReportingRequestedWhileIdle =
+                isSystemThresholdReportingRequestedWhileIdle;
+        mLiveToken = new Binder();
+    }
+
+    /**
+     * Builder class to create {@link SignalStrengthUpdateRequest} object.
+     */
+    public static final class Builder {
+        private List<SignalThresholdInfo> mSignalThresholdInfos = null;
+        private boolean mIsReportingRequestedWhileIdle = false;
+        private boolean mIsSystemThresholdReportingRequestedWhileIdle = false;
+
+        /**
+         * Set the collection of SignalThresholdInfo for the builder object
+         *
+         * @param signalThresholdInfos the collection of SignalThresholdInfo
+         *
+         * @return the builder to facilitate the chaining
+         */
+        public @NonNull Builder setSignalThresholdInfos(
+                @NonNull Collection<SignalThresholdInfo> signalThresholdInfos) {
+            Objects.requireNonNull(signalThresholdInfos,
+                    "SignalThresholdInfo collection must not be null");
+            for (SignalThresholdInfo info : signalThresholdInfos) {
+                Objects.requireNonNull(info,
+                        "SignalThresholdInfo in the collection must not be null");
+            }
+
+            mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos);
+            // Sort the collection with RAN ascending order, make the ordering not matter for equals
+            mSignalThresholdInfos.sort(
+                    Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType));
+            return this;
+        }
+
+        /**
+         * Set the builder object if require reporting on thresholds in this request when device is
+         * idle.
+         *
+         * @param isReportingRequestedWhileIdle true if request reporting when device is idle
+         *
+         * @return the builder to facilitate the chaining
+         */
+        public @NonNull Builder setReportingRequestedWhileIdle(
+                boolean isReportingRequestedWhileIdle) {
+            mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
+            return this;
+        }
+
+        /**
+         * Set the builder object if require reporting on the system thresholds when device is idle.
+         *
+         * This can only used by the system caller.
+         *
+         * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the
+         *                                                     system thresholds when device is idle
+         * @return the builder to facilitate the chaining
+         * @hide
+         */
+        public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle(
+                boolean isSystemThresholdReportingRequestedWhileIdle) {
+            mIsSystemThresholdReportingRequestedWhileIdle =
+                    isSystemThresholdReportingRequestedWhileIdle;
+            return this;
+        }
+
+        /**
+         * Build a {@link SignalStrengthUpdateRequest} object.
+         *
+         * @return the SignalStrengthUpdateRequest object
+         *
+         * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the
+         * radio access network type in the collection is not unique
+         */
+        public @NonNull SignalStrengthUpdateRequest build() {
+            return new SignalStrengthUpdateRequest(mSignalThresholdInfos,
+                    mIsReportingRequestedWhileIdle, mIsSystemThresholdReportingRequestedWhileIdle);
+        }
+    }
+
+    private SignalStrengthUpdateRequest(Parcel in) {
+        mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR);
+        mIsReportingRequestedWhileIdle = in.readBoolean();
+        mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean();
+        mLiveToken = in.readStrongBinder();
+    }
+
+    /**
+     * Get the collection of SignalThresholdInfo in the request.
+     *
+     * @return the collection of SignalThresholdInfo
+     */
+    @NonNull
+    public Collection<SignalThresholdInfo> getSignalThresholdInfos() {
+        return Collections.unmodifiableList(mSignalThresholdInfos);
+    }
+
+    /**
+     * Get whether reporting is requested for the threshold in the request while device is idle.
+     *
+     * @return true if reporting requested while device is idle
+     */
+    public boolean isReportingRequestedWhileIdle() {
+        return mIsReportingRequestedWhileIdle;
+    }
+
+    /**
+     * @return true if reporting requested for system thresholds while device is idle
+     *
+     * @hide
+     */
+    public boolean isSystemThresholdReportingRequestedWhileIdle() {
+        return mIsSystemThresholdReportingRequestedWhileIdle;
+    }
+
+    /*
+     * @return the live token of the request
+     *
+     * @hide
+     */
+    public @NonNull IBinder getLiveToken() {
+        return mLiveToken;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedList(mSignalThresholdInfos);
+        dest.writeBoolean(mIsReportingRequestedWhileIdle);
+        dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle);
+        dest.writeStrongBinder(mLiveToken);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) return true;
+
+        if (!(other instanceof SignalStrengthUpdateRequest)) {
+            return false;
+        }
+
+        SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other;
+        return mSignalThresholdInfos.equals(request.mSignalThresholdInfos)
+                && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle
+                && mIsSystemThresholdReportingRequestedWhileIdle
+                    == request.mIsSystemThresholdReportingRequestedWhileIdle;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSignalThresholdInfos, mIsReportingRequestedWhileIdle,
+                mIsSystemThresholdReportingRequestedWhileIdle);
+    }
+
+    public static final @NonNull Parcelable.Creator<SignalStrengthUpdateRequest> CREATOR =
+            new Parcelable.Creator<SignalStrengthUpdateRequest>() {
+                @Override
+                public SignalStrengthUpdateRequest createFromParcel(Parcel source) {
+                    return new SignalStrengthUpdateRequest(source);
+                }
+
+                @Override
+                public SignalStrengthUpdateRequest[] newArray(int size) {
+                    return new SignalStrengthUpdateRequest[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return new StringBuilder("SignalStrengthUpdateRequest{")
+                .append("mSignalThresholdInfos=")
+                .append(mSignalThresholdInfos)
+                .append(" mIsReportingRequestedWhileIdle=")
+                .append(mIsReportingRequestedWhileIdle)
+                .append(" mIsSystemThresholdReportingRequestedWhileIdle=")
+                .append(mIsSystemThresholdReportingRequestedWhileIdle)
+                .append(" mLiveToken")
+                .append(mLiveToken)
+                .append("}").toString();
+    }
+
+    /**
+     * Throw IAE when the RAN in the collection is not unique.
+     */
+    private static void validate(Collection<SignalThresholdInfo> infos) {
+        Set<Integer> uniqueRan = new HashSet<>(infos.size());
+        for (SignalThresholdInfo info : infos) {
+            final int ran = info.getRadioAccessNetworkType();
+            if (!uniqueRan.add(ran)) {
+                throw new IllegalArgumentException("RAN: " + ran + " is not unique");
+            }
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
index bb9c0da3..0059ad6 100644
--- a/telephony/java/android/telephony/SignalThresholdInfo.java
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -280,6 +280,20 @@
     public static final int SIGNAL_SSSINR_MAX_VALUE = 40;
 
     /**
+     * The minimum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @hide
+     */
+    public static final int MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 1;
+
+    /**
+     * The maximum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @hide
+     */
+    public static final int MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 4;
+
+    /**
      * Constructor
      *
      * @param ran               Radio Access Network type
@@ -368,7 +382,11 @@
         /**
          * Set the signal strength thresholds of the corresponding signal measurement type.
          *
-         * The range and unit must reference specific SignalMeasurementType.
+         * The range and unit must reference specific SignalMeasurementType. The length of the
+         * thresholds should between the numbers return from
+         * {@link #getMinimumNumberOfThresholdsAllowed()} and
+         * {@link #getMaximumNumberOfThresholdsAllowed()}. An IllegalArgumentException will throw
+         * otherwise.
          *
          * @param thresholds array of integer as the signal threshold values
          * @return the builder to facilitate the chaining
@@ -385,12 +403,35 @@
          */
         public @NonNull Builder setThresholds(@NonNull int[] thresholds) {
             Objects.requireNonNull(thresholds, "thresholds must not be null");
+            if (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+                    || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED) {
+                throw new IllegalArgumentException(
+                        "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+                                + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED);
+            }
             mThresholds = thresholds.clone();
             Arrays.sort(mThresholds);
             return this;
         }
 
         /**
+         * Set the signal strength thresholds for the corresponding signal measurement type without
+         * the length limitation.
+         *
+         * @param thresholds array of integer as the signal threshold values
+         * @return the builder to facilitate the chaining
+         *
+         * @hide
+         */
+        public @NonNull Builder setThresholdsUnlimited(@NonNull int[] thresholds) {
+            Objects.requireNonNull(thresholds, "thresholds must not be null");
+            mThresholds = thresholds.clone();
+            Arrays.sort(mThresholds);
+            return this;
+        }
+
+
+        /**
          * Set if the modem should trigger the report based on the criteria.
          *
          * @param isEnabled true if the modem should trigger the report based on the criteria
@@ -474,6 +515,24 @@
         return mThresholds.clone();
     }
 
+    /**
+     * Get the minimum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @return the minimum number of thresholds allowed
+     */
+    public static int getMinimumNumberOfThresholdsAllowed() {
+        return MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
+    }
+
+    /**
+     * Get the maximum number of threshold allowed in each SignalThresholdInfo.
+     *
+     * @return the maximum number of thresholds allowed
+     */
+    public static int getMaximumNumberOfThresholdsAllowed() {
+        return MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index bcc2c67..b958bff 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -345,7 +345,6 @@
      * where this operation may fail.
      * </p>
      *
-     *
      * @param destinationAddress the address to send the message to
      * @param scAddress is the service center address or null to use
      *  the current default SMSC
@@ -358,7 +357,6 @@
      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
      *  <code>RESULT_ERROR_NULL_PDU</code><br>
      *  <code>RESULT_ERROR_NO_SERVICE</code><br>
-     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -473,7 +471,6 @@
      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
      *  <code>RESULT_ERROR_NULL_PDU</code><br>
      *  <code>RESULT_ERROR_NO_SERVICE</code><br>
-     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -862,22 +859,20 @@
      * where this operation may fail.
      * </p>
      *
-     *
      * @param destinationAddress the address to send the message to
      * @param scAddress is the service center address or null to use
-     *   the current default SMSC
+     *  the current default SMSC
      * @param parts an <code>ArrayList</code> of strings that, in order,
-     *   comprise the original message
+     *  comprise the original message
      * @param sentIntents if not null, an <code>ArrayList</code> of
-     *   <code>PendingIntent</code>s (one for each message part) that is
-     *   broadcast when the corresponding message part has been sent.
-     *   The result code will be <code>Activity.RESULT_OK</code> for success,
-     *   or one of these errors:<br>
+     *  <code>PendingIntent</code>s (one for each message part) that is
+     *  broadcast when the corresponding message part has been sent.
+     *  The result code will be <code>Activity.RESULT_OK</code> for success,
+     *  or one of these errors:<br>
      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
      *  <code>RESULT_ERROR_NULL_PDU</code><br>
      *  <code>RESULT_ERROR_NO_SERVICE</code><br>
-     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -933,14 +928,14 @@
      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
      *  value, generally only useful for troubleshooting.<br>
-     *   The per-application based SMS control checks sentIntent. If sentIntent
-     *   is NULL the caller will be checked against all unknown applications,
-     *   which cause smaller number of SMS to be sent in checking period.
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applications,
+     *  which cause smaller number of SMS to be sent in checking period.
      * @param deliveryIntents if not null, an <code>ArrayList</code> of
-     *   <code>PendingIntent</code>s (one for each message part) that is
-     *   broadcast when the corresponding message part has been delivered
-     *   to the recipient.  The raw pdu of the status report is in the
-     *   extended data ("pdu").
+     *  <code>PendingIntent</code>s (one for each message part) that is
+     *  broadcast when the corresponding message part has been delivered
+     *  to the recipient.  The raw pdu of the status report is in the
+     *  extended data ("pdu").
      *
      * @throws IllegalArgumentException if destinationAddress or data are empty
      */
@@ -1123,22 +1118,21 @@
      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
      * where this operation may fail.
      * </p>
-
+     *
      * @param destinationAddress the address to send the message to
      * @param scAddress is the service center address or null to use
-     *   the current default SMSC
+     *  the current default SMSC
      * @param parts an <code>ArrayList</code> of strings that, in order,
-     *   comprise the original message
+     *  comprise the original message
      * @param sentIntents if not null, an <code>ArrayList</code> of
-     *   <code>PendingIntent</code>s (one for each message part) that is
-     *   broadcast when the corresponding message part has been sent.
-     *   The result code will be <code>Activity.RESULT_OK</code> for success,
-     *   or one of these errors:<br>
+     *  <code>PendingIntent</code>s (one for each message part) that is
+     *  broadcast when the corresponding message part has been sent.
+     *  The result code will be <code>Activity.RESULT_OK</code> for success,
+     *  or one of these errors:<br>
      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
      *  <code>RESULT_ERROR_NULL_PDU</code><br>
      *  <code>RESULT_ERROR_NO_SERVICE</code><br>
-     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
@@ -1194,14 +1188,14 @@
      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
      *  the sentIntent may include the extra "errorCode" containing a radio technology specific
      *  value, generally only useful for troubleshooting.<br>
-     *   The per-application based SMS control checks sentIntent. If sentIntent
-     *   is NULL the caller will be checked against all unknown applications,
-     *   which cause smaller number of SMS to be sent in checking period.
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applications,
+     *  which cause smaller number of SMS to be sent in checking period.
      * @param deliveryIntents if not null, an <code>ArrayList</code> of
-     *   <code>PendingIntent</code>s (one for each message part) that is
-     *   broadcast when the corresponding message part has been delivered
-     *   to the recipient.  The raw pdu of the status report is in the
-     *   extended data ("pdu").
+     *  <code>PendingIntent</code>s (one for each message part) that is
+     *  broadcast when the corresponding message part has been delivered
+     *  to the recipient.  The raw pdu of the status report is in the
+     *  extended data ("pdu").
      * @param priority Priority level of the message
      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
      *  ---------------------------------
@@ -1340,7 +1334,6 @@
      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
      *  <code>RESULT_ERROR_NULL_PDU</code><br>
      *  <code>RESULT_ERROR_NO_SERVICE</code><br>
-     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java
index 3d5c6aa..1fcb504 100644
--- a/telephony/java/android/telephony/TelephonyDisplayInfo.java
+++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java
@@ -29,6 +29,10 @@
  * information is provided in accordance with carrier policy and branding preferences; it is not
  * necessarily a precise or accurate representation of the current state and should be treated
  * accordingly.
+ * To be notified of changes in TelephonyDisplayInfo, use
+ * {@link TelephonyManager#registerPhoneStateListener} with a {@link PhoneStateListener}
+ * that implements {@link PhoneStateListener.DisplayInfoChangedListener}.
+ * Override the onDisplayInfoChanged() method to handle the broadcast.
  */
 public final class TelephonyDisplayInfo implements Parcelable {
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f39ee09..f018f2f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -120,6 +120,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -7456,18 +7457,23 @@
     }
 
     /**
-     * Set IMS registration state
+     * Set IMS registration state on all active subscriptions.
+     * <p/>
+     * Use {@link android.telephony.ims.stub.ImsRegistrationImplBase#onRegistered} and
+     * {@link android.telephony.ims.stub.ImsRegistrationImplBase#onDeregistered} to set Ims
+     * registration state instead.
      *
-     * @param Registration state
+     * @param registered whether ims is registered
+     *
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void setImsRegistrationState(boolean registered) {
+    public void setImsRegistrationState(final boolean registered) {
         try {
-            ITelephony telephony = getITelephony();
+            final ITelephony telephony = getITelephony();
             if (telephony != null)
                 telephony.setImsRegistrationState(registered);
-        } catch (RemoteException e) {
+        } catch (final RemoteException e) {
         }
     }
 
@@ -9456,9 +9462,16 @@
      * @return true if mobile data is enabled.
      */
     @RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
-            android.Manifest.permission.MODIFY_PHONE_STATE})
+            android.Manifest.permission.MODIFY_PHONE_STATE,
+            android.Manifest.permission.READ_PHONE_STATE})
     public boolean isDataEnabled() {
-        return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
+        try {
+            return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
+        } catch (IllegalStateException ise) {
+            // TODO(b/176163590): Remove this catch once TelephonyManager is booting safely.
+            Log.e(TAG, "Error calling #isDataEnabled, returning default (false).", ise);
+            return false;
+        }
     }
 
     /**
@@ -9703,7 +9716,7 @@
     @SystemApi
     public boolean getDataEnabled(int subId) {
         try {
-            return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
+            return isDataEnabledForReason(subId, DATA_ENABLED_REASON_USER);
         } catch (RuntimeException e) {
             Log.e(TAG, "Error calling isDataEnabledForReason e:" + e);
         }
@@ -14668,4 +14681,98 @@
             throw new IllegalStateException("telephony service is null.");
         }
     }
+
+    /**
+     * The network type is valid or not.
+     *
+     * @param networkType The network type {@link NetworkType}.
+     * @return {@code true} if valid, {@code false} otherwise.
+     *
+     * @hide
+     */
+    public static boolean isNetworkTypeValid(@NetworkType int networkType) {
+        return networkType >= TelephonyManager.NETWORK_TYPE_UNKNOWN &&
+                networkType <= TelephonyManager.NETWORK_TYPE_NR;
+    }
+
+    /**
+     * Set a {@link SignalStrengthUpdateRequest} to receive notification when signal quality
+     * measurements breach the specified thresholds.
+     *
+     * To be notified, set the signal strength update request and then register
+     * {@link TelephonyManager#listen(PhoneStateListener, int)} with
+     * {@link PhoneStateListener#LISTEN_SIGNAL_STRENGTHS}. The notification will arrive through
+     * {@link PhoneStateListener#onSignalStrengthsChanged(SignalStrength)}.
+     *
+     * To stop receiving the notification over the specified thresholds, pass the same
+     * {@link SignalStrengthUpdateRequest} object to
+     * {@link #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}.
+     *
+     * System will clean up the {@link SignalStrengthUpdateRequest} if the caller process died
+     * without calling {@link #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}.
+     *
+     * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+     * applies to the given subId. Otherwise, applies to
+     * {@link SubscriptionManager#getDefaultSubscriptionId()}. To request for multiple subIds,
+     * pass a request object to each TelephonyManager object created with
+     * {@link #createForSubscriptionId}.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * or that the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * Note that the thresholds in the request will be used on a best-effort basis; the system may
+     * modify requests to multiplex various request sources or to optimize power consumption. The
+     * caller should not expect to be notified with the exactly the same thresholds.
+     *
+     * @see #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)
+     *
+     * @param request the SignalStrengthUpdateRequest to be set into the System
+     *
+     * @throws IllegalStateException if a new request is set with same subId from the same caller
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void setSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) {
+        Objects.requireNonNull(request, "request must not be null");
+
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                service.setSignalStrengthUpdateRequest(getSubId(), request, getOpPackageName());
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#setSignalStrengthUpdateRequest", e);
+        }
+    }
+
+    /**
+     * Clear a {@link SignalStrengthUpdateRequest} from the system.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * or that the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * <p>If the given request was not set before, this operation is a no-op.
+     *
+     * @see #setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)
+     *
+     * @param request the SignalStrengthUpdateRequest to be cleared from the System
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void clearSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) {
+        Objects.requireNonNull(request, "request must not be null");
+
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                service.clearSignalStrengthUpdateRequest(getSubId(), request, getOpPackageName());
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#clearSignalStrengthUpdateRequest", e);
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index e085dec..2c75368 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -25,6 +25,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -85,6 +86,22 @@
                         AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
             }};
 
+    /** @hide */
+    @NonNull
+    static String registrationStateToString(
+            final @NetworkRegistrationInfo.RegistrationState int value) {
+        switch (value) {
+            case REGISTRATION_STATE_NOT_REGISTERED:
+                return "REGISTRATION_STATE_NOT_REGISTERED";
+            case REGISTRATION_STATE_REGISTERING:
+                return "REGISTRATION_STATE_REGISTERING";
+            case REGISTRATION_STATE_REGISTERED:
+                return "REGISTRATION_STATE_REGISTERED";
+            default:
+                return Integer.toString(value);
+        }
+    }
+
     /**
      * Callback class for receiving IMS network Registration callback events.
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 541ec04..f566269 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -49,6 +49,7 @@
 import android.telephony.RadioAccessSpecifier;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.SignalStrengthUpdateRequest;
 import android.telephony.TelephonyHistogram;
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import android.telephony.emergency.EmergencyNumber;
@@ -2367,4 +2368,17 @@
      *  their mobile plan.
      */
     String getMobileProvisioningUrl();
+
+    /**
+     * Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
+     * specified thresholds.
+     */
+    void setSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request,
+            String callingPackage);
+
+    /**
+     * Clear a SignalStrengthUpdateRequest from system.
+     */
+    void clearSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request,
+            String callingPackage);
 }
diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt
index 1110790..d1a68d4 100644
--- a/test-mock/api/current.txt
+++ b/test-mock/api/current.txt
@@ -117,6 +117,7 @@
     method public void sendOrderedBroadcast(android.content.Intent, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
     method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
     method public void sendStickyBroadcast(android.content.Intent);
+    method public void sendStickyBroadcast(android.content.Intent, android.os.Bundle);
     method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
     method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index cf3b03c..6046d78 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -493,6 +493,11 @@
     }
 
     @Override
+    public void sendStickyBroadcast(Intent intent, Bundle options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void sendStickyOrderedBroadcast(Intent intent,
             BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
            Bundle initialExtras) {
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index 2cb16d3372..b2bcfeb 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -58,7 +58,8 @@
 
     @Test
     fun testParcelUnparcel() {
-        assertParcelSane(data, fieldCount = 8)
+        val fieldCount = if (SdkLevel.isAtLeastS()) 8 else 7
+        assertParcelSane(data, fieldCount)
 
         assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
         assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index abf16f2..37307a4 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -21,6 +21,7 @@
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.Intent.ACTION_USER_UNLOCKED;
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -221,6 +222,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.security.Credentials;
 import android.security.KeyStore;
 import android.system.Os;
 import android.telephony.TelephonyManager;
@@ -237,6 +239,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
+import com.android.internal.net.VpnProfile;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -279,6 +282,7 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -384,6 +388,7 @@
     @Mock MockableSystemProperties mSystemProperties;
     @Mock EthernetManager mEthernetManager;
     @Mock NetworkPolicyManager mNetworkPolicyManager;
+    @Mock KeyStore mKeyStore;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
             ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -1062,6 +1067,15 @@
         private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
         private VpnInfo mVpnInfo;
 
+        // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
+        // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
+        // test expects two starts in a row, or even if the production code calls start twice in a
+        // row. find a better solution. Simply putting a method to create a LegacyVpnRunner into
+        // Vpn.Dependencies doesn't work because LegacyVpnRunner is not a static class and has
+        // extensive access into the internals of Vpn.
+        private ConditionVariable mStartLegacyVpnCv = new ConditionVariable();
+        private ConditionVariable mStopVpnRunnerCv = new ConditionVariable();
+
         public MockVpn(int userId) {
             super(startHandlerThreadAndReturnLooper(), mServiceContext,
                     new Dependencies() {
@@ -1075,7 +1089,7 @@
                             return mDeviceIdleInternal;
                         }
                     },
-                    mNetworkManagementService, mMockNetd, userId, mock(KeyStore.class));
+                    mNetworkManagementService, mMockNetd, userId, mKeyStore);
         }
 
         public void setUids(Set<UidRange> uids) {
@@ -1187,10 +1201,44 @@
             }
             mAgentRegistered = false;
             setUids(null);
+            // Remove NET_CAPABILITY_INTERNET or MockNetworkAgent will refuse to connect later on.
+            mNetworkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
             mInterface = null;
         }
 
         @Override
+        public void startLegacyVpnRunner() {
+            mStartLegacyVpnCv.open();
+        }
+
+        public void expectStartLegacyVpnRunner() {
+            assertTrue("startLegacyVpnRunner not called after " + TIMEOUT_MS + " ms",
+                    mStartLegacyVpnCv.block(TIMEOUT_MS));
+
+            // startLegacyVpn calls stopVpnRunnerPrivileged, which will open mStopVpnRunnerCv, just
+            // before calling startLegacyVpnRunner. Restore mStopVpnRunnerCv, so the test can expect
+            // that the VpnRunner is stopped and immediately restarted by calling
+            // expectStartLegacyVpnRunner() and expectStopVpnRunnerPrivileged() back-to-back.
+            mStopVpnRunnerCv = new ConditionVariable();
+        }
+
+        @Override
+        public void stopVpnRunnerPrivileged() {
+            if (mVpnRunner != null) {
+                super.stopVpnRunnerPrivileged();
+                disconnect();
+                mStartLegacyVpnCv = new ConditionVariable();
+            }
+            mVpnRunner = null;
+            mStopVpnRunnerCv.open();
+        }
+
+        public void expectStopVpnRunnerPrivileged() {
+            assertTrue("stopVpnRunnerPrivileged not called after " + TIMEOUT_MS + " ms",
+                    mStopVpnRunnerCv.block(TIMEOUT_MS));
+        }
+
+        @Override
         public synchronized VpnInfo getVpnInfo() {
             if (mVpnInfo != null) return mVpnInfo;
 
@@ -1271,10 +1319,19 @@
         }
     }
 
-    private static final int VPN_USER = 0;
-    private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100);
-    private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101);
-    private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043);
+    private static final int PRIMARY_USER = 0;
+    private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
+    private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
+    private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
+    private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
+            UserInfo.FLAG_PRIMARY);
+
+    private static final int RESTRICTED_USER = 1;
+    private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
+            UserInfo.FLAG_RESTRICTED);
+    static {
+        RESTRICTED_USER_INFO.restrictedProfileParentId = PRIMARY_USER;
+    }
 
     @Before
     public void setUp() throws Exception {
@@ -1284,10 +1341,13 @@
 
         MockitoAnnotations.initMocks(this);
 
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(VPN_USER, "", 0),
-                }));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+        when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
+        // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
+        // it was started from, i.e., PRIMARY_USER.
+        when(mUserManager.canHaveRestrictedProfile()).thenReturn(true);
+        when(mUserManager.getUserInfo(RESTRICTED_USER)).thenReturn(RESTRICTED_USER_INFO);
+
         final ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
@@ -1359,6 +1419,7 @@
         doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
         doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
         doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
+        doReturn(mKeyStore).when(deps).getKeyStore();
         doAnswer(inv -> {
             mPolicyTracker = new WrappedMultinetworkPolicyTracker(
                     inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -1527,7 +1588,7 @@
             waitForIdle();
             try {
                 final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
-                fail("Unexpected broadcast: " + intent.getAction());
+                fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras());
             } catch (TimeoutException expected) {
             } finally {
                 mServiceContext.unregisterReceiver(mReceiver);
@@ -5831,6 +5892,131 @@
         mCm.unregisterNetworkCallback(callback);
     }
 
+    private void assertGetNetworkInfoOfGetActiveNetworkIsConnected(boolean expectedConnectivity) {
+        // What Chromium used to do before https://chromium-review.googlesource.com/2605304
+        assertEquals("Unexpected result for getActiveNetworkInfo(getActiveNetwork())",
+                expectedConnectivity, mCm.getNetworkInfo(mCm.getActiveNetwork()).isConnected());
+    }
+
+    @Test
+    public void testVpnUnderlyingNetworkSuspended() throws Exception {
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(callback);
+
+        // Connect a VPN.
+        mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
+                false /* isStrictMode */);
+        callback.expectAvailableCallbacksUnvalidated(mMockVpn);
+
+        // Connect cellular data.
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(false /* validated */);
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.assertNoCallback();
+
+        assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
+
+        // Suspend the cellular network and expect the VPN to be suspended.
+        mCellNetworkAgent.suspend();
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
+        callback.assertNoCallback();
+
+        assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+        // VPN's main underlying network is suspended, so no connectivity.
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+        // Switch to another network. The VPN should no longer be suspended.
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false /* validated */);
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_WIFI));
+
+        // BUG: the VPN is no longer suspended, so a RESUMED callback should have been sent.
+        // callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
+        callback.assertNoCallback();
+
+        assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);  // BUG: VPN caps have NOT_SUSPENDED.
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        // BUG: the device has connectivity, so this should return true.
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+        // Unsuspend cellular and then switch back to it.
+        // The same bug happens in the opposite direction: the VPN's capabilities correctly have
+        // NOT_SUSPENDED, but the VPN's NetworkInfo is in state SUSPENDED.
+        mCellNetworkAgent.resume();
+        callback.assertNoCallback();
+        mWiFiNetworkAgent.disconnect();
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        // Spurious double callback?
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.assertNoCallback();
+
+        assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);  // BUG: VPN caps have NOT_SUSPENDED.
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        // BUG: the device has connectivity, so this should return true.
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+        // Re-suspending the current network fixes the problem.
+        mCellNetworkAgent.suspend();
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
+        callback.assertNoCallback();
+
+        assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
+
+        mCellNetworkAgent.resume();
+        callback.expectCapabilitiesThat(mMockVpn,
+                nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
+                        && nc.hasTransport(TRANSPORT_CELLULAR));
+        callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
+        callback.assertNoCallback();
+
+        assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+                .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
+    }
+
     @Test
     public void testVpnNetworkActive() throws Exception {
         final int uid = Process.myUid();
@@ -6309,7 +6495,7 @@
     }
 
     @Test
-    public void testVpnRestrictedUsers() throws Exception {
+    public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
         // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
         mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
                 PERMISSION_GRANTED);
@@ -6341,19 +6527,11 @@
         callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
                 -> caps.hasCapability(NET_CAPABILITY_VALIDATED));
 
-        // Create a fake restricted profile whose parent is our user ID.
-        final int userId = UserHandle.getUserId(uid);
-        when(mUserManager.canHaveRestrictedProfile()).thenReturn(true);
-        final int restrictedUserId = userId + 1;
-        final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED);
-        info.restrictedProfileParentId = userId;
-        assertTrue(info.isRestricted());
-        when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info);
-        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, restrictedUserId))
-                .thenReturn(UserHandle.getUid(restrictedUserId, VPN_UID));
+        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
+                .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
 
         final Intent addedIntent = new Intent(ACTION_USER_ADDED);
-        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
 
         // Send a USER_ADDED broadcast for it.
         // The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
@@ -6365,7 +6543,7 @@
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
                 && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+                && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && caps.hasTransport(TRANSPORT_WIFI));
 
@@ -6375,13 +6553,13 @@
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
                 && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+                && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
 
         // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
-        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
         handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
 
         // Expect that the VPN gains the UID range for the restricted user, and that the capability
@@ -6391,53 +6569,72 @@
                 && caps.getUids().contains(new UidRange(uid, uid))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
+    }
 
-        // Test lockdown with restricted profiles.
+    @Test
+    public void testLockdownVpnWithRestrictedProfiles() throws Exception {
+        // For ConnectivityService#setAlwaysOnVpnPackage.
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
+        // For call Vpn#setAlwaysOnPackage.
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+        // Necessary to see the UID ranges in NetworkCapabilities.
         mServiceContext.setPermission(
                 Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
 
+        final NetworkRequest request = new NetworkRequest.Builder()
+                .removeCapability(NET_CAPABILITY_NOT_VPN)
+                .build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+
+        final int uid = Process.myUid();
+
         // Connect wifi and check that UIDs in the main and restricted profiles have network access.
-        mMockVpn.disconnect();
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true /* validated */);
-        final int restrictedUid = UserHandle.getUid(restrictedUserId, 42 /* appId */);
+        final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */);
         assertNotNull(mCm.getActiveNetworkForUid(uid));
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
         final ArrayList<String> allowList = new ArrayList<>();
-        mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */,
+                allowList);
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
+        // This is arguably overspecified: a UID that is not running doesn't have an active network.
+        // But it's useful to check that non-default users do not lose network access, and to prove
+        // that the loss of connectivity below is indeed due to the restricted profile coming up.
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Start the restricted profile, and check that the UID within it loses network access.
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(userId, "", 0),
-                        info
-                }));
+        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
+                .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO,
+                RESTRICTED_USER_INFO));
         // TODO: check that VPN app within restricted profile still has access, etc.
+        final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
+        final Handler handler = new Handler(mCsHandlerThread.getLooper());
         handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
         assertNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Stop the restricted profile, and check that the UID within it has network access again.
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(userId, "", 0),
-                }));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+
+        // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
+        final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
         handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
-        mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList);
         waitForIdle();
     }
 
@@ -6778,6 +6975,7 @@
         final int userId = UserHandle.getUserId(uid);
         final ArrayList<String> allowList = new ArrayList<>();
         mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        waitForIdle();
 
         UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
         UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999);
@@ -6799,10 +6997,10 @@
 
         // Disable lockdown, expect to see the network unblocked.
         mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
-        expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
         callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         vpnUidCallback.assertNoCallback();
+        expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -6845,9 +7043,11 @@
         // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
         // Everything should now be blocked.
         mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
         allowList.clear();
         mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
         defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
         assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
@@ -6925,6 +7125,200 @@
         mCm.unregisterNetworkCallback(vpnUidCallback);
     }
 
+    private void setupLegacyLockdownVpn() {
+        final String profileName = "testVpnProfile";
+        final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
+        when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true);
+        when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
+
+        final VpnProfile profile = new VpnProfile(profileName);
+        profile.name = "My VPN";
+        profile.server = "192.0.2.1";
+        profile.dnsServers = "8.8.8.8";
+        profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
+        final byte[] encodedProfile = profile.encode();
+        when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
+    }
+
+    @Test
+    public void testLegacyLockdownVpn() throws Exception {
+        mServiceContext.setPermission(
+                Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+
+        final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+
+        final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(defaultCallback);
+
+        // Pretend lockdown VPN was configured.
+        setupLegacyLockdownVpn();
+
+        // LockdownVpnTracker disables the Vpn teardown code and enables lockdown.
+        // Check the VPN's state before it does so.
+        assertTrue(mMockVpn.getEnableTeardown());
+        assertFalse(mMockVpn.getLockdown());
+
+        // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker.
+        final int userId = UserHandle.getUserId(Process.myUid());
+        final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        final Handler handler = new Handler(mCsHandlerThread.getLooper());
+        handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+        waitForIdle();
+
+        // Lockdown VPN disables teardown and enables lockdown.
+        assertFalse(mMockVpn.getEnableTeardown());
+        assertTrue(mMockVpn.getLockdown());
+
+        // Bring up a network.
+        // Expect nothing to happen because the network does not have an IPv4 default route: legacy
+        // VPN only supports IPv4.
+        final LinkProperties cellLp = new LinkProperties();
+        cellLp.setInterfaceName("rmnet0");
+        cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+        cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0"));
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(false /* validated */);
+        callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        waitForIdle();
+        assertNull(mMockVpn.getAgent());
+
+        // Add an IPv4 address. Ideally the VPN should start, but it doesn't because nothing calls
+        // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
+        // TODO: consider fixing this.
+        cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25"));
+        cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0"));
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        waitForIdle();
+        assertNull(mMockVpn.getAgent());
+
+        // Disconnect, then try again with a network that supports IPv4 at connection time.
+        // Expect lockdown VPN to come up.
+        ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        mCellNetworkAgent.disconnect();
+        callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        b1.expectBroadcast();
+
+        // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten
+        // with the state of the VPN network. So expect a CONNECTING broadcast.
+        b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(false /* validated */);
+        callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        b1.expectBroadcast();
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+
+        // TODO: it would be nice if we could simply rely on the production code here, and have
+        // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with
+        // ConnectivityService, etc. That would require duplicating a fair bit of code from the
+        // Vpn tests around how to mock out LegacyVpnRunner. But even if we did that, this does not
+        // work for at least two reasons:
+        // 1. In this test, calling registerNetworkAgent does not actually result in an agent being
+        //    registered. This is because nothing calls onNetworkMonitorCreated, which is what
+        //    actually ends up causing handleRegisterNetworkAgent to be called. Code in this test
+        //    that wants to register an agent must use TestNetworkAgentWrapper.
+        // 2. Even if we exposed Vpn#agentConnect to the test, and made MockVpn#agentConnect call
+        //    the TestNetworkAgentWrapper code, this would deadlock because the
+        //    TestNetworkAgentWrapper code cannot be called on the handler thread since it calls
+        //    waitForIdle().
+        mMockVpn.expectStartLegacyVpnRunner();
+        b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
+        ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
+        mMockVpn.establishForMyUid();
+        callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
+        final LinkProperties wifiLp = new LinkProperties();
+        wifiLp.setInterfaceName("wlan0");
+        wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25"));
+        wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0"));
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+
+        b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        // Wifi is CONNECTING because the VPN isn't up yet.
+        b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING);
+        ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
+        mWiFiNetworkAgent.connect(false /* validated */);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+        b3.expectBroadcast();
+        mMockVpn.expectStopVpnRunnerPrivileged();
+        mMockVpn.expectStartLegacyVpnRunner();
+
+        // TODO: why is wifi not blocked? Is it because when this callback is sent, the VPN is still
+        // connected, so the network is not considered blocked by the lockdown UID ranges? But the
+        // fact that a VPN is connected should only result in the VPN itself being unblocked, not
+        // any other network. Bug in isUidBlockedByVpn?
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        callback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
+        callback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        defaultCallback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
+        defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+
+        // While the VPN is reconnecting on the new network, everything is blocked.
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+
+        // The VPN comes up again on wifi.
+        b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
+        b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
+        mMockVpn.establishForMyUid();
+        callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        // Disconnect cell. Nothing much happens since it's not the default network.
+        // Whenever LockdownVpnTracker is connected, it will send a connected broadcast any time any
+        // NetworkInfo is updated. This is probably a bug.
+        // TODO: consider fixing this.
+        b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
+        mCellNetworkAgent.disconnect();
+        b1.expectBroadcast();
+        callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        defaultCallback.assertNoCallback();
+
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
+        mWiFiNetworkAgent.disconnect();
+        callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+        b1.expectBroadcast();
+        callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
+        b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
+        mMockVpn.expectStopVpnRunnerPrivileged();
+        callback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        b2.expectBroadcast();
+    }
+
     @Test
     public final void testLoseTrusted() throws Exception {
         final NetworkRequest trustedRequest = new NetworkRequest.Builder()
@@ -7599,7 +7993,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -7627,7 +8021,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -7643,7 +8037,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -7658,7 +8052,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -7710,7 +8104,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final UidRange vpnRange = UidRange.createForUser(VPN_USER);
+        final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
         final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -7908,7 +8302,7 @@
 
     private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
             throws Exception {
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
         mMockVpn.setVpnType(vpnType);
@@ -8112,11 +8506,18 @@
         assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
     }
 
+    public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) {
+        final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
+                ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
+                TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
+        return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
+                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
+                0, INVALID_UID);
+    }
+
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(
                 android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
@@ -8129,9 +8530,7 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
 
@@ -8144,9 +8543,7 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
 
@@ -8159,10 +8556,7 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
-        final Network network = new Network(NET_ID);
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mMockVpn.establishForMyUid();
         assertUidRangesUpdatedForMyUid(true);
@@ -8172,7 +8566,7 @@
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
-        assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
+        assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {naiWithoutUid.network}));
         waitForIdle();
         assertTrue(
                 "Active VPN permission not applied",
@@ -8193,9 +8587,7 @@
     public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
         final NetworkCapabilities nc = new NetworkCapabilities();
         nc.setAdministratorUids(new int[] {Process.myUid()});
-        final NetworkAgentInfo naiWithUid =
-                new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
-                        mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
@@ -8212,9 +8604,7 @@
         final NetworkCapabilities nc = new NetworkCapabilities();
         nc.setOwnerUid(Process.myUid());
         nc.setAdministratorUids(new int[] {Process.myUid()});
-        final NetworkAgentInfo naiWithUid =
-                new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
-                        mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
@@ -8481,7 +8871,7 @@
         lp.setInterfaceName("tun0");
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
-        final UidRange vpnRange = UidRange.createForUser(VPN_USER);
+        final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
         Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 96c56e3..4d151af 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -34,7 +34,9 @@
 import android.net.ConnectivityManager;
 import android.net.IDnsResolver;
 import android.net.INetd;
+import android.net.LinkProperties;
 import android.net.Network;
+import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
@@ -353,9 +355,10 @@
         NetworkCapabilities caps = new NetworkCapabilities();
         caps.addCapability(0);
         caps.addTransportType(transport);
-        NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null,
-                caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
-                NetworkProvider.ID_NONE, Binder.getCallingUid());
+        NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
+                new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
+                mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
+                Binder.getCallingUid());
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 25bd7c0..1102624 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -29,7 +29,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -197,6 +196,11 @@
     }
 
     @Override
+    public void sendStickyBroadcast(Intent intent, Bundle options) {
+        sendBroadcast(intent);
+    }
+
+    @Override
     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
         sendBroadcast(intent);
     }
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
index 3c08d34..c04ddd7 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -16,6 +16,7 @@
         "frameworks-base-testutils",
         "framework-protos",
         "mockito-target-minus-junit4",
+        "net-tests-utils",
         "platform-test-annotations",
         "services.core",
     ],
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
new file mode 100644
index 0000000..9c6b719
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 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.net.vcn;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.concurrent.Executor;
+
+public class VcnManagerTest {
+    private static final Executor INLINE_EXECUTOR = Runnable::run;
+
+    private IVcnManagementService mMockVcnManagementService;
+    private VcnUnderlyingNetworkPolicyListener mMockPolicyListener;
+
+    private Context mContext;
+    private VcnManager mVcnManager;
+
+    @Before
+    public void setUp() {
+        mMockVcnManagementService = mock(IVcnManagementService.class);
+        mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class);
+
+        mContext = getContext();
+        mVcnManager = new VcnManager(mContext, mMockVcnManagementService);
+    }
+
+    @Test
+    public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+        mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener);
+
+        ArgumentCaptor<IVcnUnderlyingNetworkPolicyListener> captor =
+                ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class);
+        verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture());
+
+        assertTrue(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+
+        IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue();
+        listenerWrapper.onPolicyChanged();
+        verify(mMockPolicyListener).onPolicyChanged();
+    }
+
+    @Test
+    public void testRemoveVcnUnderlyingNetworkPolicyListener() throws Exception {
+        mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener);
+
+        mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+        verify(mMockVcnManagementService)
+                .addVcnUnderlyingNetworkPolicyListener(
+                        any(IVcnUnderlyingNetworkPolicyListener.class));
+    }
+
+    @Test
+    public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception {
+        mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+        verify(mMockVcnManagementService, never())
+                .addVcnUnderlyingNetworkPolicyListener(
+                        any(IVcnUnderlyingNetworkPolicyListener.class));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testAddVcnUnderlyingNetworkPolicyListenerNullExecutor() throws Exception {
+        mVcnManager.addVcnUnderlyingNetworkPolicyListener(null, mMockPolicyListener);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testAddVcnUnderlyingNetworkPolicyListenerNullListener() throws Exception {
+        mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() {
+        mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null);
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
new file mode 100644
index 0000000..3ba0a1f
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 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.net.vcn;
+
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.NetworkCapabilities;
+
+import org.junit.Test;
+
+public class VcnUnderlyingNetworkPolicyTest {
+    private static final VcnUnderlyingNetworkPolicy DEFAULT_NETWORK_POLICY =
+            new VcnUnderlyingNetworkPolicy(
+                    false /* isTearDownRequested */, new NetworkCapabilities());
+    private static final VcnUnderlyingNetworkPolicy SAMPLE_NETWORK_POLICY =
+            new VcnUnderlyingNetworkPolicy(
+                    true /* isTearDownRequested */,
+                    new NetworkCapabilities.Builder()
+                            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                            .build());
+
+    @Test
+    public void testEquals() {
+        assertEquals(DEFAULT_NETWORK_POLICY, DEFAULT_NETWORK_POLICY);
+        assertEquals(SAMPLE_NETWORK_POLICY, SAMPLE_NETWORK_POLICY);
+
+        assertNotEquals(DEFAULT_NETWORK_POLICY, SAMPLE_NETWORK_POLICY);
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        assertParcelSane(SAMPLE_NETWORK_POLICY, 2);
+    }
+}