Merge "Create the ResumeOnRebootService."
diff --git a/Android.bp b/Android.bp
index 2316823..402cf1c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -483,6 +483,7 @@
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
         "android.security.apc-java",
+        "android.security.authorization-java",
         "android.system.keystore2-java",
         "android.system.suspend.control.internal-java",
         "devicepolicyprotosnano",
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 97600135..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 405d6f6..dc2868a 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -20,6 +20,7 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.storage.DiskInfo;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
@@ -30,6 +31,8 @@
 
 public final class Sm {
     private static final String TAG = "Sm";
+    private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
+            "persist.sys.vold_app_data_isolation_enabled";
 
     IStorageManager mSm;
 
@@ -256,6 +259,10 @@
     }
 
     public void runDisableAppDataIsolation() throws RemoteException {
+        if (!SystemProperties.getBoolean(
+                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
+            throw new IllegalStateException("Storage app data isolation is not enabled.");
+        }
         final String pkgName = nextArg();
         final int pid = Integer.parseInt(nextArg());
         final int userId = Integer.parseInt(nextArg());
diff --git a/config/OWNERS b/config/OWNERS
index d59c6f2..001038d 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -4,5 +4,11 @@
 
 per-file hiddenapi-* = andreionea@google.com, mathewi@google.com, satayev@google.com
 
+# art-team@ manages the boot image profiles
+per-file boot-* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file dirty-image-objects = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file generate-preloaded-classes.sh = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file preloaded-classes* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+
 # Escalations:
 per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index a7a82f9..c71ec3d 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";
@@ -35868,6 +35889,9 @@
     method @NonNull public String getVersion();
     method public boolean isConnected();
     method public void shutdown();
+    field public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED = "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";
+    field public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";
+    field public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";
   }
 
   public static interface SEService.OnConnectedListener {
@@ -39226,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
@@ -39237,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
@@ -39266,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 {
@@ -39553,6 +39581,7 @@
     field public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
     field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
     field public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+    field public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = "rtt_supported_while_roaming";
     field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
     field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
     field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
@@ -40703,17 +40732,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
   }
 
@@ -40798,6 +40837,7 @@
 
   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);
@@ -41175,6 +41215,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();
@@ -41253,7 +41294,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);
@@ -41287,6 +41328,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..bc4a3ca 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -10,6 +10,14 @@
 
 package android.net {
 
+  public class ConnectivityManager {
+    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 final class NetworkCapabilities implements android.os.Parcelable {
+    field public static final int TRANSPORT_TEST = 7; // 0x7
+  }
+
   public final class TcpRepairWindow {
     ctor public TcpRepairWindow(int, int, int, int, int, int);
     field public final int maxWindow;
@@ -20,6 +28,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 {
@@ -28,6 +52,10 @@
     method public final void markVintfStability();
   }
 
+  public static class Build.VERSION {
+    field public static final int FIRST_SDK_INT;
+  }
+
   public interface Parcelable {
     method public default int getStability();
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 8552f44..e72a9b4 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -127,6 +127,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";
@@ -1413,8 +1414,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
@@ -1596,6 +1603,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 {
@@ -1685,7 +1711,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";
@@ -5995,6 +6020,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
+    method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
@@ -6004,6 +6030,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
+    method public void unregisterQosCallback(@NonNull android.net.QosCallback);
     method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
     field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
     field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
@@ -6197,6 +6224,8 @@
     method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
     method public void onAutomaticReconnectDisabled();
     method public void onNetworkUnwanted();
+    method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
+    method public void onQosCallbackUnregistered(int);
     method public void onRemoveKeepalivePacketFilter(int);
     method public void onSaveAcceptUnvalidated(boolean);
     method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
@@ -6207,6 +6236,9 @@
     method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
     method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
     method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
+    method public final void sendQosCallbackError(int, int);
+    method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
+    method public final void sendQosSessionLost(int, int);
     method public final void sendSocketKeepaliveEvent(int, int);
     method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
     method public void unregister();
@@ -6293,6 +6325,9 @@
     method public abstract void onRequestScores(android.net.NetworkKey[]);
   }
 
+  public class NetworkReleasedException extends java.lang.Exception {
+  }
+
   public class NetworkRequest implements android.os.Parcelable {
     method @Nullable public String getRequestorPackageName();
     method public int getRequestorUid();
@@ -6365,6 +6400,47 @@
     ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
   }
 
+  public abstract class QosCallback {
+    ctor public QosCallback();
+    method public void onError(@NonNull android.net.QosCallbackException);
+    method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
+    method public void onQosSessionLost(@NonNull android.net.QosSession);
+  }
+
+  public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
+  }
+
+  public final class QosCallbackException extends java.lang.Exception {
+  }
+
+  public abstract class QosFilter {
+    method @NonNull public abstract android.net.Network getNetwork();
+    method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+  }
+
+  public final class QosSession implements android.os.Parcelable {
+    ctor public QosSession(int, int);
+    method public int describeContents();
+    method public int getSessionId();
+    method public int getSessionType();
+    method public long getUniqueId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
+    field public static final int TYPE_EPS_BEARER = 1; // 0x1
+  }
+
+  public interface QosSessionAttributes {
+  }
+
+  public final class QosSocketInfo implements android.os.Parcelable {
+    ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
+    method public int describeContents();
+    method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
+    method @NonNull public android.net.Network getNetwork();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
+  }
+
   public final class RouteInfo implements android.os.Parcelable {
     ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
     ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
@@ -6410,6 +6486,12 @@
     field public static final int SUCCESS = 0; // 0x0
   }
 
+  public class SocketLocalAddressChangedException extends java.lang.Exception {
+  }
+
+  public class SocketNotBoundException extends java.lang.Exception {
+  }
+
   public final class StaticIpConfiguration implements android.os.Parcelable {
     ctor public StaticIpConfiguration();
     ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
@@ -6506,157 +6588,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);
   }
 
 }
@@ -6927,7 +7009,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
   }
@@ -7047,24 +7132,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();
@@ -10763,6 +10834,19 @@
     field public static final int RESULT_SUCCESS = 0; // 0x0
   }
 
+  public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
+    method @NonNull public static android.telephony.data.EpsBearerQosSessionAttributes create(@NonNull android.os.Parcel);
+    method public int describeContents();
+    method public long getGuaranteedDownlinkBitRate();
+    method public long getGuaranteedUplinkBitRate();
+    method public long getMaxDownlinkBitRate();
+    method public long getMaxUplinkBitRate();
+    method public int getQci();
+    method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
+  }
+
   public abstract class QualifiedNetworksService extends android.app.Service {
     ctor public QualifiedNetworksService();
     method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
@@ -11809,6 +11893,7 @@
     ctor public SipMessage(@NonNull String, @NonNull String, @NonNull byte[]);
     method public int describeContents();
     method @NonNull public byte[] getContent();
+    method @NonNull public byte[] getEncodedMessage();
     method @NonNull public String getHeaderSection();
     method @NonNull public String getStartLine();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -12246,6 +12331,164 @@
 
 }
 
+package android.uwb {
+
+  public final class AngleMeasurement implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
+    method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians();
+    method @FloatRange(from=-3.141592653589793, to=3.141592653589793) public double getRadians();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleMeasurement> CREATOR;
+  }
+
+  public static final class AngleMeasurement.Builder {
+    ctor public AngleMeasurement.Builder();
+    method @NonNull public android.uwb.AngleMeasurement build();
+    method @NonNull public android.uwb.AngleMeasurement.Builder setConfidenceLevel(double);
+    method @NonNull public android.uwb.AngleMeasurement.Builder setErrorRadians(double);
+    method @NonNull public android.uwb.AngleMeasurement.Builder setRadians(double);
+  }
+
+  public final class AngleOfArrivalMeasurement implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.uwb.AngleMeasurement getAltitude();
+    method @NonNull public android.uwb.AngleMeasurement getAzimuth();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleOfArrivalMeasurement> CREATOR;
+  }
+
+  public static final class AngleOfArrivalMeasurement.Builder {
+    ctor public AngleOfArrivalMeasurement.Builder();
+    method @NonNull public android.uwb.AngleOfArrivalMeasurement build();
+    method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAltitude(@NonNull android.uwb.AngleMeasurement);
+    method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAzimuth(@NonNull android.uwb.AngleMeasurement);
+  }
+
+  public final class DistanceMeasurement implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
+    method public double getErrorMeters();
+    method public double getMeters();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.DistanceMeasurement> CREATOR;
+  }
+
+  public static final class DistanceMeasurement.Builder {
+    ctor public DistanceMeasurement.Builder();
+    method @NonNull public android.uwb.DistanceMeasurement build();
+    method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(double);
+    method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(double);
+    method @NonNull public android.uwb.DistanceMeasurement.Builder setMeters(double);
+  }
+
+  public final class RangingMeasurement implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.uwb.AngleOfArrivalMeasurement getAngleOfArrivalMeasurement();
+    method @Nullable public android.uwb.DistanceMeasurement getDistanceMeasurement();
+    method public long getElapsedRealtimeNanos();
+    method @NonNull public android.uwb.UwbAddress getRemoteDeviceAddress();
+    method public int getStatus();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingMeasurement> CREATOR;
+    field public static final int RANGING_STATUS_FAILURE_OUT_OF_RANGE = 1; // 0x1
+    field public static final int RANGING_STATUS_FAILURE_UNKNOWN_ERROR = -1; // 0xffffffff
+    field public static final int RANGING_STATUS_SUCCESS = 0; // 0x0
+  }
+
+  public static final class RangingMeasurement.Builder {
+    ctor public RangingMeasurement.Builder();
+    method @NonNull public android.uwb.RangingMeasurement build();
+    method @NonNull public android.uwb.RangingMeasurement.Builder setAngleOfArrivalMeasurement(@NonNull android.uwb.AngleOfArrivalMeasurement);
+    method @NonNull public android.uwb.RangingMeasurement.Builder setDistanceMeasurement(@NonNull android.uwb.DistanceMeasurement);
+    method @NonNull public android.uwb.RangingMeasurement.Builder setElapsedRealtimeNanos(long);
+    method @NonNull public android.uwb.RangingMeasurement.Builder setRemoteDeviceAddress(@NonNull android.uwb.UwbAddress);
+    method @NonNull public android.uwb.RangingMeasurement.Builder setStatus(int);
+  }
+
+  public final class RangingReport implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.uwb.RangingMeasurement> getMeasurements();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingReport> CREATOR;
+  }
+
+  public static final class RangingReport.Builder {
+    ctor public RangingReport.Builder();
+    method @NonNull public android.uwb.RangingReport.Builder addMeasurement(@NonNull android.uwb.RangingMeasurement);
+    method @NonNull public android.uwb.RangingReport.Builder addMeasurements(@NonNull java.util.List<android.uwb.RangingMeasurement>);
+    method @NonNull public android.uwb.RangingReport build();
+  }
+
+  public final class RangingSession implements java.lang.AutoCloseable {
+    method public void close();
+    method public void reconfigure(@NonNull android.os.PersistableBundle);
+    method public void start(@NonNull android.os.PersistableBundle);
+    method public void stop();
+  }
+
+  public static interface RangingSession.Callback {
+    method public void onClosed(int, @NonNull android.os.PersistableBundle);
+    method public void onOpenFailed(int, @NonNull android.os.PersistableBundle);
+    method public void onOpened(@NonNull android.uwb.RangingSession);
+    method public void onReconfigureFailed(int, @NonNull android.os.PersistableBundle);
+    method public void onReconfigured(@NonNull android.os.PersistableBundle);
+    method public void onReportReceived(@NonNull android.uwb.RangingReport);
+    method public void onStartFailed(int, @NonNull android.os.PersistableBundle);
+    method public void onStarted(@NonNull android.os.PersistableBundle);
+    method public void onStopFailed(int, @NonNull android.os.PersistableBundle);
+    method public void onStopped();
+    field public static final int REASON_BAD_PARAMETERS = 3; // 0x3
+    field public static final int REASON_GENERIC_ERROR = 4; // 0x4
+    field public static final int REASON_LOCAL_REQUEST = 1; // 0x1
+    field public static final int REASON_MAX_SESSIONS_REACHED = 5; // 0x5
+    field public static final int REASON_PROTOCOL_SPECIFIC_ERROR = 7; // 0x7
+    field public static final int REASON_REMOTE_REQUEST = 2; // 0x2
+    field public static final int REASON_SYSTEM_POLICY = 6; // 0x6
+    field public static final int REASON_UNKNOWN = 0; // 0x0
+  }
+
+  public final class UwbAddress implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public static android.uwb.UwbAddress fromBytes(@NonNull byte[]);
+    method public int size();
+    method @NonNull public byte[] toBytes();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.uwb.UwbAddress> CREATOR;
+    field public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8; // 0x8
+    field public static final int SHORT_ADDRESS_BYTE_LENGTH = 2; // 0x2
+  }
+
+  public final class UwbManager {
+    method public long elapsedRealtimeResolutionNanos();
+    method public int getAngleOfArrivalSupport();
+    method public int getMaxRemoteDevicesPerInitiatorSession();
+    method public int getMaxRemoteDevicesPerResponderSession();
+    method public int getMaxSimultaneousSessions();
+    method @NonNull public android.os.PersistableBundle getSpecificationInfo();
+    method @NonNull public java.util.List<java.lang.Integer> getSupportedChannelNumbers();
+    method @NonNull public java.util.Set<java.lang.Integer> getSupportedPreambleCodeIndices();
+    method public boolean isRangingSupported();
+    method @NonNull public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
+    method public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
+    method public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
+    field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; // 0x2
+    field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; // 0x3
+    field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; // 0x4
+    field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; // 0x1
+  }
+
+  public static interface UwbManager.AdapterStateCallback {
+    method public void onStateChanged(boolean, int);
+    field public static final int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1; // 0x1
+    field public static final int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4; // 0x4
+    field public static final int STATE_CHANGED_REASON_SESSION_STARTED = 0; // 0x0
+    field public static final int STATE_CHANGED_REASON_SYSTEM_BOOT = 3; // 0x3
+    field public static final int STATE_CHANGED_REASON_SYSTEM_POLICY = 2; // 0x2
+  }
+
+}
+
 package android.view {
 
   public abstract class Window {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9cf9ce4..ea9e926 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -980,10 +980,6 @@
 
 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);
-  }
-
   public class EthernetManager {
     method public void setIncludeTestInterfaces(boolean);
   }
@@ -992,31 +988,10 @@
     field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
-  public final class NetworkCapabilities implements android.os.Parcelable {
-    method public int[] getCapabilities();
-    field public static final int TRANSPORT_TEST = 7; // 0x7
-  }
-
   public class NetworkStack {
     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/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/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9acf6756..69d3879 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -85,8 +85,10 @@
 import android.service.restrictions.RestrictionsReceiver;
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.net.NetworkUtilsInternal;
@@ -4524,30 +4526,10 @@
                     if (!proxySpec.type().equals(Proxy.Type.HTTP)) {
                         throw new IllegalArgumentException();
                     }
-                    InetSocketAddress sa = (InetSocketAddress)proxySpec.address();
-                    String hostName = sa.getHostName();
-                    int port = sa.getPort();
-                    StringBuilder hostBuilder = new StringBuilder();
-                    hostSpec = hostBuilder.append(hostName)
-                        .append(":").append(Integer.toString(port)).toString();
-                    if (exclusionList == null) {
-                        exclSpec = "";
-                    } else {
-                        StringBuilder listBuilder = new StringBuilder();
-                        boolean firstDomain = true;
-                        for (String exclDomain : exclusionList) {
-                            if (!firstDomain) {
-                                listBuilder = listBuilder.append(",");
-                            } else {
-                                firstDomain = false;
-                            }
-                            listBuilder = listBuilder.append(exclDomain.trim());
-                        }
-                        exclSpec = listBuilder.toString();
-                    }
-                    if (android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec)
-                            != android.net.Proxy.PROXY_VALID)
-                        throw new IllegalArgumentException();
+                    final Pair<String, String> proxyParams =
+                            getProxyParameters(proxySpec, exclusionList);
+                    hostSpec = proxyParams.first;
+                    exclSpec = proxyParams.second;
                 }
                 return mService.setGlobalProxy(admin, hostSpec, exclSpec);
             } catch (RemoteException e) {
@@ -4558,6 +4540,35 @@
     }
 
     /**
+     * Build HTTP proxy parameters for {@link IDevicePolicyManager#setGlobalProxy}.
+     * @throws IllegalArgumentException Invalid proxySpec
+     * @hide
+     */
+    @VisibleForTesting
+    public Pair<String, String> getProxyParameters(Proxy proxySpec, List<String> exclusionList) {
+        InetSocketAddress sa = (InetSocketAddress) proxySpec.address();
+        String hostName = sa.getHostName();
+        int port = sa.getPort();
+        final List<String> trimmedExclList;
+        if (exclusionList == null) {
+            trimmedExclList = Collections.emptyList();
+        } else {
+            trimmedExclList = new ArrayList<>(exclusionList.size());
+            for (String exclDomain : exclusionList) {
+                trimmedExclList.add(exclDomain.trim());
+            }
+        }
+        final ProxyInfo info = ProxyInfo.buildDirectProxy(hostName, port, trimmedExclList);
+        // The hostSpec is built assuming that there is a specified port and hostname,
+        // but ProxyInfo.isValid() accepts 0 / empty as unspecified: also reject them.
+        if (port == 0 || TextUtils.isEmpty(hostName) || !info.isValid()) {
+            throw new IllegalArgumentException();
+        }
+
+        return new Pair<>(hostName + ":" + port, TextUtils.join(",", trimmedExclList));
+    }
+
+    /**
      * Set a network-independent global HTTP proxy. This is not normally what you want for typical
      * HTTP proxies - they are generally network dependent. However if you're doing something
      * unusual like general internal filtering this may be useful. On a private network where the
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/graphics/fonts/OWNERS b/core/java/android/graphics/fonts/OWNERS
new file mode 100644
index 0000000..18486af
--- /dev/null
+++ b/core/java/android/graphics/fonts/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ce0ed5b..d107261 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -19,6 +19,7 @@
 import static android.net.NetworkRequest.Type.LISTEN;
 import static android.net.NetworkRequest.Type.REQUEST;
 import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
+import static android.net.QosCallback.QosCallbackRegistrationException;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
@@ -29,7 +30,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.app.PendingIntent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -4823,6 +4823,8 @@
     /**
      * Simulates a Data Stall for the specified Network.
      *
+     * <p>This method should only be used for tests.
+     *
      * <p>The caller must be the owner of the specified Network.
      *
      * @param detectionMethod The detection method used to identify the Data Stall.
@@ -4832,7 +4834,7 @@
      * @throws SecurityException if the caller is not the owner of the given network.
      * @hide
      */
-    @TestApi
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS,
             android.Manifest.permission.NETWORK_STACK})
     public void simulateDataStall(int detectionMethod, long timestampMillis,
@@ -4848,4 +4850,118 @@
         Log.d(TAG, "setOemNetworkPreference called with preference: "
                 + preference.toString());
     }
+
+    @NonNull
+    private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
+
+    /**
+     * Registers a {@link QosSocketInfo} with an associated {@link QosCallback}.  The callback will
+     * receive available QoS events related to the {@link Network} and local ip + port
+     * specified within socketInfo.
+     * <p/>
+     * The same {@link QosCallback} must be unregistered before being registered a second time,
+     * otherwise {@link QosCallbackRegistrationException} is thrown.
+     * <p/>
+     * This API does not, in itself, require any permission if called with a network that is not
+     * restricted. However, the underlying implementation currently only supports the IMS network,
+     * which is always restricted. That means non-preinstalled callers can't possibly find this API
+     * useful, because they'd never be called back on networks that they would have access to.
+     *
+     * @throws SecurityException if {@link QosSocketInfo#getNetwork()} is restricted and the app is
+     * missing CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
+     * @throws QosCallback.QosCallbackRegistrationException if qosCallback is already registered.
+     * @throws RuntimeException if the app already has too many callbacks registered.
+     *
+     * Exceptions after the time of registration is passed through
+     * {@link QosCallback#onError(QosCallbackException)}.  see: {@link QosCallbackException}.
+     *
+     * @param socketInfo the socket information used to match QoS events
+     * @param callback receives qos events that satisfy socketInfo
+     * @param executor The executor on which the callback will be invoked. The provided
+     *                 {@link Executor} must run callback sequentially, otherwise the order of
+     *                 callbacks cannot be guaranteed.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void registerQosCallback(@NonNull final QosSocketInfo socketInfo,
+            @NonNull final QosCallback callback,
+            @CallbackExecutor @NonNull final Executor executor) {
+        Objects.requireNonNull(socketInfo, "socketInfo must be non-null");
+        Objects.requireNonNull(callback, "callback must be non-null");
+        Objects.requireNonNull(executor, "executor must be non-null");
+
+        try {
+            synchronized (mQosCallbackConnections) {
+                if (getQosCallbackConnection(callback) == null) {
+                    final QosCallbackConnection connection =
+                            new QosCallbackConnection(this, callback, executor);
+                    mQosCallbackConnections.add(connection);
+                    mService.registerQosSocketCallback(socketInfo, connection);
+                } else {
+                    Log.e(TAG, "registerQosCallback: Callback already registered");
+                    throw new QosCallbackRegistrationException();
+                }
+            }
+        } catch (final RemoteException e) {
+            Log.e(TAG, "registerQosCallback: Error while registering ", e);
+
+            // The same unregister method method is called for consistency even though nothing
+            // will be sent to the ConnectivityService since the callback was never successfully
+            // registered.
+            unregisterQosCallback(callback);
+            e.rethrowFromSystemServer();
+        } catch (final ServiceSpecificException e) {
+            Log.e(TAG, "registerQosCallback: Error while registering ", e);
+            unregisterQosCallback(callback);
+            throw convertServiceException(e);
+        }
+    }
+
+    /**
+     * Unregisters the given {@link QosCallback}.  The {@link QosCallback} will no longer receive
+     * events once unregistered and can be registered a second time.
+     * <p/>
+     * If the {@link QosCallback} does not have an active registration, it is a no-op.
+     *
+     * @param callback the callback being unregistered
+     *
+     * @hide
+     */
+    @SystemApi
+    public void unregisterQosCallback(@NonNull final QosCallback callback) {
+        Objects.requireNonNull(callback, "The callback must be non-null");
+        try {
+            synchronized (mQosCallbackConnections) {
+                final QosCallbackConnection connection = getQosCallbackConnection(callback);
+                if (connection != null) {
+                    connection.stopReceivingMessages();
+                    mService.unregisterQosCallback(connection);
+                    mQosCallbackConnections.remove(connection);
+                } else {
+                    Log.d(TAG, "unregisterQosCallback: Callback not registered");
+                }
+            }
+        } catch (final RemoteException e) {
+            Log.e(TAG, "unregisterQosCallback: Error while unregistering ", e);
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets the connection related to the callback.
+     *
+     * @param callback the callback to look up
+     * @return the related connection
+     */
+    @Nullable
+    private QosCallbackConnection getQosCallbackConnection(final QosCallback callback) {
+        for (final QosCallbackConnection connection : mQosCallbackConnections) {
+            // Checking by reference here is intentional
+            if (connection.getCallback() == callback) {
+                return connection;
+            }
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 5e925b6..6fecee6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -20,6 +20,8 @@
 import android.net.ConnectionInfo;
 import android.net.ConnectivityDiagnosticsManager;
 import android.net.IConnectivityDiagnosticsCallback;
+import android.net.IQosCallback;
+import android.net.ISocketKeepaliveCallback;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkAgentConfig;
@@ -27,9 +29,9 @@
 import android.net.NetworkInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
-import android.net.ISocketKeepaliveCallback;
 import android.net.ProxyInfo;
 import android.net.UidRange;
+import android.net.QosSocketInfo;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.INetworkActivityListener;
@@ -206,11 +208,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);
@@ -239,4 +241,7 @@
     void unregisterNetworkActivityListener(in INetworkActivityListener l);
 
     boolean isDefaultNetworkActive();
+
+    void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
+    void unregisterQosCallback(in IQosCallback callback);
 }
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 792e5b4..29a3fdf 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -81,4 +81,5 @@
     void factoryReset(String subscriber);
 
     boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
+    boolean isUidRestrictedOnMeteredNetworks(int uid);
 }
diff --git a/core/java/android/net/IQosCallback.aidl b/core/java/android/net/IQosCallback.aidl
new file mode 100644
index 0000000..91c7575
--- /dev/null
+++ b/core/java/android/net/IQosCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import android.os.Bundle;
+import android.net.QosSession;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+/**
+ * AIDL interface for QosCallback
+ *
+ * @hide
+ */
+oneway interface IQosCallback
+{
+     void onQosEpsBearerSessionAvailable(in QosSession session,
+        in EpsBearerQosSessionAttributes attributes);
+     void onQosSessionLost(in QosSession session);
+     void onError(in int type);
+}
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..d22d82d 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -30,6 +30,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.telephony.data.EpsBearerQosSessionAttributes;
 import android.util.Log;
 
 import com.android.connectivity.aidl.INetworkAgent;
@@ -228,12 +229,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
      * CONNECTED so it can be given special treatment at that time.
@@ -347,6 +342,24 @@
      */
     private static final int EVENT_AGENT_DISCONNECTED = BASE + 19;
 
+    /**
+     * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with
+     * callback.
+     *
+     * arg1 = QoS agent callback ID
+     * obj = {@link QosFilter}
+     * @hide
+     */
+    public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20;
+
+    /**
+     * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback.
+     *
+     * arg1 = QoS agent callback ID
+     * @hide
+     */
+    public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
+
     private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
         // The subtype can be changed with (TODO) setLegacySubtype, but it starts
         // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -526,6 +539,17 @@
                     onRemoveKeepalivePacketFilter(msg.arg1 /* slot */);
                     break;
                 }
+                case CMD_REGISTER_QOS_CALLBACK: {
+                    onQosCallbackRegistered(
+                            msg.arg1 /* QoS callback id */,
+                            (QosFilter) msg.obj /* QoS filter */);
+                    break;
+                }
+                case CMD_UNREGISTER_QOS_CALLBACK: {
+                    onQosCallbackUnregistered(
+                            msg.arg1 /* QoS callback id */);
+                    break;
+                }
             }
         }
     }
@@ -559,6 +583,8 @@
     }
 
     private static class NetworkAgentBinder extends INetworkAgent.Stub {
+        private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName();
+
         private final Handler mHandler;
 
         private NetworkAgentBinder(Handler handler) {
@@ -645,6 +671,25 @@
             mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
                     slot, 0));
         }
+
+        @Override
+        public void onQosFilterCallbackRegistered(final int qosCallbackId,
+                final QosFilterParcelable qosFilterParcelable) {
+            if (qosFilterParcelable.getQosFilter() != null) {
+                mHandler.sendMessage(
+                        mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0,
+                                qosFilterParcelable.getQosFilter()));
+                return;
+            }
+
+            Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null.");
+        }
+
+        @Override
+        public void onQosCallbackUnregistered(final int qosCallbackId) {
+            mHandler.sendMessage(mHandler.obtainMessage(
+                    CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
+        }
     }
 
     /**
@@ -1073,8 +1118,68 @@
     protected void preventAutomaticReconnect() {
     }
 
+    /**
+     * Called when a qos callback is registered with a filter.
+     * @param qosCallbackId the id for the callback registered
+     * @param filter the filter being registered
+     */
+    public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) {
+    }
+
+    /**
+     * Called when a qos callback is registered with a filter.
+     * <p/>
+     * Any QoS events that are sent with the same callback id after this method is called
+     * are a no-op.
+     *
+     * @param qosCallbackId the id for the callback being unregistered
+     */
+    public void onQosCallbackUnregistered(final int qosCallbackId) {
+    }
+
+
+    /**
+     * Sends the attributes of Eps Bearer Qos Session back to the Application
+     *
+     * @param qosCallbackId the callback id that the session belongs to
+     * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+     * @param attributes the attributes of the Eps Qos Session
+     */
+    public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
+            @NonNull final EpsBearerQosSessionAttributes attributes) {
+        Objects.requireNonNull(attributes, "The attributes must be non-null");
+        queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
+                new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
+                attributes));
+    }
+
+    /**
+     * Sends event that the Eps Qos Session was lost.
+     *
+     * @param qosCallbackId the callback id that the session belongs to
+     * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+     */
+    public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
+        queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
+                new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
+    }
+
+    /**
+     * Sends the exception type back to the application.
+     *
+     * The NetworkAgent should not send anymore messages with this id.
+     *
+     * @param qosCallbackId the callback id this exception belongs to
+     * @param exceptionType the type of exception
+     */
+    public final void sendQosCallbackError(final int qosCallbackId,
+            @QosCallbackException.ExceptionType final int exceptionType) {
+        queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
+    }
+
+
     /** @hide */
-    protected void log(String s) {
+    protected void log(final String s) {
         Log.d(LOG_TAG, "NetworkAgent: " + s);
     }
 }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 2d9f6d8..0a895b9 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -23,7 +23,6 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.os.Build;
@@ -576,7 +575,6 @@
      * @hide
      */
     @UnsupportedAppUsage
-    @TestApi
     public @NetCapability int[] getCapabilities() {
         return BitUtils.unpackBits(mNetworkCapabilities);
     }
@@ -821,7 +819,7 @@
      *
      * @hide
      */
-    @TestApi
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int TRANSPORT_TEST = 7;
 
     /** @hide */
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index c029dea..82b035b 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -460,6 +460,22 @@
     }
 
     /**
+     * Check that the given uid is restricted from doing networking on metered networks.
+     *
+     * @param uid The target uid.
+     * @return true if the given uid is restricted from doing networking on metered networks.
+     *
+     * @hide
+     */
+    public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+        try {
+            return mService.isUidRestrictedOnMeteredNetworks(uid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Get multipath preference for the given network.
      */
     public int getMultipathPreference(Network network) {
diff --git a/core/java/android/net/NetworkReleasedException.java b/core/java/android/net/NetworkReleasedException.java
new file mode 100644
index 0000000..0629b75
--- /dev/null
+++ b/core/java/android/net/NetworkReleasedException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.annotation.SystemApi;
+
+/**
+ * Indicates that the {@link Network} was released and is no longer available.
+ *
+ * @hide
+ */
+@SystemApi
+public class NetworkReleasedException extends Exception {
+    /** @hide */
+    public NetworkReleasedException() {
+        super("The network was released and is no longer available");
+    }
+}
diff --git a/core/java/android/net/QosCallback.java b/core/java/android/net/QosCallback.java
new file mode 100644
index 0000000..22f06bc
--- /dev/null
+++ b/core/java/android/net/QosCallback.java
@@ -0,0 +1,91 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Receives Qos information given a {@link Network}.  The callback is registered with
+ * {@link ConnectivityManager#registerQosCallback}.
+ *
+ * <p>
+ * <br/>
+ * The callback will no longer receive calls if any of the following takes place:
+ * <ol>
+ * <li>{@link ConnectivityManager#unregisterQosCallback(QosCallback)} is called with the same
+ * callback instance.</li>
+ * <li>{@link QosCallback#onError(QosCallbackException)} is called.</li>
+ * <li>A network specific issue occurs.  eg. Congestion on a carrier network.</li>
+ * <li>The network registered with the callback has no associated QoS providers</li>
+ * </ul>
+ * {@hide}
+ */
+@SystemApi
+public abstract class QosCallback {
+    /**
+     * Invoked after an error occurs on a registered callback.  Once called, the callback is
+     * automatically unregistered and the callback will no longer receive calls.
+     *
+     * <p>The underlying exception can either be a runtime exception or a custom exception made for
+     * {@link QosCallback}. see: {@link QosCallbackException}.
+     *
+     * @param exception wraps the underlying cause
+     */
+    public void onError(@NonNull final QosCallbackException exception) {
+    }
+
+    /**
+     * Called when a Qos Session first becomes available to the callback or if its attributes have
+     * changed.
+     * <p>
+     * Note: The callback may be called multiple times with the same attributes.
+     *
+     * @param session the available session
+     * @param sessionAttributes the attributes of the session
+     */
+    public void onQosSessionAvailable(@NonNull final QosSession session,
+            @NonNull final QosSessionAttributes sessionAttributes) {
+    }
+
+    /**
+     * Called after a Qos Session is lost.
+     * <p>
+     * At least one call to
+     * {@link QosCallback#onQosSessionAvailable(QosSession, QosSessionAttributes)}
+     * with the same {@link QosSession} will precede a call to lost.
+     *
+     * @param session the lost session
+     */
+    public void onQosSessionLost(@NonNull final QosSession session) {
+    }
+
+    /**
+     * Thrown when there is a problem registering {@link QosCallback} with
+     * {@link ConnectivityManager#registerQosCallback(QosSocketInfo, QosCallback, Executor)}.
+     */
+    public static class QosCallbackRegistrationException extends RuntimeException {
+        /**
+         * @hide
+         */
+        public QosCallbackRegistrationException() {
+            super();
+        }
+    }
+}
diff --git a/core/java/android/net/QosCallbackConnection.java b/core/java/android/net/QosCallbackConnection.java
new file mode 100644
index 0000000..bdb4ad6
--- /dev/null
+++ b/core/java/android/net/QosCallbackConnection.java
@@ -0,0 +1,128 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Sends messages from {@link com.android.server.ConnectivityService} to the registered
+ * {@link QosCallback}.
+ * <p/>
+ * This is a satellite class of {@link ConnectivityManager} and not meant
+ * to be used in other contexts.
+ *
+ * @hide
+ */
+class QosCallbackConnection extends android.net.IQosCallback.Stub {
+
+    @NonNull private final ConnectivityManager mConnectivityManager;
+    @Nullable private volatile QosCallback mCallback;
+    @NonNull private final Executor mExecutor;
+
+    @VisibleForTesting
+    @Nullable
+    public QosCallback getCallback() {
+        return mCallback;
+    }
+
+    /**
+     * The constructor for the connection
+     *
+     * @param connectivityManager the mgr that created this connection
+     * @param callback the callback to send messages back to
+     * @param executor The executor on which the callback will be invoked. The provided
+     *                 {@link Executor} must run callback sequentially, otherwise the order of
+     *                 callbacks cannot be guaranteed.
+     */
+    QosCallbackConnection(@NonNull final ConnectivityManager connectivityManager,
+            @NonNull final QosCallback callback,
+            @NonNull final Executor executor) {
+        mConnectivityManager = Objects.requireNonNull(connectivityManager,
+                "connectivityManager must be non-null");
+        mCallback = Objects.requireNonNull(callback, "callback must be non-null");
+        mExecutor = Objects.requireNonNull(executor, "executor must be non-null");
+    }
+
+    /**
+     * Called when either the {@link EpsBearerQosSessionAttributes} has changed or on the first time
+     * the attributes have become available.
+     *
+     * @param session the session that is now available
+     * @param attributes the corresponding attributes of session
+     */
+    @Override
+    public void onQosEpsBearerSessionAvailable(@NonNull final QosSession session,
+            @NonNull final EpsBearerQosSessionAttributes attributes) {
+
+        mExecutor.execute(() -> {
+            final QosCallback callback = mCallback;
+            if (callback != null) {
+                callback.onQosSessionAvailable(session, attributes);
+            }
+        });
+    }
+
+    /**
+     * Called when the session is lost.
+     *
+     * @param session the session that was lost
+     */
+    @Override
+    public void onQosSessionLost(@NonNull final QosSession session) {
+        mExecutor.execute(() -> {
+            final QosCallback callback = mCallback;
+            if (callback != null) {
+                callback.onQosSessionLost(session);
+            }
+        });
+    }
+
+    /**
+     * Called when there is an error on the registered callback.
+     *
+     *  @param errorType the type of error
+     */
+    @Override
+    public void onError(@QosCallbackException.ExceptionType final int errorType) {
+        mExecutor.execute(() -> {
+            final QosCallback callback = mCallback;
+            if (callback != null) {
+                // Messages no longer need to be received since there was an error.
+                stopReceivingMessages();
+                mConnectivityManager.unregisterQosCallback(callback);
+                callback.onError(QosCallbackException.createException(errorType));
+            }
+        });
+    }
+
+    /**
+     * The callback will stop receiving messages.
+     * <p/>
+     * There are no synchronization guarantees on exactly when the callback will stop receiving
+     * messages.
+     */
+    void stopReceivingMessages() {
+        mCallback = null;
+    }
+}
diff --git a/core/java/android/net/QosCallbackException.java b/core/java/android/net/QosCallbackException.java
new file mode 100644
index 0000000..7fd9a527e
--- /dev/null
+++ b/core/java/android/net/QosCallbackException.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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This is the exception type passed back through the onError method on {@link QosCallback}.
+ * {@link QosCallbackException#getCause()} contains the actual error that caused this exception.
+ *
+ * The possible exception types as causes are:
+ * 1. {@link NetworkReleasedException}
+ * 2. {@link SocketNotBoundException}
+ * 3. {@link UnsupportedOperationException}
+ * 4. {@link SocketLocalAddressChangedException}
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosCallbackException extends Exception {
+
+    /** @hide */
+    @IntDef(prefix = {"EX_TYPE_"}, value = {
+            EX_TYPE_FILTER_NONE,
+            EX_TYPE_FILTER_NETWORK_RELEASED,
+            EX_TYPE_FILTER_SOCKET_NOT_BOUND,
+            EX_TYPE_FILTER_NOT_SUPPORTED,
+            EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ExceptionType {}
+
+    private static final String TAG = "QosCallbackException";
+
+    // Types of exceptions supported //
+    /** {@hide} */
+    public static final int EX_TYPE_FILTER_NONE = 0;
+
+    /** {@hide} */
+    public static final int EX_TYPE_FILTER_NETWORK_RELEASED = 1;
+
+    /** {@hide} */
+    public static final int EX_TYPE_FILTER_SOCKET_NOT_BOUND = 2;
+
+    /** {@hide} */
+    public static final int EX_TYPE_FILTER_NOT_SUPPORTED = 3;
+
+    /** {@hide} */
+    public static final int EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED = 4;
+
+    /**
+     * Creates exception based off of a type and message.  Not all types of exceptions accept a
+     * custom message.
+     *
+     * {@hide}
+     */
+    @NonNull
+    static QosCallbackException createException(@ExceptionType final int type) {
+        switch (type) {
+            case EX_TYPE_FILTER_NETWORK_RELEASED:
+                return new QosCallbackException(new NetworkReleasedException());
+            case EX_TYPE_FILTER_SOCKET_NOT_BOUND:
+                return new QosCallbackException(new SocketNotBoundException());
+            case EX_TYPE_FILTER_NOT_SUPPORTED:
+                return new QosCallbackException(new UnsupportedOperationException(
+                        "This device does not support the specified filter"));
+            case EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED:
+                return new QosCallbackException(
+                        new SocketLocalAddressChangedException());
+            default:
+                Log.wtf(TAG, "create: No case setup for exception type: '" + type + "'");
+                return new QosCallbackException(
+                        new RuntimeException("Unknown exception code: " + type));
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public QosCallbackException(@NonNull final String message) {
+        super(message);
+    }
+
+    /**
+     * @hide
+     */
+    public QosCallbackException(@NonNull final Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/core/java/android/net/QosFilter.java b/core/java/android/net/QosFilter.java
new file mode 100644
index 0000000..ab55002
--- /dev/null
+++ b/core/java/android/net/QosFilter.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.net.InetAddress;
+
+/**
+ * Provides the related filtering logic to the {@link NetworkAgent} to match {@link QosSession}s
+ * to their related {@link QosCallback}.
+ *
+ * Used by the {@link com.android.server.ConnectivityService} to validate a {@link QosCallback}
+ * is still able to receive a {@link QosSession}.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class QosFilter {
+
+    /**
+     * The constructor is kept hidden from outside this package to ensure that all derived types
+     * are known and properly handled when being passed to and from {@link NetworkAgent}.
+     *
+     * @hide
+     */
+    QosFilter() {
+    }
+
+    /**
+     * The network used with this filter.
+     *
+     * @return the registered {@link Network}
+     */
+    @NonNull
+    public abstract Network getNetwork();
+
+    /**
+     * Validates that conditions have not changed such that no further {@link QosSession}s should
+     * be passed back to the {@link QosCallback} associated to this filter.
+     *
+     * @return the error code when present, otherwise the filter is valid
+     *
+     * @hide
+     */
+    @QosCallbackException.ExceptionType
+    public abstract int validate();
+
+    /**
+     * Determines whether or not the parameters is a match for the filter.
+     *
+     * @param address the local address
+     * @param startPort the start of the port range
+     * @param endPort the end of the port range
+     * @return whether the parameters match the local address of the filter
+     */
+    public abstract boolean matchesLocalAddress(@NonNull InetAddress address,
+            int startPort, int endPort);
+}
+
diff --git a/core/java/android/net/QosFilterParcelable.aidl b/core/java/android/net/QosFilterParcelable.aidl
new file mode 100644
index 0000000..312d635
--- /dev/null
+++ b/core/java/android/net/QosFilterParcelable.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** 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;
+
+parcelable QosFilterParcelable;
+
diff --git a/core/java/android/net/QosFilterParcelable.java b/core/java/android/net/QosFilterParcelable.java
new file mode 100644
index 0000000..da3b2cf
--- /dev/null
+++ b/core/java/android/net/QosFilterParcelable.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * Aware of how to parcel different types of {@link QosFilter}s.  Any new type of qos filter must
+ * have a specialized case written here.
+ * <p/>
+ * Specifically leveraged when transferring {@link QosFilter} from
+ * {@link com.android.server.ConnectivityService} to {@link NetworkAgent} when the filter is first
+ * registered.
+ * <p/>
+ * This is not meant to be used in other contexts.
+ *
+ * @hide
+ */
+public final class QosFilterParcelable implements Parcelable {
+
+    private static final String LOG_TAG = QosFilterParcelable.class.getSimpleName();
+
+    // Indicates that the filter was not successfully written to the parcel.
+    private static final int NO_FILTER_PRESENT = 0;
+
+    // The parcel is of type qos socket filter.
+    private static final int QOS_SOCKET_FILTER = 1;
+
+    private final QosFilter mQosFilter;
+
+    /**
+     * The underlying qos filter.
+     * <p/>
+     * Null only in the case parceling failed.
+     */
+    @Nullable
+    public QosFilter getQosFilter() {
+        return mQosFilter;
+    }
+
+    public QosFilterParcelable(@NonNull final QosFilter qosFilter) {
+        Objects.requireNonNull(qosFilter, "qosFilter must be non-null");
+
+        // NOTE: Normally a type check would belong here, but doing so breaks unit tests that rely
+        // on mocking qos filter.
+        mQosFilter = qosFilter;
+    }
+
+    private QosFilterParcelable(final Parcel in) {
+        final int filterParcelType = in.readInt();
+
+        switch (filterParcelType) {
+            case QOS_SOCKET_FILTER: {
+                mQosFilter = new QosSocketFilter(QosSocketInfo.CREATOR.createFromParcel(in));
+                break;
+            }
+
+            case NO_FILTER_PRESENT:
+            default: {
+                mQosFilter = null;
+            }
+        }
+    }
+
+    public static final Creator<QosFilterParcelable> CREATOR = new Creator<QosFilterParcelable>() {
+        @Override
+        public QosFilterParcelable createFromParcel(final Parcel in) {
+            return new QosFilterParcelable(in);
+        }
+
+        @Override
+        public QosFilterParcelable[] newArray(final int size) {
+            return new QosFilterParcelable[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(final Parcel dest, final int flags) {
+        if (mQosFilter instanceof QosSocketFilter) {
+            dest.writeInt(QOS_SOCKET_FILTER);
+            final QosSocketFilter qosSocketFilter = (QosSocketFilter) mQosFilter;
+            qosSocketFilter.getQosSocketInfo().writeToParcel(dest, 0);
+            return;
+        }
+        dest.writeInt(NO_FILTER_PRESENT);
+        Log.e(LOG_TAG, "Parceling failed, unknown type of filter present: " + mQosFilter);
+    }
+}
diff --git a/core/java/android/net/QosSession.aidl b/core/java/android/net/QosSession.aidl
new file mode 100644
index 0000000..c2cf366
--- /dev/null
+++ b/core/java/android/net/QosSession.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** 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;
+
+parcelable QosSession;
+
diff --git a/core/java/android/net/QosSession.java b/core/java/android/net/QosSession.java
new file mode 100644
index 0000000..4f3bb77
--- /dev/null
+++ b/core/java/android/net/QosSession.java
@@ -0,0 +1,136 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Provides identifying information of a QoS session.  Sent to an application through
+ * {@link QosCallback}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosSession implements Parcelable {
+
+    /**
+     * The {@link QosSession} is a LTE EPS Session.
+     */
+    public static final int TYPE_EPS_BEARER = 1;
+
+    private final int mSessionId;
+
+    private final int mSessionType;
+
+    /**
+     * Gets the unique id of the session that is used to differentiate sessions across different
+     * types.
+     * <p/>
+     * Note: Different qos sessions can be provided by different actors.
+     *
+     * @return the unique id
+     */
+    public long getUniqueId() {
+        return (long) mSessionType << 32 | mSessionId;
+    }
+
+    /**
+     * Gets the session id that is unique within that type.
+     * <p/>
+     * Note: The session id is set by the actor providing the qos.  It can be either manufactured by
+     * the actor, but also may have a particular meaning within that type.  For example, using the
+     * bearer id as the session id for {@link android.telephony.data.EpsBearerQosSessionAttributes}
+     * is a straight forward way to keep the sessions unique from one another within that type.
+     *
+     * @return the id of the session
+     */
+    public int getSessionId() {
+        return mSessionId;
+    }
+
+    /**
+     * Gets the type of session.
+     */
+    @QosSessionType
+    public int getSessionType() {
+        return mSessionType;
+    }
+
+    /**
+     * Creates a {@link QosSession}.
+     *
+     * @param sessionId uniquely identifies the session across all sessions of the same type
+     * @param sessionType the type of session
+     */
+    public QosSession(final int sessionId, @QosSessionType final int sessionType) {
+        //Ensures the session id is unique across types of sessions
+        mSessionId = sessionId;
+        mSessionType = sessionType;
+    }
+
+
+    @Override
+    public String toString() {
+        return "QosSession{"
+                + "mSessionId=" + mSessionId
+                + ", mSessionType=" + mSessionType
+                + '}';
+    }
+
+    /**
+     * Annotations for types of qos sessions.
+     */
+    @IntDef(value = {
+            TYPE_EPS_BEARER,
+    })
+    @interface QosSessionType {}
+
+    private QosSession(final Parcel in) {
+        mSessionId = in.readInt();
+        mSessionType = in.readInt();
+    }
+
+    @NonNull
+    public static final Creator<QosSession> CREATOR = new Creator<QosSession>() {
+        @NonNull
+        @Override
+        public QosSession createFromParcel(@NonNull final Parcel in) {
+            return new QosSession(in);
+        }
+
+        @NonNull
+        @Override
+        public QosSession[] newArray(final int size) {
+            return new QosSession[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+        dest.writeInt(mSessionId);
+        dest.writeInt(mSessionType);
+    }
+}
diff --git a/core/java/android/net/QosSessionAttributes.java b/core/java/android/net/QosSessionAttributes.java
new file mode 100644
index 0000000..7a88594
--- /dev/null
+++ b/core/java/android/net/QosSessionAttributes.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+import android.annotation.SystemApi;
+
+/**
+ * Implemented by classes that encapsulate Qos related attributes that describe a Qos Session.
+ *
+ * Use the instanceof keyword to determine the underlying type.
+ *
+ * @hide
+ */
+@SystemApi
+public interface QosSessionAttributes {
+}
diff --git a/core/java/android/net/QosSocketFilter.java b/core/java/android/net/QosSocketFilter.java
new file mode 100644
index 0000000..2080e68
--- /dev/null
+++ b/core/java/android/net/QosSocketFilter.java
@@ -0,0 +1,166 @@
+/*
+ * 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;
+
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.Objects;
+
+/**
+ * Filters a {@link QosSession} according to the binding on the provided {@link Socket}.
+ *
+ * @hide
+ */
+public class QosSocketFilter extends QosFilter {
+
+    private static final String TAG = QosSocketFilter.class.getSimpleName();
+
+    @NonNull
+    private final QosSocketInfo mQosSocketInfo;
+
+    /**
+     * Creates a {@link QosSocketFilter} based off of {@link QosSocketInfo}.
+     *
+     * @param qosSocketInfo the information required to filter and validate
+     */
+    public QosSocketFilter(@NonNull final QosSocketInfo qosSocketInfo) {
+        Objects.requireNonNull(qosSocketInfo, "qosSocketInfo must be non-null");
+        mQosSocketInfo = qosSocketInfo;
+    }
+
+    /**
+     * Gets the parcelable qos socket info that was used to create the filter.
+     */
+    @NonNull
+    public QosSocketInfo getQosSocketInfo() {
+        return mQosSocketInfo;
+    }
+
+    /**
+     * Performs two validations:
+     * 1. If the socket is not bound, then return
+     *    {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND}. This is detected
+     *    by checking the local address on the filter which becomes null when the socket is no
+     *    longer bound.
+     * 2. In the scenario that the socket is now bound to a different local address, which can
+     *    happen in the case of UDP, then
+     *    {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED} is returned.
+     * @return validation error code
+     */
+    @Override
+    public int validate() {
+        final InetSocketAddress sa = getAddressFromFileDescriptor();
+        if (sa == null) {
+            return QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
+        }
+
+        if (!sa.equals(mQosSocketInfo.getLocalSocketAddress())) {
+            return EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+        }
+
+        return EX_TYPE_FILTER_NONE;
+    }
+
+    /**
+     * The local address of the socket's binding.
+     *
+     * Note: If the socket is no longer bound, null is returned.
+     *
+     * @return the local address
+     */
+    @Nullable
+    private InetSocketAddress getAddressFromFileDescriptor() {
+        final ParcelFileDescriptor parcelFileDescriptor = mQosSocketInfo.getParcelFileDescriptor();
+        if (parcelFileDescriptor == null) return null;
+
+        final FileDescriptor fd = parcelFileDescriptor.getFileDescriptor();
+        if (fd == null) return null;
+
+        final SocketAddress address;
+        try {
+            address = Os.getsockname(fd);
+        } catch (final ErrnoException e) {
+            Log.e(TAG, "getAddressFromFileDescriptor: getLocalAddress exception", e);
+            return null;
+        }
+        if (address instanceof InetSocketAddress) {
+            return (InetSocketAddress) address;
+        }
+        return null;
+    }
+
+    /**
+     * The network used with this filter.
+     *
+     * @return the registered {@link Network}
+     */
+    @NonNull
+    @Override
+    public Network getNetwork() {
+        return mQosSocketInfo.getNetwork();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    @Override
+    public boolean matchesLocalAddress(@NonNull final InetAddress address, final int startPort,
+            final int endPort) {
+        if (mQosSocketInfo.getLocalSocketAddress() == null) {
+            return false;
+        }
+
+        return matchesLocalAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
+                endPort);
+    }
+
+    /**
+     * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} with the
+     * filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
+     * <p>
+     * This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked
+     * due to being final.
+     *
+     * @param filterSocketAddress the socket address of the filter
+     * @param address the address to compare the filterSocketAddressWith
+     * @param startPort the start of the port range to check
+     * @param endPort the end of the port range to check
+     */
+    @VisibleForTesting
+    public static boolean matchesLocalAddress(@NonNull final InetSocketAddress filterSocketAddress,
+            @NonNull final InetAddress address,
+            final int startPort, final int endPort) {
+        return startPort <= filterSocketAddress.getPort()
+                && endPort >= filterSocketAddress.getPort()
+                && filterSocketAddress.getAddress().equals(address);
+    }
+}
diff --git a/core/java/android/net/QosSocketInfo.aidl b/core/java/android/net/QosSocketInfo.aidl
new file mode 100644
index 0000000..476c090
--- /dev/null
+++ b/core/java/android/net/QosSocketInfo.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** 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;
+
+parcelable QosSocketInfo;
+
diff --git a/core/java/android/net/QosSocketInfo.java b/core/java/android/net/QosSocketInfo.java
new file mode 100644
index 0000000..d37c469
--- /dev/null
+++ b/core/java/android/net/QosSocketInfo.java
@@ -0,0 +1,154 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.Objects;
+
+/**
+ * Used in conjunction with
+ * {@link ConnectivityManager#registerQosCallback}
+ * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosSocketInfo implements Parcelable {
+
+    @NonNull
+    private final Network mNetwork;
+
+    @NonNull
+    private final ParcelFileDescriptor mParcelFileDescriptor;
+
+    @NonNull
+    private final InetSocketAddress mLocalSocketAddress;
+
+    /**
+     * The {@link Network} the socket is on.
+     *
+     * @return the registered {@link Network}
+     */
+    @NonNull
+    public Network getNetwork() {
+        return mNetwork;
+    }
+
+    /**
+     * The parcel file descriptor wrapped around the socket's file descriptor.
+     *
+     * @return the parcel file descriptor of the socket
+     */
+    @NonNull
+    ParcelFileDescriptor getParcelFileDescriptor() {
+        return mParcelFileDescriptor;
+    }
+
+    /**
+     * The local address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
+     * The value does not reflect any changes that occur to the socket after it is first set
+     * in the constructor.
+     *
+     * @return the local address of the socket
+     */
+    @NonNull
+    public InetSocketAddress getLocalSocketAddress() {
+        return mLocalSocketAddress;
+    }
+
+    /**
+     * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}.  The
+     * {@link Socket} must remain bound in order to receive {@link QosSession}s.
+     *
+     * @param network the network
+     * @param socket the bound {@link Socket}
+     */
+    public QosSocketInfo(@NonNull final Network network, @NonNull final Socket socket)
+            throws IOException {
+        Objects.requireNonNull(socket, "socket cannot be null");
+
+        mNetwork = Objects.requireNonNull(network, "network cannot be null");
+        mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
+        mLocalSocketAddress =
+                new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
+    }
+
+    /* Parcelable methods */
+    private QosSocketInfo(final Parcel in) {
+        mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
+        mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+
+        final int addressLength = in.readInt();
+        mLocalSocketAddress = readSocketAddress(in, addressLength);
+    }
+
+    private InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
+        final byte[] address = new byte[addressLength];
+        in.readByteArray(address);
+        final int port = in.readInt();
+
+        try {
+            return new InetSocketAddress(InetAddress.getByAddress(address), port);
+        } catch (final UnknownHostException e) {
+            /* The catch block was purposely left empty.  UnknownHostException will never be thrown
+               since the address provided is numeric and non-null. */
+        }
+        return new InetSocketAddress();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+        mNetwork.writeToParcel(dest, 0);
+        mParcelFileDescriptor.writeToParcel(dest, 0);
+
+        final byte[] address = mLocalSocketAddress.getAddress().getAddress();
+        dest.writeInt(address.length);
+        dest.writeByteArray(address);
+        dest.writeInt(mLocalSocketAddress.getPort());
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<QosSocketInfo> CREATOR =
+            new Parcelable.Creator<QosSocketInfo>() {
+            @NonNull
+            @Override
+            public QosSocketInfo createFromParcel(final Parcel in) {
+                return new QosSocketInfo(in);
+            }
+
+            @NonNull
+            @Override
+            public QosSocketInfo[] newArray(final int size) {
+                return new QosSocketInfo[size];
+            }
+        };
+}
diff --git a/core/java/android/net/SocketLocalAddressChangedException.java b/core/java/android/net/SocketLocalAddressChangedException.java
new file mode 100644
index 0000000..9daad83
--- /dev/null
+++ b/core/java/android/net/SocketLocalAddressChangedException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.annotation.SystemApi;
+
+/**
+ * Thrown when the local address of the socket has changed.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketLocalAddressChangedException extends Exception {
+    /** @hide */
+    public SocketLocalAddressChangedException() {
+        super("The local address of the socket changed");
+    }
+}
diff --git a/core/java/android/net/SocketNotBoundException.java b/core/java/android/net/SocketNotBoundException.java
new file mode 100644
index 0000000..b1d7026
--- /dev/null
+++ b/core/java/android/net/SocketNotBoundException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 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;
+
+import android.annotation.SystemApi;
+
+/**
+ * Thrown when a previously bound socket becomes unbound.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketNotBoundException extends Exception {
+    /** @hide */
+    public SocketNotBoundException() {
+        super("The socket is unbound");
+    }
+}
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..3d79f284 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 bb91f89..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();
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 33736d3..305c686 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -22,6 +22,7 @@
 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;
@@ -40,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 {
 
@@ -60,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;
 
@@ -99,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) {}
@@ -113,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() {}
 
         /**
@@ -137,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,
@@ -164,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,14 +193,60 @@
     }
 
     /**
+     * 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.
+     */
+    @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
      */
-    @RequiresPermission(android.Manifest.permission.DUMP)
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     public void cancelBugreport() {
         try {
             mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
@@ -209,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();
         }
@@ -236,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;
@@ -247,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);
             }
@@ -259,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);
             }
@@ -271,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);
             }
@@ -288,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/Build.java b/core/java/android/os/Build.java
index 0d8769e..1076118 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -317,6 +317,7 @@
          * @see #SDK_INT
          * @hide
          */
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
         @TestApi
         public static final int FIRST_SDK_INT = SystemProperties
                 .getInt("ro.product.first_api_level", 0);
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 8af7de5..7e17a08 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -5,3 +5,6 @@
 corinac@google.com
 zezeozue@google.com
 maco@google.com
+sahanas@google.com
+abkaur@google.com
+chiangi@google.com
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/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index a5c5c61..333af91 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -22,7 +22,10 @@
 
 package android.se.omapi;
 
+import android.annotation.BroadcastBehavior;
 import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -71,6 +74,28 @@
     }
 
     /**
+     * Broadcast Action: Intent to notify if the secure element state is changed.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @BroadcastBehavior(registeredOnly = true, protectedBroadcast = true)
+    public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED =
+            "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";
+
+    /**
+     * Mandatory extra containing the reader name of the state changed secure element.
+     *
+     * @see Reader#getName()
+     */
+    public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";
+
+    /**
+     * Mandatory extra containing the connected state of the state changed secure element.
+     *
+     * True if the secure element is connected correctly, false otherwise.
+     */
+    public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";
+
+    /**
      * Listener object that allows the notification of the caller if this
      * SEService could be bound to the backend.
      */
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/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index 93b5fd4..9df213b 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -18,6 +18,7 @@
 
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -31,6 +32,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class AngleMeasurement implements Parcelable {
     private final double mRadians;
     private final double mErrorRadians;
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
index 20a1c7a..3d8626b 100644
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,6 +29,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class AngleOfArrivalMeasurement implements Parcelable {
     private final AngleMeasurement mAzimuthAngleMeasurement;
     private final AngleMeasurement mAltitudeAngleMeasurement;
@@ -53,7 +55,7 @@
      * @return the azimuth {@link AngleMeasurement}
      */
     @NonNull
-    public AngleMeasurement getAzimuthAngleMeasurement() {
+    public AngleMeasurement getAzimuth() {
         return mAzimuthAngleMeasurement;
     }
 
@@ -70,7 +72,7 @@
      * @return altitude {@link AngleMeasurement} or null when this is not available
      */
     @Nullable
-    public AngleMeasurement getAltitudeAngleMeasurement() {
+    public AngleMeasurement getAltitude() {
         return mAltitudeAngleMeasurement;
     }
 
@@ -85,8 +87,8 @@
 
         if (obj instanceof AngleOfArrivalMeasurement) {
             AngleOfArrivalMeasurement other = (AngleOfArrivalMeasurement) obj;
-            return mAzimuthAngleMeasurement.equals(other.getAzimuthAngleMeasurement())
-                    && mAltitudeAngleMeasurement.equals(other.getAltitudeAngleMeasurement());
+            return mAzimuthAngleMeasurement.equals(other.getAzimuth())
+                    && mAltitudeAngleMeasurement.equals(other.getAltitude());
         }
         return false;
     }
@@ -116,11 +118,9 @@
                 public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
                     Builder builder = new Builder();
 
-                    builder.setAzimuthAngleMeasurement(
-                            in.readParcelable(AngleMeasurement.class.getClassLoader()));
+                    builder.setAzimuth(in.readParcelable(AngleMeasurement.class.getClassLoader()));
 
-                    builder.setAltitudeAngleMeasurement(
-                            in.readParcelable(AngleMeasurement.class.getClassLoader()));
+                    builder.setAltitude(in.readParcelable(AngleMeasurement.class.getClassLoader()));
 
                     return builder.build();
                 }
@@ -144,7 +144,7 @@
          * @param azimuthAngle azimuth angle
          */
         @NonNull
-        public Builder setAzimuthAngleMeasurement(@NonNull AngleMeasurement azimuthAngle) {
+        public Builder setAzimuth(@NonNull AngleMeasurement azimuthAngle) {
             mAzimuthAngleMeasurement = azimuthAngle;
             return this;
         }
@@ -155,7 +155,7 @@
          * @param altitudeAngle altitude angle
          */
         @NonNull
-        public Builder setAltitudeAngleMeasurement(@NonNull AngleMeasurement altitudeAngle) {
+        public Builder setAltitude(@NonNull AngleMeasurement altitudeAngle) {
             mAltitudeAngleMeasurement = altitudeAngle;
             return this;
         }
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 10c2172..2a9bbdf 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -19,6 +19,7 @@
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -32,6 +33,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class DistanceMeasurement implements Parcelable {
     private final double mMeters;
     private final double mErrorMeters;
diff --git a/core/java/android/uwb/RangingMeasurement.java b/core/java/android/uwb/RangingMeasurement.java
index 50e5f0d..249e2b7 100644
--- a/core/java/android/uwb/RangingMeasurement.java
+++ b/core/java/android/uwb/RangingMeasurement.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -33,6 +34,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class RangingMeasurement implements Parcelable {
     private final UwbAddress mRemoteDeviceAddress;
     private final @Status int mStatus;
diff --git a/core/java/android/uwb/RangingReport.java b/core/java/android/uwb/RangingReport.java
index 5b5f084..7a2df86 100644
--- a/core/java/android/uwb/RangingReport.java
+++ b/core/java/android/uwb/RangingReport.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -30,6 +31,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class RangingReport implements Parcelable {
     private final List<RangingMeasurement> mRangingMeasurements;
 
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
index 0f87af4..bfa8bf2 100644
--- a/core/java/android/uwb/RangingSession.java
+++ b/core/java/android/uwb/RangingSession.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
@@ -42,6 +43,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class RangingSession implements AutoCloseable {
     private static final String TAG = "Uwb.RangingSession";
     private final SessionHandle mSessionHandle;
diff --git a/core/java/android/uwb/UwbAddress.java b/core/java/android/uwb/UwbAddress.java
index b9523a3..22883be 100644
--- a/core/java/android/uwb/UwbAddress.java
+++ b/core/java/android/uwb/UwbAddress.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,6 +29,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class UwbAddress implements Parcelable {
     public static final int SHORT_ADDRESS_BYTE_LENGTH = 2;
     public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8;
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 15ee5b5..8adfe06 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.IBinder;
@@ -44,6 +45,7 @@
  *
  * @hide
  */
+@SystemApi
 @SystemService(Context.UWB_SERVICE)
 public final class UwbManager {
     private IUwbAdapter mUwbAdapter;
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/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index c5a956a..99692d0 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -3,3 +3,5 @@
 per-file *Chooser* = file:/packages/SystemUI/OWNERS
 per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
 per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
+per-file IVoice* = file:/core/java/android/service/voice/OWNERS
+per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
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/graphics/fonts/OWNERS b/core/java/com/android/internal/graphics/fonts/OWNERS
new file mode 100644
index 0000000..18486af
--- /dev/null
+++ b/core/java/com/android/internal/graphics/fonts/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
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 03ef35b..3183ed3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -309,9 +309,14 @@
 
     <protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
 
+    <!-- For OMAPI -->
+    <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" />
@@ -1622,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 222471a..09f16a8 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
@@ -76,6 +76,12 @@
     private static final long DUMPSTATE_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
     private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
 
+
+    // A small timeout used when waiting for the result of a BugreportCallback to be received.
+    // This value must be at least 1000ms since there is an intentional delay in
+    // BugreportManagerServiceImpl in the error case.
+    private static final long CALLBACK_RESULT_TIMEOUT_MS = 1500;
+
     // Sent by Shell when its bugreport finishes (contains final bugreport/screenshot file name
     // associated with the bugreport).
     private static final String INTENT_BUGREPORT_FINISHED =
@@ -185,7 +191,7 @@
         ParcelFileDescriptor bugreportFd2 = parcelFd(bugreportFile2);
         ParcelFileDescriptor screenshotFd2 = parcelFd(screenshotFile2);
         mBrm.startBugreport(bugreportFd2, screenshotFd2, wifi(), mExecutor, callback2);
-        Thread.sleep(500 /* .5s */);
+        Thread.sleep(CALLBACK_RESULT_TIMEOUT_MS);
 
         // Verify #2 encounters an error.
         assertThat(callback2.getErrorCode()).isEqualTo(
@@ -194,7 +200,7 @@
 
         // Cancel #1 so we can move on to the next test.
         mBrm.cancelBugreport();
-        Thread.sleep(500 /* .5s */);
+        waitTillDoneOrTimeout(callback);
         assertThat(callback.isDone()).isTrue();
         assertFdsAreClosed(mBugreportFd, mScreenshotFd);
     }
@@ -220,7 +226,7 @@
         // Try again, with DUMP permission.
         getPermissions();
         mBrm.cancelBugreport();
-        Thread.sleep(500 /* .5s */);
+        waitTillDoneOrTimeout(callback);
         assertThat(callback.isDone()).isTrue();
         assertFdsAreClosed(mBugreportFd, mScreenshotFd);
     }
diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS
index bd7da0c..b3f3993 100644
--- a/core/tests/coretests/src/android/app/OWNERS
+++ b/core/tests/coretests/src/android/app/OWNERS
@@ -1 +1,6 @@
 per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS
+
+# 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
diff --git a/core/tests/coretests/src/android/app/people/OWNERS b/core/tests/coretests/src/android/app/people/OWNERS
new file mode 100644
index 0000000..6ec8e6a
--- /dev/null
+++ b/core/tests/coretests/src/android/app/people/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/people/OWNERS
\ No newline at end of file
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..7b76706
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/OWNERS
@@ -0,0 +1,3 @@
+per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+per-file SigningDetailsTest.java = mpgroover@google.com
+per-file SigningDetailsTest.java = cbrubaker@google.com
diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
index 0f17d27..6be9306 100644
--- a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
@@ -254,7 +254,7 @@
         assertEquals("19–22 de ene. de 2009",
                 formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
                         FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
-        assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009",
+        assertEquals("lun, 19 de ene. – jue, 22 de ene. de 2009",
                 formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
                         FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
         assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
@@ -265,7 +265,7 @@
         assertEquals("19 de ene. – 22 de abr. 2009",
                 formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
                         FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
-        assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009",
+        assertEquals("lun, 19 de ene. – mié, 22 de abr. de 2009",
                 formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
                         FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
         assertEquals("enero–abril de 2009",
@@ -286,9 +286,9 @@
 
         assertEquals("19–22 de enero de 2009",
                 formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
-        assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+        assertEquals("19–22 ene 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
                 FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
-        assertEquals("lun., 19 ene. – jue., 22 ene. 2009",
+        assertEquals("lun, 19 ene – jue, 22 ene 2009",
                 formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
                         FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
         assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
@@ -296,19 +296,19 @@
 
         assertEquals("19 de enero–22 de abril de 2009",
                 formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
-        assertEquals("19 ene. – 22 abr. 2009",
+        assertEquals("19 ene – 22 abr 2009",
                 formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
                         FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
-        assertEquals("lun., 19 ene. – mié., 22 abr. 2009",
+        assertEquals("lun, 19 ene – mié, 22 abr 2009",
                 formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
                         FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
         assertEquals("enero–abril de 2009",
                 formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
 
-        assertEquals("19 ene. 2009 – 9 feb. 2012",
+        assertEquals("19 ene 2009 – 9 feb 2012",
                 formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
                         FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
-        assertEquals("ene. 2009 – feb. 2012",
+        assertEquals("ene 2009 – feb 2012",
                 formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
                         FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
         assertEquals("19 de enero de 2009–9 de febrero de 2012",
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 068d047..5612833 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -212,7 +212,7 @@
 
         // Make sure it works on different locales.
         setLocale(new Locale("ru", "RU"));
-        assertEquals("1 мин.", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+        assertEquals("1 мин", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                 mContext, 1 * SECOND));
     }
 
diff --git a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
index 4b3b573..b342516 100644
--- a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
@@ -755,8 +755,8 @@
         final Locale locale = new Locale("fr");
         android.icu.text.RelativeDateTimeFormatter icuFormatter =
                 android.icu.text.RelativeDateTimeFormatter.getInstance(locale);
-        assertEquals("D à T", icuFormatter.combineDateAndTime("D", "T"));
+        assertEquals("D, T", icuFormatter.combineDateAndTime("D", "T"));
         // Ensure single quote ' and curly braces {} are not interpreted in input values.
-        assertEquals("D'x' à T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
+        assertEquals("D'x', T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
     }
 }
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/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
index e0884e3..9394dec 100644
--- a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
+++ b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
@@ -42,14 +42,14 @@
         AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder();
         tryBuild(builder, false);
 
-        builder.setAltitudeAngleMeasurement(altitude);
+        builder.setAltitude(altitude);
         tryBuild(builder, false);
 
-        builder.setAzimuthAngleMeasurement(azimuth);
+        builder.setAzimuth(azimuth);
         AngleOfArrivalMeasurement measurement = tryBuild(builder, true);
 
-        assertEquals(azimuth, measurement.getAzimuthAngleMeasurement());
-        assertEquals(altitude, measurement.getAltitudeAngleMeasurement());
+        assertEquals(azimuth, measurement.getAzimuth());
+        assertEquals(altitude, measurement.getAltitude());
     }
 
     private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) {
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
index b4b2e30..8e7f7c56 100644
--- a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -42,8 +42,8 @@
 
     public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
         return new AngleOfArrivalMeasurement.Builder()
-                .setAltitudeAngleMeasurement(getAngleMeasurement())
-                .setAzimuthAngleMeasurement(getAngleMeasurement())
+                .setAltitude(getAngleMeasurement())
+                .setAzimuth(getAngleMeasurement())
                 .build();
     }
 
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 9867d81..65d3a01 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1,3 +1,4 @@
+alanstokes@google.com
 cbrubaker@google.com
 hackbod@android.com
 hackbod@google.com
@@ -12,4 +13,4 @@
 toddke@google.com
 yamasani@google.com
 
-per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
\ No newline at end of file
+per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
diff --git a/keystore/java/android/security/AuthTokenUtils.java b/keystore/java/android/security/AuthTokenUtils.java
new file mode 100644
index 0000000..e637600
--- /dev/null
+++ b/keystore/java/android/security/AuthTokenUtils.java
@@ -0,0 +1,75 @@
+/*
+ * 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.security;
+
+import android.annotation.NonNull;
+import android.hardware.security.keymint.HardwareAuthToken;
+import android.hardware.security.secureclock.Timestamp;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * @hide This Utils class provides method(s) for AuthToken conversion.
+ */
+public class AuthTokenUtils {
+
+    private AuthTokenUtils(){
+    }
+
+    /**
+     * Build a HardwareAuthToken from a byte array
+     * @param array byte array representing an auth token
+     * @return HardwareAuthToken representation of an auth token
+     */
+    public static @NonNull HardwareAuthToken toHardwareAuthToken(@NonNull byte[] array) {
+        final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken();
+
+        // First byte is version, which does not exist in HardwareAuthToken anymore
+        // Next 8 bytes is the challenge.
+        hardwareAuthToken.challenge =
+                ByteBuffer.wrap(array, 1, 8).order(ByteOrder.nativeOrder()).getLong();
+
+        // Next 8 bytes is the userId
+        hardwareAuthToken.userId =
+                ByteBuffer.wrap(array, 9, 8).order(ByteOrder.nativeOrder()).getLong();
+
+        // Next 8 bytes is the authenticatorId.
+        hardwareAuthToken.authenticatorId =
+                ByteBuffer.wrap(array, 17, 8).order(ByteOrder.nativeOrder()).getLong();
+
+        // while the other fields are in machine byte order, authenticatorType and timestamp
+        // are in network byte order.
+        // Next 4 bytes is the authenticatorType.
+        hardwareAuthToken.authenticatorType =
+                ByteBuffer.wrap(array, 25, 4).order(ByteOrder.BIG_ENDIAN).getInt();
+        // Next 8 bytes is the timestamp.
+        final Timestamp timestamp = new Timestamp();
+        timestamp.milliSeconds =
+                ByteBuffer.wrap(array, 29, 8).order(ByteOrder.BIG_ENDIAN).getLong();
+        hardwareAuthToken.timestamp = timestamp;
+
+        // Last 32 bytes is the mac, 37:69
+        hardwareAuthToken.mac = new byte[32];
+        System.arraycopy(array, 37 /* srcPos */,
+                hardwareAuthToken.mac,
+                0 /* destPos */,
+                32 /* length */);
+
+        return hardwareAuthToken;
+    }
+}
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
new file mode 100644
index 0000000..fcc518c
--- /dev/null
+++ b/keystore/java/android/security/Authorization.java
@@ -0,0 +1,107 @@
+/*
+ * 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.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;
+
+/**
+ * @hide This is the client side for IKeystoreAuthorization AIDL.
+ * It shall only be used by biometric authentication providers and Gatekeeper.
+ */
+public class Authorization {
+    private static final String TAG = "KeystoreAuthorization";
+    private static IKeystoreAuthorization sIKeystoreAuthorization;
+
+    public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
+
+    public Authorization() {
+        sIKeystoreAuthorization = null;
+    }
+
+    private static synchronized IKeystoreAuthorization getService() {
+        if (sIKeystoreAuthorization == null) {
+            sIKeystoreAuthorization = IKeystoreAuthorization.Stub.asInterface(
+                    ServiceManager.checkService("android.security.authorization"));
+        }
+        return sIKeystoreAuthorization;
+    }
+
+    /**
+     * Adds an auth token to keystore2.
+     *
+     * @param authToken created by Android authenticators.
+     * @return 0 if successful or {@code ResponseCode.SYSTEM_ERROR}.
+     */
+    public int addAuthToken(@NonNull HardwareAuthToken authToken) {
+        if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+        try {
+            getService().addAuthToken(authToken);
+            return 0;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Can not connect to keystore", e);
+            return SYSTEM_ERROR;
+        } catch (ServiceSpecificException e) {
+            return e.errorCode;
+        }
+    }
+
+    /**
+     * Add an auth token to Keystore 2.0 in the legacy serialized auth token format.
+     * @param authToken
+     * @return 0 if successful or a {@code ResponseCode}.
+     */
+    public int addAuthToken(@NonNull byte[] authToken) {
+        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/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index c70c986..4a67135 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -996,6 +996,7 @@
      */
     public int addAuthToken(byte[] authToken) {
         try {
+            new Authorization().addAuthToken(authToken);
             return mBinder.addAuthToken(authToken);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 6c6c5c9..8a10599 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -64,42 +64,43 @@
     /* 60 */ {'N', 'k', 'o', 'o'},
     /* 61 */ {'N', 's', 'h', 'u'},
     /* 62 */ {'O', 'g', 'a', 'm'},
-    /* 63 */ {'O', 'r', 'k', 'h'},
-    /* 64 */ {'O', 'r', 'y', 'a'},
-    /* 65 */ {'O', 's', 'g', 'e'},
-    /* 66 */ {'P', 'a', 'u', 'c'},
-    /* 67 */ {'P', 'h', 'l', 'i'},
-    /* 68 */ {'P', 'h', 'n', 'x'},
-    /* 69 */ {'P', 'l', 'r', 'd'},
-    /* 70 */ {'P', 'r', 't', 'i'},
-    /* 71 */ {'R', 'u', 'n', 'r'},
-    /* 72 */ {'S', 'a', 'm', 'r'},
-    /* 73 */ {'S', 'a', 'r', 'b'},
-    /* 74 */ {'S', 'a', 'u', 'r'},
-    /* 75 */ {'S', 'g', 'n', 'w'},
-    /* 76 */ {'S', 'i', 'n', 'h'},
-    /* 77 */ {'S', 'o', 'g', 'd'},
-    /* 78 */ {'S', 'o', 'r', 'a'},
-    /* 79 */ {'S', 'o', 'y', 'o'},
-    /* 80 */ {'S', 'y', 'r', 'c'},
-    /* 81 */ {'T', 'a', 'l', 'e'},
-    /* 82 */ {'T', 'a', 'l', 'u'},
-    /* 83 */ {'T', 'a', 'm', 'l'},
-    /* 84 */ {'T', 'a', 'n', 'g'},
-    /* 85 */ {'T', 'a', 'v', 't'},
-    /* 86 */ {'T', 'e', 'l', 'u'},
-    /* 87 */ {'T', 'f', 'n', 'g'},
-    /* 88 */ {'T', 'h', 'a', 'a'},
-    /* 89 */ {'T', 'h', 'a', 'i'},
-    /* 90 */ {'T', 'i', 'b', 't'},
-    /* 91 */ {'U', 'g', 'a', 'r'},
-    /* 92 */ {'V', 'a', 'i', 'i'},
-    /* 93 */ {'W', 'c', 'h', 'o'},
-    /* 94 */ {'X', 'p', 'e', 'o'},
-    /* 95 */ {'X', 's', 'u', 'x'},
-    /* 96 */ {'Y', 'i', 'i', 'i'},
-    /* 97 */ {'~', '~', '~', 'A'},
-    /* 98 */ {'~', '~', '~', 'B'},
+    /* 63 */ {'O', 'l', 'c', 'k'},
+    /* 64 */ {'O', 'r', 'k', 'h'},
+    /* 65 */ {'O', 'r', 'y', 'a'},
+    /* 66 */ {'O', 's', 'g', 'e'},
+    /* 67 */ {'P', 'a', 'u', 'c'},
+    /* 68 */ {'P', 'h', 'l', 'i'},
+    /* 69 */ {'P', 'h', 'n', 'x'},
+    /* 70 */ {'P', 'l', 'r', 'd'},
+    /* 71 */ {'P', 'r', 't', 'i'},
+    /* 72 */ {'R', 'u', 'n', 'r'},
+    /* 73 */ {'S', 'a', 'm', 'r'},
+    /* 74 */ {'S', 'a', 'r', 'b'},
+    /* 75 */ {'S', 'a', 'u', 'r'},
+    /* 76 */ {'S', 'g', 'n', 'w'},
+    /* 77 */ {'S', 'i', 'n', 'h'},
+    /* 78 */ {'S', 'o', 'g', 'd'},
+    /* 79 */ {'S', 'o', 'r', 'a'},
+    /* 80 */ {'S', 'o', 'y', 'o'},
+    /* 81 */ {'S', 'y', 'r', 'c'},
+    /* 82 */ {'T', 'a', 'l', 'e'},
+    /* 83 */ {'T', 'a', 'l', 'u'},
+    /* 84 */ {'T', 'a', 'm', 'l'},
+    /* 85 */ {'T', 'a', 'n', 'g'},
+    /* 86 */ {'T', 'a', 'v', 't'},
+    /* 87 */ {'T', 'e', 'l', 'u'},
+    /* 88 */ {'T', 'f', 'n', 'g'},
+    /* 89 */ {'T', 'h', 'a', 'a'},
+    /* 90 */ {'T', 'h', 'a', 'i'},
+    /* 91 */ {'T', 'i', 'b', 't'},
+    /* 92 */ {'U', 'g', 'a', 'r'},
+    /* 93 */ {'V', 'a', 'i', 'i'},
+    /* 94 */ {'W', 'c', 'h', 'o'},
+    /* 95 */ {'X', 'p', 'e', 'o'},
+    /* 96 */ {'X', 's', 'u', 'x'},
+    /* 97 */ {'Y', 'i', 'i', 'i'},
+    /* 98 */ {'~', '~', '~', 'A'},
+    /* 99 */ {'~', '~', '~', 'B'},
 };
 
 
@@ -120,7 +121,7 @@
     {0x80600000u, 46u}, // ada -> Latn
     {0x90600000u, 46u}, // ade -> Latn
     {0xA4600000u, 46u}, // adj -> Latn
-    {0xBC600000u, 90u}, // adp -> Tibt
+    {0xBC600000u, 91u}, // adp -> Tibt
     {0xE0600000u, 17u}, // ady -> Cyrl
     {0xE4600000u, 46u}, // adz -> Latn
     {0x61650000u,  4u}, // ae -> Avst
@@ -138,7 +139,7 @@
     {0xB8E00000u,  0u}, // aho -> Ahom
     {0x99200000u, 46u}, // ajg -> Latn
     {0x616B0000u, 46u}, // ak -> Latn
-    {0xA9400000u, 95u}, // akk -> Xsux
+    {0xA9400000u, 96u}, // akk -> Xsux
     {0x81600000u, 46u}, // ala -> Latn
     {0xA1600000u, 46u}, // ali -> Latn
     {0xB5600000u, 46u}, // aln -> Latn
@@ -163,7 +164,7 @@
     {0xC9E00000u, 46u}, // aps -> Latn
     {0xE5E00000u, 46u}, // apz -> Latn
     {0x61720000u,  1u}, // ar -> Arab
-    {0x61725842u, 98u}, // ar-XB -> ~~~B
+    {0x61725842u, 99u}, // ar-XB -> ~~~B
     {0x8A200000u,  2u}, // arc -> Armi
     {0x9E200000u, 46u}, // arh -> Latn
     {0xB6200000u, 46u}, // arn -> Latn
@@ -174,7 +175,7 @@
     {0xE6200000u,  1u}, // arz -> Arab
     {0x61730000u,  7u}, // as -> Beng
     {0x82400000u, 46u}, // asa -> Latn
-    {0x92400000u, 75u}, // ase -> Sgnw
+    {0x92400000u, 76u}, // ase -> Sgnw
     {0x9A400000u, 46u}, // asg -> Latn
     {0xBA400000u, 46u}, // aso -> Latn
     {0xCE400000u, 46u}, // ast -> Latn
@@ -231,7 +232,7 @@
     {0xDC810000u, 46u}, // bex -> Latn
     {0xE4810000u, 46u}, // bez -> Latn
     {0x8CA10000u, 46u}, // bfd -> Latn
-    {0xC0A10000u, 83u}, // bfq -> Taml
+    {0xC0A10000u, 84u}, // bfq -> Taml
     {0xCCA10000u,  1u}, // bft -> Arab
     {0xE0A10000u, 18u}, // bfy -> Deva
     {0x62670000u, 17u}, // bg -> Cyrl
@@ -265,7 +266,7 @@
     {0xC1410000u, 46u}, // bkq -> Latn
     {0xD1410000u, 46u}, // bku -> Latn
     {0xD5410000u, 46u}, // bkv -> Latn
-    {0xCD610000u, 85u}, // blt -> Tavt
+    {0xCD610000u, 86u}, // blt -> Tavt
     {0x626D0000u, 46u}, // bm -> Latn
     {0x9D810000u, 46u}, // bmh -> Latn
     {0xA9810000u, 46u}, // bmk -> Latn
@@ -275,7 +276,7 @@
     {0x99A10000u, 46u}, // bng -> Latn
     {0xB1A10000u, 46u}, // bnm -> Latn
     {0xBDA10000u, 46u}, // bnp -> Latn
-    {0x626F0000u, 90u}, // bo -> Tibt
+    {0x626F0000u, 91u}, // bo -> Tibt
     {0xA5C10000u, 46u}, // boj -> Latn
     {0xB1C10000u, 46u}, // bom -> Latn
     {0xB5C10000u, 46u}, // bon -> Latn
@@ -322,6 +323,7 @@
     {0x9F210000u, 46u}, // bzh -> Latn
     {0xDB210000u, 46u}, // bzw -> Latn
     {0x63610000u, 46u}, // ca -> Latn
+    {0x8C020000u, 46u}, // cad -> Latn
     {0xB4020000u, 46u}, // can -> Latn
     {0xA4220000u, 46u}, // cbj -> Latn
     {0x9C420000u, 46u}, // cch -> Latn
@@ -346,7 +348,7 @@
     {0xE1420000u, 46u}, // cky -> Latn
     {0x81620000u, 46u}, // cla -> Latn
     {0x91820000u, 46u}, // cme -> Latn
-    {0x99820000u, 79u}, // cmg -> Soyo
+    {0x99820000u, 80u}, // cmg -> Soyo
     {0x636F0000u, 46u}, // co -> Latn
     {0xBDC20000u, 15u}, // cop -> Copt
     {0xC9E20000u, 46u}, // cps -> Latn
@@ -360,7 +362,7 @@
     {0x63730000u, 46u}, // cs -> Latn
     {0x86420000u, 46u}, // csb -> Latn
     {0xDA420000u, 10u}, // csw -> Cans
-    {0x8E620000u, 66u}, // ctd -> Pauc
+    {0x8E620000u, 67u}, // ctd -> Pauc
     {0x63750000u, 17u}, // cu -> Cyrl
     {0x63760000u, 17u}, // cv -> Cyrl
     {0x63790000u, 46u}, // cy -> Latn
@@ -389,7 +391,7 @@
     {0x91230000u, 46u}, // dje -> Latn
     {0xA5A30000u, 46u}, // dnj -> Latn
     {0x85C30000u, 46u}, // dob -> Latn
-    {0xA1C30000u,  1u}, // doi -> Arab
+    {0xA1C30000u, 18u}, // doi -> Deva
     {0xBDC30000u, 46u}, // dop -> Latn
     {0xD9C30000u, 46u}, // dow -> Latn
     {0x9E230000u, 56u}, // drh -> Mong
@@ -404,12 +406,12 @@
     {0x8A830000u, 46u}, // duc -> Latn
     {0x8E830000u, 46u}, // dud -> Latn
     {0x9A830000u, 46u}, // dug -> Latn
-    {0x64760000u, 88u}, // dv -> Thaa
+    {0x64760000u, 89u}, // dv -> Thaa
     {0x82A30000u, 46u}, // dva -> Latn
     {0xDAC30000u, 46u}, // dww -> Latn
     {0xBB030000u, 46u}, // dyo -> Latn
     {0xD3030000u, 46u}, // dyu -> Latn
-    {0x647A0000u, 90u}, // dz -> Tibt
+    {0x647A0000u, 91u}, // dz -> Tibt
     {0x9B230000u, 46u}, // dzg -> Latn
     {0xD0240000u, 46u}, // ebu -> Latn
     {0x65650000u, 46u}, // ee -> Latn
@@ -422,7 +424,7 @@
     {0x81840000u, 46u}, // ema -> Latn
     {0xA1840000u, 46u}, // emi -> Latn
     {0x656E0000u, 46u}, // en -> Latn
-    {0x656E5841u, 97u}, // en-XA -> ~~~A
+    {0x656E5841u, 98u}, // en-XA -> ~~~A
     {0xB5A40000u, 46u}, // enn -> Latn
     {0xC1A40000u, 46u}, // enq -> Latn
     {0x656F0000u, 46u}, // eo -> Latn
@@ -438,6 +440,7 @@
     {0x65750000u, 46u}, // eu -> Latn
     {0xBAC40000u, 46u}, // ewo -> Latn
     {0xCEE40000u, 46u}, // ext -> Latn
+    {0x83240000u, 46u}, // eza -> Latn
     {0x66610000u,  1u}, // fa -> Arab
     {0x80050000u, 46u}, // faa -> Latn
     {0x84050000u, 46u}, // fab -> Latn
@@ -521,7 +524,7 @@
     {0x95C60000u, 20u}, // gof -> Ethi
     {0xA1C60000u, 46u}, // goi -> Latn
     {0xB1C60000u, 18u}, // gom -> Deva
-    {0xB5C60000u, 86u}, // gon -> Telu
+    {0xB5C60000u, 87u}, // gon -> Telu
     {0xC5C60000u, 46u}, // gor -> Latn
     {0xC9C60000u, 46u}, // gos -> Latn
     {0xCDC60000u, 24u}, // got -> Goth
@@ -566,7 +569,7 @@
     {0xAD070000u, 46u}, // hil -> Latn
     {0x81670000u, 46u}, // hla -> Latn
     {0xD1670000u, 32u}, // hlu -> Hluw
-    {0x8D870000u, 69u}, // hmd -> Plrd
+    {0x8D870000u, 70u}, // hmd -> Plrd
     {0xCD870000u, 46u}, // hmt -> Latn
     {0x8DA70000u,  1u}, // hnd -> Arab
     {0x91A70000u, 18u}, // hne -> Deva
@@ -601,7 +604,7 @@
     {0x69670000u, 46u}, // ig -> Latn
     {0x84C80000u, 46u}, // igb -> Latn
     {0x90C80000u, 46u}, // ige -> Latn
-    {0x69690000u, 96u}, // ii -> Yiii
+    {0x69690000u, 97u}, // ii -> Yiii
     {0xA5280000u, 46u}, // ijj -> Latn
     {0x696B0000u, 46u}, // ik -> Latn
     {0xA9480000u, 46u}, // ikk -> Latn
@@ -626,6 +629,7 @@
     {0x6A610000u, 36u}, // ja -> Jpan
     {0x84090000u, 46u}, // jab -> Latn
     {0xB0090000u, 46u}, // jam -> Latn
+    {0xC4090000u, 46u}, // jar -> Latn
     {0xB8290000u, 46u}, // jbo -> Latn
     {0xD0290000u, 46u}, // jbu -> Latn
     {0xB4890000u, 46u}, // jen -> Latn
@@ -661,7 +665,7 @@
     {0x906A0000u, 46u}, // kde -> Latn
     {0x9C6A0000u,  1u}, // kdh -> Arab
     {0xAC6A0000u, 46u}, // kdl -> Latn
-    {0xCC6A0000u, 89u}, // kdt -> Thai
+    {0xCC6A0000u, 90u}, // kdt -> Thai
     {0x808A0000u, 46u}, // kea -> Latn
     {0xB48A0000u, 46u}, // ken -> Latn
     {0xE48A0000u, 46u}, // kez -> Latn
@@ -673,7 +677,7 @@
     {0x94CA0000u, 46u}, // kgf -> Latn
     {0xBCCA0000u, 46u}, // kgp -> Latn
     {0x80EA0000u, 46u}, // kha -> Latn
-    {0x84EA0000u, 82u}, // khb -> Talu
+    {0x84EA0000u, 83u}, // khb -> Talu
     {0xB4EA0000u, 18u}, // khn -> Deva
     {0xC0EA0000u, 46u}, // khq -> Latn
     {0xC8EA0000u, 46u}, // khs -> Latn
@@ -766,7 +770,8 @@
     {0x82EA0000u, 46u}, // kxa -> Latn
     {0x8AEA0000u, 20u}, // kxc -> Ethi
     {0x92EA0000u, 46u}, // kxe -> Latn
-    {0xB2EA0000u, 89u}, // kxm -> Thai
+    {0xAEEA0000u, 18u}, // kxl -> Deva
+    {0xB2EA0000u, 90u}, // kxm -> Thai
     {0xBEEA0000u,  1u}, // kxp -> Arab
     {0xDAEA0000u, 46u}, // kxw -> Latn
     {0xE6EA0000u, 46u}, // kxz -> Latn
@@ -775,6 +780,7 @@
     {0x6B795452u, 46u}, // ky-TR -> Latn
     {0x930A0000u, 46u}, // kye -> Latn
     {0xDF0A0000u, 46u}, // kyx -> Latn
+    {0x9F2A0000u,  1u}, // kzh -> Arab
     {0xA72A0000u, 46u}, // kzj -> Latn
     {0xC72A0000u, 46u}, // kzr -> Latn
     {0xCF2A0000u, 46u}, // kzt -> Latn
@@ -790,7 +796,7 @@
     {0xD02B0000u, 46u}, // lbu -> Latn
     {0xD82B0000u, 46u}, // lbw -> Latn
     {0xB04B0000u, 46u}, // lcm -> Latn
-    {0xBC4B0000u, 89u}, // lcp -> Thai
+    {0xBC4B0000u, 90u}, // lcp -> Thai
     {0x846B0000u, 46u}, // ldb -> Latn
     {0x8C8B0000u, 46u}, // led -> Latn
     {0x908B0000u, 46u}, // lee -> Latn
@@ -814,7 +820,7 @@
     {0xCD4B0000u, 46u}, // lkt -> Latn
     {0x916B0000u, 46u}, // lle -> Latn
     {0xB56B0000u, 46u}, // lln -> Latn
-    {0xB58B0000u, 86u}, // lmn -> Telu
+    {0xB58B0000u, 87u}, // lmn -> Telu
     {0xB98B0000u, 46u}, // lmo -> Latn
     {0xBD8B0000u, 46u}, // lmp -> Latn
     {0x6C6E0000u, 46u}, // ln -> Latn
@@ -836,7 +842,7 @@
     {0xE28B0000u, 46u}, // luy -> Latn
     {0xE68B0000u,  1u}, // luz -> Arab
     {0x6C760000u, 46u}, // lv -> Latn
-    {0xAECB0000u, 89u}, // lwl -> Thai
+    {0xAECB0000u, 90u}, // lwl -> Thai
     {0x9F2B0000u, 28u}, // lzh -> Hans
     {0xE72B0000u, 46u}, // lzz -> Latn
     {0x8C0C0000u, 46u}, // mad -> Latn
@@ -927,7 +933,6 @@
     {0xBA2C0000u, 57u}, // mro -> Mroo
     {0x6D730000u, 46u}, // ms -> Latn
     {0x6D734343u,  1u}, // ms-CC -> Arab
-    {0x6D734944u,  1u}, // ms-ID -> Arab
     {0x6D740000u, 46u}, // mt -> Latn
     {0x8A6C0000u, 46u}, // mtc -> Latn
     {0x966C0000u, 46u}, // mtf -> Latn
@@ -1006,11 +1011,11 @@
     {0x9DAD0000u, 46u}, // nnh -> Latn
     {0xA9AD0000u, 46u}, // nnk -> Latn
     {0xB1AD0000u, 46u}, // nnm -> Latn
-    {0xBDAD0000u, 93u}, // nnp -> Wcho
+    {0xBDAD0000u, 94u}, // nnp -> Wcho
     {0x6E6F0000u, 46u}, // no -> Latn
     {0x8DCD0000u, 44u}, // nod -> Lana
     {0x91CD0000u, 18u}, // noe -> Deva
-    {0xB5CD0000u, 71u}, // non -> Runr
+    {0xB5CD0000u, 72u}, // non -> Runr
     {0xBDCD0000u, 46u}, // nop -> Latn
     {0xD1CD0000u, 46u}, // nou -> Latn
     {0xBA0D0000u, 60u}, // nqo -> Nkoo
@@ -1044,18 +1049,18 @@
     {0xB5AE0000u, 46u}, // onn -> Latn
     {0xC9AE0000u, 46u}, // ons -> Latn
     {0xB1EE0000u, 46u}, // opm -> Latn
-    {0x6F720000u, 64u}, // or -> Orya
+    {0x6F720000u, 65u}, // or -> Orya
     {0xBA2E0000u, 46u}, // oro -> Latn
     {0xD22E0000u,  1u}, // oru -> Arab
     {0x6F730000u, 17u}, // os -> Cyrl
-    {0x824E0000u, 65u}, // osa -> Osge
+    {0x824E0000u, 66u}, // osa -> Osge
     {0x826E0000u,  1u}, // ota -> Arab
-    {0xAA6E0000u, 63u}, // otk -> Orkh
+    {0xAA6E0000u, 64u}, // otk -> Orkh
     {0xB32E0000u, 46u}, // ozm -> Latn
     {0x70610000u, 27u}, // pa -> Guru
     {0x7061504Bu,  1u}, // pa-PK -> Arab
     {0x980F0000u, 46u}, // pag -> Latn
-    {0xAC0F0000u, 67u}, // pal -> Phli
+    {0xAC0F0000u, 68u}, // pal -> Phli
     {0xB00F0000u, 46u}, // pam -> Latn
     {0xBC0F0000u, 46u}, // pap -> Latn
     {0xD00F0000u, 46u}, // pau -> Latn
@@ -1065,11 +1070,11 @@
     {0x886F0000u, 46u}, // pdc -> Latn
     {0xCC6F0000u, 46u}, // pdt -> Latn
     {0x8C8F0000u, 46u}, // ped -> Latn
-    {0xB88F0000u, 94u}, // peo -> Xpeo
+    {0xB88F0000u, 95u}, // peo -> Xpeo
     {0xDC8F0000u, 46u}, // pex -> Latn
     {0xACAF0000u, 46u}, // pfl -> Latn
     {0xACEF0000u,  1u}, // phl -> Arab
-    {0xB4EF0000u, 68u}, // phn -> Phnx
+    {0xB4EF0000u, 69u}, // phn -> Phnx
     {0xAD0F0000u, 46u}, // pil -> Latn
     {0xBD0F0000u, 46u}, // pip -> Latn
     {0x814F0000u,  8u}, // pka -> Brah
@@ -1105,7 +1110,7 @@
     {0xB4D10000u, 46u}, // rgn -> Latn
     {0x98F10000u,  1u}, // rhg -> Arab
     {0x81110000u, 46u}, // ria -> Latn
-    {0x95110000u, 87u}, // rif -> Tfng
+    {0x95110000u, 88u}, // rif -> Tfng
     {0x95114E4Cu, 46u}, // rif-NL -> Latn
     {0xC9310000u, 18u}, // rjs -> Deva
     {0xCD510000u,  7u}, // rkt -> Beng
@@ -1135,9 +1140,9 @@
     {0x9C120000u, 17u}, // sah -> Cyrl
     {0xC0120000u, 46u}, // saq -> Latn
     {0xC8120000u, 46u}, // sas -> Latn
-    {0xCC120000u, 46u}, // sat -> Latn
+    {0xCC120000u, 63u}, // sat -> Olck
     {0xD4120000u, 46u}, // sav -> Latn
-    {0xE4120000u, 74u}, // saz -> Saur
+    {0xE4120000u, 75u}, // saz -> Saur
     {0x80320000u, 46u}, // sba -> Latn
     {0x90320000u, 46u}, // sbe -> Latn
     {0xBC320000u, 46u}, // sbp -> Latn
@@ -1161,11 +1166,11 @@
     {0xD8D20000u, 20u}, // sgw -> Ethi
     {0xE4D20000u, 46u}, // sgz -> Latn
     {0x73680000u, 46u}, // sh -> Latn
-    {0xA0F20000u, 87u}, // shi -> Tfng
+    {0xA0F20000u, 88u}, // shi -> Tfng
     {0xA8F20000u, 46u}, // shk -> Latn
     {0xB4F20000u, 58u}, // shn -> Mymr
     {0xD0F20000u,  1u}, // shu -> Arab
-    {0x73690000u, 76u}, // si -> Sinh
+    {0x73690000u, 77u}, // si -> Sinh
     {0x8D120000u, 46u}, // sid -> Latn
     {0x99120000u, 46u}, // sig -> Latn
     {0xAD120000u, 46u}, // sil -> Latn
@@ -1184,7 +1189,7 @@
     {0x81920000u, 46u}, // sma -> Latn
     {0xA5920000u, 46u}, // smj -> Latn
     {0xB5920000u, 46u}, // smn -> Latn
-    {0xBD920000u, 72u}, // smp -> Samr
+    {0xBD920000u, 73u}, // smp -> Samr
     {0xC1920000u, 46u}, // smq -> Latn
     {0xC9920000u, 46u}, // sms -> Latn
     {0x736E0000u, 46u}, // sn -> Latn
@@ -1194,10 +1199,10 @@
     {0xDDB20000u, 46u}, // snx -> Latn
     {0xE1B20000u, 46u}, // sny -> Latn
     {0x736F0000u, 46u}, // so -> Latn
-    {0x99D20000u, 77u}, // sog -> Sogd
+    {0x99D20000u, 78u}, // sog -> Sogd
     {0xA9D20000u, 46u}, // sok -> Latn
     {0xC1D20000u, 46u}, // soq -> Latn
-    {0xD1D20000u, 89u}, // sou -> Thai
+    {0xD1D20000u, 90u}, // sou -> Thai
     {0xE1D20000u, 46u}, // soy -> Latn
     {0x8DF20000u, 46u}, // spd -> Latn
     {0xADF20000u, 46u}, // spl -> Latn
@@ -1208,7 +1213,7 @@
     {0x7372524Fu, 46u}, // sr-RO -> Latn
     {0x73725255u, 46u}, // sr-RU -> Latn
     {0x73725452u, 46u}, // sr-TR -> Latn
-    {0x86320000u, 78u}, // srb -> Sora
+    {0x86320000u, 79u}, // srb -> Sora
     {0xB6320000u, 46u}, // srn -> Latn
     {0xC6320000u, 46u}, // srr -> Latn
     {0xDE320000u, 18u}, // srx -> Deva
@@ -1235,9 +1240,9 @@
     {0xB6F20000u, 46u}, // sxn -> Latn
     {0xDAF20000u, 46u}, // sxw -> Latn
     {0xAF120000u,  7u}, // syl -> Beng
-    {0xC7120000u, 80u}, // syr -> Syrc
+    {0xC7120000u, 81u}, // syr -> Syrc
     {0xAF320000u, 46u}, // szl -> Latn
-    {0x74610000u, 83u}, // ta -> Taml
+    {0x74610000u, 84u}, // ta -> Taml
     {0xA4130000u, 18u}, // taj -> Deva
     {0xAC130000u, 46u}, // tal -> Latn
     {0xB4130000u, 46u}, // tan -> Latn
@@ -1251,11 +1256,11 @@
     {0xE4330000u, 46u}, // tbz -> Latn
     {0xA0530000u, 46u}, // tci -> Latn
     {0xE0530000u, 42u}, // tcy -> Knda
-    {0x8C730000u, 81u}, // tdd -> Tale
+    {0x8C730000u, 82u}, // tdd -> Tale
     {0x98730000u, 18u}, // tdg -> Deva
     {0x9C730000u, 18u}, // tdh -> Deva
     {0xD0730000u, 46u}, // tdu -> Latn
-    {0x74650000u, 86u}, // te -> Telu
+    {0x74650000u, 87u}, // te -> Telu
     {0x8C930000u, 46u}, // ted -> Latn
     {0xB0930000u, 46u}, // tem -> Latn
     {0xB8930000u, 46u}, // teo -> Latn
@@ -1266,7 +1271,7 @@
     {0x88D30000u, 46u}, // tgc -> Latn
     {0xB8D30000u, 46u}, // tgo -> Latn
     {0xD0D30000u, 46u}, // tgu -> Latn
-    {0x74680000u, 89u}, // th -> Thai
+    {0x74680000u, 90u}, // th -> Thai
     {0xACF30000u, 18u}, // thl -> Deva
     {0xC0F30000u, 18u}, // thq -> Deva
     {0xC4F30000u, 18u}, // thr -> Deva
@@ -1305,14 +1310,14 @@
     {0x8E530000u, 25u}, // tsd -> Grek
     {0x96530000u, 18u}, // tsf -> Deva
     {0x9A530000u, 46u}, // tsg -> Latn
-    {0xA6530000u, 90u}, // tsj -> Tibt
+    {0xA6530000u, 91u}, // tsj -> Tibt
     {0xDA530000u, 46u}, // tsw -> Latn
     {0x74740000u, 17u}, // tt -> Cyrl
     {0x8E730000u, 46u}, // ttd -> Latn
     {0x92730000u, 46u}, // tte -> Latn
     {0xA6730000u, 46u}, // ttj -> Latn
     {0xC6730000u, 46u}, // ttr -> Latn
-    {0xCA730000u, 89u}, // tts -> Thai
+    {0xCA730000u, 90u}, // tts -> Thai
     {0xCE730000u, 46u}, // ttt -> Latn
     {0x9E930000u, 46u}, // tuh -> Latn
     {0xAE930000u, 46u}, // tul -> Latn
@@ -1323,7 +1328,7 @@
     {0xD2B30000u, 46u}, // tvu -> Latn
     {0x9ED30000u, 46u}, // twh -> Latn
     {0xC2D30000u, 46u}, // twq -> Latn
-    {0x9AF30000u, 84u}, // txg -> Tang
+    {0x9AF30000u, 85u}, // txg -> Tang
     {0x74790000u, 46u}, // ty -> Latn
     {0x83130000u, 46u}, // tya -> Latn
     {0xD7130000u, 17u}, // tyv -> Cyrl
@@ -1333,7 +1338,7 @@
     {0x75670000u,  1u}, // ug -> Arab
     {0x75674B5Au, 17u}, // ug-KZ -> Cyrl
     {0x75674D4Eu, 17u}, // ug-MN -> Cyrl
-    {0x80D40000u, 91u}, // uga -> Ugar
+    {0x80D40000u, 92u}, // uga -> Ugar
     {0x756B0000u, 17u}, // uk -> Cyrl
     {0xA1740000u, 46u}, // uli -> Latn
     {0x85940000u, 46u}, // umb -> Latn
@@ -1346,6 +1351,7 @@
     {0xCE340000u, 46u}, // urt -> Latn
     {0xDA340000u, 46u}, // urw -> Latn
     {0x82540000u, 46u}, // usa -> Latn
+    {0x9E740000u, 46u}, // uth -> Latn
     {0xC6740000u, 46u}, // utr -> Latn
     {0x9EB40000u, 46u}, // uvh -> Latn
     {0xAEB40000u, 46u}, // uvl -> Latn
@@ -1353,7 +1359,7 @@
     {0x757A4146u,  1u}, // uz-AF -> Arab
     {0x757A434Eu, 17u}, // uz-CN -> Cyrl
     {0x98150000u, 46u}, // vag -> Latn
-    {0xA0150000u, 92u}, // vai -> Vaii
+    {0xA0150000u, 93u}, // vai -> Vaii
     {0xB4150000u, 46u}, // van -> Latn
     {0x76650000u, 46u}, // ve -> Latn
     {0x88950000u, 46u}, // vec -> Latn
@@ -1376,7 +1382,7 @@
     {0xB4160000u, 46u}, // wan -> Latn
     {0xC4160000u, 46u}, // war -> Latn
     {0xBC360000u, 46u}, // wbp -> Latn
-    {0xC0360000u, 86u}, // wbq -> Telu
+    {0xC0360000u, 87u}, // wbq -> Telu
     {0xC4360000u, 18u}, // wbr -> Deva
     {0xA0560000u, 46u}, // wci -> Latn
     {0xC4960000u, 46u}, // wer -> Latn
@@ -1418,9 +1424,9 @@
     {0xC5B70000u, 18u}, // xnr -> Deva
     {0x99D70000u, 46u}, // xog -> Latn
     {0xB5D70000u, 46u}, // xon -> Latn
-    {0xC5F70000u, 70u}, // xpr -> Prti
+    {0xC5F70000u, 71u}, // xpr -> Prti
     {0x86370000u, 46u}, // xrb -> Latn
-    {0x82570000u, 73u}, // xsa -> Sarb
+    {0x82570000u, 74u}, // xsa -> Sarb
     {0xA2570000u, 46u}, // xsi -> Latn
     {0xB2570000u, 46u}, // xsm -> Latn
     {0xC6570000u, 18u}, // xsr -> Deva
@@ -1461,7 +1467,7 @@
     {0x98190000u, 46u}, // zag -> Latn
     {0xA4790000u,  1u}, // zdj -> Arab
     {0x80990000u, 46u}, // zea -> Latn
-    {0x9CD90000u, 87u}, // zgh -> Tfng
+    {0x9CD90000u, 88u}, // zgh -> Tfng
     {0x7A680000u, 28u}, // zh -> Hans
     {0x7A684155u, 29u}, // zh-AU -> Hant
     {0x7A68424Eu, 29u}, // zh-BN -> Hant
@@ -1470,7 +1476,6 @@
     {0x7A68484Bu, 29u}, // zh-HK -> Hant
     {0x7A684944u, 29u}, // zh-ID -> Hant
     {0x7A684D4Fu, 29u}, // zh-MO -> Hant
-    {0x7A684D59u, 29u}, // zh-MY -> Hant
     {0x7A685041u, 29u}, // zh-PA -> Hant
     {0x7A685046u, 29u}, // zh-PF -> Hant
     {0x7A685048u, 29u}, // zh-PH -> Hant
@@ -1592,6 +1597,7 @@
     0xD701434D4C61746ELLU, // byv_Latn_CM
     0x93214D4C4C61746ELLU, // bze_Latn_ML
     0x636145534C61746ELLU, // ca_Latn_ES
+    0x8C0255534C61746ELLU, // cad_Latn_US
     0x9C424E474C61746ELLU, // cch_Latn_NG
     0xBC42424443616B6DLLU, // ccp_Cakm_BD
     0x636552554379726CLLU, // ce_Cyrl_RU
@@ -1627,6 +1633,7 @@
     0x637652554379726CLLU, // cv_Cyrl_RU
     0x637947424C61746ELLU, // cy_Latn_GB
     0x6461444B4C61746ELLU, // da_Latn_DK
+    0x940343494C61746ELLU, // daf_Latn_CI
     0xA80355534C61746ELLU, // dak_Latn_US
     0xC40352554379726CLLU, // dar_Cyrl_RU
     0xD4034B454C61746ELLU, // dav_Latn_KE
@@ -1636,7 +1643,7 @@
     0xC4C343414C61746ELLU, // dgr_Latn_CA
     0x91234E454C61746ELLU, // dje_Latn_NE
     0xA5A343494C61746ELLU, // dnj_Latn_CI
-    0xA1C3494E41726162LLU, // doi_Arab_IN
+    0xA1C3494E44657661LLU, // doi_Deva_IN
     0x9E23434E4D6F6E67LLU, // drh_Mong_CN
     0x864344454C61746ELLU, // dsb_Latn_DE
     0xB2634D4C4C61746ELLU, // dtm_Latn_ML
@@ -1839,6 +1846,7 @@
     0xC6AA49444C61746ELLU, // kvr_Latn_ID
     0xDEAA504B41726162LLU, // kvx_Arab_PK
     0x6B7747424C61746ELLU, // kw_Latn_GB
+    0xAEEA494E44657661LLU, // kxl_Deva_IN
     0xB2EA544854686169LLU, // kxm_Thai_TH
     0xBEEA504B41726162LLU, // kxp_Arab_PK
     0x6B79434E41726162LLU, // ky_Arab_CN
@@ -2047,7 +2055,7 @@
     0x9C1252554379726CLLU, // sah_Cyrl_RU
     0xC0124B454C61746ELLU, // saq_Latn_KE
     0xC81249444C61746ELLU, // sas_Latn_ID
-    0xCC12494E4C61746ELLU, // sat_Latn_IN
+    0xCC12494E4F6C636BLLU, // sat_Olck_IN
     0xD412534E4C61746ELLU, // sav_Latn_SN
     0xE412494E53617572LLU, // saz_Saur_IN
     0xBC32545A4C61746ELLU, // sbp_Latn_TZ
@@ -2149,6 +2157,7 @@
     0x747254524C61746ELLU, // tr_Latn_TR
     0xD23354524C61746ELLU, // tru_Latn_TR
     0xD63354574C61746ELLU, // trv_Latn_TW
+    0xDA33504B41726162LLU, // trw_Arab_PK
     0x74735A414C61746ELLU, // ts_Latn_ZA
     0x8E5347524772656BLLU, // tsd_Grek_GR
     0x96534E5044657661LLU, // tsf_Deva_NP
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index bce70e2..2233827 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -30,6 +30,7 @@
 #include <memory>
 #include <set>
 #include <type_traits>
+#include <vector>
 
 #include <android-base/macros.h>
 #include <androidfw/ByteBucketArray.h>
@@ -1029,7 +1030,7 @@
             // But we don't want to hit the cache, so instead we will have a
             // local temporary allocation for the conversions.
             size_t convBufferLen = strLen + 4;
-            char16_t* convBuffer = (char16_t*)calloc(convBufferLen, sizeof(char16_t));
+            std::vector<char16_t> convBuffer(convBufferLen);
             ssize_t l = 0;
             ssize_t h = mHeader->stringCount-1;
 
@@ -1043,8 +1044,8 @@
                 }
                 if (s.has_value()) {
                     char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()),
-                                                  s->size(), convBuffer, convBufferLen);
-                    c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
+                                                  s->size(), convBuffer.data(), convBufferLen);
+                    c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen);
                 }
                 if (kDebugStringPoolNoisy) {
                     ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
@@ -1054,7 +1055,6 @@
                     if (kDebugStringPoolNoisy) {
                         ALOGI("MATCH!");
                     }
-                    free(convBuffer);
                     return mid;
                 } else if (c < 0) {
                     l = mid + 1;
@@ -1062,7 +1062,6 @@
                     h = mid - 1;
                 }
             }
-            free(convBuffer);
         } else {
             // It is unusual to get the ID from an unsorted string block...
             // most often this happens because we want to get IDs for style
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/Android.bp b/packages/SystemUI/Android.bp
index 6ecf303..249b194 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -45,7 +45,7 @@
         "WindowManager-Shell",
         "SystemUIPluginLib",
         "SystemUISharedLib",
-	"SystemUI-statsd",
+        "SystemUI-statsd",
         "SettingsLib",
         "androidx.viewpager2_viewpager2",
         "androidx.legacy_legacy-support-v4",
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/OWNERS b/services/OWNERS
index 88d0b61..f1fa542 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1 +1,4 @@
 per-file Android.bp = file:platform/build/soong:/OWNERS
+
+# art-team@ manages the system server profile
+per-file art-profile* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
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..5ad5805 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",
@@ -200,6 +203,8 @@
         "java/com/android/server/connectivity/NetworkRanker.java",
         "java/com/android/server/connectivity/PermissionMonitor.java",
         "java/com/android/server/connectivity/ProxyTracker.java",
+        "java/com/android/server/connectivity/QosCallbackAgentConnection.java",
+        "java/com/android/server/connectivity/QosCallbackTracker.java",
         "java/com/android/server/connectivity/TcpKeepaliveController.java",
         "java/com/android/server/connectivity/Vpn.java",
         "java/com/android/server/connectivity/VpnIkev2Utils.java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 90a17e7..b6232a0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -94,6 +94,7 @@
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkStatsService;
+import android.net.IQosCallback;
 import android.net.ISocketKeepaliveCallback;
 import android.net.InetAddresses;
 import android.net.IpMemoryStore;
@@ -121,6 +122,10 @@
 import android.net.NetworkWatchlistManager;
 import android.net.PrivateDnsConfigParcel;
 import android.net.ProxyInfo;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSocketFilter;
+import android.net.QosSocketInfo;
 import android.net.RouteInfo;
 import android.net.RouteInfoParcel;
 import android.net.SocketKeepalive;
@@ -204,6 +209,7 @@
 import com.android.server.connectivity.NetworkRanker;
 import com.android.server.connectivity.PermissionMonitor;
 import com.android.server.connectivity.ProxyTracker;
+import com.android.server.connectivity.QosCallbackTracker;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
 import com.android.server.net.LockdownVpnTracker;
@@ -279,6 +285,10 @@
     // Default to 30s linger time-out. Modifiable only for testing.
     private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
     private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
+
+    // The maximum number of network request allowed per uid before an exception is thrown.
+    private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+
     @VisibleForTesting
     protected int mLingerDelayMs;  // Can't be final, or test subclass constructors can't change it.
 
@@ -291,6 +301,8 @@
     @VisibleForTesting
     protected final PermissionMonitor mPermissionMonitor;
 
+    private final PerUidCounter mNetworkRequestCounter;
+
     private KeyStore mKeyStore;
 
     @VisibleForTesting
@@ -614,6 +626,7 @@
     private final LocationPermissionChecker mLocationPermissionChecker;
 
     private KeepaliveTracker mKeepaliveTracker;
+    private QosCallbackTracker mQosCallbackTracker;
     private NetworkNotificationManager mNotifier;
     private LingerMonitor mLingerMonitor;
 
@@ -858,6 +871,66 @@
     };
 
     /**
+     * Keeps track of the number of requests made under different uids.
+     */
+    public static class PerUidCounter {
+        private final int mMaxCountPerUid;
+
+        // Map from UID to number of NetworkRequests that UID has filed.
+        @GuardedBy("mUidToNetworkRequestCount")
+        private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
+
+        /**
+         * Constructor
+         *
+         * @param maxCountPerUid the maximum count per uid allowed
+         */
+        public PerUidCounter(final int maxCountPerUid) {
+            mMaxCountPerUid = maxCountPerUid;
+        }
+
+        /**
+         * Increments the request count of the given uid.  Throws an exception if the number
+         * of open requests for the uid exceeds the value of maxCounterPerUid which is the value
+         * passed into the constructor. see: {@link #PerUidCounter(int)}.
+         *
+         * @throws ServiceSpecificException with
+         * {@link ConnectivityManager.Errors.TOO_MANY_REQUESTS} if the number of requests for
+         * the uid exceed the allowed number.
+         *
+         * @param uid the uid that the request was made under
+         */
+        public void incrementCountOrThrow(final int uid) {
+            synchronized (mUidToNetworkRequestCount) {
+                final int networkRequests = mUidToNetworkRequestCount.get(uid, 0) + 1;
+                if (networkRequests >= mMaxCountPerUid) {
+                    throw new ServiceSpecificException(
+                            ConnectivityManager.Errors.TOO_MANY_REQUESTS);
+                }
+                mUidToNetworkRequestCount.put(uid, networkRequests);
+            }
+        }
+
+        /**
+         * Decrements the request count of the given uid.
+         *
+         * @param uid the uid that the request was made under
+         */
+        public void decrementCount(final int uid) {
+            synchronized (mUidToNetworkRequestCount) {
+                final int requests = mUidToNetworkRequestCount.get(uid, 0);
+                if (requests < 1) {
+                    logwtf("BUG: too small request count " + requests + " for UID " + uid);
+                } else if (requests == 1) {
+                    mUidToNetworkRequestCount.delete(uid);
+                } else {
+                    mUidToNetworkRequestCount.put(uid, requests - 1);
+                }
+            }
+        }
+    }
+
+    /**
      * Dependencies of ConnectivityService, for injection in tests.
      */
     @VisibleForTesting
@@ -945,6 +1018,7 @@
         mSystemProperties = mDeps.getSystemProperties();
         mNetIdManager = mDeps.makeNetIdManager();
         mContext = Objects.requireNonNull(context, "missing Context");
+        mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
 
         mMetricsLog = logger;
         mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -1115,11 +1189,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();
@@ -1129,6 +1199,7 @@
 
         mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
         mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
+        mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
 
         final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
@@ -1802,30 +1873,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.
      */
@@ -2274,20 +2321,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
@@ -2393,74 +2426,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.
      */
@@ -2874,13 +2839,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;
@@ -2893,6 +2852,7 @@
                         updateCapabilitiesForNetwork(nai);
                         notifyIfacesChangedForNetworkStats();
                     }
+                    break;
                 }
             }
         }
@@ -3454,6 +3414,8 @@
         // of rematchAllNetworksAndRequests
         notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
         mKeepaliveTracker.handleStopAllKeepalives(nai, SocketKeepalive.ERROR_INVALID_NETWORK);
+
+        mQosCallbackTracker.handleNetworkReleased(nai.network);
         for (String iface : nai.linkProperties.getAllInterfaceNames()) {
             // Disable wakeup packet monitoring for each interface.
             wakeupModifyInterface(iface, nai.networkCapabilities, false);
@@ -3466,6 +3428,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);
@@ -3478,10 +3441,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());
         }
@@ -3720,7 +3685,7 @@
         nri.unlinkDeathRecipient();
         mNetworkRequests.remove(nri.request);
 
-        decrementNetworkRequestPerUidCount(nri);
+        mNetworkRequestCounter.decrementCount(nri.mUid);
 
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
         if (nri.request.isRequest()) {
@@ -3793,19 +3758,6 @@
         }
     }
 
-    private void decrementNetworkRequestPerUidCount(final NetworkRequestInfo nri) {
-        synchronized (mUidToNetworkRequestCount) {
-            final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
-            if (requests < 1) {
-                Log.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
-            } else if (requests == 1) {
-                mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
-            } else {
-                mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
-            }
-        }
-    }
-
     @Override
     public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
         enforceNetworkStackSettingsOrSetup();
@@ -4632,6 +4584,10 @@
         Log.w(TAG, s);
     }
 
+    private static void logwtf(String s) {
+        Log.wtf(TAG, s);
+    }
+
     private static void loge(String s) {
         Log.e(TAG, s);
     }
@@ -4995,6 +4951,8 @@
 
     @Override
     public boolean updateLockdownVpn() {
+        // 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");
@@ -5372,11 +5330,6 @@
     private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
     private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
 
-    private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
-    // Map from UID to number of NetworkRequests that UID has filed.
-    @GuardedBy("mUidToNetworkRequestCount")
-    private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
-
     private static class NetworkProviderInfo {
         public final String name;
         public final Messenger messenger;
@@ -5490,7 +5443,7 @@
             mBinder = null;
             mPid = getCallingPid();
             mUid = mDeps.getCallingUid();
-            enforceRequestCountLimit();
+            mNetworkRequestCounter.incrementCountOrThrow(mUid);
         }
 
         NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) {
@@ -5503,7 +5456,7 @@
             mPid = getCallingPid();
             mUid = mDeps.getCallingUid();
             mPendingIntent = null;
-            enforceRequestCountLimit();
+            mNetworkRequestCounter.incrementCountOrThrow(mUid);
 
             try {
                 mBinder.linkToDeath(this, 0);
@@ -5540,17 +5493,6 @@
             return null;
         }
 
-        private void enforceRequestCountLimit() {
-            synchronized (mUidToNetworkRequestCount) {
-                int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
-                if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) {
-                    throw new ServiceSpecificException(
-                            ConnectivityManager.Errors.TOO_MANY_REQUESTS);
-                }
-                mUidToNetworkRequestCount.put(mUid, networkRequests);
-            }
-        }
-
         void unlinkDeathRecipient() {
             if (mBinder != null) {
                 mBinder.unlinkToDeath(this, 0);
@@ -5772,9 +5714,14 @@
             // Policy already enforced.
             return;
         }
-        if (mPolicyManagerInternal.isUidRestrictedOnMeteredNetworks(uid)) {
-            // If UID is restricted, don't allow them to bring up metered APNs.
-            networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            if (mPolicyManager.isUidRestrictedOnMeteredNetworks(uid)) {
+                // If UID is restricted, don't allow them to bring up metered APNs.
+                networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -6109,7 +6056,7 @@
         final NetworkAgentInfo nai = new NetworkAgentInfo(na,
                 new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
                 currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
-                this, mNetd, mDnsResolver, mNMS, providerId, uid);
+                this, mNetd, mDnsResolver, mNMS, providerId, uid, mQosCallbackTracker);
 
         // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
         processCapabilitiesFromAgent(nai, nc);
@@ -7309,7 +7256,8 @@
             if (oldDefaultNetwork != null) {
                 mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
             }
-            updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+            mNetworkActivityTracker.updateDataActivityTracking(
+                    newDefaultNetwork, oldDefaultNetwork);
             // Notify system services of the new default.
             makeDefault(newDefaultNetwork);
 
@@ -7907,10 +7855,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,
@@ -7918,24 +7867,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);
             }
         }
     }
@@ -8386,7 +8336,7 @@
             // Decrement the reference count for this NetworkRequestInfo. The reference count is
             // incremented when the NetworkRequestInfo is created as part of
             // enforceRequestCountLimit().
-            decrementNetworkRequestPerUidCount(nri);
+            mNetworkRequestCounter.decrementCount(nri.mUid);
             return;
         }
 
@@ -8452,7 +8402,7 @@
         // Decrement the reference count for this NetworkRequestInfo. The reference count is
         // incremented when the NetworkRequestInfo is created as part of
         // enforceRequestCountLimit().
-        decrementNetworkRequestPerUidCount(nri);
+        mNetworkRequestCounter.decrementCount(nri.mUid);
 
         iCb.unlinkToDeath(cbInfo, 0);
     }
@@ -8661,4 +8611,194 @@
 
         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);
+            }
+        }
+    }
+    /**
+     * Registers {@link QosSocketFilter} with {@link IQosCallback}.
+     *
+     * @param socketInfo the socket information
+     * @param callback the callback to register
+     */
+    @Override
+    public void registerQosSocketCallback(@NonNull final QosSocketInfo socketInfo,
+            @NonNull final IQosCallback callback) {
+        final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(socketInfo.getNetwork());
+        if (nai == null || nai.networkCapabilities == null) {
+            try {
+                callback.onError(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+            } catch (final RemoteException ex) {
+                loge("registerQosCallbackInternal: RemoteException", ex);
+            }
+            return;
+        }
+        registerQosCallbackInternal(new QosSocketFilter(socketInfo), callback, nai);
+    }
+
+    /**
+     * Register a {@link IQosCallback} with base {@link QosFilter}.
+     *
+     * @param filter the filter to register
+     * @param callback the callback to register
+     * @param nai the agent information related to the filter's network
+     */
+    @VisibleForTesting
+    public void registerQosCallbackInternal(@NonNull final QosFilter filter,
+            @NonNull final IQosCallback callback, @NonNull final NetworkAgentInfo nai) {
+        if (filter == null) throw new IllegalArgumentException("filter must be non-null");
+        if (callback == null) throw new IllegalArgumentException("callback must be non-null");
+
+        if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+            enforceConnectivityRestrictedNetworksPermission();
+        }
+        mQosCallbackTracker.registerCallback(callback, filter, nai);
+    }
+
+    /**
+     * Unregisters the given callback.
+     *
+     * @param callback the callback to unregister
+     */
+    @Override
+    public void unregisterQosCallback(@NonNull final IQosCallback callback) {
+        mQosCallbackTracker.unregisterCallback(callback);
+    }
 }
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 5c34584..4e2519b 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3297,6 +3297,12 @@
         enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
 
         if (isFsEncrypted) {
+            // When a user has secure lock screen, require secret to actually unlock.
+            // This check is mostly in place for emulation mode.
+            if (StorageManager.isFileEncryptedEmulatedOnly() &&
+                mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
+                throw new IllegalStateException("Secret required to unlock secure user " + userId);
+            }
             try {
                 mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
                         encodeBytes(secret));
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..76db019 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -26,20 +26,24 @@
 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;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.ParcelUuid;
 import android.os.PersistableBundle;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -154,6 +158,11 @@
 
     @NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
 
+    @GuardedBy("mLock")
+    @NonNull
+    private final Map<IBinder, PolicyListenerBinderDeath> mRegisteredPolicyListeners =
+            new ArrayMap<>();
+
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
         mContext = requireNonNull(context, "Missing context");
@@ -495,4 +504,61 @@
             return Collections.unmodifiableMap(mVcns);
         }
     }
+
+    /** Binder death recipient used to remove a registered policy listener. */
+    private class PolicyListenerBinderDeath implements Binder.DeathRecipient {
+        @NonNull private final IVcnUnderlyingNetworkPolicyListener mListener;
+
+        PolicyListenerBinderDeath(@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void binderDied() {
+            Log.e(TAG, "app died without removing VcnUnderlyingNetworkPolicyListener");
+            removeVcnUnderlyingNetworkPolicyListener(mListener);
+        }
+    }
+
+    /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
+    @GuardedBy("mLock")
+    @Override
+    public void addVcnUnderlyingNetworkPolicyListener(
+            @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+        requireNonNull(listener, "listener was null");
+
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.NETWORK_FACTORY,
+                "Must have permission NETWORK_FACTORY to register a policy listener");
+
+        PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener);
+
+        synchronized (mLock) {
+            mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath);
+
+            try {
+                listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */);
+            } catch (RemoteException e) {
+                // Remote binder already died - cleanup registered Listener
+                listenerBinderDeath.binderDied();
+            }
+        }
+    }
+
+    /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
+    @GuardedBy("mLock")
+    @Override
+    public void removeVcnUnderlyingNetworkPolicyListener(
+            @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+        requireNonNull(listener, "listener was null");
+
+        synchronized (mLock) {
+            PolicyListenerBinderDeath listenerBinderDeath =
+                    mRegisteredPolicyListeners.remove(listener.asBinder());
+
+            if (listenerBinderDeath != null) {
+                listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */);
+            }
+        }
+    }
 }
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/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index ba6cbcd..ab0360b 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -36,13 +36,17 @@
 import android.net.NetworkMonitorManager;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosFilterParcelable;
+import android.net.QosSession;
 import android.net.TcpKeepalivePacketData;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.telephony.data.EpsBearerQosSessionAttributes;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
@@ -53,7 +57,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;
@@ -323,18 +326,20 @@
     private final ConnectivityService mConnService;
     private final Context mContext;
     private final Handler mHandler;
+    private final QosCallbackTracker mQosCallbackTracker;
 
     public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context,
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
             IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
-            int creatorUid) {
+            int creatorUid, QosCallbackTracker qosCallbackTracker) {
         Objects.requireNonNull(net);
         Objects.requireNonNull(info);
         Objects.requireNonNull(lp);
         Objects.requireNonNull(nc);
         Objects.requireNonNull(context);
         Objects.requireNonNull(config);
+        Objects.requireNonNull(qosCallbackTracker);
         networkAgent = na;
         network = net;
         networkInfo = info;
@@ -348,6 +353,7 @@
         networkAgentConfig = config;
         this.factorySerialNumber = factorySerialNumber;
         this.creatorUid = creatorUid;
+        mQosCallbackTracker = qosCallbackTracker;
     }
 
     private class AgentDeathMonitor implements IBinder.DeathRecipient {
@@ -533,6 +539,31 @@
         }
     }
 
+    /**
+     * Notify the NetworkAgent that the qos filter should be registered against the given qos
+     * callback id.
+     */
+    public void onQosFilterCallbackRegistered(final int qosCallbackId,
+            final QosFilter qosFilter) {
+        try {
+            networkAgent.onQosFilterCallbackRegistered(qosCallbackId,
+                    new QosFilterParcelable(qosFilter));
+        } catch (final RemoteException e) {
+            Log.e(TAG, "Error registering a qos callback id against a qos filter", e);
+        }
+    }
+
+    /**
+     * Notify the NetworkAgent that the given qos callback id should be unregistered.
+     */
+    public void onQosCallbackUnregistered(final int qosCallbackId) {
+        try {
+            networkAgent.onQosCallbackUnregistered(qosCallbackId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error unregistering a qos callback id", e);
+        }
+    }
+
     // TODO: consider moving out of NetworkAgentInfo into its own class
     private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
         private final Handler mHandler;
@@ -583,16 +614,25 @@
 
         @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();
+        }
+
+        @Override
+        public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
+                final EpsBearerQosSessionAttributes attributes) {
+            mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes);
+        }
+
+        @Override
+        public void sendQosSessionLost(final int qosCallbackId, final QosSession session) {
+            mQosCallbackTracker.sendEventQosSessionLost(qosCallbackId, session);
+        }
+
+        @Override
+        public void sendQosCallbackError(final int qosCallbackId,
+                @QosCallbackException.ExceptionType final int exceptionType) {
+            mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
new file mode 100644
index 0000000..816bf2b
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -0,0 +1,192 @@
+/*
+ * 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.connectivity;
+
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+
+import android.annotation.NonNull;
+import android.net.IQosCallback;
+import android.net.Network;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * Wraps callback related information and sends messages between network agent and the application.
+ * <p/>
+ * This is a satellite class of {@link com.android.server.ConnectivityService} and not meant
+ * to be used in other contexts.
+ *
+ * @hide
+ */
+class QosCallbackAgentConnection implements IBinder.DeathRecipient {
+    private static final String TAG = QosCallbackAgentConnection.class.getSimpleName();
+    private static final boolean DBG = false;
+
+    private final int mAgentCallbackId;
+    @NonNull private final QosCallbackTracker mQosCallbackTracker;
+    @NonNull private final IQosCallback mCallback;
+    @NonNull private final IBinder mBinder;
+    @NonNull private final QosFilter mFilter;
+    @NonNull private final NetworkAgentInfo mNetworkAgentInfo;
+
+    private final int mUid;
+
+    /**
+     * Gets the uid
+     * @return uid
+     */
+    int getUid() {
+        return mUid;
+    }
+
+    /**
+     * Gets the binder
+     * @return binder
+     */
+    @NonNull
+    IBinder getBinder() {
+        return mBinder;
+    }
+
+    /**
+     * Gets the callback id
+     *
+     * @return callback id
+     */
+    int getAgentCallbackId() {
+        return mAgentCallbackId;
+    }
+
+    /**
+     * Gets the network tied to the callback of this connection
+     *
+     * @return network
+     */
+    @NonNull
+    Network getNetwork() {
+        return mFilter.getNetwork();
+    }
+
+    QosCallbackAgentConnection(@NonNull final QosCallbackTracker qosCallbackTracker,
+            final int agentCallbackId,
+            @NonNull final IQosCallback callback,
+            @NonNull final QosFilter filter,
+            final int uid,
+            @NonNull final NetworkAgentInfo networkAgentInfo) {
+        Objects.requireNonNull(qosCallbackTracker, "qosCallbackTracker must be non-null");
+        Objects.requireNonNull(callback, "callback must be non-null");
+        Objects.requireNonNull(filter, "filter must be non-null");
+        Objects.requireNonNull(networkAgentInfo, "networkAgentInfo must be non-null");
+
+        mQosCallbackTracker = qosCallbackTracker;
+        mAgentCallbackId = agentCallbackId;
+        mCallback = callback;
+        mFilter = filter;
+        mUid = uid;
+        mBinder = mCallback.asBinder();
+        mNetworkAgentInfo = networkAgentInfo;
+    }
+
+    @Override
+    public void binderDied() {
+        logw("binderDied: binder died with callback id: " + mAgentCallbackId);
+        mQosCallbackTracker.unregisterCallback(mCallback);
+    }
+
+    void unlinkToDeathRecipient() {
+        mBinder.unlinkToDeath(this, 0);
+    }
+
+    // Returns false if the NetworkAgent was never notified.
+    boolean sendCmdRegisterCallback() {
+        final int exceptionType = mFilter.validate();
+        if (exceptionType != EX_TYPE_FILTER_NONE) {
+            try {
+                if (DBG) log("sendCmdRegisterCallback: filter validation failed");
+                mCallback.onError(exceptionType);
+            } catch (final RemoteException e) {
+                loge("sendCmdRegisterCallback:", e);
+            }
+            return false;
+        }
+
+        try {
+            mBinder.linkToDeath(this, 0);
+        } catch (final RemoteException e) {
+            loge("failed linking to death recipient", e);
+            return false;
+        }
+        mNetworkAgentInfo.onQosFilterCallbackRegistered(mAgentCallbackId, mFilter);
+        return true;
+    }
+
+    void sendCmdUnregisterCallback() {
+        if (DBG) log("sendCmdUnregisterCallback: unregistering");
+        mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
+    }
+
+    void sendEventQosSessionAvailable(final QosSession session,
+            final EpsBearerQosSessionAttributes attributes) {
+        try {
+            if (DBG) log("sendEventQosSessionAvailable: sending...");
+            mCallback.onQosEpsBearerSessionAvailable(session, attributes);
+        } catch (final RemoteException e) {
+            loge("sendEventQosSessionAvailable: remote exception", e);
+        }
+    }
+
+    void sendEventQosSessionLost(@NonNull final QosSession session) {
+        try {
+            if (DBG) log("sendEventQosSessionLost: sending...");
+            mCallback.onQosSessionLost(session);
+        } catch (final RemoteException e) {
+            loge("sendEventQosSessionLost: remote exception", e);
+        }
+    }
+
+    void sendEventQosCallbackError(@QosCallbackException.ExceptionType final int exceptionType) {
+        try {
+            if (DBG) log("sendEventQosCallbackError: sending...");
+            mCallback.onError(exceptionType);
+        } catch (final RemoteException e) {
+            loge("sendEventQosCallbackError: remote exception", e);
+        }
+    }
+
+    private static void log(@NonNull final String msg) {
+        Slog.d(TAG, msg);
+    }
+
+    private static void logw(@NonNull final String msg) {
+        Slog.w(TAG, msg);
+    }
+
+    private static void loge(@NonNull final String msg, final Throwable t) {
+        Slog.e(TAG, msg, t);
+    }
+
+    private static void logwtf(@NonNull final String msg) {
+        Slog.wtf(TAG, msg);
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
new file mode 100644
index 0000000..87b4c16
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -0,0 +1,277 @@
+/*
+ * 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.connectivity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IQosCallback;
+import android.net.Network;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.util.Slog;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.server.ConnectivityService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tracks qos callbacks and handles the communication between the network agent and application.
+ * <p/>
+ * Any method prefixed by handle must be called from the
+ * {@link com.android.server.ConnectivityService} handler thread.
+ *
+ * @hide
+ */
+public class QosCallbackTracker {
+    private static final String TAG = QosCallbackTracker.class.getSimpleName();
+    private static final boolean DBG = true;
+
+    @NonNull
+    private final Handler mConnectivityServiceHandler;
+
+    @NonNull
+    private final ConnectivityService.PerUidCounter mNetworkRequestCounter;
+
+    /**
+     * Each agent gets a unique callback id that is used to proxy messages back to the original
+     * callback.
+     * <p/>
+     * Note: The fact that this is initialized to 0 is to ensure that the thread running
+     * {@link #handleRegisterCallback(IQosCallback, QosFilter, int, NetworkAgentInfo)} sees the
+     * initialized value. This would not necessarily be the case if the value was initialized to
+     * the non-default value.
+     * <p/>
+     * Note: The term previous does not apply to the first callback id that is assigned.
+     */
+    private int mPreviousAgentCallbackId = 0;
+
+    @NonNull
+    private final List<QosCallbackAgentConnection> mConnections = new ArrayList<>();
+
+    /**
+     *
+     * @param connectivityServiceHandler must be the same handler used with
+     *                {@link com.android.server.ConnectivityService}
+     * @param networkRequestCounter keeps track of the number of open requests under a given
+     *                              uid
+     */
+    public QosCallbackTracker(@NonNull final Handler connectivityServiceHandler,
+            final ConnectivityService.PerUidCounter networkRequestCounter) {
+        mConnectivityServiceHandler = connectivityServiceHandler;
+        mNetworkRequestCounter = networkRequestCounter;
+    }
+
+    /**
+     * Registers the callback with the tracker
+     *
+     * @param callback the callback to register
+     * @param filter the filter being registered alongside the callback
+     */
+    public void registerCallback(@NonNull final IQosCallback callback,
+            @NonNull final QosFilter filter, @NonNull final NetworkAgentInfo networkAgentInfo) {
+        final int uid = Binder.getCallingUid();
+
+        // Enforce that the number of requests under this uid has exceeded the allowed number
+        mNetworkRequestCounter.incrementCountOrThrow(uid);
+
+        mConnectivityServiceHandler.post(
+                () -> handleRegisterCallback(callback, filter, uid, networkAgentInfo));
+    }
+
+    private void handleRegisterCallback(@NonNull final IQosCallback callback,
+            @NonNull final QosFilter filter, final int uid,
+            @NonNull final NetworkAgentInfo networkAgentInfo) {
+        final QosCallbackAgentConnection ac =
+                handleRegisterCallbackInternal(callback, filter, uid, networkAgentInfo);
+        if (ac != null) {
+            if (DBG) log("handleRegisterCallback: added callback " + ac.getAgentCallbackId());
+            mConnections.add(ac);
+        } else {
+            mNetworkRequestCounter.decrementCount(uid);
+        }
+    }
+
+    private QosCallbackAgentConnection handleRegisterCallbackInternal(
+            @NonNull final IQosCallback callback,
+            @NonNull final QosFilter filter, final int uid,
+            @NonNull final NetworkAgentInfo networkAgentInfo) {
+        final IBinder binder = callback.asBinder();
+        if (CollectionUtils.any(mConnections, c -> c.getBinder().equals(binder))) {
+            // A duplicate registration would have only made this far due to a programming error.
+            logwtf("handleRegisterCallback: Callbacks can only be register once.");
+            return null;
+        }
+
+        mPreviousAgentCallbackId = mPreviousAgentCallbackId + 1;
+        final int newCallbackId = mPreviousAgentCallbackId;
+
+        final QosCallbackAgentConnection ac =
+                new QosCallbackAgentConnection(this, newCallbackId, callback,
+                        filter, uid, networkAgentInfo);
+
+        final int exceptionType = filter.validate();
+        if (exceptionType != QosCallbackException.EX_TYPE_FILTER_NONE) {
+            ac.sendEventQosCallbackError(exceptionType);
+            return null;
+        }
+
+        // Only add to the callback maps if the NetworkAgent successfully registered it
+        if (!ac.sendCmdRegisterCallback()) {
+            // There was an issue when registering the agent
+            if (DBG) log("handleRegisterCallback: error sending register callback");
+            mNetworkRequestCounter.decrementCount(uid);
+            return null;
+        }
+        return ac;
+    }
+
+    /**
+     * Unregisters callback
+     * @param callback callback to unregister
+     */
+    public void unregisterCallback(@NonNull final IQosCallback callback) {
+        mConnectivityServiceHandler.post(() -> handleUnregisterCallback(callback.asBinder(), true));
+    }
+
+    private void handleUnregisterCallback(@NonNull final IBinder binder,
+            final boolean sendToNetworkAgent) {
+        final QosCallbackAgentConnection agentConnection =
+                CollectionUtils.find(mConnections, c -> c.getBinder().equals(binder));
+        if (agentConnection == null) {
+            logw("handleUnregisterCallback: agentConnection is null");
+            return;
+        }
+
+        if (DBG) {
+            log("handleUnregisterCallback: unregister "
+                    + agentConnection.getAgentCallbackId());
+        }
+
+        mNetworkRequestCounter.decrementCount(agentConnection.getUid());
+        mConnections.remove(agentConnection);
+
+        if (sendToNetworkAgent) {
+            agentConnection.sendCmdUnregisterCallback();
+        }
+        agentConnection.unlinkToDeathRecipient();
+    }
+
+    /**
+     * Called when the NetworkAgent sends the qos session available event
+     *
+     * @param qosCallbackId the callback id that the qos session is now available to
+     * @param session the qos session that is now available
+     * @param attributes the qos attributes that are now available on the qos session
+     */
+    public void sendEventQosSessionAvailable(final int qosCallbackId,
+            final QosSession session,
+            final EpsBearerQosSessionAttributes attributes) {
+        runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ",
+                ac -> ac.sendEventQosSessionAvailable(session, attributes));
+    }
+
+    /**
+     * Called when the NetworkAgent sends the qos session lost event
+     *
+     * @param qosCallbackId the callback id that lost the qos session
+     * @param session the corresponding qos session
+     */
+    public void sendEventQosSessionLost(final int qosCallbackId,
+            final QosSession session) {
+        runOnAgentConnection(qosCallbackId, "sendEventQosSessionLost: ",
+                ac -> ac.sendEventQosSessionLost(session));
+    }
+
+    /**
+     * Called when the NetworkAgent sends the qos session on error event
+     *
+     * @param qosCallbackId the callback id that should receive the exception
+     * @param exceptionType the type of exception that caused the callback to error
+     */
+    public void sendEventQosCallbackError(final int qosCallbackId,
+            @QosCallbackException.ExceptionType final int exceptionType) {
+        runOnAgentConnection(qosCallbackId, "sendEventQosCallbackError: ",
+                ac -> {
+                    ac.sendEventQosCallbackError(exceptionType);
+                    handleUnregisterCallback(ac.getBinder(), false);
+                });
+    }
+
+    /**
+     * Unregisters all callbacks associated to this network agent
+     *
+     * Note: Must be called on the connectivity service handler thread
+     *
+     * @param network the network that was released
+     */
+    public void handleNetworkReleased(@Nullable final Network network) {
+        final List<QosCallbackAgentConnection> connections =
+                CollectionUtils.filter(mConnections, ac -> ac.getNetwork().equals(network));
+
+        for (final QosCallbackAgentConnection agentConnection : connections) {
+            agentConnection.sendEventQosCallbackError(
+                    QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+
+            // Call unregister workflow w\o sending anything to agent since it is disconnected.
+            handleUnregisterCallback(agentConnection.getBinder(), false);
+        }
+    }
+
+    private interface AgentConnectionAction {
+        void execute(@NonNull QosCallbackAgentConnection agentConnection);
+    }
+
+    @Nullable
+    private void runOnAgentConnection(final int qosCallbackId,
+            @NonNull final String logPrefix,
+            @NonNull final AgentConnectionAction action) {
+        mConnectivityServiceHandler.post(() -> {
+            final QosCallbackAgentConnection ac =
+                    CollectionUtils.find(mConnections,
+                            c -> c.getAgentCallbackId() == qosCallbackId);
+            if (ac == null) {
+                loge(logPrefix + ": " + qosCallbackId + " missing callback id");
+                return;
+            }
+
+            action.execute(ac);
+        });
+    }
+
+    private static void log(final String msg) {
+        Slog.d(TAG, msg);
+    }
+
+    private static void logw(final String msg) {
+        Slog.w(TAG, msg);
+    }
+
+    private static void loge(final String msg) {
+        Slog.e(TAG, msg);
+    }
+
+    private static void logwtf(final String msg) {
+        Slog.wtf(TAG, msg);
+    }
+}
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/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 141fa6a..f92f3dc 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -39,11 +39,6 @@
     public abstract void resetUserState(int userId);
 
     /**
-     * @return true if the given uid is restricted from doing networking on metered networks.
-     */
-    public abstract boolean isUidRestrictedOnMeteredNetworks(int uid);
-
-    /**
      * Figure out if networking is blocked for a given set of conditions.
      *
      * This is used by ConnectivityService via passing stale copies of conditions, so it must not
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 1c41dc0..01d4faf 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -5361,7 +5361,7 @@
     public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
         final long startTime = mStatLogger.getTime();
 
-        enforceAnyPermissionOf(OBSERVE_NETWORK_POLICY, PERMISSION_MAINLINE_NETWORK_STACK);
+        mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
         final int uidRules;
         final boolean isBackgroundRestricted;
         synchronized (mUidRulesFirstLock) {
@@ -5376,6 +5376,23 @@
         return ret;
     }
 
+    @Override
+    public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+        mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
+        final int uidRules;
+        final boolean isBackgroundRestricted;
+        synchronized (mUidRulesFirstLock) {
+            uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+            isBackgroundRestricted = mRestrictBackground;
+        }
+        //TODO(b/177490332): The logic here might not be correct because it doesn't consider
+        // RULE_REJECT_METERED condition. And it could be replaced by
+        // isUidNetworkingBlockedInternal().
+        return isBackgroundRestricted
+                && !hasRule(uidRules, RULE_ALLOW_METERED)
+                && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
+    }
+
     private static boolean isSystem(int uid) {
         return uid < Process.FIRST_APPLICATION_UID;
     }
@@ -5444,22 +5461,6 @@
             }
         }
 
-        /**
-         * @return true if the given uid is restricted from doing networking on metered networks.
-         */
-        @Override
-        public boolean isUidRestrictedOnMeteredNetworks(int uid) {
-            final int uidRules;
-            final boolean isBackgroundRestricted;
-            synchronized (mUidRulesFirstLock) {
-                uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
-                isBackgroundRestricted = mRestrictBackground;
-            }
-            return isBackgroundRestricted
-                    && !hasRule(uidRules, RULE_ALLOW_METERED)
-                    && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
-        }
-
         @Override
         public void onTempPowerSaveWhitelistChange(int appId, boolean added) {
             synchronized (mUidRulesFirstLock) {
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 01eeb31..4ff75fa 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,12 +93,10 @@
     }
 
     @Override
-    @RequiresPermission(android.Manifest.permission.DUMP)
+    @RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges
     public void cancelBugreport(int callingUidUnused, String callingPackage) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
-                "cancelBugreport");
         int callingUid = Binder.getCallingUid();
-        mAppOps.checkPackage(callingUid, callingPackage);
+        enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */);
 
         synchronized (mLock) {
             IDumpstate ds = getDumpstateBinderServiceLocked();
@@ -134,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.
      *
@@ -310,6 +336,13 @@
 
         @Override
         public void binderDied() {
+            try {
+                // Allow a small amount of time for any error or finished callbacks to be made.
+                // This ensures that the listener does not receive an erroneous runtime error
+                // callback.
+                Thread.sleep(1000);
+            } catch (InterruptedException ignored) {
+            }
             synchronized (mLock) {
                 if (!mDone) {
                     // If we have not gotten a "done" callback this must be a crash.
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/security/OWNERS b/services/core/java/com/android/server/security/OWNERS
new file mode 100644
index 0000000..91b240b
--- /dev/null
+++ b/services/core/java/com/android/server/security/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36824
+
+per-file FileIntegrityService.java = victorhsieh@google.com
+per-file VerityUtils.java = victorhsieh@google.com
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/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index e1feb5a..6427ae2 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -24,6 +24,9 @@
 import android.os.Handler;
 import android.os.ParcelUuid;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
 import java.util.Objects;
 
 /**
@@ -72,7 +75,8 @@
         @NonNull public final LinkProperties linkProperties;
         public final boolean blocked;
 
-        private UnderlyingNetworkRecord(
+        @VisibleForTesting(visibility = Visibility.PRIVATE)
+        UnderlyingNetworkRecord(
                 @NonNull Network network,
                 @NonNull NetworkCapabilities networkCapabilities,
                 @NonNull LinkProperties linkProperties,
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 7024e67..93cf470 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;
@@ -360,11 +360,25 @@
      */
     private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8;
 
-    @NonNull private final DisconnectedState mDisconnectedState = new DisconnectedState();
-    @NonNull private final DisconnectingState mDisconnectingState = new DisconnectingState();
-    @NonNull private final ConnectingState mConnectingState = new ConnectingState();
-    @NonNull private final ConnectedState mConnectedState = new ConnectedState();
-    @NonNull private final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final DisconnectedState mDisconnectedState = new DisconnectedState();
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final DisconnectingState mDisconnectingState = new DisconnectingState();
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final ConnectingState mConnectingState = new ConnectingState();
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final ConnectedState mConnectedState = new ConnectedState();
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    @NonNull
+    final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
 
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
@@ -455,7 +469,8 @@
         this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies());
     }
 
-    private VcnGatewayConnection(
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    VcnGatewayConnection(
             @NonNull VcnContext vcnContext,
             @NonNull ParcelUuid subscriptionGroup,
             @NonNull VcnGatewayConnectionConfig connectionConfig,
@@ -504,21 +519,23 @@
      * <p>Once torn down, this VcnTunnel CANNOT be started again.
      */
     public void teardownAsynchronously() {
-        mUnderlyingNetworkTracker.teardown();
+        sendMessage(
+                EVENT_DISCONNECT_REQUESTED,
+                TOKEN_ALL,
+                new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
 
+        // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
+        // 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();
         }
 
-        sendMessage(
-                EVENT_DISCONNECT_REQUESTED,
-                TOKEN_ANY,
-                new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
-        quit();
-
-        // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
-        // is also called asynchronously when a NetworkAgent becomes unwanted
+        mUnderlyingNetworkTracker.teardown();
     }
 
     private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
@@ -530,26 +547,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 +609,103 @@
     }
 
     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);
+            mIsRunning = false;
+
+            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.
      *
@@ -605,10 +713,62 @@
      */
     private class DisconnectedState extends BaseState {
         @Override
-        protected void processStateMsg(Message msg) {}
+        protected void enterState() {
+            if (!mIsRunning) {
+                quitNow(); // Ignore all queued events; cleanup is complete.
+            }
+
+            if (mIkeSession != null || mNetworkAgent != null) {
+                Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
+            }
+        }
+
+        @Override
+        protected void processStateMsg(Message msg) {
+            switch (msg.what) {
+                case EVENT_UNDERLYING_NETWORK_CHANGED:
+                    // First network found; start tunnel
+                    mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+                    if (mUnderlying != null) {
+                        transitionTo(mConnectingState);
+                    }
+                    break;
+                case EVENT_DISCONNECT_REQUESTED:
+                    mIsRunning = false;
+
+                    quitNow();
+                    break;
+                default:
+                    logUnhandledMessage(msg);
+                    break;
+            }
+        }
     }
 
-    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.
@@ -779,7 +939,32 @@
         }
     }
 
-    /** External dependencies used by VcnGatewayConnection, for injection in tests. */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
+        return mUnderlyingNetworkTrackerCallback;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    UnderlyingNetworkRecord getUnderlyingNetwork() {
+        return mUnderlying;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setUnderlyingNetwork(@Nullable UnderlyingNetworkRecord record) {
+        mUnderlying = record;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    boolean isRunning() {
+        return mIsRunning;
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setIsRunning(boolean isRunning) {
+        mIsRunning = isRunning;
+    }
+
+    /** External dependencies used by VcnGatewayConnection, for injection in tests */
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     public static class Dependencies {
         /** Builds a new UnderlyingNetworkTracker. */
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/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 6786f60..5d06da7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -30,6 +30,7 @@
 import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
 import static android.app.admin.PasswordMetrics.computeForPassword;
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+import static android.net.InetAddresses.parseNumericAddress;
 
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
@@ -65,6 +66,8 @@
 import static org.mockito.hamcrest.MockitoHamcrest.argThat;
 import static org.testng.Assert.assertThrows;
 
+import static java.util.Collections.emptyList;
+
 import android.Manifest.permission;
 import android.app.Activity;
 import android.app.AppOpsManager;
@@ -118,6 +121,8 @@
 import org.mockito.stubbing.Answer;
 
 import java.io.File;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -2246,6 +2251,48 @@
         assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts);
     }
 
+    public void testGetProxyParameters() throws Exception {
+        assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234), emptyList()))
+                .isEqualTo(new Pair<>("192.0.2.1:1234", ""));
+        assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234),
+                listOf("one.example.com  ", "  two.example.com ")))
+                .isEqualTo(new Pair<>("192.0.2.1:1234", "one.example.com,two.example.com"));
+        assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234), emptyList()))
+                .isEqualTo(new Pair<>("proxy.example.com:1234", ""));
+        assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234),
+                listOf("excluded.example.com")))
+                .isEqualTo(new Pair<>("proxy.example.com:1234", "excluded.example.com"));
+
+        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+                inetAddrProxy("192.0.2.1", 0), emptyList()));
+        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+                hostnameProxy("", 1234), emptyList()));
+        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+                hostnameProxy("", 0), emptyList()));
+        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+                hostnameProxy("invalid! hostname", 1234), emptyList()));
+        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+                hostnameProxy("proxy.example.com", 1234), listOf("invalid exclusion")));
+        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+                hostnameProxy("proxy.example.com", -1), emptyList()));
+        assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+                hostnameProxy("proxy.example.com", 0xFFFF + 1), emptyList()));
+    }
+
+    private static Proxy inetAddrProxy(String inetAddr, int port) {
+        return new Proxy(
+                Proxy.Type.HTTP, new InetSocketAddress(parseNumericAddress(inetAddr), port));
+    }
+
+    private static Proxy hostnameProxy(String hostname, int port) {
+        return new Proxy(
+                Proxy.Type.HTTP, InetSocketAddress.createUnresolved(hostname, port));
+    }
+
+    private static List<String> listOf(String... args) {
+        return Arrays.asList(args);
+    }
+
     public void testSetKeyguardDisabledFeaturesWithDO() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
@@ -5156,7 +5203,7 @@
         // Attempt to set to empty list (which means no listener is allowlisted)
         mContext.binder.callingUid = adminUid;
         assertFalse(dpms.setPermittedCrossProfileNotificationListeners(
-                admin1, Collections.emptyList()));
+                admin1, emptyList()));
         assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1));
 
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5248,7 +5295,7 @@
         // Setting an empty allowlist - only system listeners allowed
         mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
         assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
-                admin1, Collections.emptyList()));
+                admin1, emptyList()));
         assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size());
 
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5312,7 +5359,7 @@
         // all allowed in primary profile
         mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
         assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
-                admin1, Collections.emptyList()));
+                admin1, emptyList()));
         assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size());
 
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
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..8841935 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2774,6 +2774,30 @@
     public static final String IMSI_KEY_DOWNLOAD_URL_STRING = "imsi_key_download_url_string";
 
     /**
+     * String representation of a carrier's public key used for IMSI encryption for ePDG. If this
+     * is provided, the device will use it as a fallback when no key exists on device, but the key
+     * download will still initiate.
+     * Example string:
+     *         "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+     * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+     * @hide
+     */
+    public static final String IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING =
+            "imsi_carrier_public_key_epdg_string";
+
+    /**
+     * String representation of a carrier's public key used for IMSI encryption for WLAN. If this
+     * is provided, the device will use it as a fallback when no key exists on device, but the key
+     * download will still initiate.
+     * Example string:
+     *         "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+     * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+     * @hide
+     */
+    public static final String IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING =
+            "imsi_carrier_public_key_wlan_string";
+
+    /**
      * Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
      * 0 indicates that neither EPDG or WLAN is enabled.
      * 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled.
@@ -4077,6 +4101,24 @@
             "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 whether RTT is supported while roaming.
+     */
+    public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL =
+            "rtt_supported_while_roaming";
+
+    /**
      * Indicates if auto-configuration server is used for the RCS config
      * Reference: GSMA RCC.14
      */
@@ -4433,6 +4475,8 @@
         sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
         sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
         sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
+        sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING, null);
+        sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING, null);
         sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
                 false);
         sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
@@ -4441,6 +4485,7 @@
         sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
+        sDefaults.putBoolean(KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
         sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
@@ -4628,6 +4673,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/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index 75a79d6..4978692 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -163,8 +163,8 @@
     public String toString(){
         return "[ImsiEncryptionInfo "
                 + "mcc=" + mcc
-                + "mnc=" + mnc
-                + "publicKey=" + publicKey
+                + " mnc=" + mnc
+                + " publicKey=" + publicKey
                 + ", keyIdentifier=" + keyIdentifier
                 + ", keyType=" + keyType
                 + ", expirationTime=" + expirationTime
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/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
index 250d9e8..3b4cf75 100644
--- a/telephony/java/android/telephony/PreciseDisconnectCause.java
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -121,7 +121,7 @@
     public static final int BEARER_CAPABILITY_NOT_AUTHORIZED                 = 57;
     /** The requested bearer capability is not available at this time. */
     public static final int BEARER_NOT_AVAIL                                 = 58;
-    /** The service option is not availble at this time. */
+    /** The service option is not available at this time. */
     public static final int SERVICE_OPTION_NOT_AVAILABLE                     = 63;
     /** The equipment sending this cause does not support the bearer capability requested. */
     public static final int BEARER_SERVICE_NOT_IMPLEMENTED                   = 65;
diff --git a/telephony/java/android/telephony/RadioInterfaceCapabilities.java b/telephony/java/android/telephony/RadioInterfaceCapabilities.java
new file mode 100644
index 0000000..7c7eb9f
--- /dev/null
+++ b/telephony/java/android/telephony/RadioInterfaceCapabilities.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util.ArraySet;
+
+/**
+ * Contains the set of supported capabilities that the Radio Interface supports on this device.
+ *
+ * @hide
+ */
+public class RadioInterfaceCapabilities {
+
+    private final ArraySet<String> mSupportedCapabilities;
+
+
+    public RadioInterfaceCapabilities() {
+        mSupportedCapabilities = new ArraySet<>();
+    }
+
+    /**
+     * Marks a capability as supported
+     *
+     * @param capabilityName the name of the capability
+     */
+    public void addSupportedCapability(
+            @TelephonyManager.RadioInterfaceCapability String capabilityName) {
+        mSupportedCapabilities.add(capabilityName);
+    }
+
+    /**
+     * Whether the capability is supported
+     *
+     * @param capabilityName the name of the capability
+     */
+    public boolean isSupported(String capabilityName) {
+        return mSupportedCapabilities.contains(capabilityName);
+    }
+}
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
index 2a16402..af67ed2 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -17,6 +17,8 @@
 package android.telephony;
 
 import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -56,6 +58,11 @@
      */
     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,
@@ -66,6 +73,7 @@
         mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
         mIsSystemThresholdReportingRequestedWhileIdle =
                 isSystemThresholdReportingRequestedWhileIdle;
+        mLiveToken = new Binder();
     }
 
     /**
@@ -148,6 +156,7 @@
         mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR);
         mIsReportingRequestedWhileIdle = in.readBoolean();
         mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean();
+        mLiveToken = in.readStrongBinder();
     }
 
     /**
@@ -178,6 +187,15 @@
         return mIsSystemThresholdReportingRequestedWhileIdle;
     }
 
+    /*
+     * @return the live token of the request
+     *
+     * @hide
+     */
+    public @NonNull IBinder getLiveToken() {
+        return mLiveToken;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -188,6 +206,7 @@
         dest.writeTypedList(mSignalThresholdInfos);
         dest.writeBoolean(mIsReportingRequestedWhileIdle);
         dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle);
+        dest.writeStrongBinder(mLiveToken);
     }
 
     @Override
@@ -199,10 +218,10 @@
         }
 
         SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other;
-        return request.mSignalThresholdInfos.equals(mSignalThresholdInfos)
-                && request.mIsReportingRequestedWhileIdle == mIsReportingRequestedWhileIdle
-                && request.mIsSystemThresholdReportingRequestedWhileIdle
-                == mIsSystemThresholdReportingRequestedWhileIdle;
+        return mSignalThresholdInfos.equals(request.mSignalThresholdInfos)
+                && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle
+                && mIsSystemThresholdReportingRequestedWhileIdle
+                    == request.mIsSystemThresholdReportingRequestedWhileIdle;
     }
 
     @Override
@@ -233,6 +252,8 @@
                 .append(mIsReportingRequestedWhileIdle)
                 .append(" mIsSystemThresholdReportingRequestedWhileIdle=")
                 .append(mIsSystemThresholdReportingRequestedWhileIdle)
+                .append(" mLiveToken")
+                .append(mLiveToken)
                 .append("}").toString();
     }
 
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..646744d 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);
         }
@@ -14331,6 +14344,40 @@
         return Collections.emptyList();
     }
 
+    /** @hide */
+    @IntDef(prefix = {"RADIO_INTERFACE_CAPABILITY_"},
+            value = {})
+    public @interface RadioInterfaceCapability {}
+
+    /**
+     * Whether the device supports a given capability on the radio interface.
+     *
+     * If the capability is not in the set of radio interface capabilities, false is returned.
+     *
+     * @param capability the name of the capability to check for
+     * @return the availability of the capability
+     *
+     * @hide
+     */
+    public boolean isRadioInterfaceCapabilitySupported(
+            @NonNull @RadioInterfaceCapability String capability) {
+        try {
+            if (capability == null) return false;
+
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.isRadioInterfaceCapabilitySupported(capability);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
+        return false;
+    }
+
     /**
      * Indicates that the thermal mitigation request was completed successfully.
      *
@@ -14668,4 +14715,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/data/EpsBearerQosSessionAttributes.aidl b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl
new file mode 100644
index 0000000..da31f98
--- /dev/null
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.data;
+
+ parcelable EpsBearerQosSessionAttributes;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
new file mode 100644
index 0000000..041edc0
--- /dev/null
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -0,0 +1,234 @@
+/*
+ * 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.data;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.QosSessionAttributes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides Qos attributes of an EPS bearer.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessionAttributes {
+    private static final String TAG = EpsBearerQosSessionAttributes.class.getSimpleName();
+    private final int mQci;
+    private final long mMaxUplinkBitRate;
+    private final long mMaxDownlinkBitRate;
+    private final long mGuaranteedUplinkBitRate;
+    private final long mGuaranteedDownlinkBitRate;
+    @NonNull private final List<InetSocketAddress> mRemoteAddresses;
+
+    /**
+     * Quality of Service Class Identifier (QCI), see 3GPP TS 23.203 and 29.212.
+     * The allowed values are standard values(1-9, 65-68, 69-70, 75, 79-80, 82-85)
+     * defined in the spec and operator specific values in the range 128-254.
+     *
+     * @return the qci of the session
+     */
+    public int getQci() {
+        return mQci;
+    }
+
+    /**
+     * Minimum bit rate in kbps that is guaranteed to be provided by the network on the uplink.
+     *
+     * see 3GPP TS 23.107 section 6.4.3.1
+     *
+     * Note: The Qos Session may be shared with OTHER applications besides yours.
+     *
+     * @return the guaranteed bit rate in kbps
+     */
+    public long getGuaranteedUplinkBitRate() {
+        return mGuaranteedUplinkBitRate;
+    }
+
+    /**
+     * Minimum bit rate in kbps that is guaranteed to be provided by the network on the downlink.
+     *
+     * see 3GPP TS 23.107 section 6.4.3.1
+     *
+     * Note: The Qos Session may be shared with OTHER applications besides yours.
+     *
+     * @return the guaranteed bit rate in kbps
+     */
+    public long getGuaranteedDownlinkBitRate() {
+        return mGuaranteedDownlinkBitRate;
+    }
+
+    /**
+     * The maximum kbps that the network will accept.
+     *
+     * see 3GPP TS 23.107 section 6.4.3.1
+     *
+     * Note: The Qos Session may be shared with OTHER applications besides yours.
+     *
+     * @return the max uplink bit rate in kbps
+     */
+    public long getMaxUplinkBitRate() {
+        return mMaxUplinkBitRate;
+    }
+
+    /**
+     * The maximum kbps that the network can provide.
+     *
+     * see 3GPP TS 23.107 section 6.4.3.1
+     *
+     * Note: The Qos Session may be shared with OTHER applications besides yours.
+     *
+     * @return the max downlink bit rate in kbps
+     */
+    public long getMaxDownlinkBitRate() {
+        return mMaxDownlinkBitRate;
+    }
+
+    /**
+     * List of remote addresses associated with the Qos Session.  The given uplink bit rates apply
+     * to this given list of remote addresses.
+     *
+     * Note: In the event that the list is empty, it is assumed that the uplink bit rates apply to
+     * all remote addresses that are not contained in a different set of attributes.
+     *
+     * @return list of remote socket addresses that the attributes apply to
+     */
+    @NonNull
+    public List<InetSocketAddress> getRemoteAddresses() {
+        return mRemoteAddresses;
+    }
+
+    /**
+     * ..ctor for attributes
+     *
+     * @param qci quality class indicator
+     * @param maxDownlinkBitRate the max downlink bit rate in kbps
+     * @param maxUplinkBitRate the max uplink bit rate in kbps
+     * @param guaranteedDownlinkBitRate the guaranteed downlink bit rate in kbps
+     * @param guaranteedUplinkBitRate the guaranteed uplink bit rate in kbps
+     * @param remoteAddresses the remote addresses that the uplink bit rates apply to
+     *
+     * @hide
+     */
+    public EpsBearerQosSessionAttributes(final int qci,
+            final long maxDownlinkBitRate, final long maxUplinkBitRate,
+            final long guaranteedDownlinkBitRate, final long guaranteedUplinkBitRate,
+            @NonNull final List<InetSocketAddress> remoteAddresses) {
+        Objects.requireNonNull(remoteAddresses, "remoteAddress must be non-null");
+        mQci = qci;
+        mMaxDownlinkBitRate = maxDownlinkBitRate;
+        mMaxUplinkBitRate = maxUplinkBitRate;
+        mGuaranteedDownlinkBitRate = guaranteedDownlinkBitRate;
+        mGuaranteedUplinkBitRate = guaranteedUplinkBitRate;
+
+        final List<InetSocketAddress> remoteAddressesTemp = copySocketAddresses(remoteAddresses);
+        mRemoteAddresses = Collections.unmodifiableList(remoteAddressesTemp);
+    }
+
+    private static List<InetSocketAddress> copySocketAddresses(
+            @NonNull final List<InetSocketAddress> remoteAddresses) {
+        final List<InetSocketAddress> remoteAddressesTemp = new ArrayList<>();
+        for (final InetSocketAddress socketAddress : remoteAddresses) {
+            if (socketAddress != null && socketAddress.getAddress() != null) {
+                remoteAddressesTemp.add(socketAddress);
+            }
+        }
+        return remoteAddressesTemp;
+    }
+
+    private EpsBearerQosSessionAttributes(@NonNull final Parcel in) {
+        mQci = in.readInt();
+        mMaxDownlinkBitRate = in.readLong();
+        mMaxUplinkBitRate = in.readLong();
+        mGuaranteedDownlinkBitRate = in.readLong();
+        mGuaranteedUplinkBitRate = in.readLong();
+
+        final int size = in.readInt();
+        final List<InetSocketAddress> remoteAddresses = new ArrayList<>(size);
+        for (int i = 0; i < size; i++) {
+            final byte[] addressBytes = in.createByteArray();
+            final int port = in.readInt();
+            try {
+                remoteAddresses.add(
+                        new InetSocketAddress(InetAddress.getByAddress(addressBytes), port));
+            } catch (final UnknownHostException e) {
+                // Impossible case since we filter out null values in the ..ctor
+                Log.e(TAG, "unable to unparcel remote address at index: " + i, e);
+            }
+        }
+        mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
+    }
+
+    /**
+     * Creates attributes based off of a parcel
+     * @param in the parcel
+     * @return the attributes
+     */
+    @NonNull
+    public static EpsBearerQosSessionAttributes create(@NonNull final Parcel in) {
+        return new EpsBearerQosSessionAttributes(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+        dest.writeInt(mQci);
+        dest.writeLong(mMaxDownlinkBitRate);
+        dest.writeLong(mMaxUplinkBitRate);
+        dest.writeLong(mGuaranteedDownlinkBitRate);
+        dest.writeLong(mGuaranteedUplinkBitRate);
+
+        final int size = mRemoteAddresses.size();
+        dest.writeInt(size);
+        for (int i = 0; i < size; i++) {
+            final InetSocketAddress address = mRemoteAddresses.get(i);
+            dest.writeByteArray(address.getAddress().getAddress());
+            dest.writeInt(address.getPort());
+        }
+    }
+
+    @NonNull
+    public static final Creator<EpsBearerQosSessionAttributes> CREATOR =
+            new Creator<EpsBearerQosSessionAttributes>() {
+        @NonNull
+        @Override
+        public EpsBearerQosSessionAttributes createFromParcel(@NonNull final Parcel in) {
+            return new EpsBearerQosSessionAttributes(in);
+        }
+
+        @NonNull
+        @Override
+        public EpsBearerQosSessionAttributes[] newArray(final int size) {
+            return new EpsBearerQosSessionAttributes[size];
+        }
+    };
+}
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/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index 006cca8..9cfa640 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -16,6 +16,8 @@
 
 package android.telephony.ims;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Build;
@@ -39,6 +41,7 @@
 public final class SipMessage implements Parcelable {
     // Should not be set to true for production!
     private static final boolean IS_DEBUGGING = Build.IS_ENG;
+    private static final String CRLF = "\r\n";
 
     private final String mStartLine;
     private final String mHeaderSection;
@@ -165,4 +168,19 @@
         result = 31 * result + Arrays.hashCode(mContent);
         return result;
     }
+
+    /**
+     * @return the UTF-8 encoded SIP message.
+     */
+    public @NonNull byte[] getEncodedMessage() {
+        byte[] header = new StringBuilder()
+                .append(mStartLine)
+                .append(mHeaderSection)
+                .append(CRLF)
+                .toString().getBytes(UTF_8);
+        byte[] sipMessage = new byte[header.length + mContent.length];
+        System.arraycopy(header, 0, sipMessage, 0, header.length);
+        System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
+        return sipMessage;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 541ec04..e556664 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;
@@ -2279,6 +2280,14 @@
     CarrierBandwidth getCarrierBandwidth(int subId);
 
     /**
+     * Checks whether the device supports the given capability on the radio interface.
+     *
+     * @param capability the name of the capability
+     * @return the availability of the capability
+     */
+    boolean isRadioInterfaceCapabilitySupported(String capability);
+
+    /**
      * Thermal mitigation request to control functionalities at modem.
      *
      * @param subId the id of the subscription
@@ -2358,6 +2367,11 @@
     boolean setCarrierSingleRegistrationEnabledOverride(int subId, String enabled);
 
     /**
+     * Sends a device to device message; only for use through shell.
+     */
+    void sendDeviceToDeviceMessage(int message, int value);
+
+    /**
      * Gets the config of RCS VoLTE single registration enabled for the carrier/subscription.
      */
     boolean getCarrierSingleRegistrationEnabled(int subId);
@@ -2367,4 +2381,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/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 52f263f..76243a5 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -520,6 +520,7 @@
     int RIL_REQUEST_START_HANDOVER = 217;
     int RIL_REQUEST_CANCEL_HANDOVER = 218;
     int RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS = 219;
+    int RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES = 220;
     int RIL_REQUEST_SET_DATA_THROTTLING = 221;
     int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPE_BITMAP = 222;
     int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPE_BITMAP = 223;
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/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 3d4dc4d..dc9e587 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -31,6 +31,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.LinkProperties;
@@ -40,6 +41,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkProvider;
 import android.net.NetworkSpecifier;
+import android.net.QosFilter;
 import android.net.SocketKeepalive;
 import android.net.UidRange;
 import android.os.ConditionVariable;
@@ -47,10 +49,12 @@
 import android.os.Message;
 import android.util.Log;
 
+import com.android.net.module.util.ArrayTrackRecord;
 import com.android.server.connectivity.ConnectivityConstants;
 import com.android.testutils.HandlerUtils;
 import com.android.testutils.TestableNetworkCallback;
 
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -71,6 +75,8 @@
     // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
     private long mKeepaliveResponseDelay = 0L;
     private Integer mExpectedKeepaliveSlot = null;
+    private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory =
+            new ArrayTrackRecord<CallbackType>().newReadHead();
 
     public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
             NetworkCapabilities ncTemplate, Context context) throws Exception {
@@ -157,6 +163,20 @@
         }
 
         @Override
+        public void onQosCallbackRegistered(final int qosCallbackId,
+                final @NonNull QosFilter filter) {
+            Log.i(mWrapper.mLogTag, "onQosCallbackRegistered");
+            mWrapper.mCallbackHistory.add(
+                    new CallbackType.OnQosCallbackRegister(qosCallbackId, filter));
+        }
+
+        @Override
+        public void onQosCallbackUnregistered(final int qosCallbackId) {
+            Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered");
+            mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId));
+        }
+
+        @Override
         protected void preventAutomaticReconnect() {
             mWrapper.mPreventReconnectReceived.open();
         }
@@ -279,7 +299,60 @@
         return mNetworkCapabilities;
     }
 
+    public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() {
+        return mCallbackHistory;
+    }
+
     public void waitForIdle(long timeoutMs) {
         HandlerUtils.waitForIdle(mHandlerThread, timeoutMs);
     }
+
+    abstract static class CallbackType {
+        final int mQosCallbackId;
+
+        protected CallbackType(final int qosCallbackId) {
+            mQosCallbackId = qosCallbackId;
+        }
+
+        static class OnQosCallbackRegister extends CallbackType {
+            final QosFilter mFilter;
+            OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) {
+                super(qosCallbackId);
+                mFilter = filter;
+            }
+
+            @Override
+            public boolean equals(final Object o) {
+                if (this == o) return true;
+                if (o == null || getClass() != o.getClass()) return false;
+                final OnQosCallbackRegister that = (OnQosCallbackRegister) o;
+                return mQosCallbackId == that.mQosCallbackId
+                        && Objects.equals(mFilter, that.mFilter);
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(mQosCallbackId, mFilter);
+            }
+        }
+
+        static class OnQosCallbackUnregister extends CallbackType {
+            OnQosCallbackUnregister(final int qosCallbackId) {
+                super(qosCallbackId);
+            }
+
+            @Override
+            public boolean equals(final Object o) {
+                if (this == o) return true;
+                if (o == null || getClass() != o.getClass()) return false;
+                final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o;
+                return mQosCallbackId == that.mQosCallbackId;
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(mQosCallbackId);
+            }
+        }
+    }
 }
diff --git a/tests/net/java/android/net/QosSocketFilterTest.java b/tests/net/java/android/net/QosSocketFilterTest.java
new file mode 100644
index 0000000..ad58960
--- /dev/null
+++ b/tests/net/java/android/net/QosSocketFilterTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+@RunWith(AndroidJUnit4.class)
+@androidx.test.filters.SmallTest
+public class QosSocketFilterTest {
+
+    @Test
+    public void testPortExactMatch() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+        assertTrue(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 10), addressB, 10, 10));
+
+    }
+
+    @Test
+    public void testPortLessThanStart() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+        assertFalse(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 8), addressB, 10, 10));
+    }
+
+    @Test
+    public void testPortGreaterThanEnd() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+        assertFalse(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 18), addressB, 10, 10));
+    }
+
+    @Test
+    public void testPortBetweenStartAndEnd() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+        assertTrue(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 10), addressB, 8, 18));
+    }
+
+    @Test
+    public void testAddressesDontMatch() {
+        final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+        final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
+        assertFalse(QosSocketFilter.matchesLocalAddress(
+                new InetSocketAddress(addressA, 10), addressB, 10, 10));
+    }
+}
+
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 5a375d2..f893e9e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -167,6 +167,7 @@
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkStatsService;
+import android.net.IQosCallback;
 import android.net.InetAddresses;
 import android.net.InterfaceConfigurationParcel;
 import android.net.IpPrefix;
@@ -190,6 +191,9 @@
 import android.net.NetworkState;
 import android.net.NetworkTestResultParcelable;
 import android.net.ProxyInfo;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
 import android.net.ResolverParamsParcel;
 import android.net.RouteInfo;
 import android.net.RouteInfoParcel;
@@ -218,6 +222,7 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -226,10 +231,12 @@
 import android.security.KeyStore;
 import android.system.Os;
 import android.telephony.TelephonyManager;
+import android.telephony.data.EpsBearerQosSessionAttributes;
 import android.test.mock.MockContentResolver;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
@@ -251,6 +258,7 @@
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
 import com.android.server.connectivity.ProxyTracker;
+import com.android.server.connectivity.QosCallbackTracker;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.NetworkPinner;
 import com.android.server.net.NetworkPolicyManagerInternal;
@@ -368,6 +376,8 @@
     private WrappedMultinetworkPolicyTracker mPolicyTracker;
     private HandlerThread mAlarmManagerThread;
     private TestNetIdManager mNetIdManager;
+    private QosCallbackMockHelper mQosCallbackMockHelper;
+    private QosCallbackTracker mQosCallbackTracker;
 
     @Mock DeviceIdleInternal mDeviceIdleInternal;
     @Mock INetworkManagementService mNetworkManagementService;
@@ -1389,15 +1399,13 @@
         verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture());
         mPolicyListener = policyListenerCaptor.getValue();
 
-        mServiceContext.setPermission(
-                Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
-
         // Create local CM before sending system ready so that we can answer
         // getSystemService() correctly.
         mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
         mService.systemReadyInternal();
         mockVpn(Process.myUid());
         mCm.bindProcessToNetwork(null);
+        mQosCallbackTracker = mock(QosCallbackTracker.class);
 
         // Ensure that the default setting for Captive Portals is used for most tests
         setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
@@ -1473,6 +1481,11 @@
             mEthernetNetworkAgent.disconnect();
             mEthernetNetworkAgent = null;
         }
+
+        if (mQosCallbackMockHelper != null) {
+            mQosCallbackMockHelper.tearDown();
+            mQosCallbackMockHelper = null;
+        }
         mMockVpn.disconnect();
         waitForIdle();
 
@@ -1588,6 +1601,7 @@
         }
 
         public void expectNoBroadcast(int timeoutMs) throws Exception {
+            waitForIdle();
             try {
                 final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
                 fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras());
@@ -4381,7 +4395,7 @@
     }
 
     private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
-        // Ensure the network is disconnected before we do anything.
+        // Ensure the network is disconnected before anything else occurs
         if (mWiFiNetworkAgent != null) {
             assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
         }
@@ -5894,6 +5908,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();
@@ -6450,9 +6589,13 @@
 
     @Test
     public void testLockdownVpnWithRestrictedProfiles() throws Exception {
-        // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
+        // 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);
 
@@ -7015,6 +7158,9 @@
 
     @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);
@@ -7132,11 +7278,14 @@
         mMockVpn.expectStopVpnRunnerPrivileged();
         mMockVpn.expectStartLegacyVpnRunner();
 
-        // TODO: why is wifi not blocked? Is this because something calls prepare()?
+        // 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));
-        defaultCallback.expectCapabilitiesThat(mMockVpn, (nc) -> nc.hasTransport(TRANSPORT_WIFI));
+        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);
 
@@ -7179,7 +7328,7 @@
         mWiFiNetworkAgent.disconnect();
         callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         b1.expectBroadcast();
-        callback.expectCapabilitiesThat(mMockVpn, (nc) -> !nc.hasTransport(TRANSPORT_WIFI));
+        callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
         b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
         mMockVpn.expectStopVpnRunnerPrivileged();
         callback.expectCallback(CallbackEntry.LOST, mMockVpn);
@@ -8379,7 +8528,7 @@
                 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);
+                0, INVALID_UID, mQosCallbackTracker);
     }
 
     @Test
@@ -8757,7 +8906,7 @@
 
     @Test
     public void testInvalidRequestTypes() {
-        final int[] invalidReqTypeInts = new int[] {-1, NetworkRequest.Type.NONE.ordinal(),
+        final int[] invalidReqTypeInts = new int[]{-1, NetworkRequest.Type.NONE.ordinal(),
                 NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length};
         final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
 
@@ -8770,4 +8919,151 @@
             );
         }
     }
+
+    private class QosCallbackMockHelper {
+        @NonNull public final QosFilter mFilter;
+        @NonNull public final IQosCallback mCallback;
+        @NonNull public final TestNetworkAgentWrapper mAgentWrapper;
+        @NonNull private final List<IQosCallback> mCallbacks = new ArrayList();
+
+        QosCallbackMockHelper() throws Exception {
+            Log.d(TAG, "QosCallbackMockHelper: ");
+            mFilter = mock(QosFilter.class);
+
+            // Ensure the network is disconnected before anything else occurs
+            assertNull(mCellNetworkAgent);
+
+            mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+            mCellNetworkAgent.connect(true);
+
+            verifyActiveNetwork(TRANSPORT_CELLULAR);
+            waitForIdle();
+            final Network network = mCellNetworkAgent.getNetwork();
+
+            final Pair<IQosCallback, IBinder> pair = createQosCallback();
+            mCallback = pair.first;
+
+            when(mFilter.getNetwork()).thenReturn(network);
+            when(mFilter.validate()).thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+            mAgentWrapper = mCellNetworkAgent;
+        }
+
+        void registerQosCallback(@NonNull final QosFilter filter,
+                @NonNull final IQosCallback callback) {
+            mCallbacks.add(callback);
+            final NetworkAgentInfo nai =
+                    mService.getNetworkAgentInfoForNetwork(filter.getNetwork());
+            mService.registerQosCallbackInternal(filter, callback, nai);
+        }
+
+        void tearDown() {
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                mService.unregisterQosCallback(mCallbacks.get(i));
+            }
+        }
+    }
+
+    private Pair<IQosCallback, IBinder> createQosCallback() {
+        final IQosCallback callback = mock(IQosCallback.class);
+        final IBinder binder = mock(Binder.class);
+        when(callback.asBinder()).thenReturn(binder);
+        when(binder.isBinderAlive()).thenReturn(true);
+        return new Pair<>(callback, binder);
+    }
+
+
+    @Test
+    public void testQosCallbackRegistration() throws Exception {
+        mQosCallbackMockHelper = new QosCallbackMockHelper();
+        final NetworkAgentWrapper wrapper = mQosCallbackMockHelper.mAgentWrapper;
+
+        when(mQosCallbackMockHelper.mFilter.validate())
+                .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+        mQosCallbackMockHelper.registerQosCallback(
+                mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+
+        final NetworkAgentWrapper.CallbackType.OnQosCallbackRegister cbRegister1 =
+                (NetworkAgentWrapper.CallbackType.OnQosCallbackRegister)
+                        wrapper.getCallbackHistory().poll(1000, x -> true);
+        assertNotNull(cbRegister1);
+
+        final int registerCallbackId = cbRegister1.mQosCallbackId;
+        mService.unregisterQosCallback(mQosCallbackMockHelper.mCallback);
+        final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
+        cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
+                wrapper.getCallbackHistory().poll(1000, x -> true);
+        assertNotNull(cbUnregister);
+        assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
+        assertNull(wrapper.getCallbackHistory().poll(200, x -> true));
+    }
+
+    @Test
+    public void testQosCallbackNoRegistrationOnValidationError() throws Exception {
+        mQosCallbackMockHelper = new QosCallbackMockHelper();
+
+        when(mQosCallbackMockHelper.mFilter.validate())
+                .thenReturn(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+        mQosCallbackMockHelper.registerQosCallback(
+                mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+        waitForIdle();
+        verify(mQosCallbackMockHelper.mCallback)
+                .onError(eq(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED));
+    }
+
+    @Test
+    public void testQosCallbackAvailableAndLost() throws Exception {
+        mQosCallbackMockHelper = new QosCallbackMockHelper();
+        final int sessionId = 10;
+        final int qosCallbackId = 1;
+
+        when(mQosCallbackMockHelper.mFilter.validate())
+                .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+        mQosCallbackMockHelper.registerQosCallback(
+                mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+        waitForIdle();
+
+        final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
+                1, 2, 3, 4, 5, new ArrayList<>());
+        mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+                .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+        waitForIdle();
+
+        verify(mQosCallbackMockHelper.mCallback).onQosEpsBearerSessionAvailable(argThat(session ->
+                session.getSessionId() == sessionId
+                        && session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
+
+        mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+                .sendQosSessionLost(qosCallbackId, sessionId);
+        waitForIdle();
+        verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
+                session.getSessionId() == sessionId
+                        && session.getSessionType() == QosSession.TYPE_EPS_BEARER));
+    }
+
+    @Test
+    public void testQosCallbackTooManyRequests() throws Exception {
+        mQosCallbackMockHelper = new QosCallbackMockHelper();
+
+        when(mQosCallbackMockHelper.mFilter.validate())
+                .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+        for (int i = 0; i < 100; i++) {
+            final Pair<IQosCallback, IBinder> pair = createQosCallback();
+
+            try {
+                mQosCallbackMockHelper.registerQosCallback(
+                        mQosCallbackMockHelper.mFilter, pair.first);
+            } catch (ServiceSpecificException e) {
+                assertEquals(e.errorCode, ConnectivityManager.Errors.TOO_MANY_REQUESTS);
+                if (i < 50) {
+                    fail("TOO_MANY_REQUESTS thrown too early, the count is " + i);
+                }
+
+                // As long as there is at least 50 requests, it is safe to assume it works.
+                // Note: The count isn't being tested precisely against 100 because the counter
+                // is shared with request network.
+                return;
+            }
+        }
+        fail("TOO_MANY_REQUESTS never thrown");
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 4d151af..52cb836 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -78,6 +78,7 @@
     @Mock Context mCtx;
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
+    @Mock QosCallbackTracker mQosCallbackTracker;
 
     @Before
     public void setUp() {
@@ -358,7 +359,7 @@
         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());
+                Binder.getCallingUid(), mQosCallbackTracker);
         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);
+    }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 696110f..f0cdde3 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -18,15 +18,21 @@
 
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
 import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+import static com.android.server.vcn.VcnTestUtils.setupSystemService;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.argThat;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -35,8 +41,10 @@
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
 import android.net.vcn.VcnConfig;
 import android.net.vcn.VcnConfigTest;
+import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.PersistableBundle;
 import android.os.Process;
@@ -126,12 +134,21 @@
 
     private final VcnManagementService mVcnMgmtSvc;
 
+    private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
+            mock(IVcnUnderlyingNetworkPolicyListener.class);
+    private final IBinder mMockIBinder = mock(IBinder.class);
+
     public VcnManagementServiceTest() throws Exception {
-        setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
-        setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
         setupSystemService(
-                mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class);
-        setupSystemService(mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
+                mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+        setupSystemService(
+                mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+        setupSystemService(
+                mMockContext,
+                mSubMgr,
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE,
+                SubscriptionManager.class);
+        setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
 
         doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
 
@@ -169,15 +186,12 @@
         setupMockedCarrierPrivilege(true);
         mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
 
+        doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
+
         // Make sure the profiles are loaded.
         mTestLooper.dispatchAll();
     }
 
-    private void setupSystemService(Object service, String name, Class<?> serviceClass) {
-        doReturn(name).when(mMockContext).getSystemServiceName(serviceClass);
-        doReturn(service).when(mMockContext).getSystemService(name);
-    }
-
     private void setupMockedCarrierPrivilege(boolean isPrivileged) {
         doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
                 .when(mSubMgr)
@@ -438,4 +452,40 @@
         mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
         verify(vcnInstance).teardownAsynchronously();
     }
+
+    @Test
+    public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+        doNothing()
+                .when(mMockContext)
+                .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        verify(mMockIBinder).linkToDeath(any(), anyInt());
+    }
+
+    @Test(expected = SecurityException.class)
+    public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+        doThrow(new SecurityException())
+                .when(mMockContext)
+                .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+    }
+
+    @Test
+    public void testRemoveVcnUnderlyingNetworkPolicyListener() {
+        // verify listener added
+        doNothing()
+                .when(mMockContext)
+                .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+        mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+        mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+    }
+
+    @Test
+    public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
+        mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
new file mode 100644
index 0000000..4ecd215
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.vcn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.DisconnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase {
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState);
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void testEnterWhileNotRunningTriggersQuit() throws Exception {
+        final VcnGatewayConnection vgc =
+                new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+
+        vgc.setIsRunning(false);
+        vgc.transitionTo(vgc.mDisconnectedState);
+        mTestLooper.dispatchAll();
+
+        assertNull(vgc.getCurrentState());
+    }
+
+    @Test
+    public void testNetworkChangesTriggerStateTransitions() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testNullNetworkDoesNotTriggerStateTransition() throws Exception {
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(null);
+        mTestLooper.dispatchAll();
+
+        assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testTeardown() throws Exception {
+        mGatewayConnection.teardownAsynchronously();
+        mTestLooper.dispatchAll();
+
+        assertNull(mGatewayConnection.getCurrentState());
+        verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
new file mode 100644
index 0000000..1725dd9
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.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 com.android.server.vcn;
+
+import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.IpSecManager;
+import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+
+import com.android.server.IpSecService;
+
+import org.junit.Before;
+
+import java.util.UUID;
+
+public class VcnGatewayConnectionTestBase {
+    protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
+    protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1;
+    protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
+    protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
+            new UnderlyingNetworkRecord(
+                    new Network(0),
+                    new NetworkCapabilities(),
+                    new LinkProperties(),
+                    false /* blocked */);
+    protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
+            new UnderlyingNetworkRecord(
+                    new Network(1),
+                    new NetworkCapabilities(),
+                    new LinkProperties(),
+                    false /* blocked */);
+
+    @NonNull protected final Context mContext;
+    @NonNull protected final TestLooper mTestLooper;
+    @NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
+    @NonNull protected final VcnContext mVcnContext;
+    @NonNull protected final VcnGatewayConnectionConfig mConfig;
+    @NonNull protected final VcnGatewayConnection.Dependencies mDeps;
+    @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+
+    @NonNull protected final IpSecService mIpSecSvc;
+
+    protected VcnGatewayConnection mGatewayConnection;
+
+    public VcnGatewayConnectionTestBase() {
+        mContext = mock(Context.class);
+        mTestLooper = new TestLooper();
+        mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+        mVcnContext = mock(VcnContext.class);
+        mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
+        mDeps = mock(VcnGatewayConnection.Dependencies.class);
+        mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
+
+        mIpSecSvc = mock(IpSecService.class);
+        setupIpSecManager(mContext, mIpSecSvc);
+
+        doReturn(mContext).when(mVcnContext).getContext();
+        doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
+        doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+
+        doReturn(mUnderlyingNetworkTracker)
+                .when(mDeps)
+                .newUnderlyingNetworkTracker(any(), any(), any());
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        IpSecTunnelInterfaceResponse resp =
+                new IpSecTunnelInterfaceResponse(
+                        IpSecManager.Status.OK,
+                        TEST_IPSEC_TUNNEL_RESOURCE_ID,
+                        TEST_IPSEC_TUNNEL_IFACE);
+        doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+
+        mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+    }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
new file mode 100644
index 0000000..2b10806
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
@@ -0,0 +1,44 @@
+/*
+ * 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.vcn;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.net.IpSecManager;
+
+import com.android.server.IpSecService;
+
+public class VcnTestUtils {
+    /** Mock system services by directly mocking the *Manager interface. */
+    public static void setupSystemService(
+            Context mockContext, Object service, String name, Class<?> serviceClass) {
+        doReturn(name).when(mockContext).getSystemServiceName(serviceClass);
+        doReturn(service).when(mockContext).getSystemService(name);
+    }
+
+    /** Mock IpSecService by mocking the underlying service binder. */
+    public static IpSecManager setupIpSecManager(Context mockContext, IpSecService service) {
+        doReturn(Context.IPSEC_SERVICE).when(mockContext).getSystemServiceName(IpSecManager.class);
+
+        final IpSecManager ipSecMgr = new IpSecManager(mockContext, service);
+        doReturn(ipSecMgr).when(mockContext).getSystemService(Context.IPSEC_SERVICE);
+
+        // Return to ensure this doesn't get reaped.
+        return ipSecMgr;
+    }
+}
diff --git a/tools/stringslint/stringslint.py b/tools/stringslint/stringslint.py
index afe91cd..15088fc 100644
--- a/tools/stringslint/stringslint.py
+++ b/tools/stringslint/stringslint.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+#-*- coding: utf-8 -*-
 
 # Copyright (C) 2018 The Android Open Source Project
 #
@@ -33,9 +34,6 @@
 import re, sys, codecs
 import lxml.etree as ET
 
-reload(sys)
-sys.setdefaultencoding('utf8')
-
 BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
 
 def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
@@ -118,7 +116,7 @@
         raw = f.read()
         if len(raw.strip()) == 0:
             return warnings
-        tree = ET.fromstring(raw)
+        tree = ET.fromstring(bytes(raw, encoding='utf-8'))
         root = tree #tree.getroot()
 
     last_comment = None
@@ -231,6 +229,6 @@
 
 if len(after) > 0:
     for a in sorted(after.keys()):
-        print after[a]
-        print
+        print(after[a])
+        print()
     sys.exit(1)
diff --git a/tools/stringslint/stringslint_sha.sh b/tools/stringslint/stringslint_sha.sh
index bd80bb4..bd05698 100755
--- a/tools/stringslint/stringslint_sha.sh
+++ b/tools/stringslint/stringslint_sha.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
 LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
 git show --name-only --pretty=format: $1 | grep values/strings.xml | while read file; do
-    python $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
+    python3 $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
 done