Merge "Pass the correct user id"
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 9760013..bde2bec 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1,7 +1,8 @@
-# Shared module build rule owners
-per-file *.bp=hansson@google.com
-per-file *.bp=jiyong@google.com
+# Mainline modularization team
 
-# This file, and all other OWNERS files
-per-file OWNERS=dariofreni@google.com
-per-file OWNERS=hansson@google.com
+andreionea@google.com
+dariofreni@google.com
+hansson@google.com
+mathewi@google.com
+pedroql@google.com
+satayev@google.com
diff --git a/api/Android.bp b/api/Android.bp
index 9a157b8..fdfef4c 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -50,10 +50,7 @@
             dest: "current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk", "win_sdk"],
             dir: "apistubs/android/public/api",
             dest: "android.txt",
         },
@@ -106,6 +103,11 @@
             dir: "api",
             dest: "removed.txt",
         },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/public/api",
+            dest: "removed.txt",
+        },
     ],
 }
 
@@ -131,10 +133,7 @@
             dest: "system-current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk", "win_sdk"],
             dir: "apistubs/android/system/api",
             dest: "android.txt",
         },
@@ -163,6 +162,11 @@
             dir: "api",
             dest: "system-removed.txt",
         },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/system/api",
+            dest: "removed.txt",
+        },
     ],
     visibility: ["//visibility:public"],
 }
@@ -189,10 +193,7 @@
             dest: "module-lib-current.txt",
         },
         {
-            targets: [
-                "sdk",
-                "win_sdk",
-            ],
+            targets: ["sdk", "win_sdk"],
             dir: "apistubs/android/module-lib/api",
             dest: "android.txt",
         },
@@ -220,6 +221,11 @@
             dir: "api",
             dest: "module-lib-removed.txt",
         },
+        {
+            targets: ["sdk", "win_sdk"],
+            dir: "apistubs/android/module-lib/api",
+            dest: "removed.txt",
+        },
     ],
 }
 
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bdb8380..846a34e 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -174,10 +174,6 @@
                 instrument.noWindowAnimation = true;
             } else if (opt.equals("--no-hidden-api-checks")) {
                 instrument.disableHiddenApiChecks = true;
-            } else if (opt.equals("--no-test-api-checks")) {
-                // TODO(satayev): remove this option, only kept for backwards compatibility with
-                // cached tradefed instance
-                instrument.disableTestApiChecks = false;
             } else if (opt.equals("--no-test-api-access")) {
                 instrument.disableTestApiChecks = false;
             } else if (opt.equals("--no-isolated-storage")) {
@@ -198,7 +194,6 @@
         }
 
         instrument.componentNameArg = nextArgRequired();
-
         instrument.run();
     }
 }
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 07221f9..14ebb71 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -62,4 +62,13 @@
     // Create a symlink from app_process to app_process32 or 64
     // depending on the target configuration.
     symlink_preferred_arch: true,
+
+    // Enable ASYNC MTE in the zygote, in order to allow apps and the system
+    // server to use MTE. We use ASYNC because we don't expect the pre-fork
+    // zygote to have substantial memory corruption bugs (as it's primarily Java
+    // code), and we don't want to waste memory recording malloc/free stack
+    // traces (which happens in SYNC mode).
+    sanitize: {
+        memtag_heap: true,
+    },
 }
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index c2ee6dc..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;
 
@@ -107,6 +110,8 @@
             runStartCheckpoint();
         } else if ("supports-checkpoint".equals(op)) {
             runSupportsCheckpoint();
+        } else if ("unmount-app-data-dirs".equals(op)) {
+            runDisableAppDataIsolation();
         } else {
             throw new IllegalArgumentException();
         }
@@ -253,6 +258,17 @@
         System.out.println(result.get());
     }
 
+    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());
+        mSm.disableAppDataIsolation(pkgName, pid, userId);
+    }
+
     public void runForget() throws RemoteException {
         final String fsUuid = nextArg();
         if ("all".equals(fsUuid)) {
@@ -373,6 +389,8 @@
         System.err.println("");
         System.err.println("       sm supports-checkpoint");
         System.err.println("");
+        System.err.println("       sm unmount-app-data-dirs PACKAGE_NAME PID USER_ID");
+        System.err.println("");
         return 1;
     }
 }
diff --git a/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/config/hiddenapi-temp-blocklist.txt b/config/hiddenapi-max-target-r-loprio.txt
similarity index 100%
rename from config/hiddenapi-temp-blocklist.txt
rename to config/hiddenapi-max-target-r-loprio.txt
diff --git a/core/api/current.txt b/core/api/current.txt
index 252c33c..8148af2 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -385,6 +385,7 @@
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
     field public static final int canControlMagnification = 16844039; // 0x1010507
+    field public static final int canPauseRecording = 16844311; // 0x1010617
     field public static final int canPerformGestures = 16844045; // 0x101050d
     field public static final int canRecord = 16844060; // 0x101051c
     field @Deprecated public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
@@ -10144,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);
@@ -10186,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";
@@ -24265,6 +24268,7 @@
   }
 
   public final class TvInputInfo implements android.os.Parcelable {
+    method public boolean canPauseRecording();
     method public boolean canRecord();
     method @Deprecated public android.content.Intent createSettingsIntent();
     method public android.content.Intent createSetupIntent();
@@ -24298,6 +24302,7 @@
   public static final class TvInputInfo.Builder {
     ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
     method public android.media.tv.TvInputInfo build();
+    method @NonNull public android.media.tv.TvInputInfo.Builder setCanPauseRecording(boolean);
     method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
     method public android.media.tv.TvInputInfo.Builder setExtras(android.os.Bundle);
     method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -24389,7 +24394,9 @@
     method public void notifyRecordingStopped(android.net.Uri);
     method public void notifyTuned(android.net.Uri);
     method public void onAppPrivateCommand(@NonNull String, android.os.Bundle);
+    method public void onPauseRecording(@NonNull android.os.Bundle);
     method public abstract void onRelease();
+    method public void onResumeRecording(@NonNull android.os.Bundle);
     method public abstract void onStartRecording(@Nullable android.net.Uri);
     method public void onStartRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle);
     method public abstract void onStopRecording();
@@ -24439,7 +24446,11 @@
 
   public class TvRecordingClient {
     ctor public TvRecordingClient(android.content.Context, String, @NonNull android.media.tv.TvRecordingClient.RecordingCallback, android.os.Handler);
+    method public void pauseRecording();
+    method public void pauseRecording(@NonNull android.os.Bundle);
     method public void release();
+    method public void resumeRecording();
+    method public void resumeRecording(@NonNull android.os.Bundle);
     method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);
     method public void startRecording(@Nullable android.net.Uri);
     method public void startRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle);
@@ -25073,6 +25084,8 @@
     method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
     method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
     method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @NonNull @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException;
@@ -25082,6 +25095,12 @@
     field public static final int DIRECTION_OUT = 1; // 0x1
   }
 
+  public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
+    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+    method public void close();
+    method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+  }
+
   public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
   }
 
@@ -29587,6 +29606,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();
@@ -33918,6 +33955,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";
@@ -35859,6 +35897,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 {
@@ -39217,6 +39258,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
@@ -39228,10 +39270,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
@@ -39257,6 +39301,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 {
@@ -39544,6 +39589,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";
@@ -40486,6 +40532,12 @@
     field public static final int SCAN_TYPE_PERIODIC = 1; // 0x1
   }
 
+  public final class PhoneCapability implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneCapability> CREATOR;
+  }
+
   public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
     ctor public PhoneNumberFormattingTextWatcher();
     ctor public PhoneNumberFormattingTextWatcher(String);
@@ -40497,12 +40549,13 @@
   public class PhoneNumberUtils {
     ctor public PhoneNumberUtils();
     method public static void addTtsSpan(android.text.Spannable, int, int);
+    method public static boolean areSamePhoneNumber(@NonNull String, @NonNull String, @NonNull String);
     method @Deprecated public static String calledPartyBCDFragmentToString(byte[], int, int);
     method public static String calledPartyBCDFragmentToString(byte[], int, int, int);
     method @Deprecated public static String calledPartyBCDToString(byte[], int, int);
     method public static String calledPartyBCDToString(byte[], int, int, int);
-    method public static boolean compare(String, String);
-    method public static boolean compare(android.content.Context, String, String);
+    method @Deprecated public static boolean compare(String, String);
+    method @Deprecated public static boolean compare(android.content.Context, String, String);
     method public static String convertKeypadLettersToDigits(String);
     method public static android.text.style.TtsSpan createTtsSpan(String);
     method public static CharSequence createTtsSpannable(CharSequence);
@@ -40554,10 +40607,10 @@
 
   public class PhoneStateListener {
     ctor public PhoneStateListener();
-    ctor public PhoneStateListener(@NonNull java.util.concurrent.Executor);
+    ctor @Deprecated public PhoneStateListener(@NonNull java.util.concurrent.Executor);
     method public void onActiveDataSubscriptionIdChanged(int);
     method public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
-    method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onCallDisconnectCauseChanged(int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
     method public void onCallForwardingIndicatorChanged(boolean);
     method public void onCallStateChanged(int, String);
     method public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
@@ -40565,36 +40618,150 @@
     method public void onDataActivity(int);
     method public void onDataConnectionStateChanged(int);
     method public void onDataConnectionStateChanged(int, int);
-    method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
     method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
-    method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
     method public void onMessageWaitingIndicatorChanged(boolean);
-    method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
     method public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
     method public void onServiceStateChanged(android.telephony.ServiceState);
     method @Deprecated public void onSignalStrengthChanged(int);
     method public void onSignalStrengthsChanged(android.telephony.SignalStrength);
     method public void onUserMobileDataStateChanged(boolean);
-    field public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
-    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
-    field public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
-    field public static final int LISTEN_CALL_STATE = 32; // 0x20
-    field public static final int LISTEN_CELL_INFO = 1024; // 0x400
-    field public static final int LISTEN_CELL_LOCATION = 16; // 0x10
-    field public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80
-    field public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40
-    field public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000
-    field public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
-    field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
+    field @Deprecated public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
+    field @Deprecated public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
+    field @Deprecated public static final int LISTEN_CALL_STATE = 32; // 0x20
+    field @Deprecated public static final int LISTEN_CELL_INFO = 1024; // 0x400
+    field @Deprecated public static final int LISTEN_CELL_LOCATION = 16; // 0x10
+    field @Deprecated public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80
+    field @Deprecated public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40
+    field @Deprecated public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000
+    field @Deprecated public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
+    field @Deprecated public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
     field public static final int LISTEN_NONE = 0; // 0x0
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
-    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
-    field public static final int LISTEN_SERVICE_STATE = 1; // 0x1
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
+    field @Deprecated public static final int LISTEN_SERVICE_STATE = 1; // 0x1
     field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
-    field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
-    field public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
+    field @Deprecated public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
+    field @Deprecated public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
+  }
+
+  public static interface PhoneStateListener.ActiveDataSubscriptionIdChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onActiveDataSubscriptionIdChanged(int);
+  }
+
+  public static interface PhoneStateListener.AlwaysReportedSignalStrengthChangedListener {
+    method @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+  }
+
+  public static interface PhoneStateListener.BarringInfoChangedListener {
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
+  }
+
+  public static interface PhoneStateListener.CallDisconnectCauseChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
+  }
+
+  public static interface PhoneStateListener.CallForwardingIndicatorChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onCallForwardingIndicatorChanged(boolean);
+  }
+
+  public static interface PhoneStateListener.CallStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public void onCallStateChanged(int, @Nullable String);
+  }
+
+  public static interface PhoneStateListener.CarrierNetworkChangeListener {
+    method public void onCarrierNetworkChange(boolean);
+  }
+
+  public static interface PhoneStateListener.CellInfoChangedListener {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellInfoChanged(@NonNull java.util.List<android.telephony.CellInfo>);
+  }
+
+  public static interface PhoneStateListener.CellLocationChangedListener {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellLocationChanged(@NonNull android.telephony.CellLocation);
+  }
+
+  public static interface PhoneStateListener.DataActivationStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivationStateChanged(int);
+  }
+
+  public static interface PhoneStateListener.DataActivityListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivity(int);
+  }
+
+  public static interface PhoneStateListener.DataConnectionStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataConnectionStateChanged(int, int);
+  }
+
+  public static interface PhoneStateListener.DisplayInfoChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+  }
+
+  public static interface PhoneStateListener.EmergencyNumberListChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
+  }
+
+  public static interface PhoneStateListener.ImsCallDisconnectCauseChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+  }
+
+  public static interface PhoneStateListener.MessageWaitingIndicatorChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onMessageWaitingIndicatorChanged(boolean);
+  }
+
+  public static interface PhoneStateListener.PhoneCapabilityChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
+  }
+
+  public static interface PhoneStateListener.PreciseDataConnectionStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+  }
+
+  public static interface PhoneStateListener.RegistrationFailedListener {
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
+  }
+
+  public static interface PhoneStateListener.ServiceStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onServiceStateChanged(@NonNull android.telephony.ServiceState);
+  }
+
+  public static interface PhoneStateListener.SignalStrengthsChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+  }
+
+  public static interface PhoneStateListener.UserMobileDataStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onUserMobileDataStateChanged(boolean);
+  }
+
+  public final class PhysicalChannelConfig implements android.os.Parcelable {
+    method public int describeContents();
+    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
   }
 
   public final class PreciseDataConnectionState implements android.os.Parcelable {
@@ -40676,6 +40843,50 @@
     field public static final int INVALID = 2147483647; // 0x7fffffff
   }
 
+  public final class SignalStrengthUpdateRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.os.IBinder getLiveToken();
+    method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos();
+    method public boolean isReportingRequestedWhileIdle();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrengthUpdateRequest> CREATOR;
+  }
+
+  public static final class SignalStrengthUpdateRequest.Builder {
+    ctor public SignalStrengthUpdateRequest.Builder();
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest build();
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setReportingRequestedWhileIdle(boolean);
+    method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setSignalThresholdInfos(@NonNull java.util.Collection<android.telephony.SignalThresholdInfo>);
+  }
+
+  public final class SignalThresholdInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public static int getMaximumNumberOfThresholdsAllowed();
+    method public static int getMinimumNumberOfThresholdsAllowed();
+    method public int getRadioAccessNetworkType();
+    method public int getSignalMeasurementType();
+    method @NonNull public int[] getThresholds();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalThresholdInfo> CREATOR;
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSCP = 2; // 0x2
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSRP = 3; // 0x3
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSRQ = 4; // 0x4
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSSI = 1; // 0x1
+    field public static final int SIGNAL_MEASUREMENT_TYPE_RSSNR = 5; // 0x5
+    field public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRP = 6; // 0x6
+    field public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRQ = 7; // 0x7
+    field public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8; // 0x8
+    field public static final int SIGNAL_MEASUREMENT_TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  public static final class SignalThresholdInfo.Builder {
+    ctor public SignalThresholdInfo.Builder();
+    method @NonNull public android.telephony.SignalThresholdInfo build();
+    method @NonNull public android.telephony.SignalThresholdInfo.Builder setRadioAccessNetworkType(int);
+    method @NonNull public android.telephony.SignalThresholdInfo.Builder setSignalMeasurementType(int);
+    method @NonNull public android.telephony.SignalThresholdInfo.Builder setThresholds(@NonNull int[]);
+  }
+
   public final class SmsManager {
     method public String createAppSpecificSmsToken(android.app.PendingIntent);
     method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
@@ -41012,6 +41223,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();
@@ -41090,7 +41302,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);
@@ -41105,7 +41317,8 @@
     method public boolean isVoiceCapable();
     method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
-    method public void listen(android.telephony.PhoneStateListener, int);
+    method @Deprecated public void listen(android.telephony.PhoneStateListener, int);
+    method public void registerPhoneStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.PhoneStateListener);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
     method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
     method public void sendDialerSpecialCode(String);
@@ -41123,11 +41336,13 @@
     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);
     method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int);
+    method public void unregisterPhoneStateListener(@NonNull android.telephony.PhoneStateListener);
     method public void updateAvailableNetworks(@NonNull java.util.List<android.telephony.AvailableNetworkInfo>, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     field public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE = "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE";
     field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
@@ -41149,6 +41364,7 @@
     field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
     field public static final int CALL_COMPOSER_STATUS_OFF = 0; // 0x0
     field public static final int CALL_COMPOSER_STATUS_ON = 1; // 0x1
+    field public static final int CALL_COMPOSER_STATUS_ON_NO_PICTURES = 2; // 0x2
     field public static final int CALL_STATE_IDLE = 0; // 0x0
     field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
     field public static final int CALL_STATE_RINGING = 1; // 0x1
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 9f41c139..a0c5213 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -44,6 +44,7 @@
     field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
     field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
+    field public static final String BIND_RESUME_ON_REBOOT_SERVICE = "android.permission.BIND_RESUME_ON_REBOOT_SERVICE";
     field public static final String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
     field public static final String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
     field public static final String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE";
@@ -126,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";
@@ -1412,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
@@ -1595,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 {
@@ -1684,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";
@@ -5994,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);
@@ -6003,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";
@@ -6092,15 +6120,11 @@
   }
 
   public final class IpSecManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
-    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
   }
 
   public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
-    method public void close();
     method @NonNull public String getInterfaceName();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
   }
 
   public static class IpSecTransform.Builder {
@@ -6196,6 +6220,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[]);
@@ -6206,6 +6232,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();
@@ -6235,6 +6264,7 @@
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
+    ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
     method @NonNull public int[] getAdministratorUids();
     method @Nullable public String getSsid();
     method @NonNull public int[] getTransportTypes();
@@ -6291,6 +6321,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();
@@ -6363,6 +6396,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);
@@ -6408,6 +6482,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);
@@ -6457,6 +6537,11 @@
     field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00
   }
 
+  public interface TransportInfo {
+    method public default boolean hasLocationSensitiveFields();
+    method @NonNull public default android.net.TransportInfo makeCopy(boolean);
+  }
+
   public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
     method @NonNull public String toSafeString();
   }
@@ -6499,157 +6584,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);
   }
 
 }
@@ -6920,7 +7005,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
   }
@@ -7040,24 +7128,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();
@@ -7510,11 +7584,13 @@
   }
 
   public class UserManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean canHaveRestrictedProfile();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getRestrictedProfileParent();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
@@ -8984,6 +9060,18 @@
 
 }
 
+package android.service.resumeonreboot {
+
+  public abstract class ResumeOnRebootService extends android.app.Service {
+    ctor public ResumeOnRebootService();
+    method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
+    method @NonNull public abstract byte[] onUnwrap(@NonNull byte[]) throws java.io.IOException;
+    method @NonNull public abstract byte[] onWrap(@NonNull byte[], long) throws java.io.IOException;
+    field public static final String SERVICE_INTERFACE = "android.service.resumeonreboot.ResumeOnRebootService";
+  }
+
+}
+
 package android.service.settings.suggestions {
 
   public final class Suggestion implements android.os.Parcelable {
@@ -9805,17 +9893,87 @@
     method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
     method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
     method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
-    method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
     method public void onRadioPowerStateChanged(int);
     method public void onSrvccStateChanged(int);
     method public void onVoiceActivationStateChanged(int);
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
-    field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
-    field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
-    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
-    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
-    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; // 0x17
+    field @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa
+    field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_BARRING_INFO_CHANGED = 32; // 0x20
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; // 0x1a
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4
+    field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6
+    field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11
+    field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
+    field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5
+    field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13
+    field public static final int EVENT_DATA_ACTIVITY_CHANGED = 8; // 0x8
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14; // 0xe
+    field public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7; // 0x7
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_ENABLED_CHANGED = 34; // 0x22
+    field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf
+    field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d
+    field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30; // 0x1e
+    field public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22; // 0x16
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33; // 0x21
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12; // 0xc
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18
+    field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f
+    field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1
+    field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9
+    field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SRVCC_STATE_CHANGED = 16; // 0x10
+    field public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20; // 0x14
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18; // 0x12
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
+  }
+
+  public static interface PhoneStateListener.CallAttributesChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+  }
+
+  public static interface PhoneStateListener.DataEnabledChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
+  }
+
+  public static interface PhoneStateListener.OutgoingEmergencyCallListener {
+    method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
+  }
+
+  public static interface PhoneStateListener.OutgoingEmergencySmsListener {
+    method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
+  }
+
+  public static interface PhoneStateListener.PhysicalChannelConfigChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPhysicalChannelConfigChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
+  }
+
+  public static interface PhoneStateListener.PreciseCallStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+  }
+
+  public static interface PhoneStateListener.RadioPowerStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int);
+  }
+
+  public static interface PhoneStateListener.SrvccStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSrvccStateChanged(int);
+  }
+
+  public static interface PhoneStateListener.VoiceActivationStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onVoiceActivationStateChanged(int);
   }
 
   public final class PinResult implements android.os.Parcelable {
@@ -10672,6 +10830,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);
@@ -11718,6 +11889,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);
@@ -12155,6 +12327,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/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index be1681b..66a8325 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -223,7 +223,7 @@
      */
     IBinder requestStartActivityPermissionToken(in IBinder delegatorToken);
 
-    void releaseSomeActivities(in IApplicationThread app);
+    oneway void releaseSomeActivities(in IApplicationThread app);
     Bitmap getTaskDescriptionIcon(in String filename, int userId);
     void registerTaskStackListener(in ITaskStackListener listener);
     void unregisterTaskStackListener(in ITaskStackListener listener);
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 6d79e2d..60bfac5 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -42,8 +42,10 @@
 # Multiuser
 per-file *User* = file:/MULTIUSER_OWNERS
 
-# Notification
+# Notification, DND, Status bar
 per-file *Notification* = file:/packages/SystemUI/OWNERS
+per-file *Zen* = file:/packages/SystemUI/OWNERS
+per-file *StatusBar* = file:/packages/SystemUI/OWNERS
 
 # ResourcesManager
 per-file ResourcesManager = rtmitchell@google.com, toddke@google.com
diff --git a/core/java/android/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/app/search/OWNERS b/core/java/android/app/search/OWNERS
new file mode 100644
index 0000000..92835c2
--- /dev/null
+++ b/core/java/android/app/search/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS
new file mode 100644
index 0000000..439df4b
--- /dev/null
+++ b/core/java/android/appwidget/OWNERS
@@ -0,0 +1,3 @@
+pinyaoting@google.com
+suprabh@google.com
+sunnygoyal@google.com
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 15daf1c..cd91aa9 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -225,6 +225,39 @@
     @SystemApi
     public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
 
+    /** @hide */
+    @IntDef(prefix = "DYNAMIC_BUFFER_SUPPORT_", value = {
+            DYNAMIC_BUFFER_SUPPORT_NONE,
+            DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD,
+            DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Type {}
+
+    /**
+     * Indicates the supported type of Dynamic Audio Buffer is not supported.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0;
+
+    /**
+     * Indicates the supported type of Dynamic Audio Buffer is A2DP offload.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1;
+
+    /**
+     * Indicates the supported type of Dynamic Audio Buffer is A2DP software encoding.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2;
+
     private BluetoothAdapter mAdapter;
     private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector =
             new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp",
@@ -845,6 +878,87 @@
     }
 
     /**
+     * Get the supported type of the Dynamic Audio Buffer.
+     * <p>Possible return values are
+     * {@link #DYNAMIC_BUFFER_SUPPORT_NONE},
+     * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD},
+     * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}.
+     *
+     * @return supported type of Dynamic Audio Buffer feature
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public @Type int getDynamicBufferSupport() {
+        if (VDBG) log("getDynamicBufferSupport()");
+        try {
+            final IBluetoothA2dp service = getService();
+            if (service != null && isEnabled()) {
+                return service.getDynamicBufferSupport();
+            }
+            if (service == null) Log.w(TAG, "Proxy not attached to service");
+            return DYNAMIC_BUFFER_SUPPORT_NONE;
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to get getDynamicBufferSupport, error: ", e);
+            return DYNAMIC_BUFFER_SUPPORT_NONE;
+        }
+    }
+
+    /**
+     * Return the record of {@link BufferConstraints} object that
+     * has the default/maximum/minimum audio buffer. This can be used to inform what the controller
+     * has support for the audio buffer.
+     *
+     * @return a record with {@link BufferConstraints} or null if report is unavailable
+     * or unsupported
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public @Nullable BufferConstraints getBufferConstraints() {
+        if (VDBG) log("getBufferConstraints()");
+        try {
+            final IBluetoothA2dp service = getService();
+            if (service != null && isEnabled()) {
+                return service.getBufferConstraints();
+            }
+            if (service == null) Log.w(TAG, "Proxy not attached to service");
+            return null;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+            return null;
+        }
+    }
+
+    /**
+     * Set Dynamic Audio Buffer Size.
+     *
+     * @param codec audio codec
+     * @param value buffer millis
+     * @return true to indicate success, or false on immediate error
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+    public boolean setBufferMillis(@BluetoothCodecConfig.SourceCodecType int codec, int value) {
+        if (VDBG) log("setBufferMillis(" + codec + ", " + value + ")");
+        try {
+            final IBluetoothA2dp service = getService();
+            if (service != null && isEnabled()) {
+                return service.setBufferMillis(codec, value);
+            }
+            if (service == null) Log.w(TAG, "Proxy not attached to service");
+            return false;
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+            return false;
+        }
+    }
+
+    /**
      * Helper for converting a state to a string.
      *
      * For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/BufferConstraint.java b/core/java/android/bluetooth/BufferConstraint.java
new file mode 100644
index 0000000..cbffc78
--- /dev/null
+++ b/core/java/android/bluetooth/BufferConstraint.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Stores a codec's constraints on buffering length in milliseconds.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class BufferConstraint implements Parcelable {
+
+    private static final String TAG = "BufferConstraint";
+    private int mDefaultMillis;
+    private int mMaxMillis;
+    private int mMinMillis;
+
+    public BufferConstraint(int defaultMillis, int maxMillis,
+            int minMillis) {
+        mDefaultMillis = defaultMillis;
+        mMaxMillis = maxMillis;
+        mMinMillis = minMillis;
+    }
+
+    BufferConstraint(Parcel in) {
+        mDefaultMillis = in.readInt();
+        mMaxMillis = in.readInt();
+        mMinMillis = in.readInt();
+    }
+
+    public static final @NonNull Parcelable.Creator<BufferConstraint> CREATOR =
+            new Parcelable.Creator<BufferConstraint>() {
+                public BufferConstraint createFromParcel(Parcel in) {
+                    return new BufferConstraint(in);
+                }
+
+                public BufferConstraint[] newArray(int size) {
+                    return new BufferConstraint[size];
+                }
+            };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mDefaultMillis);
+        out.writeInt(mMaxMillis);
+        out.writeInt(mMinMillis);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Get the default buffer millis
+     *
+     * @return default buffer millis
+     * @hide
+     */
+    @SystemApi
+    public int getDefaultMillis() {
+        return mDefaultMillis;
+    }
+
+    /**
+     * Get the maximum buffer millis
+     *
+     * @return maximum buffer millis
+     * @hide
+     */
+    @SystemApi
+    public int getMaxMillis() {
+        return mMaxMillis;
+    }
+
+    /**
+     * Get the minimum buffer millis
+     *
+     * @return minimum buffer millis
+     * @hide
+     */
+    @SystemApi
+    public int getMinMillis() {
+        return mMinMillis;
+    }
+}
diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java
new file mode 100644
index 0000000..7e5ec1e
--- /dev/null
+++ b/core/java/android/bluetooth/BufferConstraints.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * A parcelable collection of buffer constraints by codec type.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class BufferConstraints implements Parcelable {
+    public static final int BUFFER_CODEC_MAX_NUM = 32;
+
+    private static final String TAG = "BufferConstraints";
+
+    private Map<Integer, BufferConstraint> mBufferConstraints;
+    private List<BufferConstraint> mBufferConstraintList;
+
+    public BufferConstraints(@NonNull List<BufferConstraint>
+            bufferConstraintList) {
+
+        mBufferConstraintList = new ArrayList<BufferConstraint>(bufferConstraintList);
+        mBufferConstraints = new HashMap<Integer, BufferConstraint>();
+        for (int i = 0; i < BUFFER_CODEC_MAX_NUM; i++) {
+            mBufferConstraints.put(i, bufferConstraintList.get(i));
+        }
+    }
+
+    BufferConstraints(Parcel in) {
+        mBufferConstraintList = new ArrayList<BufferConstraint>();
+        mBufferConstraints = new HashMap<Integer, BufferConstraint>();
+        in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader());
+        for (int i = 0; i < mBufferConstraintList.size(); i++) {
+            mBufferConstraints.put(i, mBufferConstraintList.get(i));
+        }
+    }
+
+    public static final @NonNull Parcelable.Creator<BufferConstraints> CREATOR =
+            new Parcelable.Creator<BufferConstraints>() {
+                public BufferConstraints createFromParcel(Parcel in) {
+                    return new BufferConstraints(in);
+                }
+
+                public BufferConstraints[] newArray(int size) {
+                    return new BufferConstraints[size];
+                }
+            };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeList(mBufferConstraintList);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Get the buffer constraints by codec type.
+     *
+     * @param codec Audio codec
+     * @return buffer constraints by codec type.
+     * @hide
+     */
+    @SystemApi
+    public @Nullable BufferConstraint getCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
+        return mBufferConstraints.get(codec);
+    }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 92ede1c..eecdb84 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2602,6 +2602,36 @@
     public abstract void sendStickyBroadcast(@RequiresPermission Intent intent);
 
     /**
+     * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+     * Intent you are sending stays around after the broadcast is complete,
+     * so that others can quickly retrieve that data through the return
+     * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}.  In
+     * all other ways, this behaves the same as
+     * {@link #sendBroadcast(Intent)}.
+     *
+     * @deprecated Sticky broadcasts should not be used.  They provide no security (anyone
+     * can access them), no protection (anyone can modify them), and many other problems.
+     * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+     * has changed, with another mechanism for apps to retrieve the current value whenever
+     * desired.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     * Intent will receive the broadcast, and the Intent will be held to
+     * be re-broadcast to future receivers.
+     * @param options (optional) Additional sending options, generated from a
+     * {@link android.app.BroadcastOptions}.
+     *
+     * @see #sendBroadcast(Intent)
+     * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+     */
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY)
+    public void sendStickyBroadcast(@RequiresPermission @NonNull Intent intent,
+            @Nullable Bundle options) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * <p>Version of {@link #sendStickyBroadcast} that allows you to
      * receive data back from the broadcast.  This is accomplished by
      * supplying your own BroadcastReceiver when calling, which will be
@@ -4999,9 +5029,7 @@
      * Service to capture a bugreport.
      * @see #getSystemService(String)
      * @see android.os.BugreportManager
-     * @hide
      */
-    @SystemApi
     public static final String BUGREPORT_SERVICE = "bugreport";
 
     /**
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 5bdd521..e351c244 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -617,6 +617,35 @@
         mBase.sendStickyBroadcast(intent);
     }
 
+    /**
+     * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+     * Intent you are sending stays around after the broadcast is complete,
+     * so that others can quickly retrieve that data through the return
+     * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}.  In
+     * all other ways, this behaves the same as
+     * {@link #sendBroadcast(Intent)}.
+     *
+     * @deprecated Sticky broadcasts should not be used.  They provide no security (anyone
+     * can access them), no protection (anyone can modify them), and many other problems.
+     * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+     * has changed, with another mechanism for apps to retrieve the current value whenever
+     * desired.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     * Intent will receive the broadcast, and the Intent will be held to
+     * be re-broadcast to future receivers.
+     * @param options (optional) Additional sending options, generated from a
+     * {@link android.app.BroadcastOptions}.
+     *
+     * @see #sendBroadcast(Intent)
+     * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
+     */
+    @Override
+    @Deprecated
+    public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) {
+        mBase.sendStickyBroadcast(intent, options);
+    }
+
     @Override
     @Deprecated
     public void sendStickyOrderedBroadcast(
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index 44b5c44..0b950b4 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -17,6 +17,7 @@
 package android.content.om;
 
 import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
 
 /**
  * Api for getting information about overlay packages.
@@ -163,4 +164,18 @@
      * @param packageName The name of the overlay package whose idmap should be deleted.
      */
     void invalidateCachesForOverlay(in String packageName, in int userIs);
+
+    /**
+     * Perform a series of requests related to overlay packages. This is an
+     * atomic operation: either all requests were performed successfully and
+     * the changes were propagated to the rest of the system, or at least one
+     * request could not be performed successfully and nothing is changed and
+     * nothing is propagated to the rest of the system.
+     *
+     * @see OverlayManagerTransaction
+     *
+     * @param transaction the series of overlay related requests to perform
+     * @throws SecurityException if the transaction failed
+     */
+    void commit(in OverlayManagerTransaction transaction);
 }
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 217f637c..7c14c28 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -254,6 +254,29 @@
     }
 
     /**
+     * Perform a series of requests related to overlay packages. This is an
+     * atomic operation: either all requests were performed successfully and
+     * the changes were propagated to the rest of the system, or at least one
+     * request could not be performed successfully and nothing is changed and
+     * nothing is propagated to the rest of the system.
+     *
+     * @see OverlayManagerTransaction
+     *
+     * @param transaction the series of overlay related requests to perform
+     * @throws Exception if not all the requests could be successfully and
+     *         atomically executed
+     *
+     * @hide
+     */
+    public void commit(@NonNull final OverlayManagerTransaction transaction) {
+        try {
+            mService.commit(transaction);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Starting on R, actor enforcement and app visibility changes introduce additional failure
      * cases, but the SecurityException thrown with these checks is unexpected for existing
      * consumers of the API.
diff --git a/core/java/android/content/om/OverlayManagerTransaction.aidl b/core/java/android/content/om/OverlayManagerTransaction.aidl
new file mode 100644
index 0000000..6715c82
--- /dev/null
+++ b/core/java/android/content/om/OverlayManagerTransaction.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.om;
+
+parcelable OverlayManagerTransaction;
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
new file mode 100644
index 0000000..1fa8973
--- /dev/null
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.om;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Container for a batch of requests to the OverlayManagerService.
+ *
+ * Transactions are created using a builder interface. Example usage:
+ *
+ * final OverlayManager om = ctx.getSystemService(OverlayManager.class);
+ * final OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+ *     .setEnabled(...)
+ *     .setEnabled(...)
+ *     .build();
+ * om.commit(t);
+ *
+ * @hide
+ */
+public class OverlayManagerTransaction
+        implements Iterable<OverlayManagerTransaction.Request>, Parcelable {
+    // TODO: remove @hide from this class when OverlayManager is added to the
+    // SDK, but keep OverlayManagerTransaction.Request @hidden
+    private final List<Request> mRequests;
+
+    OverlayManagerTransaction(@NonNull final List<Request> requests) {
+        checkNotNull(requests);
+        if (requests.contains(null)) {
+            throw new IllegalArgumentException("null request");
+        }
+        mRequests = requests;
+    }
+
+    private OverlayManagerTransaction(@NonNull final Parcel source) {
+        final int size = source.readInt();
+        mRequests = new ArrayList<Request>(size);
+        for (int i = 0; i < size; i++) {
+            final int request = source.readInt();
+            final String packageName = source.readString();
+            final int userId = source.readInt();
+            mRequests.add(new Request(request, packageName, userId));
+        }
+    }
+
+    @Override
+    public Iterator<Request> iterator() {
+        return mRequests.iterator();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("OverlayManagerTransaction { mRequests = %s }", mRequests);
+    }
+
+    /**
+     * A single unit of the transaction, such as a request to enable an
+     * overlay, or to disable an overlay.
+     *
+     * @hide
+     */
+    public static class Request {
+        @IntDef(prefix = "TYPE_", value = {
+                TYPE_SET_ENABLED,
+                TYPE_SET_DISABLED,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        @interface RequestType {}
+
+        public static final int TYPE_SET_ENABLED = 0;
+        public static final int TYPE_SET_DISABLED = 1;
+
+        @RequestType public final int type;
+        public final String packageName;
+        public final int userId;
+
+        public Request(@RequestType final int type, @NonNull final String packageName,
+                final int userId) {
+            this.type = type;
+            this.packageName = packageName;
+            this.userId = userId;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("Request{type=0x%02x (%s), packageName=%s, userId=%d}",
+                    type, typeToString(), packageName, userId);
+        }
+
+        /**
+         * Translate the request type into a human readable string. Only
+         * intended for debugging.
+         *
+         * @hide
+         */
+        public String typeToString() {
+            switch (type) {
+                case TYPE_SET_ENABLED: return "TYPE_SET_ENABLED";
+                case TYPE_SET_DISABLED: return "TYPE_SET_DISABLED";
+                default: return String.format("TYPE_UNKNOWN (0x%02x)", type);
+            }
+        }
+    }
+
+    /**
+     * Builder class for OverlayManagerTransaction objects.
+     *
+     * @hide
+     */
+    public static class Builder {
+        private final List<Request> mRequests = new ArrayList<>();
+
+        /**
+         * Request that an overlay package be enabled and change its loading
+         * order to the last package to be loaded, or disabled
+         *
+         * If the caller has the correct permissions, it is always possible to
+         * disable an overlay. Due to technical and security reasons it may not
+         * always be possible to enable an overlay, for instance if the overlay
+         * does not successfully overlay any target resources due to
+         * overlayable policy restrictions.
+         *
+         * An enabled overlay is a part of target package's resources, i.e. it will
+         * be part of any lookups performed via {@link android.content.res.Resources}
+         * and {@link android.content.res.AssetManager}. A disabled overlay will no
+         * longer affect the resources of the target package. If the target is
+         * currently running, its outdated resources will be replaced by new ones.
+         *
+         * @param packageName The name of the overlay package.
+         * @param enable true to enable the overlay, false to disable it.
+         * @return this Builder object, so you can chain additional requests
+         */
+        public Builder setEnabled(@NonNull String packageName, boolean enable) {
+            return setEnabled(packageName, enable, UserHandle.myUserId());
+        }
+
+        /**
+         * @hide
+         */
+        public Builder setEnabled(@NonNull String packageName, boolean enable, int userId) {
+            checkNotNull(packageName);
+            @Request.RequestType final int type =
+                enable ? Request.TYPE_SET_ENABLED : Request.TYPE_SET_DISABLED;
+            mRequests.add(new Request(type, packageName, userId));
+            return this;
+        }
+
+        /**
+         * Create a new transaction out of the requests added so far. Execute
+         * the transaction by calling OverlayManager#commit.
+         *
+         * @see OverlayManager#commit
+         * @return a new transaction
+         */
+        public OverlayManagerTransaction build() {
+            return new OverlayManagerTransaction(mRequests);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        final int size = mRequests.size();
+        dest.writeInt(size);
+        for (int i = 0; i < size; i++) {
+            final Request req = mRequests.get(i);
+            dest.writeInt(req.type);
+            dest.writeString(req.packageName);
+            dest.writeInt(req.userId);
+        }
+    }
+
+    public static final Parcelable.Creator<OverlayManagerTransaction> CREATOR =
+            new Parcelable.Creator<OverlayManagerTransaction>() {
+
+        @Override
+        public OverlayManagerTransaction createFromParcel(Parcel source) {
+            return new OverlayManagerTransaction(source);
+        }
+
+        @Override
+        public OverlayManagerTransaction[] newArray(int size) {
+            return new OverlayManagerTransaction[size];
+        }
+    };
+}
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
index fd32efc..f0def805 100644
--- a/core/java/android/content/pm/OWNERS
+++ b/core/java/android/content/pm/OWNERS
@@ -6,5 +6,6 @@
 
 per-file PackageParser.java = chiuwinson@google.com
 per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
 per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
 per-file UserInfo* = file:/MULTIUSER_OWNERS
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 06c15980..d107261 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -16,6 +16,10 @@
 package android.net;
 
 import static android.net.IpSecManager.INVALID_RESOURCE_ID;
+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;
@@ -26,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;
@@ -69,7 +72,6 @@
 
 import libcore.net.event.NetworkEventDispatcher;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.lang.annotation.Retention;
@@ -1955,6 +1957,12 @@
         return k;
     }
 
+    // Construct an invalid fd.
+    private ParcelFileDescriptor createInvalidFd() {
+        final int invalidFd = -1;
+        return ParcelFileDescriptor.adoptFd(invalidFd);
+    }
+
     /**
      * Request that keepalives be started on a IPsec NAT-T socket.
      *
@@ -1985,7 +1993,7 @@
         } catch (IOException ignored) {
             // Construct an invalid fd, so that if the user later calls start(), it will fail with
             // ERROR_INVALID_SOCKET.
-            dup = new ParcelFileDescriptor(new FileDescriptor());
+            dup = createInvalidFd();
         }
         return new NattSocketKeepalive(mService, network, dup, socket.getResourceId(), source,
                 destination, executor, callback);
@@ -2027,7 +2035,7 @@
         } catch (IOException ignored) {
             // Construct an invalid fd, so that if the user later calls start(), it will fail with
             // ERROR_INVALID_SOCKET.
-            dup = new ParcelFileDescriptor(new FileDescriptor());
+            dup = createInvalidFd();
         }
         return new NattSocketKeepalive(mService, network, dup,
                 INVALID_RESOURCE_ID /* Unused */, source, destination, executor, callback);
@@ -2064,7 +2072,7 @@
         } catch (UncheckedIOException ignored) {
             // Construct an invalid fd, so that if the user later calls start(), it will fail with
             // ERROR_INVALID_SOCKET.
-            dup = new ParcelFileDescriptor(new FileDescriptor());
+            dup = createInvalidFd();
         }
         return new TcpSocketKeepalive(mService, network, dup, executor, callback);
     }
@@ -3730,14 +3738,12 @@
     private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
     private static CallbackHandler sCallbackHandler;
 
-    private static final int LISTEN  = 1;
-    private static final int REQUEST = 2;
-
     private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
-            int timeoutMs, int action, int legacyType, CallbackHandler handler) {
+            int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
         printStackTrace();
         checkCallbackNotNull(callback);
-        Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
+        Preconditions.checkArgument(
+                reqType == TRACK_DEFAULT || need != null, "null NetworkCapabilities");
         final NetworkRequest request;
         final String callingPackageName = mContext.getOpPackageName();
         try {
@@ -3750,13 +3756,13 @@
                 }
                 Messenger messenger = new Messenger(handler);
                 Binder binder = new Binder();
-                if (action == LISTEN) {
+                if (reqType == LISTEN) {
                     request = mService.listenForNetwork(
                             need, messenger, binder, callingPackageName);
                 } else {
                     request = mService.requestNetwork(
-                            need, messenger, timeoutMs, binder, legacyType, callingPackageName,
-                            getAttributionTag());
+                            need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
+                            callingPackageName, getAttributionTag());
                 }
                 if (request != null) {
                     sCallbacks.put(request, callback);
@@ -4260,7 +4266,7 @@
         // request, i.e., the system default network.
         CallbackHandler cbHandler = new CallbackHandler(handler);
         sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
-                REQUEST, TYPE_NONE, cbHandler);
+                TRACK_DEFAULT, TYPE_NONE, cbHandler);
     }
 
     /**
@@ -4817,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.
@@ -4826,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,
@@ -4842,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 b32c98b..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;
@@ -167,7 +169,7 @@
             in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
             in int factorySerialNumber);
 
-    NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
+    NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
             in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
             String callingPackageName, String callingAttributionTag);
 
@@ -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/IpSecManager.java b/core/java/android/net/IpSecManager.java
index d83715c..b6ae7ec 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -705,7 +705,7 @@
     }
 
     /**
-     * This class represents an IpSecTunnelInterface
+     * This class represents an IpSecTunnelInterface.
      *
      * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as
      * local endpoints for IPsec tunnels.
@@ -714,9 +714,7 @@
      * applied to provide IPsec security to packets sent through the tunnel. While a tunnel
      * cannot be used in standalone mode within Android, the higher layers may use the tunnel
      * to create Network objects which are accessible to the Android system.
-     * @hide
      */
-    @SystemApi
     public static final class IpSecTunnelInterface implements AutoCloseable {
         private final String mOpPackageName;
         private final IIpSecService mService;
@@ -727,23 +725,26 @@
         private String mInterfaceName;
         private int mResourceId = INVALID_RESOURCE_ID;
 
-        /** Get the underlying SPI held by this object. */
+        /**
+         * Get the underlying SPI held by this object.
+         *
+         * @hide
+         */
+        @SystemApi
         @NonNull
         public String getInterfaceName() {
             return mInterfaceName;
         }
 
         /**
-         * Add an address to the IpSecTunnelInterface
+         * Add an address to the IpSecTunnelInterface.
          *
          * <p>Add an address which may be used as the local inner address for
          * tunneled traffic.
          *
          * @param address the local address for traffic inside the tunnel
          * @param prefixLen length of the InetAddress prefix
-         * @hide
          */
-        @SystemApi
         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
         @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
         public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
@@ -758,15 +759,13 @@
         }
 
         /**
-         * Remove an address from the IpSecTunnelInterface
+         * Remove an address from the IpSecTunnelInterface.
          *
-         * <p>Remove an address which was previously added to the IpSecTunnelInterface
+         * <p>Remove an address which was previously added to the IpSecTunnelInterface.
          *
          * @param address to be removed
          * @param prefixLen length of the InetAddress prefix
-         * @hide
          */
-        @SystemApi
         @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
         @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
         public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException {
@@ -817,7 +816,7 @@
         }
 
         /**
-         * Delete an IpSecTunnelInterface
+         * Delete an IpSecTunnelInterface.
          *
          * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system
          * resources. Any packets bound for this interface either inbound or outbound will
@@ -839,7 +838,12 @@
             }
         }
 
-        /** Check that the Interface was closed properly. */
+
+        /**
+         * Check that the Interface was closed properly.
+         *
+         * @hide
+         */
         @Override
         protected void finalize() throws Throwable {
             if (mCloseGuard != null) {
@@ -871,17 +875,52 @@
      * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
      *
      * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
-     * underlying network goes away, and the onLost() callback is received.
+     * underlying network disconnects, and the {@link
+     * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received.
      *
-     * @param localAddress The local addres of the tunnel
-     * @param remoteAddress The local addres of the tunnel
-     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel.
-     *        This network should almost certainly be a network such as WiFi with an L2 address.
-     * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties
-     * @throws IOException indicating that the socket could not be opened or bound
-     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
-     * @hide
+     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets
+     *     that go through the tunnel will need a underlying network to transit to the IPsec peer.
+     *     This network should almost certainly be a physical network such as WiFi.
+     * @return a new {@link IpSecTunnelInterface} with the specified properties
+     * @throws IOException indicating that the tunnel could not be created due to a lower-layer
+     *     error
+     * @throws ResourceUnavailableException indicating that the number of opening tunnels has
+     *     reached the limit.
      */
+    @NonNull
+    @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+    @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+    public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull Network underlyingNetwork)
+            throws ResourceUnavailableException, IOException {
+
+        // TODO: Remove the need for adding two unused addresses with IPsec tunnels when {@link
+        // #createIpSecTunnelInterface(localAddress, remoteAddress, underlyingNetwork)} can be
+        // safely removed.
+        final InetAddress address = InetAddress.getLocalHost();
+        return createIpSecTunnelInterface(address, address, underlyingNetwork);
+    }
+
+    /**
+     * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic.
+     *
+     * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the
+     * underlying network disconnects, and the {@link
+     * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received.
+     *
+     * @param localAddress The local address of the tunnel
+     * @param remoteAddress The local address of the tunnel
+     * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets
+     *     that go through the tunnel will need a underlying network to transit to the IPsec peer.
+     *     This network should almost certainly be a physical network such as WiFi.
+     * @return a new {@link IpSecTunnelInterface} with the specified properties
+     * @throws IOException indicating that the tunnel could not be created due to a lower-layer
+     *     error
+     * @throws ResourceUnavailableException indicating that the number of opening tunnels has
+     *     reached the limit.
+     * @hide
+     * @deprecated Callers should use {@link #createIpSecTunnelInterface(Network)}
+     */
+    @Deprecated
     @SystemApi
     @NonNull
     @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
@@ -905,16 +944,14 @@
      * <p>Applications should probably not use this API directly.
      *
      *
-     * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied
+     * @param tunnel The {@link IpSecTunnelInterface} that will use the supplied
      *        transform.
-     * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which
+     * @param direction the direction, {@link #DIRECTION_OUT} or {@link #DIRECTION_IN} in which
      *        the transform will be used.
      * @param transform an {@link IpSecTransform} created in tunnel mode
-     * @throws IOException indicating that the transform could not be applied due to a lower
-     *         layer failure.
-     * @hide
+     * @throws IOException indicating that the transform could not be applied due to a lower-layer
+     *     error
      */
-    @SystemApi
     @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
     @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
     public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel,
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 4166c2c..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.
@@ -408,7 +421,8 @@
             throw new IllegalArgumentException();
         }
 
-        mInitialConfiguration = new InitialConfiguration(context, new NetworkCapabilities(nc),
+        mInitialConfiguration = new InitialConfiguration(context,
+                new NetworkCapabilities(nc, /* parcelLocationSensitiveFields */ true),
                 new LinkProperties(lp), score, config, ni);
     }
 
@@ -525,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;
+                }
             }
         }
     }
@@ -558,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) {
@@ -644,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));
+        }
     }
 
     /**
@@ -818,7 +864,9 @@
         Objects.requireNonNull(networkCapabilities);
         mBandwidthUpdatePending.set(false);
         mLastBwRefreshTime = System.currentTimeMillis();
-        final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+        final NetworkCapabilities nc =
+                new NetworkCapabilities(networkCapabilities,
+                        /* parcelLocationSensitiveFields */ true);
         queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc));
     }
 
@@ -1070,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 48c4832..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;
@@ -76,12 +75,33 @@
      */
     private String mRequestorPackageName;
 
+    /**
+     * Indicates whether parceling should preserve fields that are set based on permissions of
+     * the process receiving the {@link NetworkCapabilities}.
+     */
+    private final boolean mParcelLocationSensitiveFields;
+
     public NetworkCapabilities() {
+        mParcelLocationSensitiveFields = false;
         clearAll();
         mNetworkCapabilities = DEFAULT_CAPABILITIES;
     }
 
     public NetworkCapabilities(NetworkCapabilities nc) {
+        this(nc, false /* parcelLocationSensitiveFields */);
+    }
+
+    /**
+     * Make a copy of NetworkCapabilities.
+     *
+     * @param nc Original NetworkCapabilities
+     * @param parcelLocationSensitiveFields Whether to parcel location sensitive data or not.
+     * @hide
+     */
+    @SystemApi
+    public NetworkCapabilities(
+            @Nullable NetworkCapabilities nc, boolean parcelLocationSensitiveFields) {
+        mParcelLocationSensitiveFields = parcelLocationSensitiveFields;
         if (nc != null) {
             set(nc);
         }
@@ -93,6 +113,12 @@
      * @hide
      */
     public void clearAll() {
+        // Ensures that the internal copies maintained by the connectivity stack does not set
+        // this bit.
+        if (mParcelLocationSensitiveFields) {
+            throw new UnsupportedOperationException(
+                    "Cannot clear NetworkCapabilities when parcelLocationSensitiveFields is set");
+        }
         mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
         mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
         mNetworkSpecifier = null;
@@ -109,6 +135,8 @@
 
     /**
      * Set all contents of this object to the contents of a NetworkCapabilities.
+     *
+     * @param nc Original NetworkCapabilities
      * @hide
      */
     public void set(@NonNull NetworkCapabilities nc) {
@@ -117,7 +145,11 @@
         mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
         mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
         mNetworkSpecifier = nc.mNetworkSpecifier;
-        mTransportInfo = nc.mTransportInfo;
+        if (nc.getTransportInfo() != null) {
+            setTransportInfo(nc.getTransportInfo().makeCopy(mParcelLocationSensitiveFields));
+        } else {
+            setTransportInfo(null);
+        }
         mSignalStrength = nc.mSignalStrength;
         setUids(nc.mUids); // Will make the defensive copy
         setAdministratorUids(nc.getAdministratorUids());
@@ -543,7 +575,6 @@
      * @hide
      */
     @UnsupportedAppUsage
-    @TestApi
     public @NetCapability int[] getCapabilities() {
         return BitUtils.unpackBits(mNetworkCapabilities);
     }
@@ -788,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/TransportInfo.java b/core/java/android/net/TransportInfo.java
index b78d3fe..aa4bbb0 100644
--- a/core/java/android/net/TransportInfo.java
+++ b/core/java/android/net/TransportInfo.java
@@ -16,10 +16,48 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
 /**
  * A container for transport-specific capabilities which is returned by
  * {@link NetworkCapabilities#getTransportInfo()}. Specific networks
  * may provide concrete implementations of this interface.
+ * @see android.net.wifi.aware.WifiAwareNetworkInfo
+ * @see android.net.wifi.WifiInfo
  */
 public interface TransportInfo {
+
+    /**
+     * Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that
+     * were set based on the permissions of the process that originally received it.
+     *
+     * <p>By default {@link TransportInfo} does not preserve such fields during parceling, as
+     * they should not be shared outside of the process that receives them without appropriate
+     * checks.
+     *
+     * @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept
+     *                                      when parceling
+     * @return Copy of this instance.
+     * @hide
+     */
+    @SystemApi
+    @NonNull
+    default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
+        return this;
+    }
+
+    /**
+     * Returns whether this TransportInfo type has location sensitive fields or not (helps
+     * to determine whether to perform a location permission check or not before sending to
+     * apps).
+     *
+     * @return {@code true} if this instance contains location sensitive info, {@code false}
+     * otherwise.
+     * @hide
+     */
+    @SystemApi
+    default boolean hasLocationSensitiveFields() {
+        return false;
+    }
 }
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
index ab12cdd..3d79f28 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -39,7 +39,11 @@
  * An event logged when there is a change or event that requires updating the
  * the APF program in place with a new APF program.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class ApfProgramEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index fcafb7e..a32d3a6 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -27,7 +27,11 @@
 /**
  * An event logged for an interface with APF capabilities when its IpClient state machine exits.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class ApfStats implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index 8de427d..e175d58 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -28,7 +28,11 @@
 /**
  * An event recorded when a DhcpClient state machine transitions to a new state.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class DhcpClientEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index de3129d..7dd0696 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -27,7 +27,11 @@
 /**
  * Event class used to record error events when parsing DHCP response packets.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class DhcpErrorEvent implements IpConnectivityLog.Event {
     public static final int L2_ERROR   = 1;
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 58ea915..5cadb45 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -35,7 +35,11 @@
 /**
  * Class for logging IpConnectvity events with IpConnectivityMetrics
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public class IpConnectivityLog {
     private static final String TAG = IpConnectivityLog.class.getSimpleName();
@@ -137,7 +141,7 @@
      * @return true if the event was successfully logged.
      */
     public boolean log(@NonNull Network network, @NonNull int[] transports, @NonNull Event data) {
-        return log(network.netId, transports, data);
+        return log(network.getNetId(), transports, data);
     }
 
     /**
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index 4f7f326..3abcc05 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -33,7 +33,11 @@
  * An event recorded by IpClient when IP provisioning completes for a network or
  * when a network disconnects.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class IpManagerEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index d5003ba..0b65bbd 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -29,7 +29,11 @@
  * An event recorded when IpReachabilityMonitor sends a neighbor probe or receives
  * a neighbor probe result.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class IpReachabilityEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 8c28f7a..47eeeff 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -31,7 +31,11 @@
 
 /**
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class NetworkEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index b54874f..05a47e5 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -25,7 +25,11 @@
 /**
  * An event logged when the APF packet socket receives an RA packet.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class RaEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 7f4e4a7..8118fe0 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -32,7 +32,11 @@
 /**
  * An event recorded by NetworkMonitor when sending a probe for finding captive portals.
  * {@hide}
+ * @deprecated The event may not be sent in Android S and above. The events
+ * are logged by a single caller in the system using signature permissions
+ * and that caller is migrating to statsd.
  */
+@Deprecated
 @SystemApi
 public final class ValidationProbeEvent implements IpConnectivityLog.Event {
 
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index aa0f622..85e3fa3 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -29,12 +29,11 @@
 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;
 import android.telephony.TelephonyManager;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -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();
     }
@@ -204,13 +203,13 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            Slog.wtf(TAG, "Should never be reached.");
+            Log.wtf(TAG, "Should never be reached.");
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (!mSettingsUris.contains(uri)) {
-                Slog.wtf(TAG, "Unexpected settings observation: " + uri);
+                Log.wtf(TAG, "Unexpected settings observation: " + uri);
             }
             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/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java
new file mode 100644
index 0000000..4d8cf91
--- /dev/null
+++ b/core/java/android/net/vcn/VcnTransportInfo.java
@@ -0,0 +1,125 @@
+/*
+ * 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.vcn;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.TransportInfo;
+import android.net.wifi.WifiInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.SubscriptionManager;
+
+import java.util.Objects;
+
+/**
+ * VcnTransportInfo contains information about the VCN's underlying transports for SysUi.
+ *
+ * <p>Presence of this class in the NetworkCapabilities.TransportInfo implies that the network is a
+ * VCN.
+ *
+ * <p>VcnTransportInfo must exist on top of either an underlying Wifi or Cellular Network. If the
+ * underlying Network is WiFi, the subId will be {@link
+ * SubscriptionManager#INVALID_SUBSCRIPTION_ID}. If the underlying Network is Cellular, the WifiInfo
+ * will be {@code null}.
+ *
+ * @hide
+ */
+public class VcnTransportInfo implements TransportInfo, Parcelable {
+    @Nullable private final WifiInfo mWifiInfo;
+    private final int mSubId;
+
+    public VcnTransportInfo(@NonNull WifiInfo wifiInfo) {
+        this(wifiInfo, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+    }
+
+    public VcnTransportInfo(int subId) {
+        this(null /* wifiInfo */, subId);
+    }
+
+    private VcnTransportInfo(@Nullable WifiInfo wifiInfo, int subId) {
+        if (wifiInfo == null && subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            throw new IllegalArgumentException(
+                    "VcnTransportInfo requires either non-null WifiInfo or valid subId");
+        }
+
+        mWifiInfo = wifiInfo;
+        mSubId = subId;
+    }
+
+    /**
+     * Get the {@link WifiInfo} for this VcnTransportInfo.
+     *
+     * <p>If the underlying Network for the associated VCN is Cellular, returns null.
+     *
+     * @return the WifiInfo if there is an underlying WiFi connection, else null.
+     */
+    @Nullable
+    public WifiInfo getWifiInfo() {
+        return mWifiInfo;
+    }
+
+    /**
+     * Get the subId for the VCN Network associated with this VcnTransportInfo.
+     *
+     * <p>If the underlying Network for the associated VCN is WiFi, returns {@link
+     * SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+     *
+     * @return the Subscription ID if a cellular underlying Network is present, else {@link
+     *     android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID}.
+     */
+    public int getSubId() {
+        return mSubId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mWifiInfo, mSubId);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof VcnTransportInfo)) return false;
+        final VcnTransportInfo that = (VcnTransportInfo) o;
+
+        return Objects.equals(mWifiInfo, that.mWifiInfo) && mSubId == that.mSubId;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {}
+
+    /** Implement the Parcelable interface */
+    public static final @NonNull Creator<VcnTransportInfo> CREATOR =
+            new Creator<VcnTransportInfo>() {
+                public VcnTransportInfo createFromParcel(Parcel in) {
+                    // return null instead of a default VcnTransportInfo to avoid leaking
+                    // information about this being a VCN Network (instead of macro cellular, etc)
+                    return null;
+                }
+
+                public VcnTransportInfo[] newArray(int size) {
+                    return new VcnTransportInfo[size];
+                }
+            };
+}
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl
new file mode 100644
index 0000000..6cb6ee6
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+/** @hide */
+parcelable VcnUnderlyingNetworkPolicy;
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
new file mode 100644
index 0000000..dd7c86d8
--- /dev/null
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vcn;
+
+import android.annotation.NonNull;
+import android.net.NetworkCapabilities;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * VcnUnderlyingNetworkPolicy represents the Network policy for a VCN-managed Network.
+ *
+ * <p>Transports that are bringing up networks capable of acting as a VCN's underlying network
+ * should query for policy state upon major capability changes (e.g. changing of TRUSTED bit), and
+ * when prompted by VcnManagementService via VcnUnderlyingNetworkPolicyListener.
+ *
+ * @hide
+ */
+public final class VcnUnderlyingNetworkPolicy implements Parcelable {
+    private final boolean mIsTearDownRequested;
+    private final NetworkCapabilities mMergedNetworkCapabilities;
+
+    /**
+     * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters.
+     *
+     * @hide
+     */
+    public VcnUnderlyingNetworkPolicy(
+            boolean isTearDownRequested, @NonNull NetworkCapabilities mergedNetworkCapabilities) {
+        Objects.requireNonNull(
+                mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull");
+
+        mIsTearDownRequested = isTearDownRequested;
+        mMergedNetworkCapabilities = mergedNetworkCapabilities;
+    }
+
+    /**
+     * Returns whether this Carrier VCN policy policy indicates that the underlying Network should
+     * be torn down.
+     */
+    public boolean isTeardownRequested() {
+        return mIsTearDownRequested;
+    }
+
+    /**
+     * Returns the NetworkCapabilities with Carrier VCN policy bits merged into the provided
+     * capabilities.
+     */
+    @NonNull
+    public NetworkCapabilities getMergedNetworkCapabilities() {
+        return mMergedNetworkCapabilities;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false;
+        final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o;
+
+        return mIsTearDownRequested == that.mIsTearDownRequested
+                && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBoolean(mIsTearDownRequested);
+        dest.writeParcelable(mMergedNetworkCapabilities, flags);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR =
+            new Creator<VcnUnderlyingNetworkPolicy>() {
+                public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) {
+                    return new VcnUnderlyingNetworkPolicy(
+                            in.readBoolean(), in.readParcelable(null));
+                }
+
+                public VcnUnderlyingNetworkPolicy[] newArray(int size) {
+                    return new VcnUnderlyingNetworkPolicy[size];
+                }
+            };
+}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 0b2cfdd..bc3d5c4 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -72,4 +72,7 @@
     boolean deviceSupportsNfcSecure();
     boolean setNfcSecure(boolean enable);
 
+    boolean setAlwaysOn(boolean value);
+    boolean isAlwaysOnEnabled();
+    boolean isAlwaysOnSupported();
 }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index a17a5370..e85eb93 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -350,6 +350,22 @@
             "android.nfc.extra.HANDOVER_TRANSFER_STATUS";
 
     /** @hide */
+    public static final String ACTION_ALWAYS_ON_STATE_CHANGED =
+            "android.nfc.action.ALWAYS_ON_STATE_CHANGED";
+
+    /**
+     * Used as an int extra field in {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
+     * intents to request the current power state. Possible values are:
+     * {@link #STATE_OFF},
+     * {@link #STATE_TURNING_ON},
+     * {@link #STATE_ON},
+     * {@link #STATE_TURNING_OFF},
+     * @hide
+     */
+    public static final String EXTRA_ALWAYS_ON_STATE =
+            "android.nfc.extra.ALWAYS_ON_STATE";
+
+    /** @hide */
     public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
     /** @hide */
     public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
@@ -358,6 +374,14 @@
     public static final String EXTRA_HANDOVER_TRANSFER_URI =
             "android.nfc.extra.HANDOVER_TRANSFER_URI";
 
+    /**
+     * Broadcast Action: Notify possible NFC transaction blocked because device is locked.
+     * <p>An external NFC field detected when device locked and SecureNfc enabled.
+     * @hide
+     */
+    public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC =
+            "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
+
     // Guarded by NfcAdapter.class
     static boolean sIsInitialized = false;
     static boolean sHasNfcFeature;
@@ -2211,4 +2235,106 @@
             return mContext.getApplicationInfo().targetSdkVersion;
         }
     }
+
+    /**
+     * Sets NFC controller always on feature.
+     * <p>This API is for the NFCC internal state management. It allows to discriminate
+     * the controller function from the NFC function by keeping the NFC Controller on without
+     * any NFC RF enabled if necessary.
+     * <p>This call is asynchronous. Listen for {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
+     * broadcasts to find out when the operation is complete.
+     * <p>If this returns true, then either NFCC is already on, or
+     * a {@link #ACTION_ALWAYS_ON_STATE_CHANGED} broadcast will be sent to indicate
+     * a state transition.
+     * If this returns false, then there is some problem that prevents an attempt to turn NFCC on.
+     * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
+     * disabled), if false the NFCC will follow completely the Nfc adapter state.
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @return void
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean setAlwaysOn(boolean value) {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.setAlwaysOn(value);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.setAlwaysOn(value);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Checks NFC controller always on feature is enabled.
+     *
+     * @return True if NFC controller always on is enabled, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @hide
+     */
+
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean isAlwaysOnEnabled() {
+        try {
+            return sService.isAlwaysOnEnabled();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.isAlwaysOnEnabled();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Checks if the device supports NFC controller always on functionality.
+     *
+     * @return True if device supports NFC controller always on, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @hide
+     */
+
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean isAlwaysOnSupported() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.isAlwaysOnSupported();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.isAlwaysOnSupported();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index fdccaae..2256365 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -112,7 +112,7 @@
     public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
     /** NFC Forum Tag Type 2 */
     public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
-    /** NFC Forum Tag Type 4 */
+    /** NFC Forum Tag Type 3 */
     public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
     /** NFC Forum Tag Type 4 */
     public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 46ad7b8..305c686 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -22,11 +22,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.ActivityManager;
 import android.content.Context;
-import android.os.Handler;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -41,12 +41,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
 
-/**
- * Class that provides a privileged API to capture and consume bugreports.
- *
- * @hide
- */
-@SystemApi
+/** Class that provides a privileged API to capture and consume bugreports. */
 @SystemService(Context.BUGREPORT_SERVICE)
 public final class BugreportManager {
 
@@ -61,28 +56,30 @@
         mBinder = binder;
     }
 
-    /**
-     * An interface describing the callback for bugreport progress and status.
-     */
+    /** An interface describing the callback for bugreport progress and status. */
     public abstract static class BugreportCallback {
-        /** @hide */
+        /**
+         * Possible error codes taking a bugreport can encounter.
+         *
+         * @hide
+         */
         @Retention(RetentionPolicy.SOURCE)
-        @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
-                BUGREPORT_ERROR_INVALID_INPUT,
-                BUGREPORT_ERROR_RUNTIME,
-                BUGREPORT_ERROR_USER_DENIED_CONSENT,
-                BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
-                BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
-        })
-
-        /** Possible error codes taking a bugreport can encounter */
+        @IntDef(
+                prefix = {"BUGREPORT_ERROR_"},
+                value = {
+                    BUGREPORT_ERROR_INVALID_INPUT,
+                    BUGREPORT_ERROR_RUNTIME,
+                    BUGREPORT_ERROR_USER_DENIED_CONSENT,
+                    BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
+                    BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
+                })
         public @interface BugreportErrorCode {}
 
         /** The input options were invalid */
         public static final int BUGREPORT_ERROR_INVALID_INPUT =
                 IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
 
-        /** A runtime error occured */
+        /** A runtime error occurred */
         public static final int BUGREPORT_ERROR_RUNTIME =
                 IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
 
@@ -100,6 +97,7 @@
 
         /**
          * Called when there is a progress update.
+         *
          * @param progress the progress in [0.0, 100.0]
          */
         public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {}
@@ -114,14 +112,12 @@
          * out, but the bugreport could be available in the internal directory of dumpstate for
          * manual retrieval.
          *
-         * <p> If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the
-         * caller should try later, as only one bugreport can be in progress at a time.
+         * <p>If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the caller
+         * should try later, as only one bugreport can be in progress at a time.
          */
         public void onError(@BugreportErrorCode int errorCode) {}
 
-        /**
-         * Called when taking bugreport finishes successfully.
-         */
+        /** Called when taking bugreport finishes successfully. */
         public void onFinished() {}
 
         /**
@@ -138,20 +134,23 @@
      * seconds to return in the worst case. {@code callback} will receive progress and status
      * updates.
      *
-     * <p>The bugreport artifacts will be copied over to the given file descriptors only if the
-     * user consents to sharing with the calling app.
+     * <p>The bugreport artifacts will be copied over to the given file descriptors only if the user
+     * consents to sharing with the calling app.
      *
      * <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}.
      *
-     * @param bugreportFd file to write the bugreport. This should be opened in write-only,
-     *     append mode.
-     * @param screenshotFd file to write the screenshot, if necessary. This should be opened
-     *     in write-only, append mode.
+     * @param bugreportFd file to write the bugreport. This should be opened in write-only, append
+     *     mode.
+     * @param screenshotFd file to write the screenshot, if necessary. This should be opened in
+     *     write-only, append mode.
      * @param params options that specify what kind of a bugreport should be taken
      * @param callback callback for progress and status updates
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd,
+    public void startBugreport(
+            @NonNull ParcelFileDescriptor bugreportFd,
             @Nullable ParcelFileDescriptor screenshotFd,
             @NonNull BugreportParams params,
             @NonNull @CallbackExecutor Executor executor,
@@ -165,17 +164,21 @@
             boolean isScreenshotRequested = screenshotFd != null;
             if (screenshotFd == null) {
                 // Binder needs a valid File Descriptor to be passed
-                screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"),
-                        ParcelFileDescriptor.MODE_READ_ONLY);
+                screenshotFd =
+                        ParcelFileDescriptor.open(
+                                new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY);
             }
-            DumpstateListener dsListener = new DumpstateListener(executor, callback,
-                    isScreenshotRequested);
+            DumpstateListener dsListener =
+                    new DumpstateListener(executor, callback, isScreenshotRequested);
             // Note: mBinder can get callingUid from the binder transaction.
-            mBinder.startBugreport(-1 /* callingUid */,
+            mBinder.startBugreport(
+                    -1 /* callingUid */,
                     mContext.getOpPackageName(),
                     bugreportFd.getFileDescriptor(),
                     screenshotFd.getFileDescriptor(),
-                    params.getMode(), dsListener, isScreenshotRequested);
+                    params.getMode(),
+                    dsListener,
+                    isScreenshotRequested);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         } catch (FileNotFoundException e) {
@@ -189,13 +192,64 @@
         }
     }
 
-    /*
-     * Cancels a currently running bugreport.
+    /**
+     * Starts a connectivity bugreport.
+     *
+     * <p>The connectivity bugreport is a specialized version of bugreport that only includes
+     * information specifically for debugging connectivity-related issues (e.g. telephony, wi-fi,
+     * and IP networking issues). It is intended primarily for use by OEMs and network providers
+     * such as mobile network operators. In addition to generally excluding information that isn't
+     * targeted to connectivity debugging, this type of bugreport excludes PII and sensitive
+     * information that isn't strictly necessary for connectivity debugging.
+     *
+     * <p>The calling app MUST have a context-specific reason for requesting a connectivity
+     * bugreport, such as detecting a connectivity-related issue. This API SHALL NOT be used to
+     * perform random sampling from a fleet of public end-user devices.
+     *
+     * <p>Calling this API will cause the system to ask the user for consent every single time. The
+     * bugreport artifacts will be copied over to the given file descriptors only if the user
+     * consents to sharing with the calling app.
+     *
+     * <p>This starts a bugreport in the background. However the call itself can take several
+     * seconds to return in the worst case. {@code callback} will receive progress and status
+     * updates.
+     *
+     * <p>Requires that the calling app has carrier privileges (see {@link
+     * android.telephony.TelephonyManager#hasCarrierPrivileges}) on any active subscription.
+     *
+     * @param bugreportFd file to write the bugreport. This should be opened in write-only, append
+     *     mode.
+     * @param callback callback for progress and status updates.
      */
-    @RequiresPermission(android.Manifest.permission.DUMP)
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    public void startConnectivityBugreport(
+            @NonNull ParcelFileDescriptor bugreportFd,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull BugreportCallback callback) {
+        startBugreport(
+                bugreportFd,
+                null /* screenshotFd */,
+                new BugreportParams(BugreportParams.BUGREPORT_MODE_TELEPHONY),
+                executor,
+                callback);
+    }
+
+    /**
+     * Cancels the currently running bugreport.
+     *
+     * <p>Apps are only able to cancel their own bugreports. App A cannot cancel a bugreport started
+     * by app B.
+     *
+     * <p>Requires permission: {@link android.Manifest.permission#DUMP} or that the calling app has
+     * carrier privileges (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on
+     * any active subscription.
+     *
+     * @throws SecurityException if trying to cancel another app's bugreport in progress
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     public void cancelBugreport() {
         try {
-            mBinder.cancelBugreport();
+            mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -205,23 +259,26 @@
      * Requests a bugreport.
      *
      * <p>This requests the platform/system to take a bugreport and makes the final bugreport
-     * available to the user. The user may choose to share it with another app, but the bugreport
-     * is never given back directly to the app that requested it.
+     * available to the user. The user may choose to share it with another app, but the bugreport is
+     * never given back directly to the app that requested it.
      *
-     * @param params           {@link BugreportParams} that specify what kind of a bugreport should
-     *                         be taken, please note that not all kinds of bugreport allow for a
-     *                         progress notification
-     * @param shareTitle       title on the final share notification
+     * @param params {@link BugreportParams} that specify what kind of a bugreport should be taken,
+     *     please note that not all kinds of bugreport allow for a progress notification
+     * @param shareTitle title on the final share notification
      * @param shareDescription description on the final share notification
+     * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle,
+    public void requestBugreport(
+            @NonNull BugreportParams params,
+            @Nullable CharSequence shareTitle,
             @Nullable CharSequence shareDescription) {
         try {
             String title = shareTitle == null ? null : shareTitle.toString();
             String description = shareDescription == null ? null : shareDescription.toString();
-            ActivityManager.getService().requestBugReportWithDescription(title, description,
-                    params.getMode());
+            ActivityManager.getService()
+                    .requestBugReportWithDescription(title, description, params.getMode());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -232,8 +289,8 @@
         private final BugreportCallback mCallback;
         private final boolean mIsScreenshotRequested;
 
-        DumpstateListener(Executor executor, BugreportCallback callback,
-                boolean isScreenshotRequested) {
+        DumpstateListener(
+                Executor executor, BugreportCallback callback, boolean isScreenshotRequested) {
             mExecutor = executor;
             mCallback = callback;
             mIsScreenshotRequested = isScreenshotRequested;
@@ -243,9 +300,7 @@
         public void onProgress(int progress) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onProgress(progress);
-                });
+                mExecutor.execute(() -> mCallback.onProgress(progress));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -255,9 +310,7 @@
         public void onError(int errorCode) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onError(errorCode);
-                });
+                mExecutor.execute(() -> mCallback.onError(errorCode));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -267,9 +320,7 @@
         public void onFinished() throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onFinished();
-                });
+                mExecutor.execute(() -> mCallback.onFinished());
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -284,20 +335,19 @@
             Handler mainThreadHandler = new Handler(Looper.getMainLooper());
             mainThreadHandler.post(
                     () -> {
-                        int message = success ? R.string.bugreport_screenshot_success_toast
-                                : R.string.bugreport_screenshot_failure_toast;
+                        int message =
+                                success
+                                        ? R.string.bugreport_screenshot_success_toast
+                                        : R.string.bugreport_screenshot_failure_toast;
                         Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
                     });
         }
 
         @Override
-        public void onUiIntensiveBugreportDumpsFinished()
-                throws RemoteException {
+        public void onUiIntensiveBugreportDumpsFinished() throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mExecutor.execute(() -> {
-                    mCallback.onEarlyReportFinished();
-                });
+                mExecutor.execute(() -> mCallback.onEarlyReportFinished());
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/core/java/android/os/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/UserManager.java b/core/java/android/os/UserManager.java
index 67d5f5f..59302afd 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1992,13 +1992,16 @@
     }
 
     /**
-     * Checks if specified user can have restricted profile.
+     * Checks if the calling context user can have a restricted profile.
+     * @return whether the context user can have a restricted profile.
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
-    public boolean canHaveRestrictedProfile(@UserIdInt int userId) {
+    @UserHandleAware
+    public boolean canHaveRestrictedProfile() {
         try {
-            return mService.canHaveRestrictedProfile(userId);
+            return mService.canHaveRestrictedProfile(mUserId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -2020,6 +2023,25 @@
     }
 
     /**
+     * Get the parent of a restricted profile.
+     *
+     * @return the parent of the user or {@code null} if the user is not restricted profile
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+            Manifest.permission.CREATE_USERS})
+    @UserHandleAware
+    public @Nullable UserHandle getRestrictedProfileParent() {
+        final UserInfo info = getUserInfo(mUserId);
+        if (info == null) return null;
+        if (!info.isRestricted()) return null;
+        final int parent = info.restrictedProfileParentId;
+        if (parent == UserHandle.USER_NULL) return null;
+        return UserHandle.of(parent);
+    }
+
+    /**
      * Checks if a user is a guest user.
      * @return whether user is a guest user.
      * @hide
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index df3c4d5..51856d8 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -50,6 +50,8 @@
     public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
     public static final int FLAG_SD = 1 << 2;
     public static final int FLAG_USB = 1 << 3;
+    /** The FLAG_STUB_VISIBLE is set from vold, which gets the flag from outside (e.g., ChromeOS) */
+    public static final int FLAG_STUB_VISIBLE = 1 << 6;
 
     public final String id;
     @UnsupportedAppUsage
@@ -152,6 +154,10 @@
         return (flags & FLAG_USB) != 0;
     }
 
+    public boolean isStubVisible() {
+        return (flags & FLAG_STUB_VISIBLE) != 0;
+    }
+
     @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 99bdfd1..4669b20 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -195,4 +195,5 @@
     void abortChanges(in String message, boolean retry) = 87;
     void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
     void fixupAppDir(in String path) = 89;
+    void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
 }
diff --git a/core/java/android/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/resumeonreboot/IResumeOnRebootService.aidl b/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl
new file mode 100644
index 0000000..d9b403c
--- /dev/null
+++ b/core/java/android/service/resumeonreboot/IResumeOnRebootService.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.service.resumeonreboot;
+
+import android.os.RemoteCallback;
+
+/** @hide */
+interface IResumeOnRebootService {
+    oneway void wrapSecret(in byte[] unwrappedBlob, in long lifeTimeInMillis, in RemoteCallback resultCallback);
+    oneway void unwrap(in byte[] wrappedBlob, in RemoteCallback resultCallback);
+}
\ No newline at end of file
diff --git a/core/java/android/service/resumeonreboot/ResumeOnRebootService.java b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
new file mode 100644
index 0000000..4ebaa96
--- /dev/null
+++ b/core/java/android/service/resumeonreboot/ResumeOnRebootService.java
@@ -0,0 +1,164 @@
+/*
+ * 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.service.resumeonreboot;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+
+import com.android.internal.os.BackgroundThread;
+
+import java.io.IOException;
+
+/**
+ * Base class for service that provides wrapping/unwrapping of the opaque blob needed for
+ * ResumeOnReboot operation. The package needs to provide a wrap/unwrap implementation for handling
+ * the opaque blob, that's secure even when on device keystore and clock is compromised. This can
+ * be achieved by using tamper-resistant hardware such as a secure element with a secure clock, or
+ * using a remote server to store and retrieve data and manage timing.
+ *
+ * <p>To extend this class, you must declare the service in your manifest file with the
+ * {@link android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE} permission,
+ * include an intent filter with the {@link #SERVICE_INTERFACE} action and mark the service as
+ * direct-boot aware. In addition, the package that contains the service must be granted
+ * {@link android.Manifest.permission#BIND_RESUME_ON_REBOOT_SERVICE}.
+ * For example:</p>
+ * <pre>
+ *     &lt;service android:name=".FooResumeOnRebootService"
+ *             android:exported="true"
+ *             android:priority="100"
+ *             android:directBootAware="true"
+ *             android:permission="android.permission.BIND_RESUME_ON_REBOOT_SERVICE"&gt;
+ *         &lt;intent-filter&gt;
+ *             &lt;action android:name="android.service.resumeonreboot.ResumeOnRebootService" /&gt;
+ *         &lt;/intent-filter&gt;
+ *     &lt;/service&gt;
+ * </pre>
+ *
+ * //TODO: Replace this with public link when available.
+ *
+ * @hide
+ * @see
+ * <a href="https://goto.google.com/server-based-ror">https://goto.google.com/server-based-ror</a>
+ */
+@SystemApi
+public abstract class ResumeOnRebootService extends Service {
+
+    /**
+     * The intent that the service must respond to. Add it to the intent filter of the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE =
+            "android.service.resumeonreboot.ResumeOnRebootService";
+    /** @hide */
+    public static final String UNWRAPPED_BLOB_KEY = "unrwapped_blob_key";
+    /** @hide */
+    public static final String WRAPPED_BLOB_KEY = "wrapped_blob_key";
+    /** @hide */
+    public static final String EXCEPTION_KEY = "exception_key";
+
+    private final Handler mHandler = BackgroundThread.getHandler();
+
+    /**
+     * Implementation for wrapping the opaque blob used for resume-on-reboot prior to
+     * reboot. The service should not assume any structure of the blob to be wrapped. The
+     * implementation should wrap the opaque blob in a reasonable time or throw {@link IOException}
+     * if it's unable to complete the action.
+     *
+     * @param blob             The opaque blob with size on the order of 100 bytes.
+     * @param lifeTimeInMillis The life time of the blob. This must be strictly enforced by the
+     *                         implementation and any attempt to unWrap the wrapped blob returned by
+     *                         this function after expiration should
+     *                         fail.
+     * @return Wrapped blob to be persisted across reboot with size on the order of 100 bytes.
+     * @throws IOException if the implementation is unable to wrap the blob successfully.
+     */
+    @NonNull
+    public abstract byte[] onWrap(@NonNull byte[] blob, @DurationMillisLong long lifeTimeInMillis)
+            throws IOException;
+
+    /**
+     * Implementation for unwrapping the wrapped blob used for resume-on-reboot after reboot. This
+     * operation would happen after reboot during direct boot mode (i.e before device is unlocked
+     * for the first time). The implementation should unwrap the wrapped blob in a reasonable time
+     * and returns the result or throw {@link IOException} if it's unable to complete the action
+     * and {@link IllegalArgumentException} if {@code unwrapBlob} fails because the wrappedBlob is
+     * stale.
+     *
+     * @param wrappedBlob The wrapped blob with size on the order of 100 bytes.
+     * @return Unwrapped blob used for resume-on-reboot with the size on the order of 100 bytes.
+     * @throws IOException if the implementation is unable to unwrap the wrapped blob successfully.
+     */
+    @NonNull
+    public abstract byte[] onUnwrap(@NonNull byte[] wrappedBlob) throws IOException;
+
+    private final android.service.resumeonreboot.IResumeOnRebootService mInterface =
+            new android.service.resumeonreboot.IResumeOnRebootService.Stub() {
+
+                @Override
+                public void wrapSecret(byte[] unwrappedBlob,
+                        @DurationMillisLong long lifeTimeInMillis,
+                        RemoteCallback resultCallback) throws RemoteException {
+                    mHandler.post(() -> {
+                        try {
+                            byte[] wrappedBlob = onWrap(unwrappedBlob,
+                                    lifeTimeInMillis);
+                            Bundle bundle = new Bundle();
+                            bundle.putByteArray(WRAPPED_BLOB_KEY, wrappedBlob);
+                            resultCallback.sendResult(bundle);
+                        } catch (Throwable e) {
+                            Bundle bundle = new Bundle();
+                            bundle.putParcelable(EXCEPTION_KEY, new ParcelableException(e));
+                            resultCallback.sendResult(bundle);
+                        }
+                    });
+                }
+
+                @Override
+                public void unwrap(byte[] wrappedBlob, RemoteCallback resultCallback)
+                        throws RemoteException {
+                    mHandler.post(() -> {
+                        try {
+                            byte[] unwrappedBlob = onUnwrap(wrappedBlob);
+                            Bundle bundle = new Bundle();
+                            bundle.putByteArray(UNWRAPPED_BLOB_KEY, unwrappedBlob);
+                            resultCallback.sendResult(bundle);
+                        } catch (Throwable e) {
+                            Bundle bundle = new Bundle();
+                            bundle.putParcelable(EXCEPTION_KEY, new ParcelableException(e));
+                            resultCallback.sendResult(bundle);
+                        }
+                    });
+                }
+            };
+
+    @Nullable
+    @Override
+    public IBinder onBind(@Nullable Intent intent) {
+        return mInterface.asBinder();
+    }
+}
diff --git a/core/java/android/service/search/OWNERS b/core/java/android/service/search/OWNERS
new file mode 100644
index 0000000..92835c2
--- /dev/null
+++ b/core/java/android/service/search/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS
index 10b8b76..0471e29 100644
--- a/core/java/android/service/textservice/OWNERS
+++ b/core/java/android/service/textservice/OWNERS
@@ -1,3 +1,3 @@
-# Bug component: 34867
+# Bug component: 816455
 
-include ../../inputmethodservice/OWNERS
\ No newline at end of file
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index d6ae434..03d3755 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -17,7 +17,10 @@
 package android.telephony;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -29,9 +32,16 @@
 import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.DataActivityType;
+import android.telephony.Annotation.DisconnectCauses;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseDisconnectCauses;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.SrvccState;
+import android.telephony.NetworkRegistrationInfo.Domain;
+import android.telephony.TelephonyManager.DataEnabledReason;
+import android.telephony.TelephonyManager.DataState;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
 
@@ -40,6 +50,8 @@
 
 import dalvik.system.VMRuntime;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.List;
 import java.util.Map;
@@ -114,7 +126,9 @@
      *
      *  @see #onServiceStateChanged
      *  @see ServiceState
+     *  @deprecated Use {@link ServiceStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_SERVICE_STATE                            = 0x00000001;
 
     /**
@@ -122,8 +136,7 @@
      * {@more}
      *
      * @see #onSignalStrengthChanged
-     *
-     * @deprecated by {@link #LISTEN_SIGNAL_STRENGTHS}
+     * @deprecated Use {@link SignalStrengthsChangedListener} instead.
      */
     @Deprecated
     public static final int LISTEN_SIGNAL_STRENGTH                          = 0x00000002;
@@ -139,7 +152,9 @@
      * voicemail icon.
      *
      * @see #onMessageWaitingIndicatorChanged
+     * @deprecated Use {@link MessageWaitingIndicatorChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_MESSAGE_WAITING_INDICATOR                = 0x00000004;
 
     /**
@@ -150,7 +165,9 @@
      * {@link TelephonyManager#hasCarrierPrivileges}).
      *
      * @see #onCallForwardingIndicatorChanged
+     * @deprecated Use {@link CallForwardingIndicatorChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CALL_FORWARDING_INDICATOR                = 0x00000008;
 
     /**
@@ -166,7 +183,9 @@
      * instead.
      *
      * @see #onCellLocationChanged
+     * @deprecated Use {@link CellLocationChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CELL_LOCATION                            = 0x00000010;
 
     /**
@@ -174,14 +193,18 @@
      * {@more}
      *
      * @see #onCallStateChanged
+     * @deprecated Use {@link CallStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CALL_STATE                               = 0x00000020;
 
     /**
      * Listen for changes to the data connection state (cellular).
      *
      * @see #onDataConnectionStateChanged
+     * @deprecated Use {@link DataConnectionStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_DATA_CONNECTION_STATE                    = 0x00000040;
 
     /**
@@ -192,7 +215,9 @@
      * data-traffic icon.
      *
      * @see #onDataActivity
+     * @deprecated Use {@link DataActivityListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_DATA_ACTIVITY                            = 0x00000080;
 
     /**
@@ -202,7 +227,9 @@
      * icon.
      *
      * @see #onSignalStrengthsChanged
+     * @deprecated Use {@link SignalStrengthsChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_SIGNAL_STRENGTHS                         = 0x00000100;
 
     /**
@@ -212,7 +239,9 @@
      * @see #onSignalStrengthsChanged
      *
      * @hide
+     * @deprecated Use {@link AlwaysReportedSignalStrengthChangedListener} instead.
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
     public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH          = 0x00000200;
 
@@ -223,7 +252,9 @@
      * permission.
      *
      * @see #onCellInfoChanged
+     * @deprecated Use {@link CellInfoChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CELL_INFO = 0x00000400;
 
     /**
@@ -235,8 +266,10 @@
      * (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
      * @hide
+     * @deprecated Use {@link PreciseCallStateChangedListener} instead.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     @SystemApi
     public static final int LISTEN_PRECISE_CALL_STATE                       = 0x00000800;
 
@@ -248,8 +281,10 @@
      * (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
      * @see #onPreciseDataConnectionStateChanged
+     * @deprecated Use {@link PreciseDataConnectionStateChangedListener} instead.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE            = 0x00001000;
 
     /**
@@ -259,7 +294,7 @@
      * READ_PRECISE_PHONE_STATE}
      * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
      *
-     * @deprecated Use {@link TelephonyManager#getModemActivityInfo()}
+     * @deprecated Use {@link TelephonyManager#requestModemActivityInfo} instead.
      * @hide
      */
     @Deprecated
@@ -272,7 +307,9 @@
      *
      * @see #onServiceStateChanged(ServiceState)
      * @hide
+     * @deprecated Use {@link SrvccStateChangedListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public static final int LISTEN_SRVCC_STATE_CHANGED                     = 0x00004000;
@@ -290,10 +327,11 @@
     /**
      * Listen for carrier network changes indicated by a carrier app.
      *
-     * @see #onCarrierNetworkRequest
-     * @see TelephonyManager#notifyCarrierNetworkChange(boolean)
+     * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
      * @hide
+     * @deprecated Use {@link CarrierNetworkChangeListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CARRIER_NETWORK_CHANGE                   = 0x00010000;
 
     /**
@@ -312,7 +350,9 @@
      *
      * @see #onVoiceActivationStateChanged
      * @hide
+     * @deprecated Use {@link VoiceActivationStateChangedListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public static final int LISTEN_VOICE_ACTIVATION_STATE                   = 0x00020000;
@@ -324,20 +364,24 @@
      * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
      * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
      * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
-     * {@more}
+     *
      * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
      * fully activated
      *
      * @see #onDataActivationStateChanged
      * @hide
+     * @deprecated Use {@link DataActivationStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_DATA_ACTIVATION_STATE                   = 0x00040000;
 
     /**
      *  Listen for changes to the user mobile data state
      *
      *  @see #onUserMobileDataStateChanged
+     *  @deprecated Use {@link UserMobileDataStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_USER_MOBILE_DATA_STATE                  = 0x00080000;
 
     /**
@@ -348,7 +392,9 @@
      *  {@link TelephonyManager#hasCarrierPrivileges}).
      *
      *  @see #onDisplayInfoChanged
+     * @deprecated Use {@link DisplayInfoChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_DISPLAY_INFO_CHANGED = 0x00100000;
 
     /**
@@ -356,7 +402,9 @@
      *
      *  @see #onPhoneCapabilityChanged
      *  @hide
+     *  @deprecated Use {@link PhoneCapabilityChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_PHONE_CAPABILITY_CHANGE                 = 0x00200000;
 
     /**
@@ -366,17 +414,19 @@
      *  subscription user selected as default data subscription in DSDS mode.
      *
      *  @see #onActiveDataSubscriptionIdChanged
+     *  @deprecated Use {@link ActiveDataSubscriptionIdChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 0x00400000;
 
     /**
      *  Listen for changes to the radio power state.
      *
-     * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
-     *
      *  @see #onRadioPowerStateChanged
      *  @hide
+     *  @deprecated Use {@link RadioPowerStateChangedListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public static final int LISTEN_RADIO_POWER_STATE_CHANGED               = 0x00800000;
@@ -386,7 +436,10 @@
      *
      * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
      * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @deprecated Use {@link EmergencyNumberListChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_EMERGENCY_NUMBER_LIST                   = 0x01000000;
 
     /**
@@ -397,8 +450,10 @@
      * or the calling app has carrier privileges
      * (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
+     * @deprecated Use {@link CallDisconnectCauseChangedListener} instead.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_CALL_DISCONNECT_CAUSES                  = 0x02000000;
 
     /**
@@ -410,9 +465,11 @@
      *
      * @see #onCallAttributesChanged
      * @hide
+     * @deprecated Use {@link CallAttributesChangedListener} instead.
      */
+    @Deprecated
     @SystemApi
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_CALL_ATTRIBUTES_CHANGED                 = 0x04000000;
 
     /**
@@ -424,18 +481,20 @@
      * (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
      * @see #onImsCallDisconnectCauseChanged(ImsReasonInfo)
+     * @deprecated Use {@link ImsCallDisconnectCauseChangedListener} instead.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES              = 0x08000000;
 
     /**
      * Listen for the emergency number placed from an outgoing call.
      *
-     * <p>Requires permission {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
-     *
      * @see #onOutgoingEmergencyCall
      * @hide
+     * @deprecated Use {@link OutgoingEmergencyCallListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
     public static final int LISTEN_OUTGOING_EMERGENCY_CALL                  = 0x10000000;
@@ -443,11 +502,11 @@
     /**
      * Listen for the emergency number placed from an outgoing SMS.
      *
-     * <p>Requires permission {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
-     *
      * @see #onOutgoingEmergencySms
      * @hide
+     * @deprecated Use {@link OutgoingEmergencySmsListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
     public static final int LISTEN_OUTGOING_EMERGENCY_SMS                   = 0x20000000;
@@ -466,7 +525,9 @@
      * of whether the calling app has carrier privileges.
      *
      * @see #onRegistrationFailed
+     * @deprecated Use {@link RegistrationFailedListener} instead.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000;
 
@@ -480,10 +541,525 @@
      * of whether the calling app has carrier privileges.
      *
      * @see #onBarringInfoChanged
+     * @deprecated Use {@link BarringInfoChangedListener} instead.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_BARRING_INFO = 0x80000000;
 
+    /**
+     *  Event for changes to the network service state (cellular).
+     *
+     *  @see ServiceStateChangedListener#onServiceStateChanged
+     *  @see ServiceState
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_SERVICE_STATE_CHANGED = 1;
+
+    /**
+     * Event for changes to the network signal strength (cellular).
+     *
+     * @see SignalStrengthsChangedListener#onSignalStrengthsChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2;
+
+    /**
+     * Event for changes to the message-waiting indicator.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
+     * the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     * <p>
+     * Example: The status bar uses this to determine when to display the
+     * voicemail icon.
+     *
+     * @see MessageWaitingIndicatorChangedListener#onMessageWaitingIndicatorChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3;
+
+    /**
+     * Event for changes to the call-forwarding indicator.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
+     * the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see CallForwardingIndicatorChangedListener#onCallForwardingIndicatorChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4;
+
+    /**
+     * Event for changes to the device's cell location. Note that
+     * this will result in frequent callbacks to the listener.
+     *
+     * If you need regular location updates but want more control over
+     * the update interval or location precision, you can set up a listener
+     * through the {@link android.location.LocationManager location manager}
+     * instead.
+     *
+     * @see CellLocationChangedListener#onCellLocationChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+    public static final int EVENT_CELL_LOCATION_CHANGED = 5;
+
+    /**
+     * Event for changes to the device call state.
+     *
+     * @see CallStateChangedListener#onCallStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+    public static final int EVENT_CALL_STATE_CHANGED = 6;
+
+    /**
+     * Event for changes to the data connection state (cellular).
+     *
+     * @see DataConnectionStateChangedListener#onDataConnectionStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7;
+
+    /**
+     * Event for changes to the direction of data traffic on the data
+     * connection (cellular).
+     *
+     * Example: The status bar uses this to display the appropriate
+     * data-traffic icon.
+     *
+     * @see DataActivityListener#onDataActivity
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_DATA_ACTIVITY_CHANGED = 8;
+
+    /**
+     * Event for changes to the network signal strengths (cellular).
+     * <p>
+     * Example: The status bar uses this to control the signal-strength
+     * icon.
+     *
+     * @see SignalStrengthsChangedListener#onSignalStrengthsChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9;
+
+    /**
+     * Event for changes of the network signal strengths (cellular) always reported from modem,
+     * even in some situations such as the screen of the device is off.
+     *
+     * @see AlwaysReportedSignalStrengthChangedListener#onSignalStrengthsChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+    public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10;
+
+    /**
+     * Event for changes to observed cell info.
+     *
+     * @see CellInfoChangedListener#onCellInfoChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+    public static final int EVENT_CELL_INFO_CHANGED = 11;
+
+    /**
+     * Event for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
+     * background and foreground calls.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see PreciseCallStateChangedListener#onPreciseCallStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12;
+
+    /**
+     * Event for {@link PreciseDataConnectionState} on the data connection (cellular).
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see PreciseDataConnectionStateChangedListener#onPreciseDataConnectionStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13;
+
+    /**
+     * Event for real time info for all data connections (cellular)).
+     *
+     * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
+     *
+     * @deprecated Use {@link TelephonyManager#requestModemActivityInfo}
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14;
+
+    /**
+     * Event for OEM hook raw event
+     *
+     * @see #onOemHookRawEvent
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public static final int EVENT_OEM_HOOK_RAW = 15;
+
+    /**
+     * Event for changes to the SRVCC state of the active call.
+     *
+     * @see SrvccStateChangedListener#onSrvccStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public static final int EVENT_SRVCC_STATE_CHANGED = 16;
+
+    /**
+     * Event for carrier network changes indicated by a carrier app.
+     *
+     * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
+     * @see CarrierNetworkChangeListener#onCarrierNetworkChange
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_CARRIER_NETWORK_CHANGED = 17;
+
+    /**
+     * Event for changes to the sim voice activation state
+     *
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+     *
+     * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been
+     * fully activated
+     *
+     * @see VoiceActivationStateChangedListener#onVoiceActivationStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18;
+
+    /**
+     * Event for changes to the sim data activation state
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+     *
+     * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
+     * fully activated
+     *
+     * @see DataActivationStateChangedListener#onDataActivationStateChanged
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19;
+
+    /**
+     *  Event for changes to the user mobile data state
+     *
+     *  @see UserMobileDataStateChangedListener#onUserMobileDataStateChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20;
+
+    /**
+     *  Event for display info changed event.
+     *
+     *  @see DisplayInfoChangedListener#onDisplayInfoChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    public static final int EVENT_DISPLAY_INFO_CHANGED = 21;
+
+    /**
+     *  Event for changes to the phone capability.
+     *
+     *  @see PhoneCapabilityChangedListener#onPhoneCapabilityChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22;
+
+    /**
+     *  Event for changes to active data subscription ID. Active data subscription is
+     *  the current subscription used to setup Cellular Internet data. For example,
+     *  it could be the current active opportunistic subscription in use, or the
+     *  subscription user selected as default data subscription in DSDS mode.
+     *
+     *  <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+     *  app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     *  @see ActiveDataSubscriptionIdChangedListener#onActiveDataSubscriptionIdChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23;
+
+    /**
+     *  Event for changes to the radio power state.
+     *
+     *  @see RadioPowerStateChangedListener#onRadioPowerStateChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24;
+
+    /**
+     * Event for changes to emergency number list based on all active subscriptions.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+     * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     *  @see EmergencyNumberListChangedListener#onEmergencyNumberListChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25;
+
+    /**
+     * Event for call disconnect causes which contains {@link DisconnectCause} and
+     * {@link PreciseDisconnectCause}.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     *  @see CallDisconnectCauseChangedListener#onCallDisconnectCauseChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26;
+
+    /**
+     * Event for changes to the call attributes of a currently active call.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see CallAttributesChangedListener#onCallAttributesChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27;
+
+    /**
+     * Event for IMS call disconnect causes which contains
+     * {@link android.telephony.ims.ImsReasonInfo}
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see ImsCallDisconnectCauseChangedListener#onImsCallDisconnectCauseChanged(ImsReasonInfo)
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28;
+
+    /**
+     * Event for the emergency number placed from an outgoing call.
+     *
+     * @see OutgoingEmergencyCallListener#onOutgoingEmergencyCall
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+    public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29;
+
+    /**
+     * Event for the emergency number placed from an outgoing SMS.
+     *
+     * @see OutgoingEmergencySmsListener#onOutgoingEmergencySms
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+    public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30;
+
+    /**
+     * Event for registration failures.
+     *
+     * Event for indications that a registration procedure has failed in either the CS or PS
+     * domain. This indication does not necessarily indicate a change of service state, which should
+     * be tracked via {@link #EVENT_SERVICE_STATE_CHANGED}.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+     * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+     * of whether the calling app has carrier privileges.
+     *
+     * @see RegistrationFailedListener#onRegistrationFailed
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {
+            Manifest.permission.READ_PRECISE_PHONE_STATE,
+            Manifest.permission.ACCESS_FINE_LOCATION
+    })
+    public static final int EVENT_REGISTRATION_FAILURE = 31;
+
+    /**
+     * Event for Barring Information for the current registered / camped cell.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+     * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+     * of whether the calling app has carrier privileges.
+     *
+     * @see BarringInfoChangedListener#onBarringInfoChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {
+            Manifest.permission.READ_PRECISE_PHONE_STATE,
+            Manifest.permission.ACCESS_FINE_LOCATION
+    })
+    public static final int EVENT_BARRING_INFO_CHANGED = 32;
+
+    /**
+     * Event for changes to the physical channel configuration.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see PhysicalChannelConfigChangedListener#onPhysicalChannelConfigChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33;
+
+    /**
+     * Event for changes to the data enabled.
+     *
+     * Event for indications that the enabled status of current data has changed.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see DataEnabledChangedListener#onDataEnabledChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_DATA_ENABLED_CHANGED = 34;
+
+    /** @hide */
+    @IntDef(prefix = { "EVENT_" }, value = {
+            EVENT_SERVICE_STATE_CHANGED,
+            EVENT_SIGNAL_STRENGTH_CHANGED,
+            EVENT_MESSAGE_WAITING_INDICATOR_CHANGED,
+            EVENT_CALL_FORWARDING_INDICATOR_CHANGED,
+            EVENT_CELL_LOCATION_CHANGED,
+            EVENT_CALL_STATE_CHANGED,
+            EVENT_DATA_CONNECTION_STATE_CHANGED,
+            EVENT_DATA_ACTIVITY_CHANGED,
+            EVENT_SIGNAL_STRENGTHS_CHANGED,
+            EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED,
+            EVENT_CELL_INFO_CHANGED,
+            EVENT_PRECISE_CALL_STATE_CHANGED,
+            EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED,
+            EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED,
+            EVENT_OEM_HOOK_RAW,
+            EVENT_SRVCC_STATE_CHANGED,
+            EVENT_CARRIER_NETWORK_CHANGED,
+            EVENT_VOICE_ACTIVATION_STATE_CHANGED,
+            EVENT_DATA_ACTIVATION_STATE_CHANGED,
+            EVENT_USER_MOBILE_DATA_STATE_CHANGED,
+            EVENT_DISPLAY_INFO_CHANGED,
+            EVENT_PHONE_CAPABILITY_CHANGED,
+            EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED,
+            EVENT_RADIO_POWER_STATE_CHANGED,
+            EVENT_EMERGENCY_NUMBER_LIST_CHANGED,
+            EVENT_CALL_DISCONNECT_CAUSE_CHANGED,
+            EVENT_CALL_ATTRIBUTES_CHANGED,
+            EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED,
+            EVENT_OUTGOING_EMERGENCY_CALL,
+            EVENT_OUTGOING_EMERGENCY_SMS,
+            EVENT_REGISTRATION_FAILURE,
+            EVENT_BARRING_INFO_CHANGED,
+            EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED,
+            EVENT_DATA_ENABLED_CHANGED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TelephonyEvent {}
+
     /*
      * Subscription used to listen to the phone state changes
      * @hide
@@ -495,13 +1071,19 @@
     /**
      * @hide
      */
+    //TODO: The maxTargetSdk should be S if the build time tool updates it.
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    @UnsupportedAppUsage
-    public final IPhoneStateListener callback;
+    @UnsupportedAppUsage(
+            maxTargetSdk = Build.VERSION_CODES.R,
+            publicAlternatives = "Use {@code TelephonyManager#registerPhoneStateListener(" +
+                    "Executor, PhoneStateListener)} instead")
+    public IPhoneStateListener callback;
 
     /**
      * Create a PhoneStateListener for the Phone with the default subscription.
-     * This class requires Looper.myLooper() not return null.
+     * If this is created for use with deprecated API
+     * {@link TelephonyManager#listen(PhoneStateListener, int)}, then this class requires
+     * Looper.myLooper() not return null.
      */
     public PhoneStateListener() {
         this(null, Looper.myLooper());
@@ -539,7 +1121,10 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public PhoneStateListener(Integer subId, Looper looper) {
-        this(subId, new HandlerExecutor(new Handler(looper)));
+        if (looper != null) {
+            setExecutor(new HandlerExecutor(new Handler(looper)));
+        }
+        mSubId = subId;
         if (subId != null && VMRuntime.getRuntime().getTargetSdkVersion()
                 >= Build.VERSION_CODES.Q) {
             throw new IllegalArgumentException("PhoneStateListener with subId: "
@@ -554,17 +1139,744 @@
      * The Executor must not be null.
      *
      * @param executor a non-null Executor that will execute callbacks for the PhoneStateListener.
+     * @deprecated Use
+     * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)} instead.
      */
+    @Deprecated
     public PhoneStateListener(@NonNull Executor executor) {
-        this(null, executor);
+        setExecutor(executor);
+        mSubId = null;
     }
 
-    private PhoneStateListener(Integer subId, Executor e) {
-        if (e == null) {
+    private @NonNull Executor mExecutor;
+
+    /**
+     * @hide
+     */
+    public void setExecutor(@NonNull @CallbackExecutor Executor executor) {
+        if (executor == null) {
             throw new IllegalArgumentException("PhoneStateListener Executor must be non-null");
         }
-        mSubId = subId;
-        callback = new IPhoneStateListenerStub(this, e);
+        mExecutor = executor;
+        callback = new IPhoneStateListenerStub(this, mExecutor);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isExecutorSet() {
+        return mExecutor != null;
+    }
+
+    /**
+     * Interface for service state listener.
+     */
+    public interface ServiceStateChangedListener {
+        /**
+         * Callback invoked when device service state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * The instance of {@link ServiceState} passed as an argument here will have various
+         * levels of location information stripped from it depending on the location permissions
+         * that your app holds.
+         * Only apps holding the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission will
+         * receive all the information in {@link ServiceState}.
+         *
+         * @see ServiceState#STATE_EMERGENCY_ONLY
+         * @see ServiceState#STATE_IN_SERVICE
+         * @see ServiceState#STATE_OUT_OF_SERVICE
+         * @see ServiceState#STATE_POWER_OFF
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onServiceStateChanged(@NonNull ServiceState serviceState);
+    }
+
+    /**
+     * Interface for message waiting indicator listener.
+     */
+    public interface MessageWaitingIndicatorChangedListener {
+        /**
+         * Callback invoked when the message-waiting indicator changes on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onMessageWaitingIndicatorChanged(boolean mwi);
+    }
+
+    /**
+     * Interface for call-forwarding indicator listener.
+     */
+    public interface CallForwardingIndicatorChangedListener {
+        /**
+         * Callback invoked when the call-forwarding indicator changes on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onCallForwardingIndicatorChanged(boolean cfi);
+    }
+
+    /**
+     * Interface for device cell location listener.
+     */
+    public interface CellLocationChangedListener {
+        /**
+         * Callback invoked when device cell location changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+        public void onCellLocationChanged(@NonNull CellLocation location);
+    }
+
+    /**
+     * Interface for call state listener.
+     */
+    public interface CallStateChangedListener {
+        /**
+         * Callback invoked when device call state changes.
+         * <p>
+         * Reports the state of Telephony (mobile) calls on the device for the registered s
+         * ubscription.
+         * <p>
+         * Note: the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to all subIds.
+         * <p>
+         * Note: The state returned here may differ from that returned by
+         * {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that
+         * calling {@link TelephonyManager#getCallState()} from within this callback may return a
+         * different state than the callback reports.
+         *
+         * @param state call state
+         * @param phoneNumber call phone number. If application does not have
+         * {@link android.Manifest.permission#READ_CALL_LOG} permission or carrier
+         * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
+         * passed as an argument.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+        public void onCallStateChanged(@CallState int state, @Nullable String phoneNumber);
+    }
+
+    /**
+     * Interface for data connection state listener.
+     */
+    public interface DataConnectionStateChangedListener {
+        /**
+         * Callback invoked when connection state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @see TelephonyManager#DATA_DISCONNECTED
+         * @see TelephonyManager#DATA_CONNECTING
+         * @see TelephonyManager#DATA_CONNECTED
+         * @see TelephonyManager#DATA_SUSPENDED
+         *
+         * @param state is the current state of data connection.
+         * @param networkType is the current network type of data connection.
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onDataConnectionStateChanged(@DataState int state,
+                                                 @NetworkType int networkType);
+    }
+
+    /**
+     * Interface for data activity state listener.
+     */
+    public interface DataActivityListener {
+        /**
+         * Callback invoked when data activity state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @see TelephonyManager#DATA_ACTIVITY_NONE
+         * @see TelephonyManager#DATA_ACTIVITY_IN
+         * @see TelephonyManager#DATA_ACTIVITY_OUT
+         * @see TelephonyManager#DATA_ACTIVITY_INOUT
+         * @see TelephonyManager#DATA_ACTIVITY_DORMANT
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onDataActivity(@DataActivityType int direction);
+    }
+
+    /**
+     * Interface for network signal strengths listener.
+     */
+    public interface SignalStrengthsChangedListener {
+        /**
+         * Callback invoked when network signal strengths changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+    }
+
+    /**
+     * Interface for network signal strengths listener which always reported from modem.
+     */
+    public interface AlwaysReportedSignalStrengthChangedListener {
+        /**
+         * Callback always invoked from modem when network signal strengths changes on the
+         * registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+        public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+    }
+
+    /**
+     * Interface for cell info listener.
+     */
+    public interface CellInfoChangedListener {
+        /**
+         * Callback invoked when a observed cell info has changed or new cells have been added
+         * or removed on the registered subscription.
+         * Note, the registration subscription ID s from {@link TelephonyManager} object
+         * which registersPhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param cellInfo is the list of currently visible cells.
+         */
+        @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+        public void onCellInfoChanged(@NonNull List<CellInfo> cellInfo);
+    }
+
+    /**
+     * Interface for precise device call state listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface PreciseCallStateChangedListener {
+        /**
+         * Callback invoked when precise device call state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param callState {@link PreciseCallState}
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onPreciseCallStateChanged(@NonNull PreciseCallState callState);
+    }
+
+    /**
+     * Interface for call disconnect cause listener.
+     */
+    public interface CallDisconnectCauseChangedListener {
+        /**
+         * Callback invoked when call disconnect cause changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param disconnectCause {@link DisconnectCause}.
+         * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause,
+                @PreciseDisconnectCauses int preciseDisconnectCause);
+    }
+
+    /**
+     * Interface for IMS call disconnect cause listener.
+     */
+    public interface ImsCallDisconnectCauseChangedListener {
+        /**
+         * Callback invoked when IMS call disconnect cause changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
+         *
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo);
+    }
+
+    /**
+     * Interface for precise data connection state listener.
+     */
+    public interface PreciseDataConnectionStateChangedListener {
+        /**
+         * Callback providing update about the default/internet data connection on the registered
+         * subscription.
+         *
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+         * or the calling app has carrier privileges
+         * (see {@link TelephonyManager#hasCarrierPrivileges}).
+         *
+         * @param dataConnectionState {@link PreciseDataConnectionState}
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onPreciseDataConnectionStateChanged(
+                @NonNull PreciseDataConnectionState dataConnectionState);
+    }
+
+    /**
+     * Interface for Single Radio Voice Call Continuity listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface SrvccStateChangedListener {
+        /**
+         * Callback invoked when there has been a change in the Single Radio Voice Call Continuity
+         * (SRVCC) state for the currently active call on the registered subscription.
+         *
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onSrvccStateChanged(@SrvccState int srvccState);
+    }
+
+    /**
+     * Interface for SIM voice activation state listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface VoiceActivationStateChangedListener {
+        /**
+         * Callback invoked when the SIM voice activation state has changed on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param state is the current SIM voice activation state
+         */
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onVoiceActivationStateChanged(@SimActivationState int state);
+
+    }
+
+    /**
+     * Interface for SIM data activation state listener.
+     */
+    public interface DataActivationStateChangedListener {
+        /**
+         * Callback invoked when the SIM data activation state has changed on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param state is the current SIM data activation state
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onDataActivationStateChanged(@SimActivationState int state);
+    }
+
+    /**
+     * Interface for user mobile data state listener.
+     */
+    public interface UserMobileDataStateChangedListener {
+        /**
+         * Callback invoked when the user mobile data state has changed on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param enabled indicates whether the current user mobile data state is enabled or
+         *                disabled.
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onUserMobileDataStateChanged(boolean enabled);
+    }
+
+    /**
+     * Interface for display info listener.
+     */
+    public interface DisplayInfoChangedListener {
+        /**
+         * Callback invoked when the display info has changed on the registered subscription.
+         * <p> The {@link TelephonyDisplayInfo} contains status information shown to the user
+         * based on carrier policy.
+         *
+         * @param telephonyDisplayInfo The display information.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo);
+    }
+
+    /**
+     * Interface for the current emergency number list listener.
+     */
+    public interface EmergencyNumberListChangedListener {
+        /**
+         * Callback invoked when the current emergency number list has changed on the registered
+         * subscription.
+         *
+         * Note, the registered subscription is associated with {@link TelephonyManager} object
+         * on which
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}
+         * was called.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * given subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param emergencyNumberList Map associating all active subscriptions on the device with
+         *                            the list of emergency numbers originating from that
+         *                            subscription.
+         *                            If there are no active subscriptions, the map will contain a
+         *                            single entry with
+         *                            {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} as
+         *                            the key and a list of emergency numbers as the value. If no
+         *                            emergency number information is available, the value will be
+         *                            empty.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onEmergencyNumberListChanged(
+                @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList);
+    }
+
+    /**
+     * Interface for outgoing emergency call listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface OutgoingEmergencyCallListener {
+        /**
+         * Callback invoked when an outgoing call is placed to an emergency number.
+         *
+         * This method will be called when an emergency call is placed on any subscription
+         * (including the no-SIM case), regardless of which subscription this listener was
+         * registered on.
+         *
+         * The default implementation of this method calls
+         * {@link #onOutgoingEmergencyCall(EmergencyNumber)} for backwards compatibility purposes.
+         * Do not call {@code super(...)} from within your implementation unless you want
+         * {@link #onOutgoingEmergencyCall(EmergencyNumber)} to be called as well.
+         *
+         * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was
+         *                              placed to.
+         * @param subscriptionId The subscription ID used to place the emergency call. If the
+         *                       emergency call was placed without a valid subscription
+         *                       (e.g. when there are no SIM cards in the device), this will be
+         *                       equal to {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+         */
+        @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+        public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+                                     int subscriptionId);
+    }
+
+    /**
+     * Interface for outgoing emergency sms listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface OutgoingEmergencySmsListener {
+        /**
+         * Smsback invoked when an outgoing sms is sent to an emergency number.
+         *
+         * This method will be called when an emergency sms is sent on any subscription,
+         * regardless of which subscription this listener was registered on.
+         *
+         * The default implementation of this method calls
+         * {@link #onOutgoingEmergencySms(EmergencyNumber)} for backwards compatibility purposes. Do
+         * not call {@code super(...)} from within your implementation unless you want
+         * {@link #onOutgoingEmergencySms(EmergencyNumber)} to be called as well.
+         *
+         * @param sentEmergencyNumber The {@link EmergencyNumber} the emergency sms was sent to.
+         * @param subscriptionId The subscription ID used to send the emergency sms.
+         */
+        @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+        public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
+                                    int subscriptionId);
+    }
+
+    /**
+     * Interface for phone capability listener.
+     *
+     */
+    public interface PhoneCapabilityChangedListener {
+        /**
+         * Callback invoked when phone capability changes.
+         * Note, this callback triggers regardless of registered subscription.
+         *
+         * @param capability the new phone capability
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability);
+    }
+
+    /**
+     * Interface for active data subscription ID listener.
+     */
+    public interface ActiveDataSubscriptionIdChangedListener {
+        /**
+         * Callback invoked when active data subscription ID changes.
+         * Note, this callback triggers regardless of registered subscription.
+         *
+         * @param subId current subscription used to setup Cellular Internet data.
+         *              For example, it could be the current active opportunistic subscription
+         *              in use, or the subscription user selected as default data subscription in
+         *              DSDS mode.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onActiveDataSubscriptionIdChanged(int subId);
+    }
+
+    /**
+     * Interface for modem radio power state listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface RadioPowerStateChangedListener {
+        /**
+         * Callback invoked when modem radio power state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param state the modem radio power state
+         */
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onRadioPowerStateChanged(@RadioPowerState int state);
+    }
+
+    /**
+     * Interface for carrier network listener.
+     */
+    public interface CarrierNetworkChangeListener {
+        /**
+         * Callback invoked when telephony has received notice from a carrier
+         * app that a network action that could result in connectivity loss
+         * has been requested by an app using
+         * {@link android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)}
+         *
+         * This is optional and is only used to allow the system to provide alternative UI while
+         * telephony is performing an action that may result in intentional, temporary network
+         * lack of connectivity.
+         *
+         * Note, this callback is pinned to the registered subscription and will be invoked when
+         * the notifying carrier app has carrier privilege rule on the registered
+         * subscription. {@link android.telephony.TelephonyManager#hasCarrierPrivileges}
+         *
+         * @param active If the carrier network change is or shortly will be active,
+         *               {@code true} indicate that showing alternative UI, {@code false} otherwise.
+         */
+        public void onCarrierNetworkChange(boolean active);
+    }
+
+    /**
+     * Interface for registration failures listener.
+     */
+    public interface RegistrationFailedListener {
+        /**
+         * Report that Registration or a Location/Routing/Tracking Area update has failed.
+         *
+         * <p>Indicate whenever a registration procedure, including a location, routing, or tracking
+         * area update fails. This includes procedures that do not necessarily result in a change of
+         * the modem's registration status. If the modem's registration status changes, that is
+         * reflected in the onNetworkStateChanged() and subsequent
+         * get{Voice/Data}RegistrationState().
+         *
+         * <p>Because registration failures are ephemeral, this callback is not sticky.
+         * Registrants will not receive the most recent past value when registering.
+         *
+         * @param cellIdentity the CellIdentity, which must include the globally unique identifier
+         *        for the cell (for example, all components of the CGI or ECGI).
+         * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the
+         *         cell that was chosen for the failed registration attempt.
+         * @param domain DOMAIN_CS, DOMAIN_PS or both in case of a combined procedure.
+         * @param causeCode the primary failure cause code of the procedure.
+         *        For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95
+         *        For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147
+         *        For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
+         *        For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2
+         *        Integer.MAX_VALUE if this value is unused.
+         * @param additionalCauseCode the cause code of any secondary/combined procedure
+         *                            if appropriate. For UMTS, if a combined attach succeeds for
+         *                            PS only, then the GMM cause code shall be included as an
+         *                            additionalCauseCode. For LTE (ESM), cause codes are in
+         *                            TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused.
+         */
+        @RequiresPermission(allOf = {
+                Manifest.permission.READ_PRECISE_PHONE_STATE,
+                Manifest.permission.ACCESS_FINE_LOCATION
+        })
+        public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
+                                         @NonNull String chosenPlmn, @Domain int domain,
+                                         int causeCode, int additionalCauseCode);
+    }
+
+    /**
+     * Interface for call attributes listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface CallAttributesChangedListener {
+        /**
+         * Callback invoked when the call attributes changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param callAttributes the call attributes
+         */
+        @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+        void onCallAttributesChanged(@NonNull CallAttributes callAttributes);
+    }
+
+    /**
+     * Interface for barring information listener.
+     */
+    public interface BarringInfoChangedListener {
+        /**
+         * Report updated barring information for the current camped/registered cell.
+         *
+         * <p>Barring info is provided for all services applicable to the current camped/registered
+         * cell, for the registered PLMN and current access class/access category.
+         *
+         * @param barringInfo for all services on the current cell.
+         * @see android.telephony.BarringInfo
+         */
+        @RequiresPermission(allOf = {
+                Manifest.permission.READ_PRECISE_PHONE_STATE,
+                Manifest.permission.ACCESS_FINE_LOCATION
+        })
+        public void onBarringInfoChanged(@NonNull BarringInfo barringInfo);
+    }
+
+    /**
+     * Interface for current physical channel configuration listener.
+     * @hide
+     */
+    @SystemApi
+    public interface PhysicalChannelConfigChangedListener {
+        /**
+         * Callback invoked when the current physical channel configuration has changed
+         *
+         * @param configs List of the current {@link PhysicalChannelConfig}s
+         */
+        @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs);
+    }
+
+    /**
+     * Interface for data enabled listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface DataEnabledChangedListener {
+        /**
+         * Callback invoked when the data enabled changes.
+         *
+         * @param enabled {@code true} if data is enabled, otherwise disabled.
+         * @param reason Reason for data enabled/disabled.
+         *               See {@link TelephonyManager.DataEnabledReason}.
+         */
+        @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onDataEnabledChanged(boolean enabled,
+                                  @DataEnabledReason int reason);
     }
 
     /**
@@ -658,8 +1970,7 @@
      * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}.
      * If this TelephonyManager object was created with
      * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
-     * subId. Otherwise, this callback applies to
-     * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+     * subId. Otherwise, this callback applies to all subIds.
      * <p>
      * Note: The state returned here may differ from that returned by
      * {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that
@@ -698,6 +2009,7 @@
      * same as above, but with the network type.  Both called.
      */
     public void onDataConnectionStateChanged(int state, int networkType) {
+        // default implementation empty
     }
 
     /**
@@ -745,6 +2057,7 @@
      * @param cellInfo is the list of currently visible cells.
      */
     public void onCellInfoChanged(List<CellInfo> cellInfo) {
+        // default implementation empty
     }
 
     /**
@@ -758,7 +2071,7 @@
      * @param callState {@link PreciseCallState}
      * @hide
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     @SystemApi
     public void onPreciseCallStateChanged(@NonNull PreciseCallState callState) {
         // default implementation empty
@@ -777,9 +2090,9 @@
      * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
      *
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
-    public void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause,
-            int preciseDisconnectCause) {
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause,
+            @PreciseDisconnectCauses int preciseDisconnectCause) {
         // default implementation empty
     }
 
@@ -795,7 +2108,7 @@
      * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
      *
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) {
         // default implementation empty
     }
@@ -817,7 +2130,7 @@
      *
      * @param dataConnectionState {@link PreciseDataConnectionState}
      */
-    @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void onPreciseDataConnectionStateChanged(
             @NonNull PreciseDataConnectionState dataConnectionState) {
         // default implementation empty
@@ -855,6 +2168,7 @@
      */
     @SystemApi
     public void onSrvccStateChanged(@SrvccState int srvccState) {
+        // default implementation empty
 
     }
 
@@ -873,6 +2187,7 @@
      */
     @SystemApi
     public void onVoiceActivationStateChanged(@SimActivationState int state) {
+        // default implementation empty
     }
 
     /**
@@ -889,6 +2204,7 @@
      * @hide
      */
     public void onDataActivationStateChanged(@SimActivationState int state) {
+        // default implementation empty
     }
 
     /**
@@ -916,7 +2232,7 @@
      *
      * @param telephonyDisplayInfo The display information.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) {
         // default implementation empty
     }
@@ -1030,7 +2346,8 @@
     /**
      * Callback invoked when OEM hook raw event is received on the registered subscription.
      * Note, the registration subId comes from {@link TelephonyManager} object which registers
-     * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}.
+     * PhoneStateListener by
+     * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
      * If this TelephonyManager object was created with
      * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
      * subId. Otherwise, this callback applies to
@@ -1052,7 +2369,7 @@
      * @param capability the new phone capability
      * @hide
      */
-    public void onPhoneCapabilityChanged(PhoneCapability capability) {
+    public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability) {
         // default implementation empty
     }
 
@@ -1096,7 +2413,8 @@
      * subId. Otherwise, this callback applies to
      * {@link SubscriptionManager#getDefaultSubscriptionId()}.
      *
-     * @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}
+     * Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+     *
      * @param state the modem radio power state
      * @hide
      */
@@ -1453,18 +2771,16 @@
             Binder.withCleanCallingIdentity(
                     () -> mExecutor.execute(
                             () -> psl.onImsCallDisconnectCauseChanged(disconnectCause)));
-
         }
 
         public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
-                @NonNull String chosenPlmn, int domain,
-                int causeCode, int additionalCauseCode) {
+                @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
             Binder.withCleanCallingIdentity(
                     () -> mExecutor.execute(() -> psl.onRegistrationFailed(
-                            cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
+                                cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
             // default implementation empty
         }
 
@@ -1475,8 +2791,27 @@
             Binder.withCleanCallingIdentity(
                     () -> mExecutor.execute(() -> psl.onBarringInfoChanged(barringInfo)));
         }
-    }
 
+        public void onPhysicalChannelConfigChanged(List<PhysicalChannelConfig> configs) {
+            PhysicalChannelConfigChangedListener listener =
+                    (PhysicalChannelConfigChangedListener) mPhoneStateListenerWeakRef.get();
+            if (listener == null) return;
+
+            Binder.withCleanCallingIdentity(
+                    () -> mExecutor.execute(() -> listener.onPhysicalChannelConfigChanged(
+                            configs)));
+        }
+
+        public void onDataEnabledChanged(boolean enabled, @DataEnabledReason int reason) {
+                DataEnabledChangedListener listener =
+                        (DataEnabledChangedListener) mPhoneStateListenerWeakRef.get();
+                if (listener == null) return;
+
+                Binder.withCleanCallingIdentity(
+                        () -> mExecutor.execute(() -> listener.onDataEnabledChanged(
+                                enabled, reason)));
+        }
+    }
 
     private void log(String s) {
         Rlog.d(LOG_TAG, s);
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 3673ae7..a9548b0 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -15,6 +15,7 @@
  */
 package android.telephony;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -24,6 +25,9 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.Annotation.CallState;
@@ -37,6 +41,7 @@
 import android.telephony.Annotation.SrvccState;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
+import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -45,6 +50,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /**
@@ -206,7 +212,7 @@
     }
 
     /**
-     * To check the SDK version for {@link #listenForSubscriber}.
+     * To check the SDK version for {@link #listenWithEventList}.
      */
     @ChangeId
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
@@ -218,23 +224,23 @@
      * @param pkg Package name
      * @param featureId Feature ID
      * @param listener Listener providing callback
-     * @param events Events
+     * @param events List events
      * @param notifyNow Whether to notify instantly
      */
-    public void listenForSubscriber(int subId, @NonNull String pkg, @NonNull String featureId,
-            @NonNull PhoneStateListener listener, int events, boolean notifyNow) {
+    public void listenWithEventList(int subId, @NonNull String pkg, @NonNull String featureId,
+            @NonNull PhoneStateListener listener, @NonNull int[] events, boolean notifyNow) {
         try {
             // subId from PhoneStateListener is deprecated Q on forward, use the subId from
             // TelephonyManager instance. Keep using subId from PhoneStateListener for pre-Q.
             if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) {
                 // Since mSubId in PhoneStateListener is deprecated from Q on forward, this is
                 // the only place to set mSubId and its for "informational" only.
-                listener.mSubId = (events == PhoneStateListener.LISTEN_NONE)
+                listener.mSubId = (events.length == 0)
                         ? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId;
             } else if (listener.mSubId != null) {
                 subId = listener.mSubId;
             }
-            sRegistry.listenForSubscriber(
+            sRegistry.listenWithEventList(
                     subId, pkg, featureId, listener.callback, events, notifyNow);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -765,4 +771,366 @@
         }
     }
 
+    /**
+     * Notify {@link PhysicalChannelConfig} has changed for a specific subscription.
+     *
+     * @param subId the subId
+     * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
+     */
+    public void notifyPhysicalChannelConfigForSubscriber(
+            int subId, List<PhysicalChannelConfig> configs) {
+        try {
+            sRegistry.notifyPhysicalChannelConfigForSubscriber(subId, configs);
+        } catch (RemoteException ex) {
+            // system server crash
+        }
+    }
+
+    /**
+     * Notify that the data enabled has changed.
+     *
+     * @param enabled True if data is enabled, otherwise disabled.
+     * @param reason Reason for data enabled/disabled. See {@code REASON_*} in
+     * {@link TelephonyManager}.
+     */
+    public void notifyDataEnabled(boolean enabled, @TelephonyManager.DataEnabledReason int reason) {
+        try {
+            sRegistry.notifyDataEnabled(enabled, reason);
+        } catch (RemoteException ex) {
+            // system server crash
+        }
+    }
+
+    public @NonNull Set<Integer> getEventsFromListener(@NonNull PhoneStateListener listener) {
+
+        Set<Integer> eventList = new ArraySet<>();
+
+        if (listener instanceof PhoneStateListener.ServiceStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.MessageWaitingIndicatorChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CallForwardingIndicatorChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CellLocationChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CallStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DataConnectionStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DataActivityListener) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.SignalStrengthsChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.AlwaysReportedSignalStrengthChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CellInfoChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.PreciseCallStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CallDisconnectCauseChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.ImsCallDisconnectCauseChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.PreciseDataConnectionStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.SrvccStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.VoiceActivationStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DataActivationStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.UserMobileDataStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DisplayInfoChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.EmergencyNumberListChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.OutgoingEmergencyCallListener) {
+            eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL);
+        }
+
+        if (listener instanceof PhoneStateListener.OutgoingEmergencySmsListener) {
+            eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+        }
+
+        if (listener instanceof PhoneStateListener.PhoneCapabilityChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.ActiveDataSubscriptionIdChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.RadioPowerStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CarrierNetworkChangeListener) {
+            eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.RegistrationFailedListener) {
+            eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+        }
+
+        if (listener instanceof PhoneStateListener.CallAttributesChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.BarringInfoChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.PhysicalChannelConfigChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DataEnabledChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ENABLED_CHANGED);
+        }
+
+        return eventList;
+    }
+
+    private @NonNull Set<Integer> getEventsFromBitmask(int eventMask) {
+
+        Set<Integer> eventList = new ArraySet<>();
+
+        if ((eventMask & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
+            eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
+            eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
+            eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+            eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
+            eventList.add(PhoneStateListener.EVENT_OEM_HOOK_RAW);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
+            eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
+            eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
+            eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
+            eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL) != 0) {
+            eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS) != 0) {
+            eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_REGISTRATION_FAILURE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_BARRING_INFO) != 0) {
+            eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+        }
+        return eventList;
+
+    }
+
+    /**
+     * Registers a listener object to receive notification of changes
+     * in specified telephony states.
+     * <p>
+     * To register a listener, pass a {@link PhoneStateListener} which implements
+     * interfaces of events. For example,
+     * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements
+     * {@link PhoneStateListener.ServiceStateChangedListener}.
+     *
+     * At registration, and when a specified telephony state changes, the telephony manager invokes
+     * the appropriate callback method on the listener object and passes the current (updated)
+     * values.
+     * <p>
+     *
+     * If this TelephonyManager object has been created with
+     * {@link TelephonyManager#createForSubscriptionId}, applies to the given subId.
+     * Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}.
+     * To listen events for multiple subIds, pass a separate listener object to
+     * each TelephonyManager object created with {@link TelephonyManager#createForSubscriptionId}.
+     *
+     * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
+     * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
+     * {@link SecurityException} will be thrown otherwise.
+     *
+     * This API should be used sparingly -- large numbers of listeners will cause system
+     * instability. If a process has registered too many listeners without unregistering them, it
+     * may encounter an {@link IllegalStateException} when trying to register more listeners.
+     *
+     * @param listener The {@link PhoneStateListener} object to register.
+     */
+    public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor, int subId,
+            String pkgName, String attributionTag, @NonNull PhoneStateListener listener,
+            boolean notifyNow) {
+        listener.setExecutor(executor);
+        registerPhoneStateListener(subId, pkgName, attributionTag, listener,
+                getEventsFromListener(listener), notifyNow);
+    }
+
+    public void registerPhoneStateListenerWithEvents(int subId, String pkgName,
+            String attributionTag, @NonNull PhoneStateListener listener, int events,
+            boolean notifyNow) {
+        registerPhoneStateListener(
+                subId, pkgName, attributionTag, listener, getEventsFromBitmask(events), notifyNow);
+    }
+
+    private void registerPhoneStateListener(int subId,
+            String pkgName, String attributionTag, @NonNull PhoneStateListener listener,
+            @NonNull Set<Integer> events, boolean notifyNow) {
+        if (listener == null) {
+            throw new IllegalStateException("telephony service is null.");
+        }
+
+        listenWithEventList(subId, pkgName, attributionTag, listener,
+                events.stream().mapToInt(i -> i).toArray(), notifyNow);
+    }
+
+    /**
+     * Unregister an existing {@link PhoneStateListener}.
+     *
+     * @param listener The {@link PhoneStateListener} object to unregister.
+     */
+    public void unregisterPhoneStateListener(int subId, String pkgName, String attributionTag,
+                                             @NonNull PhoneStateListener listener,
+                                             boolean notifyNow) {
+        listenWithEventList(subId, pkgName, attributionTag, listener, new int[0], notifyNow);
+    }
 }
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 17d3ae4..471f2c2 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -24,11 +24,12 @@
 import android.icu.text.MeasureFormat;
 import android.icu.util.Measure;
 import android.icu.util.MeasureUnit;
-import android.net.NetworkUtils;
 import android.text.BidiFormatter;
 import android.text.TextUtils;
 import android.view.View;
 
+import com.android.net.module.util.Inet4AddressUtils;
+
 import java.util.Locale;
 
 /**
@@ -207,7 +208,7 @@
      */
     @Deprecated
     public static String formatIpAddress(int ipv4Address) {
-        return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress();
+        return Inet4AddressUtils.intToInet4AddressHTL(ipv4Address).getHostAddress();
     }
 
     private static final int SECONDS_PER_MINUTE = 60;
diff --git a/core/java/android/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/textclassifier/OWNERS b/core/java/android/view/textclassifier/OWNERS
index ac80d9f..4bcdeea 100644
--- a/core/java/android/view/textclassifier/OWNERS
+++ b/core/java/android/view/textclassifier/OWNERS
@@ -6,3 +6,5 @@
 svetoslavganov@google.com
 augale@google.com
 joannechung@google.com
+tonymak@google.com
+licha@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/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index c0648ab..2e7629a 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -129,7 +129,7 @@
         String[] routes = routesStr.trim().split(" ");
         for (String route : routes) {
             //each route is ip/prefix
-            RouteInfo info = new RouteInfo(new IpPrefix(route), null);
+            RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST);
             this.routes.add(info);
             updateAllowedFamilies(info.getDestination().getAddress());
         }
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/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index d2dc7c2..854fb17 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -23,6 +23,7 @@
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.TelephonyDisplayInfo;
 import android.telephony.PhoneCapability;
+import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.ServiceState;
@@ -68,4 +69,6 @@
     void onRegistrationFailed(in CellIdentity cellIdentity,
              String chosenPlmn, int domain, int causeCode, int additionalCauseCode);
     void onBarringInfoChanged(in BarringInfo barringInfo);
+    void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs);
+    void onDataEnabledChanged(boolean enabled, int reason);
 }
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 5f2dcc3..2a73dac 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -41,16 +41,8 @@
             IOnSubscriptionsChangedListener callback);
     void removeOnSubscriptionsChangedListener(String pkg,
             IOnSubscriptionsChangedListener callback);
-    /**
-      * @deprecated Use {@link #listenWithFeature(String, String, IPhoneStateListener, int,
-      * boolean) instead
-      */
-    @UnsupportedAppUsage
-    void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
-    void listenWithFeature(String pkg, String featureId, IPhoneStateListener callback, int events,
-            boolean notifyNow);
-    void listenForSubscriber(in int subId, String pkg, String featureId,
-            IPhoneStateListener callback, int events, boolean notifyNow);
+    void listenWithEventList(in int subId, String pkg, String featureId,
+            IPhoneStateListener callback, in int[] events, boolean notifyNow);
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     void notifyCallStateForAllSubs(int state, String incomingNumber);
     void notifyCallState(in int phoneId, in int subId, int state, String incomingNumber);
@@ -99,4 +91,7 @@
     void notifyRegistrationFailed(int slotIndex, int subId, in CellIdentity cellIdentity,
             String chosenPlmn, int domain, int causeCode, int additionalCauseCode);
     void notifyBarringInfoChanged(int slotIndex, int subId, in BarringInfo barringInfo);
+    void notifyPhysicalChannelConfigForSubscriber(in int subId,
+            in List<PhysicalChannelConfig> configs);
+    void notifyDataEnabled(boolean enabled, int reason);
 }
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/java/com/android/internal/util/LocationPermissionChecker.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
index cd8fc35..c583d5a 100644
--- a/core/java/com/android/internal/util/LocationPermissionChecker.java
+++ b/core/java/com/android/internal/util/LocationPermissionChecker.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.location.LocationManager;
+import android.net.NetworkStack;
 import android.os.Binder;
 import android.os.Build;
 import android.os.UserHandle;
@@ -147,6 +148,13 @@
             int uid, @Nullable String message) {
         checkPackage(uid, pkgName);
 
+        // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_STACK & MAINLINE_NETWORK_STACK
+        // are granted a bypass.
+        if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)
+                || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)) {
+            return SUCCEEDED;
+        }
+
         // Location mode must be enabled
         if (!isLocationModeEnabled()) {
             return ERROR_LOCATION_MODE_OFF;
@@ -259,4 +267,37 @@
         // We don't care about pid, pass in -1
         return mContext.checkPermission(permissionType, -1, uid);
     }
+
+    /**
+     * Returns true if the |uid| holds NETWORK_SETTINGS permission.
+     */
+    public boolean checkNetworkSettingsPermission(int uid) {
+        return getUidPermission(android.Manifest.permission.NETWORK_SETTINGS, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission.
+     */
+    public boolean checkNetworkSetupWizardPermission(int uid) {
+        return getUidPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * Returns true if the |uid| holds NETWORK_STACK permission.
+     */
+    public boolean checkNetworkStackPermission(int uid) {
+        return getUidPermission(android.Manifest.permission.NETWORK_STACK, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission.
+     */
+    public boolean checkMainlineNetworkStackPermission(int uid) {
+        return getUidPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
 }
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index cca39ea..ae566c3 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -1 +1,7 @@
 per-file PointerLocationView.java = michaelwr@google.com, svv@google.com
+
+# LockSettings related
+per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *LockScreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/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 22dd765..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);
@@ -1810,7 +1810,7 @@
       heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
       break;
   }
-  android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level));
+  mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
   // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
   runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 714a09d..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.
     -->
@@ -2979,6 +2984,12 @@
     <permission android:name="android.permission.RECOVERY"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to do certain operations needed for
+         resume on reboot feature.
+         @hide -->
+    <permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to read system update info.
          @hide -->
     <permission android:name="android.permission.READ_SYSTEM_UPDATE_INFO"
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 02cf0b7..a30111b 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -1,7 +1,9 @@
 adamp@google.com
 alanv@google.com
+asc@google.com
 dsandler@android.com
 dsandler@google.com
+dupin@google.com
 hackbod@android.com
 hackbod@google.com
 jsharkey@android.com
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2f1bcdc..4b3d82a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8968,6 +8968,11 @@
              changed at runtime by calling
              {@link android.media.tv.TvInputManager#updateTvInputInfo(android.media.tv.TvInputInfo)}. -->
         <attr name="tunerCount" format="integer" />
+        <!-- Attribute whether the TV input service can pause recording programs.
+             This value can be changed at runtime by calling
+             {@link android.media.tv.TvInputManager#updateTvInputInfo(android.media.tv.TvInputInfo)}
+             . -->
+        <attr name="canPauseRecording" format="boolean" />
     </declare-styleable>
 
     <!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e00aff1..a0be068 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3043,6 +3043,7 @@
        =============================================================== -->
 
   <public-group type="attr" first-id="0x01010617">
+    <public name="canPauseRecording" />
     <!-- attribute definitions go here -->
   </public-group>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1143467..8ac00dc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -110,7 +110,7 @@
     <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
     <string name="ClipMmi">Incoming Caller ID</string>
     <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
-    <string name="ClirMmi">Outgoing Caller ID</string>
+    <string name="ClirMmi">Hide Outgoing Caller ID</string>
     <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID. -->
     <string name="ColpMmi">Connected Line ID</string>
     <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID restriction. -->
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index f9e3bc6..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
@@ -23,7 +23,10 @@
 import static org.junit.Assert.fail;
 
 import android.Manifest;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.BugreportManager;
 import android.os.BugreportManager.BugreportCallback;
 import android.os.BugreportParams;
@@ -31,7 +34,9 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.StrictMode;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -53,10 +58,11 @@
 import org.junit.runners.JUnit4;
 
 import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
-
 /**
  * Tests for BugreportManager API.
  */
@@ -67,8 +73,22 @@
 
     private static final String TAG = "BugreportManagerTest";
     private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10);
+    private static final long DUMPSTATE_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
     private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
 
+
+    // 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 =
+            "com.android.internal.intent.action.BUGREPORT_FINISHED";
+    private static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
+    private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+
     private Handler mHandler;
     private Executor mExecutor;
     private BugreportManager mBrm;
@@ -171,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(
@@ -180,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);
     }
@@ -206,12 +226,54 @@
         // Try again, with DUMP permission.
         getPermissions();
         mBrm.cancelBugreport();
-        Thread.sleep(500 /* .5s */);
+        waitTillDoneOrTimeout(callback);
         assertThat(callback.isDone()).isTrue();
         assertFdsAreClosed(mBugreportFd, mScreenshotFd);
     }
 
     @Test
+    public void cancelBugreport_noReportStarted() throws Exception {
+        // Without the native DumpstateService running, we don't get a SecurityException.
+        mBrm.cancelBugreport();
+    }
+
+    @LargeTest
+    @Test
+    public void cancelBugreport_fromDifferentUid() throws Exception {
+        assertThat(Process.myUid()).isNotEqualTo(Process.SHELL_UID);
+
+        // Start a bugreport through ActivityManager's shell command - this starts a BR from the
+        // shell UID rather than our own.
+        BugreportBroadcastReceiver br = new BugreportBroadcastReceiver();
+        InstrumentationRegistry.getContext()
+                .registerReceiver(br, new IntentFilter(INTENT_BUGREPORT_FINISHED));
+        UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+                .executeShellCommand("am bug-report");
+
+        // The command triggers the report through a broadcast, so wait until dumpstate actually
+        // starts up, which may take a bit.
+        waitTillDumpstateRunningOrTimeout();
+
+        try {
+            mBrm.cancelBugreport();
+            fail("Expected cancelBugreport to throw SecurityException when report started by "
+                    + "different UID");
+        } catch (SecurityException expected) {
+        } finally {
+            // Do this in the finally block so that even if this test case fails, we don't break
+            // other test cases unexpectedly due to the still-running shell report.
+            try {
+                // The shell's BR is still running and should complete successfully.
+                br.waitForBugreportFinished();
+            } finally {
+                // The latch may fail for a number of reasons but we still need to unregister the
+                // BroadcastReceiver.
+                InstrumentationRegistry.getContext().unregisterReceiver(br);
+            }
+        }
+    }
+
+    @Test
     public void insufficientPermissions_throwsException() throws Exception {
         dropPermissions();
 
@@ -346,6 +408,28 @@
                 .adoptShellPermissionIdentity(Manifest.permission.DUMP);
     }
 
+    private static boolean isDumpstateRunning() {
+        String[] output;
+        try {
+            output =
+                    UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+                            .executeShellCommand("ps -A -o NAME | grep dumpstate")
+                            .trim()
+                            .split("\n");
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to check if dumpstate is running", e);
+            return false;
+        }
+        for (String line : output) {
+            // Check for an exact match since there may be other things that contain "dumpstate" as
+            // a substring (e.g. the dumpstate HAL).
+            if (TextUtils.equals("dumpstate", line)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static void assertFdIsClosed(ParcelFileDescriptor pfd) {
         try {
             int fd = pfd.getFd();
@@ -364,18 +448,25 @@
         return System.currentTimeMillis();
     }
 
-    private static boolean shouldTimeout(long startTimeMs) {
-        return now() - startTimeMs >= BUGREPORT_TIMEOUT_MS;
+    private static void waitTillDumpstateRunningOrTimeout() throws Exception {
+        long startTimeMs = now();
+        while (!isDumpstateRunning()) {
+            Thread.sleep(500 /* .5s */);
+            if (now() - startTimeMs >= DUMPSTATE_STARTUP_TIMEOUT_MS) {
+                break;
+            }
+            Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for dumpstate to start");
+        }
     }
 
     private static void waitTillDoneOrTimeout(BugreportCallbackImpl callback) throws Exception {
         long startTimeMs = now();
         while (!callback.isDone()) {
             Thread.sleep(1000 /* 1s */);
-            if (shouldTimeout(startTimeMs)) {
+            if (now() - startTimeMs >= BUGREPORT_TIMEOUT_MS) {
                 break;
             }
-            Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms");
+            Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for bugreport to finish");
         }
     }
 
@@ -450,6 +541,36 @@
         assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS));
     }
 
+    private class BugreportBroadcastReceiver extends BroadcastReceiver {
+        Intent mBugreportFinishedIntent = null;
+        final CountDownLatch mLatch;
+
+        BugreportBroadcastReceiver() {
+            mLatch = new CountDownLatch(1);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            setBugreportFinishedIntent(intent);
+            mLatch.countDown();
+        }
+
+        private void setBugreportFinishedIntent(Intent intent) {
+            mBugreportFinishedIntent = intent;
+        }
+
+        public Intent getBugreportFinishedIntent() {
+            return mBugreportFinishedIntent;
+        }
+
+        public void waitForBugreportFinished() throws Exception {
+            if (!mLatch.await(BUGREPORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                throw new Exception("Failed to receive BUGREPORT_FINISHED in "
+                        + BUGREPORT_TIMEOUT_MS + " ms.");
+            }
+        }
+    }
+
     /**
      * A rule to change strict mode vm policy temporarily till test method finished.
      *
diff --git a/core/tests/coretests/src/android/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/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/autofill/OWNERS b/core/tests/coretests/src/android/view/autofill/OWNERS
new file mode 100644
index 0000000..9a30e82
--- /dev/null
+++ b/core/tests/coretests/src/android/view/autofill/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 351486
+
+include /core/java/android/view/autofill/OWNERS
diff --git a/core/tests/coretests/src/android/view/contentcapture/OWNERS b/core/tests/coretests/src/android/view/contentcapture/OWNERS
new file mode 100644
index 0000000..24561c5
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 544200
+
+include /core/java/android/view/contentcapture/OWNERS
diff --git a/core/tests/coretests/src/android/view/textclassifier/OWNERS b/core/tests/coretests/src/android/view/textclassifier/OWNERS
new file mode 100644
index 0000000..46b3cb8
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/textclassifier/OWNERS
diff --git a/core/tests/coretests/src/android/view/textservice/OWNERS b/core/tests/coretests/src/android/view/textservice/OWNERS
new file mode 100644
index 0000000..0471e29
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textservice/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/textservices/OWNERS
diff --git a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
index 5371a0f..ccd873d 100644
--- a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
+++ b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java
@@ -30,7 +30,6 @@
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.RectShape;
 import android.platform.test.annotations.Presubmit;
-import android.view.View;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -48,6 +47,7 @@
 @Presubmit
 public class AbsSeekBarTest {
 
+    public static final int PADDING = 10;
     private Context mContext;
     private AbsSeekBar mBar;
 
@@ -59,34 +59,42 @@
 
     @Test
     public void testExclusionForThumb_limitedTo48dp() {
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
         mBar.setProgress(50);
+
+        final int thumbOffset = mBar.getThumbOffset();
+
         measureAndLayout(dpToPxSize(200), dpToPxSize(100));
         List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
 
         assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
         assertEquals("exclusion should be centered on thumb",
-                center(mBar), center(exclusions.get(0)));
+                center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)),
+                center(exclusions.get(0)));
         assertEquals("exclusion should be 48dp high", dpToPxSize(48), exclusions.get(0).height());
         assertEquals("exclusion should be 48dp wide", dpToPxSize(48), exclusions.get(0).width());
     }
 
     @Test
     public void testExclusionForThumb_limitedToHeight() {
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
         mBar.setProgress(50);
+
+        final int thumbOffset = mBar.getThumbOffset();
+
         measureAndLayout(dpToPxSize(200), dpToPxSize(32));
         List<Rect> exclusions = mBar.getSystemGestureExclusionRects();
 
         assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size());
         assertEquals("exclusion should be centered on thumb",
-                center(mBar), center(exclusions.get(0)));
+                center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)),
+                center(exclusions.get(0)));
         assertEquals("exclusion should be 32dp high", dpToPxSize(32), exclusions.get(0).height());
         assertEquals("exclusion should be 32dp wide", dpToPxSize(32), exclusions.get(0).width());
     }
@@ -95,7 +103,7 @@
     public void testExclusionForThumb_passesThroughUserExclusions() {
         mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(1, 2, 3, 4)));
 
-        mBar.setPadding(10, 10, 10, 10);
+        mBar.setPadding(PADDING, PADDING, PADDING, PADDING);
         mBar.setThumb(newThumb(dpToPxSize(20)));
         mBar.setMin(0);
         mBar.setMax(100);
@@ -110,12 +118,37 @@
         assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2));
     }
 
+    @Test
+    public void testGrowRectTo_evenInitialDifference() {
+        doGrowRectTest(new Rect(0, 0, 0, 0), 10, new Rect(-5, -5, 5, 5));
+    }
+
+    @Test
+    public void testGrowRectTo_unevenInitialDifference() {
+        doGrowRectTest(new Rect(0, 0, 1, 1), 10, new Rect(-5, -5, 5, 5));
+    }
+
+    @Test
+    public void testGrowRectTo_unevenInitialDifference_unevenSize() {
+        doGrowRectTest(new Rect(0, 0, 0, 0), 9, new Rect(-5, -5, 4, 4));
+    }
+
+    public void doGrowRectTest(Rect in, int minimumSize, Rect expected) {
+        Rect result = new Rect(in);
+        mBar.growRectTo(result, minimumSize);
+
+        assertEquals("grown rect", expected, result);
+        assertEquals("grown rect center point", center(expected), center(result));
+    }
+
     private Point center(Rect rect) {
         return new Point(rect.centerX(), rect.centerY());
     }
 
-    private Point center(View view) {
-        return center(new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
+    private Rect offset(Rect rect, int dx, int dy) {
+        Rect result = new Rect(rect);
+        result.offset(dx, dy);
+        return result;
     }
 
     private ShapeDrawable newThumb(int size) {
diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp
index 12a2b08..f86ac9c 100644
--- a/core/tests/overlaytests/device/Android.bp
+++ b/core/tests/overlaytests/device/Android.bp
@@ -16,7 +16,11 @@
     name: "OverlayDeviceTests",
     srcs: ["src/**/*.java"],
     platform_apis: true,
-    static_libs: ["androidx.test.rules"],
+    certificate: "platform",
+    static_libs: [
+        "androidx.test.rules",
+        "testng",
+    ],
     test_suites: ["device-tests"],
     data: [
         ":OverlayDeviceTests_AppOverlayOne",
diff --git a/core/tests/overlaytests/device/AndroidManifest.xml b/core/tests/overlaytests/device/AndroidManifest.xml
index 4881636..a69911f 100644
--- a/core/tests/overlaytests/device/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/AndroidManifest.xml
@@ -19,6 +19,8 @@
 
     <uses-sdk android:minSdkVersion="21" />
 
+    <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" />
+
     <application>
         <uses-library android:name="android.test.runner"/>
     </application>
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
index 6507839..ebbdda5 100644
--- a/core/tests/overlaytests/device/AndroidTest.xml
+++ b/core/tests/overlaytests/device/AndroidTest.xml
@@ -19,9 +19,20 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-instrumentation" />
 
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="remount-system" value="true" />
+        <option name="push" value="OverlayDeviceTests.apk->/system/app/OverlayDeviceTests.apk" />
+    </target_preparer>
+
+    <!-- Reboot to have the test APK scanned by PM and reboot after to remove the test APK. -->
+    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer">
+      <option name="pre-reboot" value="true" />
+      <option name="post-reboot" value="true" />
+    </target_preparer>
+
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="OverlayDeviceTests.apk" />
         <option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" />
         <option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" />
         <option name="test-file-name" value="OverlayDeviceTests_FrameworkOverlay.apk" />
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
index 390bb76..76c01a7 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java
@@ -18,60 +18,76 @@
 
 import static java.util.concurrent.TimeUnit.SECONDS;
 
-import android.app.UiAutomation;
-import android.content.res.Resources;
-import android.os.ParcelFileDescriptor;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.os.UserHandle;
 
 import androidx.test.InstrumentationRegistry;
 
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
 import java.util.concurrent.Executor;
 import java.util.concurrent.FutureTask;
 
 class LocalOverlayManager {
     private static final long TIMEOUT = 30;
 
-    public static void setEnabledAndWait(Executor executor, final String packageName,
-            boolean enable) throws Exception {
-        final String pattern = (enable ? "[x]" : "[ ]") + " " + packageName;
-        if (executeShellCommand("cmd overlay list").contains(pattern)) {
-            // nothing to do, overlay already in the requested state
-            return;
+    public static void toggleOverlaysAndWait(@NonNull final String[] overlaysToEnable,
+            @NonNull final String[] overlaysToDisable) throws Exception {
+        final int userId = UserHandle.myUserId();
+        OverlayManagerTransaction.Builder builder = new OverlayManagerTransaction.Builder();
+        for (String pkg : overlaysToEnable) {
+            builder.setEnabled(pkg, true, userId);
         }
+        for (String pkg : overlaysToDisable) {
+            builder.setEnabled(pkg, false, userId);
+        }
+        OverlayManagerTransaction transaction = builder.build();
 
-        final Resources res = InstrumentationRegistry.getContext().getResources();
-        final String[] oldApkPaths = res.getAssets().getApkPaths();
+        final Context ctx = InstrumentationRegistry.getTargetContext();
         FutureTask<Boolean> task = new FutureTask<>(() -> {
             while (true) {
-                if (!Arrays.equals(oldApkPaths, res.getAssets().getApkPaths())) {
+                final String[] paths = ctx.getResources().getAssets().getApkPaths();
+                if (arrayTailContains(paths, overlaysToEnable)
+                        && arrayDoesNotContain(paths, overlaysToDisable)) {
                     return true;
                 }
                 Thread.sleep(10);
             }
         });
+
+        OverlayManager om = ctx.getSystemService(OverlayManager.class);
+        om.commit(transaction);
+
+        Executor executor = (cmd) -> new Thread(cmd).start();
         executor.execute(task);
-        executeShellCommand("cmd overlay " + (enable ? "enable " : "disable ") + packageName);
         task.get(TIMEOUT, SECONDS);
     }
 
-    private static String executeShellCommand(final String command)
-            throws Exception {
-        final UiAutomation uiAutomation =
-                InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        final ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command);
-        try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
-            final BufferedReader reader = new BufferedReader(
-                    new InputStreamReader(in, StandardCharsets.UTF_8));
-            StringBuilder str = new StringBuilder();
-            String line;
-            while ((line = reader.readLine()) != null) {
-                str.append(line);
-            }
-            return str.toString();
+    private static boolean arrayTailContains(@NonNull final String[] array,
+            @NonNull final String[] substrings) {
+        if (array.length < substrings.length) {
+            return false;
         }
+        for (int i = 0; i < substrings.length; i++) {
+            String a = array[array.length - substrings.length + i];
+            String s = substrings[i];
+            if (!a.contains(s)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean arrayDoesNotContain(@NonNull final String[] array,
+            @NonNull final String[] substrings) {
+        for (String s : substrings) {
+            for (String a : array) {
+                if (a.contains(s)) {
+                    return false;
+                }
+            }
+        }
+        return true;
     }
 }
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java
new file mode 100644
index 0000000..0b4f5e2
--- /dev/null
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.overlaytest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.content.om.OverlayManagerTransaction;
+import android.content.res.Resources;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.List;
+
+@RunWith(JUnit4.class)
+@MediumTest
+public class TransactionTest {
+    static final String APP_OVERLAY_ONE_PKG = "com.android.overlaytest.app_overlay_one";
+    static final String APP_OVERLAY_TWO_PKG = "com.android.overlaytest.app_overlay_two";
+
+    private Context mContext;
+    private Resources mResources;
+    private OverlayManager mOverlayManager;
+    private int mUserId;
+    private UserHandle mUserHandle;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        mResources = mContext.getResources();
+        mOverlayManager = mContext.getSystemService(OverlayManager.class);
+        mUserId = UserHandle.myUserId();
+        mUserHandle = UserHandle.of(mUserId);
+
+        LocalOverlayManager.toggleOverlaysAndWait(
+                new String[]{},
+                new String[]{APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG});
+    }
+
+    @Test
+    public void testValidTransaction() throws Exception {
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+
+        OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+                .setEnabled(APP_OVERLAY_ONE_PKG, true)
+                .setEnabled(APP_OVERLAY_TWO_PKG, true)
+                .build();
+        mOverlayManager.commit(t);
+
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId);
+        List<OverlayInfo> ois =
+                mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+        assertEquals(ois.size(), 2);
+        assertEquals(ois.get(0).packageName, APP_OVERLAY_ONE_PKG);
+        assertEquals(ois.get(1).packageName, APP_OVERLAY_TWO_PKG);
+
+        OverlayManagerTransaction t2 = new OverlayManagerTransaction.Builder()
+                .setEnabled(APP_OVERLAY_TWO_PKG, true)
+                .setEnabled(APP_OVERLAY_ONE_PKG, true)
+                .build();
+        mOverlayManager.commit(t2);
+
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId);
+        List<OverlayInfo> ois2 =
+                mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+        assertEquals(ois2.size(), 2);
+        assertEquals(ois2.get(0).packageName, APP_OVERLAY_TWO_PKG);
+        assertEquals(ois2.get(1).packageName, APP_OVERLAY_ONE_PKG);
+
+        OverlayManagerTransaction t3 = new OverlayManagerTransaction.Builder()
+                .setEnabled(APP_OVERLAY_TWO_PKG, false)
+                .build();
+        mOverlayManager.commit(t3);
+
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+        List<OverlayInfo> ois3 =
+                mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle);
+        assertEquals(ois3.size(), 2);
+        assertEquals(ois3.get(0).packageName, APP_OVERLAY_TWO_PKG);
+        assertEquals(ois3.get(1).packageName, APP_OVERLAY_ONE_PKG);
+    }
+
+    @Test
+    public void testInvalidRequestHasNoEffect() {
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+
+        OverlayManagerTransaction t = new OverlayManagerTransaction.Builder()
+                .setEnabled(APP_OVERLAY_ONE_PKG, true)
+                .setEnabled("does-not-exist", true)
+                .setEnabled(APP_OVERLAY_TWO_PKG, true)
+                .build();
+        assertThrows(SecurityException.class, () -> mOverlayManager.commit(t));
+
+        assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId);
+        assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId);
+    }
+
+    private void assertOverlayIsEnabled(final String packageName, boolean enabled, int userId) {
+        final OverlayInfo oi = mOverlayManager.getOverlayInfo(packageName, UserHandle.of(userId));
+        assertNotNull(oi);
+        assertEquals(oi.isEnabled(), enabled);
+    }
+}
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
index d28c47d..420f755 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -22,8 +22,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.concurrent.Executor;
-
 @RunWith(JUnit4.class)
 @MediumTest
 public class WithMultipleOverlaysTest extends OverlayBaseTest {
@@ -33,9 +31,8 @@
 
     @BeforeClass
     public static void enableOverlay() throws Exception {
-        Executor executor = (cmd) -> new Thread(cmd).start();
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, true);
-        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
+        LocalOverlayManager.toggleOverlaysAndWait(
+                new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG},
+                new String[]{});
     }
 }
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
index 6566ad3..a86255e 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java
@@ -22,8 +22,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.concurrent.Executor;
-
 @RunWith(JUnit4.class)
 @MediumTest
 public class WithOverlayTest extends OverlayBaseTest {
@@ -32,10 +30,9 @@
     }
 
     @BeforeClass
-    public static void enableOverlay() throws Exception {
-        Executor executor = (cmd) -> new Thread(cmd).start();
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true);
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
-        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true);
+    public static void enableOverlays() throws Exception {
+        LocalOverlayManager.toggleOverlaysAndWait(
+                new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG},
+                new String[]{APP_OVERLAY_TWO_PKG});
     }
 }
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
index 48cfeab..51c4118 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -22,8 +22,6 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.concurrent.Executor;
-
 @RunWith(JUnit4.class)
 @MediumTest
 public class WithoutOverlayTest extends OverlayBaseTest {
@@ -33,9 +31,8 @@
 
     @BeforeClass
     public static void disableOverlays() throws Exception {
-        Executor executor = (cmd) -> new Thread(cmd).start();
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, false);
-        LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false);
-        LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, false);
+        LocalOverlayManager.toggleOverlaysAndWait(
+                new String[]{},
+                new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG});
     }
 }
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
index da3aa00..847b491 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp
@@ -15,6 +15,6 @@
 android_test {
     name: "OverlayDeviceTests_AppOverlayOne",
     sdk_version: "current",
-
+    certificate: "platform",
     aaptflags: ["--no-resource-removal"],
 }
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
index 215b66da3..7d5f82a 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp
@@ -15,6 +15,6 @@
 android_test {
     name: "OverlayDeviceTests_AppOverlayTwo",
     sdk_version: "current",
-
+    certificate: "platform",
     aaptflags: ["--no-resource-removal"],
 }
diff --git a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
index 4c3eaeb..7175f56 100644
--- a/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.internal.util;
 
+import static android.Manifest.permission.NETWORK_SETTINGS;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -82,6 +84,7 @@
     private int mAllowCoarseLocationApps;
     private int mFineLocationPermission;
     private int mAllowFineLocationApps;
+    private int mNetworkSettingsPermission;
     private int mCurrentUser;
     private boolean mIsLocationEnabled;
     private boolean mThrowSecurityException;
@@ -138,6 +141,7 @@
         mFineLocationPermission = PackageManager.PERMISSION_DENIED;
         mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
         mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
+        mNetworkSettingsPermission = PackageManager.PERMISSION_DENIED;
     }
 
     private void setupMockInterface() {
@@ -151,6 +155,8 @@
                 .thenReturn(mCoarseLocationPermission);
         when(mMockContext.checkPermission(mManifestStringFine, -1, mUid))
                 .thenReturn(mFineLocationPermission);
+        when(mMockContext.checkPermission(NETWORK_SETTINGS, -1, mUid))
+                .thenReturn(mNetworkSettingsPermission);
         when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled);
     }
 
@@ -264,6 +270,21 @@
         assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result);
     }
 
+    @Test
+    public void testenforceCanAccessScanResults_LocationModeDisabledHasNetworkSettings()
+            throws Exception {
+        mThrowSecurityException = false;
+        mIsLocationEnabled = false;
+        mNetworkSettingsPermission = PackageManager.PERMISSION_GRANTED;
+        setupTestCase();
+
+        final int result =
+                mChecker.checkLocationPermissionWithDetailInfo(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+        assertEquals(LocationPermissionChecker.SUCCEEDED, result);
+    }
+
+
     private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
         try {
             r.run();
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/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
index 6c733ba..33e8ded 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationChunkedStreamer.java
@@ -139,7 +139,9 @@
             int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength,
                     inputLength);
             inputLength -= inputConsumed;
-            inputOffset += inputOffset;
+            inputOffset += inputConsumed;
+            mChunkLength += inputConsumed;
+            if (mChunkLength < mChunkSizeMax) return output;
             byte[] o = mKeyStoreStream.update(mChunk);
             if (o != null) {
                 output = ArrayUtils.concat(output, o);
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/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 1fbb672..5d7fdff 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -91,6 +91,8 @@
     // For the recording session
     void startRecording(in IBinder sessionToken, in Uri programUri, in Bundle params, int userId);
     void stopRecording(in IBinder sessionToken, int userId);
+    void pauseRecording(in IBinder sessionToken, in Bundle params, int userId);
+    void resumeRecording(in IBinder sessionToken, in Bundle params, int userId);
 
     // For TV input hardware binding
     List<TvInputHardwareInfo> getHardwareList();
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 24b87d5..158cf21 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -58,4 +58,6 @@
     // For the recording session
     void startRecording(in Uri programUri, in Bundle params);
     void stopRecording();
+    void pauseRecording(in Bundle params);
+    void resumeRecording(in Bundle params);
 }
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index e89d33d..abccf8d 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -68,6 +68,8 @@
     private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 19;
     private static final int DO_START_RECORDING = 20;
     private static final int DO_STOP_RECORDING = 21;
+    private static final int DO_PAUSE_RECORDING = 22;
+    private static final int DO_RESUME_RECORDING = 23;
 
     private final boolean mIsRecordingSession;
     private final HandlerCaller mCaller;
@@ -224,6 +226,14 @@
                 mTvInputRecordingSessionImpl.stopRecording();
                 break;
             }
+            case DO_PAUSE_RECORDING: {
+                mTvInputRecordingSessionImpl.pauseRecording((Bundle) msg.obj);
+                break;
+            }
+            case DO_RESUME_RECORDING: {
+                mTvInputRecordingSessionImpl.resumeRecording((Bundle) msg.obj);
+                break;
+            }
             default: {
                 Log.w(TAG, "Unhandled message code: " + msg.what);
                 break;
@@ -363,6 +373,16 @@
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_STOP_RECORDING));
     }
 
+    @Override
+    public void pauseRecording(@Nullable Bundle params) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_PAUSE_RECORDING, params));
+    }
+
+    @Override
+    public void resumeRecording(@Nullable Bundle params) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RESUME_RECORDING, params));
+    }
+
     private final class TvInputEventReceiver extends InputEventReceiver {
         public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java
index b12f7c5..0bedbd3 100644
--- a/media/java/android/media/tv/TvInputHardwareInfo.java
+++ b/media/java/android/media/tv/TvInputHardwareInfo.java
@@ -188,6 +188,20 @@
         mCableConnectionStatus = source.readInt();
     }
 
+    /** @hide */
+    public Builder toBuilder() {
+        Builder newBuilder = new Builder()
+            .deviceId(mDeviceId)
+            .type(mType)
+            .audioType(mAudioType)
+            .audioAddress(mAudioAddress)
+            .cableConnectionStatus(mCableConnectionStatus);
+        if (mType == TV_INPUT_TYPE_HDMI) {
+            newBuilder.hdmiPortId(mHdmiPortId);
+        }
+        return newBuilder;
+    }
+
     public static final class Builder {
         private Integer mDeviceId = null;
         private Integer mType = null;
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 195ad5b..54cb2bf 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -143,6 +143,7 @@
     // Attributes from XML meta data.
     private final String mSetupActivity;
     private final boolean mCanRecord;
+    private final boolean mCanPauseRecording;
     private final int mTunerCount;
 
     // Attributes specific to HDMI
@@ -264,8 +265,8 @@
 
     private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
             CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
-            String setupActivity, boolean canRecord, int tunerCount, HdmiDeviceInfo hdmiDeviceInfo,
-            boolean isConnectedToHdmiSwitch,
+            String setupActivity, boolean canRecord, boolean canPauseRecording, int tunerCount,
+            HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch,
             @HdmiAddressRelativePosition int hdmiConnectionRelativePosition, String parentId,
             Bundle extras) {
         mService = service;
@@ -279,6 +280,7 @@
         mIconDisconnected = iconDisconnected;
         mSetupActivity = setupActivity;
         mCanRecord = canRecord;
+        mCanPauseRecording = canPauseRecording;
         mTunerCount = tunerCount;
         mHdmiDeviceInfo = hdmiDeviceInfo;
         mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
@@ -386,6 +388,14 @@
     }
 
     /**
+     * Returns {@code true} if this TV input can pause recording TV programs,
+     * {@code false} otherwise.
+     */
+    public boolean canPauseRecording() {
+        return mCanPauseRecording;
+    }
+
+    /**
      * Returns domain-specific extras associated with this TV input.
      */
     public Bundle getExtras() {
@@ -571,6 +581,7 @@
                 && Objects.equals(mIconDisconnected, obj.mIconDisconnected)
                 && TextUtils.equals(mSetupActivity, obj.mSetupActivity)
                 && mCanRecord == obj.mCanRecord
+                && mCanPauseRecording == obj.mCanPauseRecording
                 && mTunerCount == obj.mTunerCount
                 && Objects.equals(mHdmiDeviceInfo, obj.mHdmiDeviceInfo)
                 && mIsConnectedToHdmiSwitch == obj.mIsConnectedToHdmiSwitch
@@ -606,6 +617,7 @@
         dest.writeParcelable(mIconDisconnected, flags);
         dest.writeString(mSetupActivity);
         dest.writeByte(mCanRecord ? (byte) 1 : 0);
+        dest.writeByte(mCanPauseRecording ? (byte) 1 : 0);
         dest.writeInt(mTunerCount);
         dest.writeParcelable(mHdmiDeviceInfo, flags);
         dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
@@ -648,6 +660,7 @@
         mIconDisconnected = in.readParcelable(null);
         mSetupActivity = in.readString();
         mCanRecord = in.readByte() == 1;
+        mCanPauseRecording = in.readByte() == 1;
         mTunerCount = in.readInt();
         mHdmiDeviceInfo = in.readParcelable(null);
         mIsConnectedToHdmiSwitch = in.readByte() == 1;
@@ -695,6 +708,7 @@
         private Icon mIconDisconnected;
         private String mSetupActivity;
         private Boolean mCanRecord;
+        private Boolean mCanPauseRecording;
         private Integer mTunerCount;
         private TvInputHardwareInfo mTvInputHardwareInfo;
         private HdmiDeviceInfo mHdmiDeviceInfo;
@@ -879,6 +893,18 @@
         }
 
         /**
+         * Sets whether this TV input can pause recording TV programs or not.
+         *
+         * @param canPauseRecording Whether this TV input can pause recording TV programs.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        @NonNull
+        public Builder setCanPauseRecording(boolean canPauseRecording) {
+            this.mCanPauseRecording = canPauseRecording;
+            return this;
+        }
+
+        /**
          * Sets domain-specific extras associated with this TV input.
          *
          * @param extras Domain-specific extras associated with this TV input. Keys <em>must</em> be
@@ -927,7 +953,9 @@
             parseServiceMetadata(type);
             return new TvInputInfo(mResolveInfo, id, type, isHardwareInput, mLabel, mLabelResId,
                     mIcon, mIconStandby, mIconDisconnected, mSetupActivity,
-                    mCanRecord == null ? false : mCanRecord, mTunerCount == null ? 0 : mTunerCount,
+                    mCanRecord == null ? false : mCanRecord,
+                    mCanPauseRecording == null ? false : mCanPauseRecording,
+                    mTunerCount == null ? 0 : mTunerCount,
                     mHdmiDeviceInfo, isConnectedToHdmiSwitch, hdmiConnectionRelativePosition,
                     mParentId, mExtras);
         }
@@ -997,6 +1025,12 @@
                     mTunerCount = sa.getInt(
                             com.android.internal.R.styleable.TvInputService_tunerCount, 1);
                 }
+                if (mCanPauseRecording == null) {
+                    mCanPauseRecording = sa.getBoolean(
+                            com.android.internal.R.styleable.TvInputService_canPauseRecording,
+                            false);
+                }
+
                 sa.recycle();
             } catch (IOException | XmlPullParserException e) {
                 throw new IllegalStateException("Failed reading meta-data for " + si.packageName, e);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 98a01a4..6341dc2 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -2476,6 +2476,40 @@
         }
 
         /**
+         * Pauses TV program recording in the current recording session.
+         *
+         * @param params A set of extra parameters which might be handled with this event.
+         */
+        void pauseRecording(@NonNull Bundle params) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.pauseRecording(mToken, params, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Resumes TV program recording in the current recording session.
+         *
+         * @param params A set of extra parameters which might be handled with this event.
+         */
+        void resumeRecording(@NonNull Bundle params) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.resumeRecording(mToken, params, mUserId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
          * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
          * TvInputService.Session.appPrivateCommand()} on the current TvView.
          *
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index abbf478..0fe9d50 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1852,6 +1852,28 @@
 
 
         /**
+         * Called when the application requests to pause TV program recording. Recording must pause
+         * immediately when this method is called.
+         *
+         * If the pause request cannot be fulfilled, the session must call
+         * {@link #notifyError(int)}.
+         *
+         * @param params Domain-specific data for recording request.
+         */
+        public void onPauseRecording(@NonNull Bundle params) { }
+
+        /**
+         * Called when the application requests to resume TV program recording. Recording must
+         * resume immediately when this method is called.
+         *
+         * If the resume request cannot be fulfilled, the session must call
+         * {@link #notifyError(int)}.
+         *
+         * @param params Domain-specific data for recording request.
+         */
+        public void onResumeRecording(@NonNull Bundle params) { }
+
+        /**
          * Called when the application requests to release all the resources held by this recording
          * session.
          */
@@ -1903,6 +1925,22 @@
         }
 
         /**
+         * Calls {@link #onPauseRecording(Bundle)}.
+         *
+         */
+        void pauseRecording(@NonNull Bundle params) {
+            onPauseRecording(params);
+        }
+
+        /**
+         * Calls {@link #onResumeRecording(Bundle)}.
+         *
+         */
+        void resumeRecording(@NonNull Bundle params) {
+            onResumeRecording(params);
+        }
+
+        /**
          * Calls {@link #onAppPrivateCommand(String, Bundle)}.
          */
         void appPrivateCommand(String action, Bundle data) {
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 23fadac..180e2bd 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -30,6 +30,7 @@
 import android.util.Pair;
 
 import java.util.ArrayDeque;
+import java.util.Objects;
 import java.util.Queue;
 
 /**
@@ -49,6 +50,8 @@
 
     private boolean mIsRecordingStarted;
     private boolean mIsTuned;
+    private boolean mIsPaused;
+    private boolean mIsRecordingStopping;
     private final Queue<Pair<String, Bundle>> mPendingAppPrivateCommands = new ArrayDeque<>();
 
     /**
@@ -113,17 +116,22 @@
         if (TextUtils.isEmpty(inputId)) {
             throw new IllegalArgumentException("inputId cannot be null or an empty string");
         }
-        if (mIsRecordingStarted) {
+        if (mIsRecordingStarted && !mIsPaused) {
             throw new IllegalStateException("tune failed - recording already started");
         }
         if (mSessionCallback != null && TextUtils.equals(mSessionCallback.mInputId, inputId)) {
             if (mSession != null) {
+                mSessionCallback.mChannelUri = channelUri;
                 mSession.tune(channelUri, params);
             } else {
                 mSessionCallback.mChannelUri = channelUri;
                 mSessionCallback.mConnectionParams = params;
             }
+            mIsTuned = false;
         } else {
+            if (mIsPaused) {
+                throw new IllegalStateException("tune failed - inputId is changed during pause");
+            }
             resetInternal();
             mSessionCallback = new MySessionCallback(inputId, channelUri, params);
             if (mTvInputManager != null) {
@@ -148,6 +156,8 @@
             mSession.release();
             mIsTuned = false;
             mIsRecordingStarted = false;
+            mIsPaused = false;
+            mIsRecordingStopping = false;
             mSession = null;
         }
     }
@@ -169,7 +179,8 @@
      *
      * @param programUri The URI for the TV program to record, built by
      *            {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
-     * @throws IllegalStateException If {@link #tune} request hasn't been handled yet.
+     * @throws IllegalStateException If {@link #tune} request hasn't been handled yet or during
+     *            pause.
      */
     public void startRecording(@Nullable Uri programUri) {
         startRecording(programUri, Bundle.EMPTY);
@@ -195,11 +206,16 @@
      * @param params Domain-specific data for this request. Keys <em>must</em> be a scoped
      *            name, i.e. prefixed with a package name you own, so that different developers will
      *            not create conflicting keys.
-     * @throws IllegalStateException If {@link #tune} request hasn't been handled yet.
+     * @throws IllegalStateException If {@link #tune} request hasn't been handled yet or during
+     *            pause.
      */
     public void startRecording(@Nullable Uri programUri, @NonNull Bundle params) {
-        if (!mIsTuned) {
-            throw new IllegalStateException("startRecording failed - not yet tuned");
+        if (mIsRecordingStopping || !mIsTuned || mIsPaused) {
+            throw new IllegalStateException("startRecording failed -"
+                    + "recording not yet stopped or not yet tuned or paused");
+        }
+        if (mIsRecordingStarted) {
+            Log.w(TAG, "startRecording failed - recording already started");
         }
         if (mSession != null) {
             mSession.startRecording(programUri, params);
@@ -225,6 +241,103 @@
         }
         if (mSession != null) {
             mSession.stopRecording();
+            if (mIsRecordingStarted) {
+                mIsRecordingStopping = true;
+            }
+        }
+    }
+
+    /**
+     * Pause TV program recording in the current recording session. Recording is expected to pause
+     * immediately when this method is called. If recording has not yet started in the current
+     * recording session, this method does nothing.
+     *
+     * <p>In pause status, the application can tune during recording. To continue recording,
+     * please call {@link TvRecordingClient#resumeRecording()} to resume instead of
+     * {@link TvRecordingClient#startRecording(Uri)}. Application can stop
+     * the recording with {@link TvRecordingClient#stopRecording()} in recording pause status.
+     *
+     * <p>If the pause request cannot be fulfilled, the recording session will respond by calling
+     * {@link RecordingCallback#onError(int)}.
+     */
+    public void pauseRecording() {
+        pauseRecording(Bundle.EMPTY);
+    }
+
+    /**
+     * Pause TV program recording in the current recording session. Recording is expected to pause
+     * immediately when this method is called. If recording has not yet started in the current
+     * recording session, this method does nothing.
+     *
+     * <p>In pause status, the application can tune during recording. To continue recording,
+     * please call {@link TvRecordingClient#resumeRecording()} to resume instead of
+     * {@link TvRecordingClient#startRecording(Uri)}. Application can stop
+     * the recording with {@link TvRecordingClient#stopRecording()} in recording pause status.
+     *
+     * <p>If the pause request cannot be fulfilled, the recording session will respond by calling
+     * {@link RecordingCallback#onError(int)}.
+     *
+     * @param params Domain-specific data for this request.
+     */
+    public void pauseRecording(@NonNull Bundle params) {
+        if (!mIsRecordingStarted || mIsRecordingStopping) {
+            throw new IllegalStateException(
+                    "pauseRecording failed - recording not yet started or stopping");
+        }
+        TvInputInfo info = mTvInputManager.getTvInputInfo(mSessionCallback.mInputId);
+        if (info == null || !info.canPauseRecording()) {
+            throw new UnsupportedOperationException(
+                    "pauseRecording failed - operation not supported");
+        }
+        if (mIsPaused) {
+            Log.w(TAG, "pauseRecording failed - recording already paused");
+        }
+        if (mSession != null) {
+            mSession.pauseRecording(params);
+            mIsPaused  = true;
+        }
+    }
+
+    /**
+     * Resume TV program recording only in recording pause status in the current recording session.
+     * Recording is expected to resume immediately when this method is called. If recording has not
+     * yet paused in the current recording session, this method does nothing.
+     *
+     * <p>When record is resumed, the recording is continue and can not re-tune. Application can
+     * stop the recording with {@link TvRecordingClient#stopRecording()} after record resumed.
+     *
+     * <p>If the pause request cannot be fulfilled, the recording session will respond by calling
+     * {@link RecordingCallback#onError(int)}.
+     */
+    public void resumeRecording() {
+        resumeRecording(Bundle.EMPTY);
+    }
+
+    /**
+     * Resume TV program recording only in recording pause status in the current recording session.
+     * Recording is expected to resume immediately when this method is called. If recording has not
+     * yet paused in the current recording session, this method does nothing.
+     *
+     * <p>When record is resumed, the recording is continues and can not re-tune. Application can
+     * stop the recording with {@link TvRecordingClient#stopRecording()} after record resumed.
+     *
+     * <p>If the resume request cannot be fulfilled, the recording session will respond by calling
+     * {@link RecordingCallback#onError(int)}.
+     *
+     * @param params Domain-specific data for this request.
+     */
+    public void resumeRecording(@NonNull Bundle params) {
+        if (!mIsRecordingStarted || mIsRecordingStopping || !mIsTuned) {
+            throw new IllegalStateException(
+                    "resumeRecording failed - recording not yet started or stopping or "
+                            + "not yet tuned");
+        }
+        if (!mIsPaused) {
+            Log.w(TAG, "resumeRecording failed - recording not yet paused");
+        }
+        if (mSession != null) {
+            mSession.resumeRecording(params);
+            mIsPaused  = false;
         }
     }
 
@@ -367,6 +480,10 @@
                 Log.w(TAG, "onTuned - session not created");
                 return;
             }
+            if (mIsTuned || !Objects.equals(mChannelUri, channelUri)) {
+                Log.w(TAG, "onTuned - already tuned or not yet tuned to last channel");
+                return;
+            }
             mIsTuned = true;
             mCallback.onTuned(channelUri);
         }
@@ -382,6 +499,8 @@
             }
             mIsTuned = false;
             mIsRecordingStarted = false;
+            mIsPaused = false;
+            mIsRecordingStopping = false;
             mSessionCallback = null;
             mSession = null;
             if (mCallback != null) {
@@ -398,7 +517,13 @@
                 Log.w(TAG, "onRecordingStopped - session not created");
                 return;
             }
+            if (!mIsRecordingStarted) {
+                Log.w(TAG, "onRecordingStopped - recording not yet started");
+                return;
+            }
             mIsRecordingStarted = false;
+            mIsPaused = false;
+            mIsRecordingStopping = false;
             mCallback.onRecordingStopped(recordedProgramUri);
         }
 
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/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index c63cf06..2b5e9cd 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -291,7 +291,7 @@
         <item>256K</item>
         <item>1M</item>
         <item>4M</item>
-        <item>16M</item>
+        <item>8M</item>
     </string-array>
 
     <!-- Titles for logd limit size lowram selection preference. [CHAR LIMIT=14] -->
@@ -309,7 +309,7 @@
         <item>262144</item>
         <item>1048576</item>
         <item>4194304</item>
-        <item>16777216</item>
+        <item>8388608</item>
     </string-array>
 
     <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=50]-->
@@ -319,7 +319,7 @@
         <item>256K per log buffer</item>
         <item>1M per log buffer</item>
         <item>4M per log buffer</item>
-        <item>16M per log buffer</item>
+        <item>8M per log buffer</item>
     </string-array>
 
     <!-- Values for logpersist state selection preference. -->
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 741a680..4b6862c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -156,6 +156,7 @@
     <uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" />
     <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
     <uses-permission android:name="android.permission.MANAGE_SEARCH_UI" />
+    <uses-permission android:name="android.permission.MANAGE_SMARTSPACE" />
     <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.SET_TIME" />
@@ -345,6 +346,9 @@
     <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
     <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
 
+    <!-- Permission required for CTS test - CtsSensorPrivacyTestCases -->
+    <uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
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/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 309d4b0..c5a35ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -29,7 +29,6 @@
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.IConnectivityManager;
 import android.net.Network;
-import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -66,12 +65,8 @@
     private static final String TAG = "SecurityController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final NetworkRequest REQUEST = new NetworkRequest.Builder()
-            .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
-            .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-            .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
-            .setUids(null)
-            .build();
+    private static final NetworkRequest REQUEST =
+            new NetworkRequest.Builder().clearCapabilities().build();
     private static final int NO_NETWORK = -1;
 
     private static final String VPN_BRANDED_META_DATA = "com.android.systemui.IS_BRANDED";
diff --git a/packages/services/CameraExtensionsProxy/OWNERS b/packages/services/CameraExtensionsProxy/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/packages/services/CameraExtensionsProxy/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
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 d0a5f33..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;
@@ -194,7 +199,6 @@
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.DnsManager;
 import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
-import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.KeepaliveTracker;
 import com.android.server.connectivity.LingerMonitor;
 import com.android.server.connectivity.MockableSystemProperties;
@@ -205,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;
@@ -280,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.
 
@@ -292,6 +301,8 @@
     @VisibleForTesting
     protected final PermissionMonitor mPermissionMonitor;
 
+    private final PerUidCounter mNetworkRequestCounter;
+
     private KeyStore mKeyStore;
 
     @VisibleForTesting
@@ -615,6 +626,7 @@
     private final LocationPermissionChecker mLocationPermissionChecker;
 
     private KeepaliveTracker mKeepaliveTracker;
+    private QosCallbackTracker mQosCallbackTracker;
     private NetworkNotificationManager mNotifier;
     private LingerMonitor mLingerMonitor;
 
@@ -859,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
@@ -889,6 +961,13 @@
         }
 
         /**
+         * Get a reference to the system keystore.
+         */
+        public KeyStore getKeyStore() {
+            return KeyStore.getInstance();
+        }
+
+        /**
          * @see ProxyTracker
          */
         public ProxyTracker makeProxyTracker(@NonNull Context context,
@@ -918,14 +997,6 @@
             return new MultinetworkPolicyTracker(c, h, r);
         }
 
-        /**
-         * @see IpConnectivityMetrics.Logger
-         */
-        public IpConnectivityMetrics.Logger getMetricsLogger() {
-            return Objects.requireNonNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
-                    "no IpConnectivityMetrics service");
-        }
-
         public IBatteryStats getBatteryStatsService() {
             return BatteryStatsService.getService();
         }
@@ -947,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);
@@ -990,7 +1062,7 @@
         mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
         mNetd = netd;
-        mKeyStore = KeyStore.getInstance();
+        mKeyStore = mDeps.getKeyStore();
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mLocationPermissionChecker = new LocationPermissionChecker(mContext);
@@ -1117,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();
@@ -1131,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,
@@ -1569,7 +1638,7 @@
         if (nc != null) {
             result.put(
                     nai.network,
-                    maybeSanitizeLocationInfoForCaller(
+                    createWithLocationInfoSanitizedIfNecessaryWhenParceled(
                             nc, mDeps.getCallingUid(), callingPackageName));
         }
 
@@ -1579,7 +1648,9 @@
             for (Network network : networks) {
                 nc = getNetworkCapabilitiesInternal(network);
                 if (nc != null) {
-                    result.put(network, maybeSanitizeLocationInfoForCaller(
+                    result.put(
+                            network,
+                            createWithLocationInfoSanitizedIfNecessaryWhenParceled(
                                     nc, mDeps.getCallingUid(), callingPackageName));
                 }
             }
@@ -1651,7 +1722,6 @@
     private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
         if (nai == null) return null;
         synchronized (nai) {
-            if (nai.networkCapabilities == null) return null;
             return networkCapabilitiesRestrictedForCallerPermissions(
                     nai.networkCapabilities, Binder.getCallingPid(), mDeps.getCallingUid());
         }
@@ -1661,7 +1731,7 @@
     public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
         mAppOpsManager.checkPackage(mDeps.getCallingUid(), callingPackageName);
         enforceAccessPermission();
-        return maybeSanitizeLocationInfoForCaller(
+        return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
                 getNetworkCapabilitiesInternal(network),
                 mDeps.getCallingUid(), callingPackageName);
     }
@@ -1682,37 +1752,51 @@
         return newNc;
     }
 
+    private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return mLocationPermissionChecker.checkLocationPermission(
+                    callerPkgName, null /* featureId */, callerUid, null /* message */);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     @VisibleForTesting
     @Nullable
-    NetworkCapabilities maybeSanitizeLocationInfoForCaller(
+    NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
             @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
         if (nc == null) {
             return null;
         }
-        final NetworkCapabilities newNc = new NetworkCapabilities(nc);
-        if (callerUid != newNc.getOwnerUid()) {
+        Boolean hasLocationPermission = null;
+        final NetworkCapabilities newNc;
+        // Avoid doing location permission check if the transport info has no location sensitive
+        // data.
+        if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
+            hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+            newNc = new NetworkCapabilities(nc, hasLocationPermission);
+        } else {
+            newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */);
+        }
+        // Reset owner uid if not destined for the owner app.
+        if (callerUid != nc.getOwnerUid()) {
             newNc.setOwnerUid(INVALID_UID);
             return newNc;
         }
-
         // Allow VPNs to see ownership of their own VPN networks - not location sensitive.
         if (nc.hasTransport(TRANSPORT_VPN)) {
             // Owner UIDs already checked above. No need to re-check.
             return newNc;
         }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            if (!mLocationPermissionChecker.checkLocationPermission(
-                    callerPkgName, null /* featureId */, callerUid, null /* message */)) {
-                // Caller does not have the requisite location permissions. Reset the
-                // owner's UID in the NetworkCapabilities.
-                newNc.setOwnerUid(INVALID_UID);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
+        if (hasLocationPermission == null) {
+            // Location permission not checked yet, check now for masking owner UID.
+            hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
         }
-
+        // Reset owner uid if the app has no location permission.
+        if (!hasLocationPermission) {
+            newNc.setOwnerUid(INVALID_UID);
+        }
         return newNc;
     }
 
@@ -1789,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.
      */
@@ -2261,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
@@ -2380,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.
      */
@@ -2761,7 +2739,6 @@
     }
 
     private boolean isLiveNetworkAgent(NetworkAgentInfo nai, int what) {
-        if (nai.network == null) return false;
         final NetworkAgentInfo officialNai = getNetworkAgentInfoForNetwork(nai.network);
         if (officialNai != null && officialNai.equals(nai)) return true;
         if (officialNai != null || VDBG) {
@@ -2862,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;
@@ -2881,6 +2852,7 @@
                         updateCapabilitiesForNetwork(nai);
                         notifyIfacesChangedForNetworkStats();
                     }
+                    break;
                 }
             }
         }
@@ -3442,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);
@@ -3454,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);
@@ -3466,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());
         }
@@ -3708,7 +3685,7 @@
         nri.unlinkDeathRecipient();
         mNetworkRequests.remove(nri.request);
 
-        decrementNetworkRequestPerUidCount(nri);
+        mNetworkRequestCounter.decrementCount(nri.mUid);
 
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
         if (nri.request.isRequest()) {
@@ -3781,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();
@@ -4620,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);
     }
@@ -4977,16 +4945,23 @@
         mVpnBlockedUidRanges = newVpnBlockedUidRanges;
     }
 
+    private boolean isLockdownVpnEnabled() {
+        return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
+    }
+
     @Override
     public boolean updateLockdownVpn() {
-        if (mDeps.getCallingUid() != Process.SYSTEM_UID) {
-            logw("Lockdown VPN only available to AID_SYSTEM");
+        // Allow the system UID for the system server and for Settings.
+        // Also, for unit tests, allow the process that ConnectivityService is running in.
+        if (mDeps.getCallingUid() != Process.SYSTEM_UID
+                && Binder.getCallingPid() != Process.myPid()) {
+            logw("Lockdown VPN only available to system process or AID_SYSTEM");
             return false;
         }
 
         synchronized (mVpns) {
             // Tear down existing lockdown if profile was removed
-            mLockdownEnabled = LockdownVpnTracker.isEnabled();
+            mLockdownEnabled = isLockdownVpnEnabled();
             if (mLockdownEnabled) {
                 byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
                 if (profileTag == null) {
@@ -5007,7 +4982,8 @@
                     logw("VPN for user " + user + " not ready yet. Skipping lockdown");
                     return false;
                 }
-                setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
+                setLockdownTracker(
+                        new LockdownVpnTracker(mContext, this, mHandler, mKeyStore, vpn,  profile));
             } else {
                 setLockdownTracker(null);
             }
@@ -5095,7 +5071,7 @@
 
         synchronized (mVpns) {
             // Can't set always-on VPN if legacy VPN is already in lockdown mode.
-            if (LockdownVpnTracker.isEnabled()) {
+            if (isLockdownVpnEnabled()) {
                 return false;
             }
 
@@ -5201,7 +5177,7 @@
             }
             userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
             mVpns.put(userId, userVpn);
-            if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
             }
         }
@@ -5285,7 +5261,7 @@
     private void onUserUnlocked(int userId) {
         synchronized (mVpns) {
             // User present may be sent because of an unlock, which might mean an unlocked keystore.
-            if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
+            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
             } else {
                 startAlwaysOnVpn(userId);
@@ -5354,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;
@@ -5472,7 +5443,7 @@
             mBinder = null;
             mPid = getCallingPid();
             mUid = mDeps.getCallingUid();
-            enforceRequestCountLimit();
+            mNetworkRequestCounter.incrementCountOrThrow(mUid);
         }
 
         NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) {
@@ -5485,7 +5456,7 @@
             mPid = getCallingPid();
             mUid = mDeps.getCallingUid();
             mPendingIntent = null;
-            enforceRequestCountLimit();
+            mNetworkRequestCounter.incrementCountOrThrow(mUid);
 
             try {
                 mBinder.linkToDeath(this, 0);
@@ -5522,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);
@@ -5642,31 +5602,40 @@
 
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
-            Messenger messenger, int timeoutMs, IBinder binder, int legacyType,
-            @NonNull String callingPackageName, @Nullable String callingAttributionTag) {
+            int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
+            int legacyType, @NonNull String callingPackageName,
+            @Nullable String callingAttributionTag) {
         if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
             if (checkUnsupportedStartingFrom(Build.VERSION_CODES.M, callingPackageName)) {
                 throw new SecurityException("Insufficient permissions to specify legacy type");
             }
         }
         final int callingUid = mDeps.getCallingUid();
-        final NetworkRequest.Type type = (networkCapabilities == null)
-                ? NetworkRequest.Type.TRACK_DEFAULT
-                : NetworkRequest.Type.REQUEST;
-        // If the requested networkCapabilities is null, take them instead from
-        // the default network request. This allows callers to keep track of
-        // the system default network.
-        if (type == NetworkRequest.Type.TRACK_DEFAULT) {
-            networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
-            enforceAccessPermission();
-        } else {
-            networkCapabilities = new NetworkCapabilities(networkCapabilities);
-            enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
-                    callingAttributionTag);
-            // TODO: this is incorrect. We mark the request as metered or not depending on the state
-            // of the app when the request is filed, but we never change the request if the app
-            // changes network state. http://b/29964605
-            enforceMeteredApnPolicy(networkCapabilities);
+        final NetworkRequest.Type reqType;
+        try {
+            reqType = NetworkRequest.Type.values()[reqTypeInt];
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw new IllegalArgumentException("Unsupported request type " + reqTypeInt);
+        }
+        switch (reqType) {
+            case TRACK_DEFAULT:
+                // If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
+                // is unused and will be replaced by the one from the default network request.
+                // This allows callers to keep track of the system default network.
+                networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
+                enforceAccessPermission();
+                break;
+            case REQUEST:
+                networkCapabilities = new NetworkCapabilities(networkCapabilities);
+                enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
+                        callingAttributionTag);
+                // TODO: this is incorrect. We mark the request as metered or not depending on
+                //  the state of the app when the request is filed, but we never change the
+                //  request if the app changes network state. http://b/29964605
+                enforceMeteredApnPolicy(networkCapabilities);
+                break;
+            default:
+                throw new IllegalArgumentException("Unsupported request type " + reqType);
         }
         ensureRequestableCapabilities(networkCapabilities);
         ensureSufficientPermissionsForRequest(networkCapabilities,
@@ -5685,7 +5654,7 @@
         ensureValid(networkCapabilities);
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
-                nextNetworkRequestId(), type);
+                nextNetworkRequestId(), reqType);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
         if (DBG) log("requestNetwork for " + nri);
 
@@ -5745,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);
         }
     }
 
@@ -6043,6 +6017,10 @@
     public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
+        Objects.requireNonNull(networkInfo, "networkInfo must not be null");
+        Objects.requireNonNull(linkProperties, "linkProperties must not be null");
+        Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+        Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null");
         if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
             enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
         } else {
@@ -6078,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);
@@ -6581,7 +6559,7 @@
         }
 
         // Don't modify caller's NetworkCapabilities.
-        NetworkCapabilities newNc = new NetworkCapabilities(nc);
+        final NetworkCapabilities newNc = new NetworkCapabilities(nc);
         if (nai.lastValidated) {
             newNc.addCapability(NET_CAPABILITY_VALIDATED);
         } else {
@@ -6669,26 +6647,21 @@
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
 
-        // TODO : static analysis indicates that prevNc can't be null here (getAndSetNetworkCaps
-        // never returns null), so mark the relevant members and functions in nai as @NonNull and
-        // remove this test
-        if (prevNc != null) {
-            final boolean oldMetered = prevNc.isMetered();
-            final boolean newMetered = newNc.isMetered();
-            final boolean meteredChanged = oldMetered != newMetered;
+        final boolean oldMetered = prevNc.isMetered();
+        final boolean newMetered = newNc.isMetered();
+        final boolean meteredChanged = oldMetered != newMetered;
 
-            if (meteredChanged) {
-                maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
-                        mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
-            }
+        if (meteredChanged) {
+            maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
+                    mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
+        }
 
-            final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
-                    newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+        final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
+                != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
 
-            // Report changes that are interesting for network statistics tracking.
-            if (meteredChanged || roamingChanged) {
-                notifyIfacesChangedForNetworkStats();
-            }
+        // Report changes that are interesting for network statistics tracking.
+        if (meteredChanged || roamingChanged) {
+            notifyIfacesChangedForNetworkStats();
         }
 
         // This network might have been underlying another network. Propagate its capabilities.
@@ -6967,7 +6940,7 @@
                                 networkAgent.networkCapabilities, nri.mPid, nri.mUid);
                 putParcelable(
                         bundle,
-                        maybeSanitizeLocationInfoForCaller(
+                        createWithLocationInfoSanitizedIfNecessaryWhenParceled(
                                 nc, nri.mUid, nri.request.getRequestorPackageName()));
                 putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
                         networkAgent.linkProperties, nri.mPid, nri.mUid));
@@ -6986,7 +6959,7 @@
                                 networkAgent.networkCapabilities, nri.mPid, nri.mUid);
                 putParcelable(
                         bundle,
-                        maybeSanitizeLocationInfoForCaller(
+                        createWithLocationInfoSanitizedIfNecessaryWhenParceled(
                                 netCap, nri.mUid, nri.request.getRequestorPackageName()));
                 break;
             }
@@ -7283,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);
 
@@ -7563,10 +7537,6 @@
         if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
             networkAgent.everConnected = true;
 
-            if (networkAgent.linkProperties == null) {
-                Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
-            }
-
             // NetworkCapabilities need to be set before sending the private DNS config to
             // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
             networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities);
@@ -7885,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,
@@ -7896,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);
             }
         }
     }
@@ -8364,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;
         }
 
@@ -8430,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);
     }
@@ -8639,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 c8d457d..4e2519b 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1537,6 +1537,9 @@
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
 
         } else if (vol.type == VolumeInfo.TYPE_STUB) {
+            if (vol.disk.isStubVisible()) {
+                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
+            }
             vol.mountUserId = mCurrentUserId;
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
         } else {
@@ -1606,7 +1609,6 @@
         }
     }
 
-
     private void onVolumeStateChangedAsync(VolumeInfo vol, int oldState, int newState) {
         synchronized (mLock) {
             // Remember that we saw this volume so we're ready to accept user
@@ -3295,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));
@@ -3427,6 +3435,27 @@
         }
     }
 
+    /*
+     * Disable storage's app data isolation for testing.
+     */
+    @Override
+    public void disableAppDataIsolation(String pkgName, int pid, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) {
+            throw new SecurityException("no permission to enable app visibility");
+        }
+        final String[] sharedPackages =
+                mPmInternal.getSharedUserPackagesForPackage(pkgName, userId);
+        final int uid = mPmInternal.getPackageUid(pkgName, 0, userId);
+        final String[] packages =
+                sharedPackages.length != 0 ? sharedPackages : new String[]{pkgName};
+        try {
+            mVold.unmountAppStorageDirs(uid, pid, packages);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     /** Not thread safe */
     class AppFuseMountScope extends AppFuseBridge.MountScope {
         private boolean mMounted = false;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 5f6e8df..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;
@@ -64,6 +63,7 @@
 import android.telephony.LocationAccessPolicy;
 import android.telephony.PhoneCapability;
 import android.telephony.PhoneStateListener;
+import android.telephony.PhysicalChannelConfig;
 import android.telephony.PreciseCallState;
 import android.telephony.PreciseDataConnectionState;
 import android.telephony.PreciseDisconnectCause;
@@ -78,6 +78,7 @@
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Pair;
 
@@ -99,10 +100,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Since phone process can be restarted, this class provides a centralized place
@@ -142,14 +146,14 @@
         int callerUid;
         int callerPid;
 
-        int events;
+        Set<Integer> eventList;
 
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
         int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 
-        boolean matchPhoneStateListenerEvent(int events) {
-            return (callback != null) && ((events & this.events) != 0);
+        boolean matchPhoneStateListenerEvent(int event) {
+            return (callback != null) && (this.eventList.contains(event));
         }
 
         boolean matchOnSubscriptionsChangedListener() {
@@ -177,7 +181,7 @@
                     + onSubscriptionsChangedListenerCallback
                     + " onOpportunisticSubscriptionsChangedListenererCallback="
                     + onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId
-                    + " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}";
+                    + " phoneId=" + phoneId + " events=" + eventList + "}";
         }
     }
 
@@ -306,6 +310,12 @@
 
     private final LocalLog mListenLog = new LocalLog(200);
 
+    private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
+
+    private boolean mIsDataEnabled = false;
+
+    private int mDataEnabledReason;
+
     /**
      * Per-phone map of precise data connection state. The key of the map is the pair of transport
      * type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
@@ -315,39 +325,62 @@
     private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
             mPreciseDataConnectionStates;
 
-    // Starting in Q, almost all cellular location requires FINE location enforcement.
-    // Prior to Q, cellular was available with COARSE location enforcement. Bits in this
-    // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later.
-    static final int ENFORCE_LOCATION_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_CELL_LOCATION
-                    | PhoneStateListener.LISTEN_CELL_INFO
-                    | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
-                    | PhoneStateListener.LISTEN_BARRING_INFO;
+    private static final Set<Integer> REQUIRE_PRECISE_PHONE_STATE_PERMISSION;
+    static {
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION = new HashSet<Integer>();
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_DATA_ENABLED_CHANGED);
+    }
 
-    static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
-                    | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
-                    | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
-                    | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED;
+    private boolean isLocationPermissionRequired(Set<Integer> events) {
+        return events.contains(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_CELL_INFO_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_REGISTRATION_FAILURE)
+                || events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+    }
 
-    static final int ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_PRECISE_CALL_STATE
-                    | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
-                    | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
-                    | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED
-                    | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
-                    | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
-                    | PhoneStateListener.LISTEN_BARRING_INFO;
+    private boolean isPhoneStatePermissionRequired(Set<Integer> events) {
+        return events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+    }
 
-    static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL
-                    | PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS;
+    private boolean isPrecisePhoneStatePermissionRequired(Set<Integer> events) {
+        for (Integer requireEvent : REQUIRE_PRECISE_PHONE_STATE_PERMISSION) {
+            if (events.contains(requireEvent)) {
+                return true;
+            }
+        }
+        return false;
+    }
 
-    static final int READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT
-                    | PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED
-                    | PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED
-                    | PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE;
+    private boolean isActiveEmergencySessionPermissionRequired(Set<Integer> events) {
+        return events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)
+                || events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+    }
+
+    private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) {
+        return events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+    }
 
     private static final int MSG_USER_SWITCHED = 1;
     private static final int MSG_UPDATE_DEFAULT_SUB = 2;
@@ -495,6 +528,7 @@
             cutListToSize(mImsReasonInfo, mNumPhones);
             cutListToSize(mPreciseDataConnectionStates, mNumPhones);
             cutListToSize(mBarringInfo, mNumPhones);
+            cutListToSize(mPhysicalChannelConfigs, mNumPhones);
             return;
         }
 
@@ -528,6 +562,7 @@
             mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
             mTelephonyDisplayInfos[i] = null;
+            mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
         }
     }
 
@@ -548,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();
@@ -588,6 +621,7 @@
         mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones];
         mBarringInfo = new ArrayList<>();
         mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones];
+        mPhysicalChannelConfigs = new ArrayList<>();
         for (int i = 0; i < numPhones; i++) {
             mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
             mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -617,6 +651,7 @@
             mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
             mTelephonyDisplayInfos[i] = null;
+            mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build());
         }
 
         mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -659,7 +694,7 @@
             r.callingFeatureId = callingFeatureId;
             r.callerUid = Binder.getCallingUid();
             r.callerPid = Binder.getCallingPid();
-            r.events = 0;
+            r.eventList = new ArraySet<>();
             if (DBG) {
                 log("listen oscl:  Register r=" + r);
             }
@@ -713,7 +748,7 @@
             r.callingFeatureId = callingFeatureId;
             r.callerUid = Binder.getCallingUid();
             r.callerPid = Binder.getCallingPid();
-            r.events = 0;
+            r.eventList = new ArraySet<>();
             if (DBG) {
                 log("listen ooscl:  Register r=" + r);
             }
@@ -786,323 +821,337 @@
         }
     }
 
-    @Deprecated
     @Override
-    public void listen(String callingPackage, IPhoneStateListener callback, int events,
-            boolean notifyNow) {
-        listenWithFeature(callingPackage, null, callback, events, notifyNow);
-    }
-
-    @Override
-    public void listenWithFeature(String callingPackage, String callingFeatureId,
-            IPhoneStateListener callback, int events, boolean notifyNow) {
-        listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, callingPackage,
-                callingFeatureId, callback, events, notifyNow);
-    }
-
-    @Override
-    public void listenForSubscriber(int subId, String callingPackage, String callingFeatureId,
-            IPhoneStateListener callback, int events, boolean notifyNow) {
-        listen(callingPackage, callingFeatureId, callback, events, notifyNow, subId);
+    public void listenWithEventList(int subId, String callingPackage, String callingFeatureId,
+            IPhoneStateListener callback, int[] events, boolean notifyNow) {
+        Set<Integer> eventList = Arrays.stream(events).boxed().collect(Collectors.toSet());
+        listen(callingPackage, callingFeatureId, callback, eventList, notifyNow, subId);
     }
 
     private void listen(String callingPackage, @Nullable String callingFeatureId,
-            IPhoneStateListener callback, int events, boolean notifyNow, int subId) {
+            IPhoneStateListener callback, Set<Integer> events, boolean notifyNow, int subId) {
         int callerUserId = UserHandle.getCallingUserId();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         String str = "listen: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
-                + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId="
-                + subId + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId;
+                + " events=" + events + " notifyNow=" + notifyNow
+                + " subId=" + subId + " myUserId=" + UserHandle.myUserId()
+                + " callerUserId=" + callerUserId;
         mListenLog.log(str);
         if (VDBG) {
             log(str);
         }
 
-        if (events != PhoneStateListener.LISTEN_NONE) {
-            // Checks permission and throws SecurityException for disallowed operations. For pre-M
-            // apps whose runtime permission has been revoked, we return immediately to skip sending
-            // events to the app without crashing it.
-            if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId,
-                    "listen")) {
+        if (events.isEmpty()) {
+            if (DBG) {
+                log("listen: Unregister");
+            }
+            events.clear();
+            remove(callback.asBinder());
+            return;
+        }
+
+        // Checks permission and throws SecurityException for disallowed operations. For pre-M
+        // apps whose runtime permission has been revoked, we return immediately to skip sending
+        // events to the app without crashing it.
+        if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId,
+                "listen")) {
+            return;
+        }
+
+        int phoneId = getPhoneIdFromSubId(subId);
+        synchronized (mRecords) {
+            // register
+            IBinder b = callback.asBinder();
+            boolean doesLimitApply =
+                    Binder.getCallingUid() != Process.SYSTEM_UID
+                            && Binder.getCallingUid() != Process.PHONE_UID
+                            && Binder.getCallingUid() != Process.myUid();
+            Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);
+
+            if (r == null) {
                 return;
             }
 
-            int phoneId = getPhoneIdFromSubId(subId);
-            synchronized (mRecords) {
-                // register
-                IBinder b = callback.asBinder();
-                boolean doesLimitApply =
-                        Binder.getCallingUid() != Process.SYSTEM_UID
-                        && Binder.getCallingUid() != Process.PHONE_UID
-                        && Binder.getCallingUid() != Process.myUid();
-                Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);
-
-                if (r == null) {
-                    return;
+            r.context = mContext;
+            r.callback = callback;
+            r.callingPackage = callingPackage;
+            r.callingFeatureId = callingFeatureId;
+            r.callerUid = Binder.getCallingUid();
+            r.callerPid = Binder.getCallingPid();
+            // Legacy applications pass SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+            // force all illegal subId to SubscriptionManager.DEFAULT_SUBSCRIPTION_ID
+            if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+                r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+            } else {//APP specify subID
+                r.subId = subId;
+            }
+            r.phoneId = phoneId;
+            r.eventList = events;
+            if (DBG) {
+                log("listen:  Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
+            }
+            if (notifyNow && validatePhoneId(phoneId)) {
+                if (events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)) {
+                    try {
+                        if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
+                        ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
+                        if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+                            r.callback.onServiceStateChanged(rawSs);
+                        } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+                            r.callback.onServiceStateChanged(
+                                    rawSs.createLocationInfoSanitizedCopy(false));
+                        } else {
+                            r.callback.onServiceStateChanged(
+                                    rawSs.createLocationInfoSanitizedCopy(true));
+                        }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
                 }
-
-                r.context = mContext;
-                r.callback = callback;
-                r.callingPackage = callingPackage;
-                r.callingFeatureId = callingFeatureId;
-                r.callerUid = Binder.getCallingUid();
-                r.callerPid = Binder.getCallingPid();
-                // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
-                // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
-                if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-                    r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
-                 } else {//APP specify subID
-                    r.subId = subId;
+                if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) {
+                    try {
+                        if (mSignalStrength[phoneId] != null) {
+                            int gsmSignalStrength = mSignalStrength[phoneId]
+                                    .getGsmSignalStrength();
+                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+                                    : gsmSignalStrength));
+                        }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
                 }
-                r.phoneId = phoneId;
-                r.events = events;
-                if (DBG) {
-                    log("listen:  Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
+                if (events.contains(
+                        PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
+                    try {
+                        r.callback.onMessageWaitingIndicatorChanged(
+                                mMessageWaiting[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
                 }
-                if (notifyNow && validatePhoneId(phoneId)) {
-                    if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
-                        try {
-                            if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
-                            ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
-                            if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                r.callback.onServiceStateChanged(rawSs);
-                            } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                r.callback.onServiceStateChanged(
-                                        rawSs.createLocationInfoSanitizedCopy(false));
-                            } else {
-                                r.callback.onServiceStateChanged(
-                                        rawSs.createLocationInfoSanitizedCopy(true));
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                if (events.contains(
+                        PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
+                    try {
+                        r.callback.onCallForwardingIndicatorChanged(
+                                mCallForwarding[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
-                        try {
-                            if (mSignalStrength[phoneId] != null) {
-                                int gsmSignalStrength = mSignalStrength[phoneId]
-                                        .getGsmSignalStrength();
-                                r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
-                                        : gsmSignalStrength));
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (validateEventAndUserLocked(
+                        r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) {
+                    try {
+                        if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
+                        if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+                                && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+                            // null will be translated to empty CellLocation object in client.
+                            r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
-                        try {
-                            r.callback.onMessageWaitingIndicatorChanged(
-                                    mMessageWaiting[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_CALL_STATE_CHANGED)) {
+                    try {
+                        r.callback.onCallStateChanged(mCallState[phoneId],
+                                getCallIncomingNumber(r, phoneId));
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
-                        try {
-                            r.callback.onCallForwardingIndicatorChanged(
-                                    mCallForwarding[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
-                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
-                        try {
-                            if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
-                            if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
-                                    && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                // null will be translated to empty CellLocation object in client.
-                                r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
-                    if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
-                        try {
-                            r.callback.onCallStateChanged(mCallState[phoneId],
-                                     getCallIncomingNumber(r, phoneId));
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
-                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
-                        try {
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                }
+                if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
+                    try {
+                        r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
                                 mDataConnectionNetworkType[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
-                        try {
-                            r.callback.onDataActivity(mDataActivity[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)) {
+                    try {
+                        r.callback.onDataActivity(mDataActivity[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
-                        try {
-                            if (mSignalStrength[phoneId] != null) {
-                                r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)) {
+                    try {
+                        if (mSignalStrength[phoneId] != null) {
+                            r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
-                            != 0) {
-                        updateReportSignalStrengthDecision(r.subId);
-                        try {
-                            if (mSignalStrength[phoneId] != null) {
-                                r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+                    updateReportSignalStrengthDecision(r.subId);
+                    try {
+                        if (mSignalStrength[phoneId] != null) {
+                            r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
-                        try {
-                            if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
-                                    + mCellInfo.get(phoneId));
-                            if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
-                                    && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (validateEventAndUserLocked(
+                        r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) {
+                    try {
+                        if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+                                + mCellInfo.get(phoneId));
+                        if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+                                && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+                            r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
-                        try {
-                            r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)) {
+                    try {
+                        r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
-                        try {
-                            r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
-                                    mCallPreciseDisconnectCause[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) {
+                    try {
+                        r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
+                                mCallPreciseDisconnectCause[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
-                        try {
-                            r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) {
+                    try {
+                        r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
-                        try {
-                            for (PreciseDataConnectionState pdcs
-                                    : mPreciseDataConnectionStates.get(phoneId).values()) {
-                                r.callback.onPreciseDataConnectionStateChanged(pdcs);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) {
+                    try {
+                        for (PreciseDataConnectionState pdcs
+                                : mPreciseDataConnectionStates.get(phoneId).values()) {
+                            r.callback.onPreciseDataConnectionStateChanged(pdcs);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
-                        try {
-                            r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)) {
+                    try {
+                        r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) !=0) {
-                        try {
-                            r.callback.onVoiceActivationStateChanged(
-                                    mVoiceActivationState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) {
+                    try {
+                        r.callback.onVoiceActivationStateChanged(
+                                mVoiceActivationState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) !=0) {
-                        try {
-                            r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)) {
+                    try {
+                        r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
-                        try {
-                            r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
+                    try {
+                        r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
-                        try {
-                            if (mTelephonyDisplayInfos[phoneId] != null) {
-                                r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) {
+                    try {
+                        if (mTelephonyDisplayInfos[phoneId] != null) {
+                            r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
-                        try {
-                            r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)) {
+                    try {
+                        r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) {
-                        try {
-                            r.callback.onPhoneCapabilityChanged(mPhoneCapability);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) {
+                    try {
+                        r.callback.onPhoneCapabilityChanged(mPhoneCapability);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener
-                            .LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) {
-                        try {
-                            r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
+                    try {
+                        r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
-                        try {
-                            r.callback.onRadioPowerStateChanged(mRadioPowerState);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)) {
+                    try {
+                        r.callback.onRadioPowerStateChanged(mRadioPowerState);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
-                        try {
-                            r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)) {
+                    try {
+                        r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
-                        try {
-                            r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)) {
+                    try {
+                        r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_BARRING_INFO) != 0) {
-                        BarringInfo barringInfo = mBarringInfo.get(phoneId);
-                        BarringInfo biNoLocation = barringInfo != null
-                                ? barringInfo.createLocationInfoSanitizedCopy() : null;
-                        if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
-                        try {
-                            r.callback.onBarringInfoChanged(
-                                    checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
-                                            ? barringInfo : biNoLocation);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED)) {
+                    BarringInfo barringInfo = mBarringInfo.get(phoneId);
+                    BarringInfo biNoLocation = barringInfo != null
+                            ? barringInfo.createLocationInfoSanitizedCopy() : null;
+                    if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
+                    try {
+                        r.callback.onBarringInfoChanged(
+                                checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
+                                        ? barringInfo : biNoLocation);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) {
+                    try {
+                        r.callback.onPhysicalChannelConfigChanged(
+                                mPhysicalChannelConfigs);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) {
+                    try {
+                        r.callback.onDataEnabledChanged(mIsDataEnabled, mDataEnabledReason);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
                 }
             }
-        } else {
-            if(DBG) log("listen: Unregister");
-            remove(callback.asBinder());
         }
     }
 
@@ -1114,7 +1163,7 @@
                 // If any of the system clients wants to always listen to signal strength,
                 // we need to set it on.
                 if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) {
+                        PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
                     telephonyManager.createForSubscriptionId(subscriptionId)
                             .setAlwaysReportSignalStrength(true);
                     return;
@@ -1215,7 +1264,7 @@
                     // strength is removed from registry records, we need to check if
                     // the signal strength decision needs to update on its slot.
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) {
+                            PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
                         updateReportSignalStrengthDecision(r.subId);
                     }
                     return;
@@ -1235,8 +1284,8 @@
 
         synchronized (mRecords) {
             for (Record r : mRecords) {
-                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
-                        (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED)
+                        && (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
                     try {
                         // Ensure the listener has read call log permission; if they do not return
                         // an empty phone number.
@@ -1270,9 +1319,9 @@
                 mCallState[phoneId] = state;
                 mCallIncomingNumber[phoneId] = incomingNumber;
                 for (Record r : mRecords) {
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
-                            (r.subId == subId) &&
-                            (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
+                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED)
+                            && (r.subId == subId)
+                            && (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
                         try {
                             String incomingNumberOrEmpty = getCallIncomingNumber(r, phoneId);
                             r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
@@ -1312,8 +1361,9 @@
                         log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
                                 + " phoneId=" + phoneId + " state=" + state);
                     }
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SERVICE_STATE) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
 
                         try {
                             ServiceState stateToSend;
@@ -1374,7 +1424,7 @@
                     try {
                         if ((activationType == SIM_ACTIVATION_TYPE_VOICE)
                                 && r.matchPhoneStateListenerEvent(
-                                        PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE)
+                                        PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
                                 && idMatch(r.subId, subId, phoneId)) {
                             if (DBG) {
                                 log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
@@ -1385,7 +1435,7 @@
                         }
                         if ((activationType == SIM_ACTIVATION_TYPE_DATA)
                                 && r.matchPhoneStateListenerEvent(
-                                        PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE)
+                                        PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)
                                 && idMatch(r.subId, subId, phoneId)) {
                             if (DBG) {
                                 log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
@@ -1424,9 +1474,11 @@
                         log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId
                                 + " phoneId=" + phoneId + " ss=" + signalStrength);
                     }
-                    if ((r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)
+                    if ((r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)
                             || r.matchPhoneStateListenerEvent(
-                                    PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH))
+                                    PhoneStateListener.
+                                            EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG) {
@@ -1439,8 +1491,9 @@
                             mRemoveList.add(r.binder);
                         }
                     }
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             int gsmSignalStrength = signalStrength.getGsmSignalStrength();
                             int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
@@ -1486,8 +1539,8 @@
                 }
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCarrierNetworkChange(active);
                         } catch (RemoteException ex) {
@@ -1517,9 +1570,10 @@
             if (validatePhoneId(phoneId)) {
                 mCellInfo.set(phoneId, cellInfo);
                 for (Record r : mRecords) {
-                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
-                            idMatch(r.subId, subId, phoneId) &&
-                            (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+                    if (validateEventAndUserLocked(
+                            r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)
+                            && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
                                     && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
                         try {
                             if (DBG_LOC) {
@@ -1551,8 +1605,8 @@
                 mMessageWaiting[phoneId] = mwi;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onMessageWaitingIndicatorChanged(mwi);
                         } catch (RemoteException ex) {
@@ -1578,8 +1632,8 @@
                 mUserMobileDataState[phoneId] = state;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onUserMobileDataStateChanged(state);
                         } catch (RemoteException ex) {
@@ -1617,7 +1671,7 @@
                 mTelephonyDisplayInfos[phoneId] = telephonyDisplayInfo;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+                            PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)
                             && idMatchWithoutDefaultPhoneCheck(r.subId, subId)) {
                         try {
                             r.callback.onDisplayInfoChanged(telephonyDisplayInfo);
@@ -1649,8 +1703,8 @@
                 mCallForwarding[phoneId] = cfi;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCallForwardingIndicatorChanged(cfi);
                         } catch (RemoteException ex) {
@@ -1677,8 +1731,9 @@
                 mDataActivity[phoneId] = state;
                 for (Record r : mRecords) {
                     // Notify by correct subId.
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_DATA_ACTIVITY) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onDataActivity(state);
                         } catch (RemoteException ex) {
@@ -1725,7 +1780,7 @@
                     mLocalLog.log(str);
                     for (Record r : mRecords) {
                         if (r.matchPhoneStateListenerEvent(
-                                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE)
+                                PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)
                                 && idMatch(r.subId, subId, phoneId)) {
                             try {
                                 if (DBG) {
@@ -1747,12 +1802,10 @@
                         preciseState.getApnSetting());
                 PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
                         .remove(key);
-                log("Jack: oldState=" + oldState);
-                log("Jack: newState=" + preciseState);
                 if (!Objects.equals(oldState, preciseState)) {
                     for (Record r : mRecords) {
                         if (r.matchPhoneStateListenerEvent(
-                                PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
+                                PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)
                                 && idMatch(r.subId, subId, phoneId)) {
                             try {
                                 r.callback.onPreciseDataConnectionStateChanged(preciseState);
@@ -1797,9 +1850,10 @@
             if (validatePhoneId(phoneId) && !Objects.equals(cellIdentity, mCellIdentity[phoneId])) {
                 mCellIdentity[phoneId] = cellIdentity;
                 for (Record r : mRecords) {
-                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
-                            idMatch(r.subId, subId, phoneId) &&
-                            (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+                    if (validateEventAndUserLocked(
+                            r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)
+                            && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
                                     && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
                         try {
                             if (DBG_LOC) {
@@ -1850,7 +1904,8 @@
                 }
 
                 for (Record r : mRecords) {
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
@@ -1859,7 +1914,7 @@
                         }
                     }
                     if (notifyCallAttributes && r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)
+                            PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
@@ -1908,7 +1963,7 @@
                 mImsReasonInfo.set(phoneId, imsReasonInfo);
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES)
+                            PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
@@ -1940,8 +1995,8 @@
                 mSrvccState[phoneId] = state;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
                                 log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r);
@@ -1969,7 +2024,7 @@
                         log("notifyOemHookRawEventForSubscriber:  r=" + r + " subId=" + subId);
                     }
                     if ((r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT))
+                            PhoneStateListener.EVENT_OEM_HOOK_RAW))
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onOemHookRawEvent(rawData);
@@ -1997,7 +2052,7 @@
 
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE)) {
+                        PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) {
                     try {
                         r.callback.onPhoneCapabilityChanged(capability);
                     } catch (RemoteException ex) {
@@ -2022,7 +2077,7 @@
         synchronized (mRecords) {
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE)) {
+                        PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
                     try {
                         r.callback.onActiveDataSubIdChanged(activeDataSubId);
                     } catch (RemoteException ex) {
@@ -2049,7 +2104,7 @@
 
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED)
+                            PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onRadioPowerStateChanged(state);
@@ -2078,7 +2133,7 @@
 
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST)
+                            PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
@@ -2110,7 +2165,7 @@
             for (Record r : mRecords) {
                 // Send to all listeners regardless of subscription
                 if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL)) {
+                        PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)) {
                     try {
                         r.callback.onOutgoingEmergencyCall(emergencyNumber, subId);
                     } catch (RemoteException ex) {
@@ -2134,7 +2189,7 @@
                 for (Record r : mRecords) {
                     // Send to all listeners regardless of subscription
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS)) {
+                            PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS)) {
                         try {
                             r.callback.onOutgoingEmergencySms(emergencyNumber, subId);
                         } catch (RemoteException ex) {
@@ -2164,7 +2219,7 @@
 
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)
+                            PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
@@ -2195,7 +2250,7 @@
             if (validatePhoneId(phoneId)) {
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_REGISTRATION_FAILURE)
+                            PhoneStateListener.EVENT_REGISTRATION_FAILURE)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onRegistrationFailed(
@@ -2238,7 +2293,7 @@
                 if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_BARRING_INFO)
+                            PhoneStateListener.EVENT_BARRING_INFO_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
@@ -2258,6 +2313,81 @@
         }
     }
 
+    /**
+     * Send a notification to registrants that the configs of physical channel has changed for
+     * a particular subscription.
+     *
+     * @param subId the subId
+     * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
+     */
+    public void notifyPhysicalChannelConfigForSubscriber(
+            int subId, List<PhysicalChannelConfig> configs) {
+        if (!checkNotifyPermission("notifyPhysicalChannelConfig()")) {
+            return;
+        }
+
+        if (VDBG) {
+            log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs);
+        }
+
+        synchronized (mRecords) {
+            int phoneId = SubscriptionManager.getPhoneId(subId);
+            if (validatePhoneId(phoneId)) {
+                mPhysicalChannelConfigs.set(phoneId, configs.get(phoneId));
+                for (Record r : mRecords) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
+                        try {
+                            if (DBG_LOC) {
+                                log("notifyPhysicalChannelConfig: "
+                                        + "mPhysicalChannelConfigs="
+                                        + configs + " r=" + r);
+                            }
+                            r.callback.onPhysicalChannelConfigChanged(configs);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
+    /**
+     * Notify that the data enabled has changed.
+     *
+     * @param enabled True if data is enabled, otherwise disabled.
+     * @param reason  Reason for data enabled/disabled. See {@code DATA_*} in
+     *                {@link TelephonyManager}.
+     */
+    public void notifyDataEnabled(boolean enabled,
+                                  @TelephonyManager.DataEnabledReason int reason) {
+        if (!checkNotifyPermission("notifyDataEnabled()")) {
+            return;
+        }
+
+        if (VDBG) {
+            log("notifyDataEnabled: enabled=" + enabled + " reason=" + reason);
+        }
+
+        mIsDataEnabled = enabled;
+        mDataEnabledReason = reason;
+        synchronized (mRecords) {
+            for (Record r : mRecords) {
+                if (r.matchPhoneStateListenerEvent(
+                        PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) {
+                    try {
+                        r.callback.onDataEnabledChanged(enabled, reason);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -2310,6 +2440,9 @@
             pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
             pw.println("mDefaultPhoneId=" + mDefaultPhoneId);
             pw.println("mDefaultSubId=" + mDefaultSubId);
+            pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs);
+            pw.println("mIsDataEnabled=" + mIsDataEnabled);
+            pw.println("mDataEnabledReason=" + mDataEnabledReason);
 
             pw.decreaseIndent();
 
@@ -2538,22 +2671,29 @@
                 == PackageManager.PERMISSION_GRANTED;
     }
 
-    private boolean checkListenerPermission(int events, int subId, String callingPackage,
+    private boolean checkListenerPermission(Set<Integer> events, int subId, String callingPackage,
             @Nullable String callingFeatureId, String message) {
         LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder =
                 new LocationAccessPolicy.LocationPermissionQuery.Builder()
-                .setCallingPackage(callingPackage)
-                .setMethod(message + " events: " + events)
-                .setCallingPid(Binder.getCallingPid())
-                .setCallingUid(Binder.getCallingUid());
+                        .setCallingPackage(callingPackage)
+                        .setMethod(message + " events: " + events)
+                        .setCallingPid(Binder.getCallingPid())
+                        .setCallingUid(Binder.getCallingUid());
 
-        if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) {
+        boolean shouldCheckLocationPermissions = false;
+
+        if (isLocationPermissionRequired(events)) {
             // Everything that requires fine location started in Q. So far...
             locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q);
             // If we're enforcing fine starting in Q, we also want to enforce coarse even for
             // older SDK versions.
             locationQueryBuilder.setMinSdkVersionForCoarse(0);
+            shouldCheckLocationPermissions = true;
+        }
 
+        boolean isPermissionCheckSuccessful = true;
+
+        if (shouldCheckLocationPermissions) {
             LocationAccessPolicy.LocationPermissionResult result =
                     LocationAccessPolicy.checkLocationPermission(
                             mContext, locationQueryBuilder.build());
@@ -2562,18 +2702,18 @@
                     throw new SecurityException("Unable to listen for events " + events + " due to "
                             + "insufficient location permissions.");
                 case DENIED_SOFT:
-                    return false;
+                    isPermissionCheckSuccessful = false;
             }
         }
 
-        if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
+        if (isPhoneStatePermissionRequired(events)) {
             if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
                     mContext, subId, callingPackage, callingFeatureId, message)) {
-                return false;
+                isPermissionCheckSuccessful = false;
             }
         }
 
-        if ((events & ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
+        if (isPrecisePhoneStatePermissionRequired(events)) {
             // check if calling app has either permission READ_PRECISE_PHONE_STATE
             // or with carrier privileges
             try {
@@ -2584,47 +2724,46 @@
             }
         }
 
-        if ((events & READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK) != 0) {
+        if (isActiveEmergencySessionPermissionRequired(events)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
         }
 
-        if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+        if ((events.contains(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
         }
 
-        if ((events & READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK) != 0) {
+        if (isPrivilegedPhoneStatePermissionRequired(events)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
         }
-
-        return true;
+        return isPermissionCheckSuccessful;
     }
 
     private void handleRemoveListLocked() {
         int size = mRemoveList.size();
         if (VDBG) log("handleRemoveListLocked: mRemoveList.size()=" + size);
         if (size > 0) {
-            for (IBinder b: mRemoveList) {
+            for (IBinder b : mRemoveList) {
                 remove(b);
             }
             mRemoveList.clear();
         }
     }
 
-    private boolean validateEventsAndUserLocked(Record r, int events) {
+    private boolean validateEventAndUserLocked(Record r, int event) {
         int foregroundUser;
         long callingIdentity = Binder.clearCallingIdentity();
         boolean valid = false;
         try {
             foregroundUser = ActivityManager.getCurrentUser();
             valid = UserHandle.getUserId(r.callerUid) == foregroundUser
-                    && r.matchPhoneStateListenerEvent(events);
+                    && r.matchPhoneStateListenerEvent(event);
             if (DBG | DBG_LOC) {
-                log("validateEventsAndUserLocked: valid=" + valid
+                log("validateEventAndUserLocked: valid=" + valid
                         + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
-                        + " r.events=" + r.events + " events=" + events);
+                        + " r.eventList=" + r.eventList + " event=" + event);
             }
         } finally {
             Binder.restoreCallingIdentity(callingIdentity);
@@ -2677,6 +2816,11 @@
         }
     }
 
+    /**
+     * Note -- this method should only be used at the site of a permission check if you need to
+     * explicitly allow apps below a certain SDK level access regardless of location permissions.
+     * If you don't need app compat logic, use {@link #checkFineLocationAccess(Record)}.
+     */
     private boolean checkFineLocationAccess(Record r, int minSdk) {
         LocationAccessPolicy.LocationPermissionQuery query =
                 new LocationAccessPolicy.LocationPermissionQuery.Builder()
@@ -2695,6 +2839,11 @@
         });
     }
 
+    /**
+     * Note -- this method should only be used at the site of a permission check if you need to
+     * explicitly allow apps below a certain SDK level access regardless of location permissions.
+     * If you don't need app compat logic, use {@link #checkCoarseLocationAccess(Record)}.
+     */
     private boolean checkCoarseLocationAccess(Record r, int minSdk) {
         LocationAccessPolicy.LocationPermissionQuery query =
                 new LocationAccessPolicy.LocationPermissionQuery.Builder()
@@ -2714,9 +2863,14 @@
     }
 
     private void checkPossibleMissNotify(Record r, int phoneId) {
-        int events = r.events;
+        Set<Integer> events = r.eventList;
 
-        if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
+        if (events == null || events.isEmpty()) {
+            log("checkPossibleMissNotify: events = null.");
+            return;
+        }
+
+        if ((events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED))) {
             try {
                 if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" +
                         mServiceState[phoneId]);
@@ -2735,8 +2889,9 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0
-                || (events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)
+                || events.contains(
+                PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
             try {
                 if (mSignalStrength[phoneId] != null) {
                     SignalStrength signalStrength = mSignalStrength[phoneId];
@@ -2751,7 +2906,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) {
             try {
                 if (mSignalStrength[phoneId] != null) {
                     int gsmSignalStrength = mSignalStrength[phoneId]
@@ -2768,7 +2923,7 @@
             }
         }
 
-        if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
+        if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) {
             try {
                 if (DBG_LOC) {
                     log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
@@ -2783,7 +2938,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
             try {
                 if (VDBG) {
                     log("checkPossibleMissNotify: onUserMobileDataStateChanged phoneId="
@@ -2795,7 +2950,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) {
             try {
                 if (VDBG) {
                     log("checkPossibleMissNotify: onDisplayInfoChanged phoneId="
@@ -2809,7 +2964,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
             try {
                 if (VDBG) {
                     log("checkPossibleMissNotify: onMessageWaitingIndicatorChanged phoneId="
@@ -2822,7 +2977,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
             try {
                 if (VDBG) {
                     log("checkPossibleMissNotify: onCallForwardingIndicatorChanged phoneId="
@@ -2835,7 +2990,7 @@
             }
         }
 
-        if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
+        if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) {
             try {
                 if (DBG_LOC) {
                     log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = "
@@ -2851,7 +3006,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
             try {
                 if (DBG) {
                     log("checkPossibleMissNotify: onDataConnectionStateChanged(mDataConnectionState"
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/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index c1b1b6a..952193b 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -246,11 +246,6 @@
             return;
         }
 
-        if (mNetwork.linkProperties == null) {
-            Log.e(TAG, "startClat: Can't start clat with null LinkProperties");
-            return;
-        }
-
         String baseIface = mNetwork.linkProperties.getInterfaceName();
         if (baseIface == null) {
             Log.e(TAG, "startClat: Can't start clat on null interface");
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index b0a73f1..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;
@@ -136,12 +139,12 @@
     // This Network object should always be used if possible, so as to encourage reuse of the
     // enclosed socket factory and connection pool.  Avoid creating other Network objects.
     // This Network object is always valid.
-    public final Network network;
-    public LinkProperties linkProperties;
+    @NonNull public final Network network;
+    @NonNull public LinkProperties linkProperties;
     // This should only be modified by ConnectivityService, via setNetworkCapabilities().
     // TODO: make this private with a getter.
-    public NetworkCapabilities networkCapabilities;
-    public final NetworkAgentConfig networkAgentConfig;
+    @NonNull public NetworkCapabilities networkCapabilities;
+    @NonNull public final NetworkAgentConfig networkAgentConfig;
 
     // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
     // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
@@ -323,12 +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;
@@ -342,6 +353,7 @@
         networkAgentConfig = config;
         this.factorySerialNumber = factorySerialNumber;
         this.creatorUid = creatorUid;
+        mQosCallbackTracker = qosCallbackTracker;
     }
 
     private class AgentDeathMonitor implements IBinder.DeathRecipient {
@@ -527,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;
@@ -536,19 +573,22 @@
         }
 
         @Override
-        public void sendNetworkCapabilities(NetworkCapabilities nc) {
+        public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) {
+            Objects.requireNonNull(nc);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget();
         }
 
         @Override
-        public void sendLinkProperties(LinkProperties lp) {
+        public void sendLinkProperties(@NonNull LinkProperties lp) {
+            Objects.requireNonNull(lp);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget();
         }
 
         @Override
-        public void sendNetworkInfo(NetworkInfo info) {
+        public void sendNetworkInfo(@NonNull NetworkInfo info) {
+            Objects.requireNonNull(info);
             mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED,
                     new Pair<>(NetworkAgentInfo.this, info)).sendToTarget();
         }
@@ -574,16 +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);
         }
     }
 
@@ -603,7 +652,7 @@
      *
      * @return the old capabilities of this network.
      */
-    public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
+    @NonNull public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
             @NonNull final NetworkCapabilities nc) {
         final NetworkCapabilities oldNc = networkCapabilities;
         networkCapabilities = nc;
diff --git a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
index aadaf4d..5dc8c1a 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity;
 
+import android.annotation.NonNull;
 import android.annotation.WorkerThread;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -71,10 +72,6 @@
     private static final int DELAY_LONG = 4;
     private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
 
-    // Return values for #setCurrentProxyScriptUrl
-    public static final boolean DONT_SEND_BROADCAST = false;
-    public static final boolean DO_SEND_BROADCAST = true;
-
     private String mCurrentPac;
     @GuardedBy("mProxyLock")
     private volatile Uri mPacUrl = Uri.EMPTY;
@@ -93,7 +90,7 @@
     private volatile boolean mHasSentBroadcast;
     private volatile boolean mHasDownloaded;
 
-    private Handler mConnectivityHandler;
+    private final Handler mConnectivityHandler;
     private final int mProxyMessage;
 
     /**
@@ -102,6 +99,13 @@
     private final Object mProxyLock = new Object();
 
     /**
+     * Lock ensuring consistency between the values of mHasSentBroadcast, mHasDownloaded, the
+     * last URL and port, and the broadcast message being sent with the correct arguments.
+     * TODO : this should probably protect all instances of these variables
+     */
+    private final Object mBroadcastStateLock = new Object();
+
+    /**
      * Runnable to download PAC script.
      * The behavior relies on the assumption it always runs on mNetThread to guarantee that the
      * latest data fetched from mPacUrl is stored in mProxyService.
@@ -146,7 +150,7 @@
         }
     }
 
-    public PacProxyInstaller(Context context, Handler handler, int proxyMessage) {
+    public PacProxyInstaller(@NonNull Context context, @NonNull Handler handler, int proxyMessage) {
         mContext = context;
         mLastPort = -1;
         final HandlerThread netThread = new HandlerThread("android.pacproxyinstaller",
@@ -176,31 +180,27 @@
      * PacProxyInstaller will trigger a new broadcast when it is ready.
      *
      * @param proxy Proxy information that is about to be broadcast.
-     * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
      */
-    public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
-        if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
-            if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
-                // Allow to send broadcast, nothing to do.
-                return DO_SEND_BROADCAST;
-            }
-            mPacUrl = proxy.getPacFileUrl();
-            mCurrentDelay = DELAY_1;
-            mHasSentBroadcast = false;
-            mHasDownloaded = false;
-            getAlarmManager().cancel(mPacRefreshIntent);
-            bind();
-            return DONT_SEND_BROADCAST;
-        } else {
-            getAlarmManager().cancel(mPacRefreshIntent);
-            synchronized (mProxyLock) {
-                mPacUrl = Uri.EMPTY;
-                mCurrentPac = null;
-                if (mProxyService != null) {
-                    unbind();
+    public void setCurrentProxyScriptUrl(@NonNull ProxyInfo proxy) {
+        synchronized (mBroadcastStateLock) {
+            if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
+                if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) return;
+                mPacUrl = proxy.getPacFileUrl();
+                mCurrentDelay = DELAY_1;
+                mHasSentBroadcast = false;
+                mHasDownloaded = false;
+                getAlarmManager().cancel(mPacRefreshIntent);
+                bind();
+            } else {
+                getAlarmManager().cancel(mPacRefreshIntent);
+                synchronized (mProxyLock) {
+                    mPacUrl = Uri.EMPTY;
+                    mCurrentPac = null;
+                    if (mProxyService != null) {
+                        unbind();
+                    }
                 }
             }
-            return DO_SEND_BROADCAST;
         }
     }
 
@@ -275,6 +275,7 @@
         getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent);
     }
 
+    @GuardedBy("mProxyLock")
     private void setCurrentProxyScript(String script) {
         if (mProxyService == null) {
             Log.e(TAG, "setCurrentProxyScript: no proxy service");
@@ -347,6 +348,9 @@
                             public void setProxyPort(int port) {
                                 if (mLastPort != -1) {
                                     // Always need to send if port changed
+                                    // TODO: Here lacks synchronization because this write cannot
+                                    // guarantee that it's visible from sendProxyIfNeeded() when
+                                    // it's called by a Runnable which is post by mNetThread.
                                     mHasSentBroadcast = false;
                                 }
                                 mLastPort = port;
@@ -386,13 +390,15 @@
         mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
     }
 
-    private synchronized void sendProxyIfNeeded() {
-        if (!mHasDownloaded || (mLastPort == -1)) {
-            return;
-        }
-        if (!mHasSentBroadcast) {
-            sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
-            mHasSentBroadcast = true;
+    private void sendProxyIfNeeded() {
+        synchronized (mBroadcastStateLock) {
+            if (!mHasDownloaded || (mLastPort == -1)) {
+                return;
+            }
+            if (!mHasSentBroadcast) {
+                sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
+                mHasSentBroadcast = true;
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index d83ff83..b618d2b 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -226,9 +226,9 @@
         final ProxyInfo defaultProxy = getDefaultProxy();
         final ProxyInfo proxyInfo = null != defaultProxy ?
                 defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
+        mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo);
 
-        if (mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo)
-                == PacProxyInstaller.DONT_SEND_BROADCAST) {
+        if (!shouldSendBroadcast(proxyInfo)) {
             return;
         }
         if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
@@ -244,6 +244,13 @@
         }
     }
 
+    private boolean shouldSendBroadcast(ProxyInfo proxy) {
+        if (Uri.EMPTY.equals(proxy.getPacFileUrl())) return false;
+        if (proxy.getPacFileUrl().equals(proxy.getPacFileUrl())
+                && (proxy.getPort() > 0)) return true;
+        return true;
+    }
+
     /**
      * Sets the global proxy in memory. Also writes the values to the global settings of the device.
      *
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/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b250f16..fb1e819 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -439,6 +439,11 @@
         mEnableTeardown = enableTeardown;
     }
 
+    @VisibleForTesting
+    public boolean getEnableTeardown() {
+        return mEnableTeardown;
+    }
+
     /**
      * Update current state, dispatching event to listeners.
      */
@@ -1229,7 +1234,8 @@
     private boolean canHaveRestrictedProfile(int userId) {
         final long token = Binder.clearCallingIdentity();
         try {
-            return UserManager.get(mContext).canHaveRestrictedProfile(userId);
+            final Context userContext = mContext.createContextAsUser(UserHandle.of(userId), 0);
+            return userContext.getSystemService(UserManager.class).canHaveRestrictedProfile();
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -2145,6 +2151,11 @@
 
         // Start a new LegacyVpnRunner and we are done!
         mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile);
+        startLegacyVpnRunner();
+    }
+
+    @VisibleForTesting
+    protected void startLegacyVpnRunner() {
         mVpnRunner.start();
     }
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index d003b89..c005af4 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -89,6 +89,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
+import android.security.Authorization;
 import android.security.KeyStore;
 import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyProperties;
@@ -1272,6 +1273,7 @@
 
     private void unlockKeystore(byte[] password, int userHandle) {
         if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
+        new Authorization().onLockScreenEvent(false, userHandle, password);
         // TODO(b/120484642): Update keystore to accept byte[] passwords
         String passwordString = password == null ? null : new String(password);
         final KeyStore ks = KeyStore.getInstance();
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 289290b..fbec915 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -224,6 +224,10 @@
         for (UserInfo user : rebootEscrowUsers) {
             allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk);
         }
+
+        // Clear the old key in keystore. A new key will be generated by new RoR requests.
+        mKeyStoreManager.clearKeyStoreEncryptionKey();
+
         onEscrowRestoreComplete(allUsersUnlocked);
     }
 
@@ -273,9 +277,6 @@
         } catch (IOException e) {
             Slog.w(TAG, "Could not load reboot escrow data for user " + userId, e);
             return false;
-        } finally {
-            // Clear the old key in keystore. A new key will be generated by new RoR requests.
-            mKeyStoreManager.clearKeyStoreEncryptionKey();
         }
     }
 
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
new file mode 100644
index 0000000..8399f54
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -0,0 +1,249 @@
+/*
+ * 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 com.android.server.locksettings;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelableException;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.service.resumeonreboot.IResumeOnRebootService;
+import android.service.resumeonreboot.ResumeOnRebootService;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/** @hide */
+public class ResumeOnRebootServiceProvider {
+
+    private static final String PROVIDER_PACKAGE = DeviceConfig.getString(
+            DeviceConfig.NAMESPACE_OTA, "resume_on_reboot_service_package", "");
+    private static final String PROVIDER_REQUIRED_PERMISSION =
+            Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE;
+    private static final String TAG = "ResumeOnRebootServiceProvider";
+
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+
+    public ResumeOnRebootServiceProvider(Context context) {
+        this(context, context.getPackageManager());
+    }
+
+    @VisibleForTesting
+    public ResumeOnRebootServiceProvider(Context context, PackageManager packageManager) {
+        this.mContext = context;
+        this.mPackageManager = packageManager;
+    }
+
+    @Nullable
+    private ServiceInfo resolveService() {
+        Intent intent = new Intent();
+        intent.setAction(ResumeOnRebootService.SERVICE_INTERFACE);
+        if (PROVIDER_PACKAGE != null && !PROVIDER_PACKAGE.equals("")) {
+            intent.setPackage(PROVIDER_PACKAGE);
+        }
+
+        List<ResolveInfo> resolvedIntents =
+                mPackageManager.queryIntentServices(intent, PackageManager.MATCH_SYSTEM_ONLY);
+        for (ResolveInfo resolvedInfo : resolvedIntents) {
+            if (resolvedInfo.serviceInfo != null
+                    && PROVIDER_REQUIRED_PERMISSION.equals(resolvedInfo.serviceInfo.permission)) {
+                return resolvedInfo.serviceInfo;
+            }
+        }
+        return null;
+    }
+
+    /** Creates a new {@link ResumeOnRebootServiceConnection} */
+    @Nullable
+    public ResumeOnRebootServiceConnection getServiceConnection() {
+        ServiceInfo serviceInfo = resolveService();
+        if (serviceInfo == null) {
+            return null;
+        }
+        return new ResumeOnRebootServiceConnection(mContext, serviceInfo.getComponentName());
+    }
+
+    /**
+     * Connection class used for contacting the registered {@link IResumeOnRebootService}
+     */
+    public static class ResumeOnRebootServiceConnection {
+
+        private static final String TAG = "ResumeOnRebootServiceConnection";
+        private final Context mContext;
+        private final ComponentName mComponentName;
+        private IResumeOnRebootService mBinder;
+
+        private ResumeOnRebootServiceConnection(Context context,
+                @NonNull ComponentName componentName) {
+            mContext = context;
+            mComponentName = componentName;
+        }
+
+        /** Unbind from the service */
+        public void unbindService() {
+            mContext.unbindService(new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName name) {
+                    mBinder = null;
+
+                }
+            });
+        }
+
+        /** Bind to the service */
+        public void bindToService(long timeOut) throws TimeoutException {
+            if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+                CountDownLatch connectionLatch = new CountDownLatch(1);
+                Intent intent = new Intent();
+                intent.setComponent(mComponentName);
+                final boolean success = mContext.bindServiceAsUser(intent, new ServiceConnection() {
+                            @Override
+                            public void onServiceConnected(ComponentName name, IBinder service) {
+                                mBinder = IResumeOnRebootService.Stub.asInterface(service);
+                                connectionLatch.countDown();
+                            }
+
+                            @Override
+                            public void onServiceDisconnected(ComponentName name) {
+                            }
+                        },
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                        BackgroundThread.getHandler(), UserHandle.SYSTEM);
+
+                if (!success) {
+                    Slog.e(TAG, "Binding: " + mComponentName + " u" + UserHandle.SYSTEM
+                            + " failed.");
+                    return;
+                }
+                waitForLatch(connectionLatch, "serviceConnection", timeOut);
+            }
+        }
+
+        /** Wrap opaque blob */
+        public byte[] wrapBlob(byte[] unwrappedBlob, long lifeTimeInMillis,
+                long timeOutInMillis)
+                throws RemoteException, TimeoutException, IOException {
+            if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+                throw new RemoteException("Service not bound");
+            }
+            CountDownLatch binderLatch = new CountDownLatch(1);
+            ResumeOnRebootServiceCallback
+                    resultCallback =
+                    new ResumeOnRebootServiceCallback(
+                            binderLatch);
+            mBinder.wrapSecret(unwrappedBlob, lifeTimeInMillis, new RemoteCallback(resultCallback));
+            waitForLatch(binderLatch, "wrapSecret", timeOutInMillis);
+            if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
+                throwTypedException(resultCallback.getResult().getParcelable(
+                        ResumeOnRebootService.EXCEPTION_KEY));
+            }
+            return resultCallback.mResult.getByteArray(ResumeOnRebootService.WRAPPED_BLOB_KEY);
+        }
+
+        /** Unwrap wrapped blob */
+        public byte[] unwrap(byte[] wrappedBlob, long timeOut)
+                throws RemoteException, TimeoutException, IOException {
+            if (mBinder == null || !mBinder.asBinder().isBinderAlive()) {
+                throw new RemoteException("Service not bound");
+            }
+            CountDownLatch binderLatch = new CountDownLatch(1);
+            ResumeOnRebootServiceCallback
+                    resultCallback =
+                    new ResumeOnRebootServiceCallback(
+                            binderLatch);
+            mBinder.unwrap(wrappedBlob, new RemoteCallback(resultCallback));
+            waitForLatch(binderLatch, "unWrapSecret", timeOut);
+            if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
+                throwTypedException(resultCallback.getResult().getParcelable(
+                        ResumeOnRebootService.EXCEPTION_KEY));
+            }
+            return resultCallback.getResult().getByteArray(
+                    ResumeOnRebootService.UNWRAPPED_BLOB_KEY);
+        }
+
+        private void throwTypedException(
+                ParcelableException exception)
+                throws IOException {
+            if (exception.getCause() instanceof IOException) {
+                exception.maybeRethrow(IOException.class);
+            } else if (exception.getCause() instanceof IllegalStateException) {
+                exception.maybeRethrow(IllegalStateException.class);
+            } else {
+                // This should not happen. Wrap the cause in IllegalStateException so that it
+                // doesn't disrupt the exception handling
+                throw new IllegalStateException(exception.getCause());
+            }
+        }
+
+        private void waitForLatch(CountDownLatch latch, String reason, long timeOut)
+                throws TimeoutException {
+            try {
+                if (!latch.await(timeOut, TimeUnit.SECONDS)) {
+                    throw new TimeoutException("Latch wait for " + reason + " elapsed");
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                throw new IllegalStateException("Latch wait for " + reason + " interrupted");
+            }
+        }
+    }
+
+    private static class ResumeOnRebootServiceCallback implements
+            RemoteCallback.OnResultListener {
+
+        private final CountDownLatch mResultLatch;
+        private Bundle mResult;
+
+        private ResumeOnRebootServiceCallback(CountDownLatch resultLatch) {
+            this.mResultLatch = resultLatch;
+        }
+
+        @Override
+        public void onResult(@Nullable Bundle result) {
+            this.mResult = result;
+            mResultLatch.countDown();
+        }
+
+        private Bundle getResult() {
+            return mResult;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index f882c57..edc9d7c 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -77,7 +77,7 @@
     @NonNull
     public List<RoutingSessionInfo> getSessionInfos() {
         synchronized (mLock) {
-            return mSessionInfos;
+            return new ArrayList<>(mSessionInfos);
         }
     }
 
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 85af346..ab38dca 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -108,8 +108,8 @@
         mLastDiscoveryPreference = discoveryPreference;
         if (mConnectionReady) {
             mActiveConnection.updateDiscoveryPreference(discoveryPreference);
-            updateBinding();
         }
+        updateBinding();
     }
 
     @Override
@@ -205,9 +205,11 @@
     }
 
     private boolean shouldBind() {
-        //TODO: Binding could be delayed until it's necessary.
         if (mRunning) {
-            return true;
+            // Bind when there is a discovery preference or an active route session.
+            return (mLastDiscoveryPreference != null
+                    && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty())
+                    || !getSessionInfos().isEmpty();
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 1114fe0..31edf43 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.media;
 
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
 import static android.media.MediaRouter2Utils.getOriginalId;
 import static android.media.MediaRouter2Utils.getProviderId;
@@ -73,10 +74,12 @@
     // TODO: (In Android S or later) if we add callback methods for generic failures
     //       in MediaRouter2, remove this constant and replace the usages with the real request IDs.
     private static final long DUMMY_REQUEST_ID = -1;
+    private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND;
 
     private final Context mContext;
     private final Object mLock = new Object();
     final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
+    final ActivityManager mActivityManager;
 
     @GuardedBy("mLock")
     private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
@@ -87,8 +90,21 @@
     @GuardedBy("mLock")
     private int mCurrentUserId = -1;
 
+    private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
+            (uid, importance) -> {
+                synchronized (mLock) {
+                    final int count = mUserRecords.size();
+                    for (int i = 0; i < count; i++) {
+                        mUserRecords.valueAt(i).mHandler.maybeUpdateDiscoveryPreferenceForUid(uid);
+                    }
+                }
+            };
+
     MediaRouter2ServiceImpl(Context context) {
         mContext = context;
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
+        mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener,
+                PACKAGE_IMPORTANCE_FOR_DISCOVERY);
     }
 
     ////////////////////////////////////////////////////////////////
@@ -388,6 +404,30 @@
         }
     }
 
+    public void startScan(IMediaRouter2Manager manager) {
+        Objects.requireNonNull(manager, "manager must not be null");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                startScanLocked(manager);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    public void stopScan(IMediaRouter2Manager manager) {
+        Objects.requireNonNull(manager, "manager must not be null");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                stopScanLocked(manager);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
             MediaRoute2Info route, int volume) {
         Objects.requireNonNull(manager, "manager must not be null");
@@ -839,6 +879,24 @@
         disposeUserIfNeededLocked(userRecord); // since manager removed from user
     }
 
+    private void startScanLocked(@NonNull IMediaRouter2Manager manager) {
+        final IBinder binder = manager.asBinder();
+        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+        if (managerRecord == null) {
+            return;
+        }
+        managerRecord.startScan();
+    }
+
+    private void stopScanLocked(@NonNull IMediaRouter2Manager manager) {
+        final IBinder binder = manager.asBinder();
+        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
+        if (managerRecord == null) {
+            return;
+        }
+        managerRecord.stopScan();
+    }
+
     private void setRouteVolumeWithManagerLocked(int requestId,
             @NonNull IMediaRouter2Manager manager,
             @NonNull MediaRoute2Info route, int volume) {
@@ -1122,6 +1180,7 @@
         public final String mPackageName;
         public final int mManagerId;
         public SessionCreationRequest mLastSessionCreationRequest;
+        public boolean mIsScanning;
 
         ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager,
                 int uid, int pid, String packageName) {
@@ -1146,6 +1205,24 @@
             pw.println(prefix + this);
         }
 
+        public void startScan() {
+            if (mIsScanning) {
+                return;
+            }
+            mIsScanning = true;
+            mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage(
+                    UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
+        }
+
+        public void stopScan() {
+            if (!mIsScanning) {
+                return;
+            }
+            mIsScanning = false;
+            mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage(
+                    UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler));
+        }
+
         @Override
         public String toString() {
             return "Manager " + mPackageName + " (pid " + mPid + ")";
@@ -1262,6 +1339,24 @@
             return null;
         }
 
+        public void maybeUpdateDiscoveryPreferenceForUid(int uid) {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return;
+            }
+            boolean isUidRelevant;
+            synchronized (service.mLock) {
+                isUidRelevant = mUserRecord.mRouterRecords.stream().anyMatch(
+                        router -> router.mUid == uid)
+                        | mUserRecord.mManagerRecords.stream().anyMatch(
+                            manager -> manager.mUid == uid);
+            }
+            if (isUidRelevant) {
+                sendMessage(PooledLambda.obtainMessage(
+                        UserHandler::updateDiscoveryPreferenceOnHandler, this));
+            }
+        }
+
         private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
             int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
             MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo();
@@ -1767,6 +1862,16 @@
             return managers;
         }
 
+        private List<RouterRecord> getRouterRecords() {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return Collections.emptyList();
+            }
+            synchronized (service.mLock) {
+                return new ArrayList<>(mUserRecord.mRouterRecords);
+            }
+        }
+
         private List<ManagerRecord> getManagerRecords() {
             MediaRouter2ServiceImpl service = mServiceRef.get();
             if (service == null) {
@@ -2001,13 +2106,28 @@
                 return;
             }
             List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>();
-            synchronized (service.mLock) {
-                for (RouterRecord routerRecord : mUserRecord.mRouterRecords) {
+            List<RouterRecord> routerRecords = getRouterRecords();
+            List<ManagerRecord> managerRecords = getManagerRecords();
+            boolean isAnyManagerScanning =
+                    managerRecords.stream().anyMatch(manager -> manager.mIsScanning
+                    && service.mActivityManager.getPackageImportance(manager.mPackageName)
+                    <= PACKAGE_IMPORTANCE_FOR_DISCOVERY);
+
+            for (RouterRecord routerRecord : routerRecords) {
+                if (isAnyManagerScanning
+                        || service.mActivityManager.getPackageImportance(routerRecord.mPackageName)
+                        <= PACKAGE_IMPORTANCE_FOR_DISCOVERY) {
                     discoveryPreferences.add(routerRecord.mDiscoveryPreference);
                 }
-                mUserRecord.mCompositeDiscoveryPreference =
-                        new RouteDiscoveryPreference.Builder(discoveryPreferences)
-                                .build();
+            }
+
+            synchronized (service.mLock) {
+                RouteDiscoveryPreference newPreference =
+                        new RouteDiscoveryPreference.Builder(discoveryPreferences).build();
+                if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) {
+                    return;
+                }
+                mUserRecord.mCompositeDiscoveryPreference = newPreference;
             }
             for (MediaRoute2Provider provider : mRouteProviders) {
                 provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 0e52a67..b6d6cc4 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -544,6 +544,18 @@
 
     // Binder call
     @Override
+    public void startScan(IMediaRouter2Manager manager) {
+        mService2.startScan(manager);
+    }
+
+    // Binder call
+    @Override
+    public void stopScan(IMediaRouter2Manager manager) {
+        mService2.stopScan(manager);
+    }
+
+    // Binder call
+    @Override
     public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId,
             MediaRoute2Info route, int volume) {
         mService2.setRouteVolumeWithManager(manager, requestId, route, volume);
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index ea1d8da..ea2788c 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -34,7 +34,6 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
 import android.os.Handler;
-import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.TextUtils;
 import android.util.Log;
@@ -70,6 +69,7 @@
     @NonNull private final Handler mHandler;
     @NonNull private final Vpn mVpn;
     @NonNull private final VpnProfile mProfile;
+    @NonNull private final KeyStore mKeyStore;
 
     @NonNull private final Object mStateLock = new Object();
 
@@ -81,13 +81,10 @@
 
     private int mErrorCount;
 
-    public static boolean isEnabled() {
-        return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN);
-    }
-
     public LockdownVpnTracker(@NonNull Context context,
             @NonNull ConnectivityService connService,
             @NonNull Handler handler,
+            @NonNull KeyStore keyStore,
             @NonNull Vpn vpn,
             @NonNull VpnProfile profile) {
         mContext = Objects.requireNonNull(context);
@@ -95,6 +92,7 @@
         mHandler = Objects.requireNonNull(handler);
         mVpn = Objects.requireNonNull(vpn);
         mProfile = Objects.requireNonNull(profile);
+        mKeyStore = Objects.requireNonNull(keyStore);
         mNotificationManager = mContext.getSystemService(NotificationManager.class);
 
         final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
@@ -157,7 +155,7 @@
                 try {
                     // Use the privileged method because Lockdown VPN is initiated by the system, so
                     // no additional permission checks are necessary.
-                    mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp);
+                    mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, egressProp);
                 } catch (IllegalStateException e) {
                     mAcceptedEgressIface = null;
                     Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/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 dd507a3..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,10 +93,11 @@
     }
 
     @Override
-    @RequiresPermission(android.Manifest.permission.DUMP)
-    public void cancelBugreport() {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
-                "cancelBugreport");
+    @RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges
+    public void cancelBugreport(int callingUidUnused, String callingPackage) {
+        int callingUid = Binder.getCallingUid();
+        enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */);
+
         synchronized (mLock) {
             IDumpstate ds = getDumpstateBinderServiceLocked();
             if (ds == null) {
@@ -104,7 +105,11 @@
                 return;
             }
             try {
-                ds.cancelBugreport();
+                // Note: this may throw SecurityException back out to the caller if they aren't
+                // allowed to cancel the report, in which case we should NOT be setting ctl.stop,
+                // since that would unintentionally kill some other app's bugreport, which we
+                // specifically disallow.
+                ds.cancelBugreport(callingUid, callingPackage);
             } catch (RemoteException e) {
                 Slog.e(TAG, "RemoteException in cancelBugreport", e);
             }
@@ -127,6 +132,34 @@
         }
     }
 
+    private void enforcePermission(
+            String callingPackage, int callingUid, boolean checkCarrierPrivileges) {
+        mAppOps.checkPackage(callingUid, callingPackage);
+
+        // To gain access through the DUMP permission, the OEM has to allow this package explicitly
+        // via sysconfig and privileged permissions.
+        if (mBugreportWhitelistedPackages.contains(callingPackage)
+                && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                        == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+        // For carrier privileges, this can include user-installed apps. This is essentially a
+        // function of the current active SIM(s) in the device to let carrier apps through.
+        if (checkCarrierPrivileges
+                && mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
+                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+            return;
+        }
+
+        String message =
+                callingPackage
+                        + " does not hold the DUMP permission or is not bugreport-whitelisted "
+                        + (checkCarrierPrivileges ? "and does not have carrier privileges " : "")
+                        + "to request a bugreport";
+        Slog.w(TAG, message);
+        throw new SecurityException(message);
+    }
+
     /**
      * Validates that the current user is the primary user.
      *
@@ -182,7 +215,7 @@
             // lifecycle correctly. If we don't subsequent callers will get
             // BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS error.
             // Note that listener will be notified by the death recipient below.
-            cancelBugreport();
+            cancelBugreport(callingUid, callingPackage);
         }
     }
 
@@ -303,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/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 0d059ae..8345424 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -361,7 +361,11 @@
         }
     }
 
+    private static boolean isSupportedVolume(VolumeInfo vol) {
+        return isEmulatedOrPublic(vol) || vol.type == VolumeInfo.TYPE_STUB;
+    }
+
     private boolean shouldHandle(@Nullable VolumeInfo vol) {
-        return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
+        return mIsFuseEnabled && !mIsResetting && (vol == null || isSupportedVolume(vol));
     }
 }
diff --git a/services/core/java/com/android/server/textservices/OWNERS b/services/core/java/com/android/server/textservices/OWNERS
new file mode 100644
index 0000000..9fa9b29
--- /dev/null
+++ b/services/core/java/com/android/server/textservices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 816455
+
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 25cd641..75277d1 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,6 +53,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.security.Authorization;
 import android.security.KeyStore;
 import android.service.trust.TrustAgentService;
 import android.text.TextUtils;
@@ -185,6 +186,8 @@
     private boolean mTrustAgentsCanRun = false;
     private int mCurrentUser = UserHandle.USER_SYSTEM;
 
+    private Authorization mAuthorizationService;
+
     public TrustManagerService(Context context) {
         super(context);
         mContext = context;
@@ -194,6 +197,7 @@
         mStrongAuthTracker = new StrongAuthTracker(context);
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mSettingsObserver = new SettingsObserver(mHandler);
+        mAuthorizationService = new Authorization();
     }
 
     @Override
@@ -696,11 +700,13 @@
         if (changed) {
             dispatchDeviceLocked(userId, locked);
 
+            mAuthorizationService.onLockScreenEvent(locked, userId, null);
             KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
             // Also update the user's profiles who have unified challenge, since they
             // share the same unlocked state (see {@link #isDeviceLocked(int)})
             for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
                 if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
+                    mAuthorizationService.onLockScreenEvent(locked, profileHandle, null);
                     KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
                 }
             }
@@ -1252,6 +1258,7 @@
                         mDeviceLockedForUser.put(userId, locked);
                     }
 
+                    mAuthorizationService.onLockScreenEvent(locked, userId, null);
                     KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
 
                     if (locked) {
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index 42f12eb..0772503 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -51,7 +51,8 @@
     public interface Callback {
         void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs);
         void onDeviceUnavailable(int deviceId);
-        void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
+        void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs,
+                int cableConnectionStatus);
         void onFirstFrameCaptured(int deviceId, int streamId);
     }
 
@@ -142,8 +143,9 @@
         mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();
     }
 
-    private void streamConfigsChangedFromNative(int deviceId) {
-        mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
+    private void streamConfigsChangedFromNative(int deviceId, int cableConnectionStatus) {
+        mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId,
+            cableConnectionStatus).sendToTarget();
     }
 
     private void firstFrameCapturedFromNative(int deviceId, int streamId) {
@@ -184,6 +186,7 @@
             case EVENT_STREAM_CONFIGURATION_CHANGED: {
                 TvStreamConfig[] configs;
                 int deviceId = msg.arg1;
+                int cableConnectionStatus = msg.arg2;
                 synchronized (mLock) {
                     if (DEBUG) {
                         Slog.d(TAG, "EVENT_STREAM_CONFIGURATION_CHANGED: deviceId = " + deviceId);
@@ -191,7 +194,7 @@
                     retrieveStreamConfigsLocked(deviceId);
                     configs = mStreamConfigs.get(deviceId);
                 }
-                mCallback.onStreamConfigurationChanged(deviceId, configs);
+                mCallback.onStreamConfigurationChanged(deviceId, configs, cableConnectionStatus);
                 break;
             }
 
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 2314afc..3dfb99e 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -156,6 +156,7 @@
         synchronized (mLock) {
             Connection connection = new Connection(info);
             connection.updateConfigsLocked(configs);
+            connection.updateCableConnectionStatusLocked(info.getCableConnectionStatus());
             mConnections.put(info.getDeviceId(), connection);
             buildHardwareListLocked();
             mHandler.obtainMessage(
@@ -202,7 +203,8 @@
     }
 
     @Override
-    public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs) {
+    public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs,
+            int cableConnectionStatus) {
         synchronized (mLock) {
             Connection connection = mConnections.get(deviceId);
             if (connection == null) {
@@ -211,12 +213,22 @@
                 return;
             }
             int previousConfigsLength = connection.getConfigsLengthLocked();
+            int previousCableConnectionStatus = connection.getInputStateLocked();
             connection.updateConfigsLocked(configs);
             String inputId = mHardwareInputIdMap.get(deviceId);
-            if (inputId != null
-                    && (previousConfigsLength == 0) != (connection.getConfigsLengthLocked() == 0)) {
-                mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
-                    connection.getInputStateLocked(), 0, inputId).sendToTarget();
+            if (inputId != null) {
+                if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) {
+                    if (previousCableConnectionStatus != connection.getInputStateLocked()) {
+                        mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+                            connection.getInputStateLocked(), 0, inputId).sendToTarget();
+                    }
+                } else {
+                    if ((previousConfigsLength == 0)
+                            != (connection.getConfigsLengthLocked() == 0)) {
+                        mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+                            connection.getInputStateLocked(), 0, inputId).sendToTarget();
+                    }
+                }
             }
             ITvInputHardwareCallback callback = connection.getCallbackLocked();
             if (callback != null) {
@@ -624,7 +636,7 @@
     }
 
     private class Connection implements IBinder.DeathRecipient {
-        private final TvInputHardwareInfo mHardwareInfo;
+        private TvInputHardwareInfo mHardwareInfo;
         private TvInputInfo mInfo;
         private TvInputHardwareImpl mHardware = null;
         private ITvInputHardwareCallback mCallback;
@@ -633,6 +645,7 @@
         private Integer mResolvedUserId = null;
         private Runnable mOnFirstFrameCaptured;
         private ResourceClientProfile mResourceClientProfile = null;
+        private boolean mIsCableConnectionStatusUpdated = false;
 
         public Connection(TvInputHardwareInfo hardwareInfo) {
             mHardwareInfo = hardwareInfo;
@@ -735,6 +748,17 @@
                     + " }";
         }
 
+        public boolean updateCableConnectionStatusLocked(int cableConnectionStatus) {
+            // Update connection status only if it's not default value
+            if (cableConnectionStatus != TvInputHardwareInfo.CABLE_CONNECTION_STATUS_UNKNOWN
+                    || mIsCableConnectionStatusUpdated) {
+                mIsCableConnectionStatusUpdated = true;
+                mHardwareInfo = mHardwareInfo.toBuilder()
+                    .cableConnectionStatus(cableConnectionStatus).build();
+            }
+            return mIsCableConnectionStatusUpdated;
+        }
+
         private int getConfigsLengthLocked() {
             return mConfigs == null ? 0 : mConfigs.length;
         }
@@ -742,7 +766,9 @@
         private int getInputStateLocked() {
             int configsLength = getConfigsLengthLocked();
             if (configsLength > 0) {
-                return INPUT_STATE_CONNECTED;
+                if (!mIsCableConnectionStatusUpdated) {
+                    return INPUT_STATE_CONNECTED;
+                }
             }
             switch (mHardwareInfo.getCableConnectionStatus()) {
                 case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_CONNECTED:
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 6cd0258..d858ae4 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -20,6 +20,7 @@
 import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
 import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
@@ -1728,6 +1729,46 @@
         }
 
         @Override
+        public void pauseRecording(IBinder sessionToken, @NonNull Bundle params, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "pauseRecording");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
+                                .pauseRecording(params);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in pauseRecording", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void resumeRecording(IBinder sessionToken, @NonNull Bundle params, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "resumeRecording");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
+                                .resumeRecording(params);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in resumeRecording", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
             if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
                     != PackageManager.PERMISSION_GRANTED) {
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/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 4e1a234..a5311f3 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -261,7 +261,7 @@
 
     void onDeviceAvailable(const TvInputDeviceInfo& info);
     void onDeviceUnavailable(int deviceId);
-    void onStreamConfigurationsChanged(int deviceId);
+    void onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus);
     void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded);
 
 private:
@@ -519,7 +519,7 @@
             deviceId);
 }
 
-void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
+void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) {
     {
         Mutex::Autolock autoLock(&mLock);
         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
@@ -529,10 +529,8 @@
         connections.clear();
     }
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(
-            mThiz,
-            gTvInputHalClassInfo.streamConfigsChanged,
-            deviceId);
+    env->CallVoidMethod(mThiz, gTvInputHalClassInfo.streamConfigsChanged, deviceId,
+                        cableConnectionStatus);
 }
 
 void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
@@ -572,7 +570,8 @@
             mHal->onDeviceUnavailable(mEvent.deviceInfo.deviceId);
         } break;
         case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: {
-            mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId);
+            int cableConnectionStatus = static_cast<int>(mEvent.deviceInfo.cableConnectionStatus);
+            mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId, cableConnectionStatus);
         } break;
         default:
             ALOGE("Unrecognizable event");
@@ -688,9 +687,8 @@
             "deviceAvailableFromNative", "(Landroid/media/tv/TvInputHardwareInfo;)V");
     GET_METHOD_ID(
             gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
-    GET_METHOD_ID(
-            gTvInputHalClassInfo.streamConfigsChanged, clazz,
-            "streamConfigsChangedFromNative", "(I)V");
+    GET_METHOD_ID(gTvInputHalClassInfo.streamConfigsChanged, clazz,
+                  "streamConfigsChangedFromNative", "(II)V");
     GET_METHOD_ID(
             gTvInputHalClassInfo.firstFrameCaptured, clazz,
             "firstFrameCapturedFromNative", "(II)V");
diff --git a/services/searchui/OWNERS b/services/searchui/OWNERS
new file mode 100644
index 0000000..92835c2
--- /dev/null
+++ b/services/searchui/OWNERS
@@ -0,0 +1,2 @@
+hyunyoungs@google.com
+sfufa@google.com
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/locksettings/ResumeOnRebootServiceProviderTests.java b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
new file mode 100644
index 0000000..b9af82b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/ResumeOnRebootServiceProviderTests.java
@@ -0,0 +1,111 @@
+/*
+ * 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 com.android.server.locksettings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.service.resumeonreboot.ResumeOnRebootService;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class ResumeOnRebootServiceProviderTests {
+
+    @Mock
+    Context mMockContext;
+    @Mock
+    PackageManager mMockPackageManager;
+    @Mock
+    ResolveInfo mMockResolvedInfo;
+    @Mock
+    ServiceInfo mMockServiceInfo;
+    @Mock
+    ComponentName mMockComponentName;
+    @Captor
+    ArgumentCaptor<Intent> mIntentArgumentCaptor;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mMockContext.getUserId()).thenReturn(0);
+        when(mMockResolvedInfo.serviceInfo).thenReturn(mMockServiceInfo);
+        when(mMockServiceInfo.getComponentName()).thenReturn(mMockComponentName);
+    }
+
+    @Test
+    public void noServiceFound() throws Exception {
+        when(mMockPackageManager.queryIntentServices(any(),
+                eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
+                null);
+        assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+                mMockPackageManager).getServiceConnection()).isNull();
+    }
+
+    @Test
+    public void serviceNotGuardedWithPermission() throws Exception {
+        ArrayList<ResolveInfo> resultList = new ArrayList<>();
+        when(mMockServiceInfo.permission).thenReturn("");
+        resultList.add(mMockResolvedInfo);
+        when(mMockPackageManager.queryIntentServices(any(), any())).thenReturn(
+                resultList);
+        assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+                mMockPackageManager).getServiceConnection()).isNull();
+    }
+
+    @Test
+    public void serviceResolved() throws Exception {
+        ArrayList<ResolveInfo> resultList = new ArrayList<>();
+        resultList.add(mMockResolvedInfo);
+        when(mMockServiceInfo.permission).thenReturn(
+                Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE);
+        when(mMockPackageManager.queryIntentServices(any(),
+                eq(PackageManager.MATCH_SYSTEM_ONLY))).thenReturn(
+                resultList);
+
+        assertThat(new ResumeOnRebootServiceProvider(mMockContext,
+                mMockPackageManager).getServiceConnection()).isNotNull();
+
+        verify(mMockPackageManager).queryIntentServices(mIntentArgumentCaptor.capture(),
+                eq(PackageManager.MATCH_SYSTEM_ONLY));
+        assertThat(mIntentArgumentCaptor.getValue().getAction()).isEqualTo(
+                ResumeOnRebootService.SERVICE_INTERFACE);
+    }
+}
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/services/tests/shortcutmanagerutils/OWNERS b/services/tests/shortcutmanagerutils/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/shortcutmanagerutils/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 724a9e4..e55720c 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -109,6 +109,20 @@
  */
 public abstract class Connection extends Conferenceable {
 
+    /**@hide*/
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "STATE_", value = {
+            STATE_INITIALIZING,
+            STATE_NEW,
+            STATE_RINGING,
+            STATE_DIALING,
+            STATE_ACTIVE,
+            STATE_HOLDING,
+            STATE_DISCONNECTED,
+            STATE_PULLING_CALL
+    })
+    public @interface ConnectionState {}
+
     /**
      * The connection is initializing. This is generally the first state for a {@code Connection}
      * returned by a {@link ConnectionService}.
diff --git a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java
new file mode 100644
index 0000000..c7e7cd5
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java
@@ -0,0 +1,238 @@
+/*
+ * 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.internal.telephony;
+
+import android.net.Uri;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Utility methods for parsing parts of {@link android.telephony.ims.SipMessage}s.
+ * See RFC 3261 for more information.
+ * @hide
+ */
+// Note: This is lightweight in order to avoid a full SIP stack import in frameworks/base.
+public class SipMessageParsingUtils {
+    private static final String TAG = "SipMessageParsingUtils";
+    // "Method" in request-line
+    // Request-Line = Method SP Request-URI SP SIP-Version CRLF
+    private static final String[] SIP_REQUEST_METHODS = new String[] {"INVITE", "ACK", "OPTIONS",
+            "BYE", "CANCEL", "REGISTER", "PRACK", "SUBSCRIBE", "NOTIFY", "PUBLISH", "INFO", "REFER",
+            "MESSAGE", "UPDATE"};
+
+    // SIP Version 2.0 (corresponding to RCS 3261), set in "SIP-Version" of Status-Line and
+    // Request-Line
+    //
+    // Request-Line = Method SP Request-URI SP SIP-Version CRLF
+    // Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+    private static final String SIP_VERSION_2 = "SIP/2.0";
+
+    // headers are formatted Key:Value
+    private static final String HEADER_KEY_VALUE_SEPARATOR = ":";
+    // Multiple of the same header can be concatenated and put into one header Key:Value pair, for
+    // example "v: XX1;branch=YY1,XX2;branch=YY2". This needs to be treated as two "v:" headers.
+    private static final String SUBHEADER_VALUE_SEPARATOR = ",";
+
+    // SIP header parameters have the format ";paramName=paramValue"
+    private static final String PARAM_SEPARATOR = ";";
+    // parameters are formatted paramName=ParamValue
+    private static final String PARAM_KEY_VALUE_SEPARATOR = "=";
+
+    // The via branch parameter definition
+    private static final String BRANCH_PARAM_KEY = "branch";
+
+    // via header key
+    private static final String VIA_SIP_HEADER_KEY = "via";
+    // compact form of the via header key
+    private static final String VIA_SIP_HEADER_KEY_COMPACT = "v";
+
+    /**
+     * @return true if the SIP message start line is considered a request (based on known request
+     * methods).
+     */
+    public static boolean isSipRequest(String startLine) {
+        String[] splitLine = splitStartLineAndVerify(startLine);
+        if (splitLine == null) return false;
+        return verifySipRequest(splitLine);
+    }
+
+    /**
+     * Return the via branch parameter, which is used to identify the transaction ID (request and
+     * response pair) in a SIP transaction.
+     * @param headerString The string containing the headers of the SIP message.
+     */
+    public static String getTransactionId(String headerString) {
+        // search for Via: or v: parameter, we only care about the first one.
+        List<Pair<String, String>> headers = parseHeaders(headerString, true,
+                VIA_SIP_HEADER_KEY, VIA_SIP_HEADER_KEY_COMPACT);
+        for (Pair<String, String> header : headers) {
+            // Headers can also be concatenated together using a "," between each header value.
+            // format becomes v: XX1;branch=YY1,XX2;branch=YY2. Need to extract only the first ID's
+            // branch param YY1.
+            String[] subHeaders = header.second.split(SUBHEADER_VALUE_SEPARATOR);
+            for (String subHeader : subHeaders) {
+                // Search for ;branch=z9hG4bKXXXXXX and return parameter value
+                String[] params = subHeader.split(PARAM_SEPARATOR);
+                if (params.length < 2) {
+                    // This param doesn't include a branch param, move to next param.
+                    Log.w(TAG, "getTransactionId: via detected without branch param:"
+                            + subHeader);
+                    continue;
+                }
+                // by spec, each param can only appear once in a header.
+                for (String param : params) {
+                    String[] pair = param.split(PARAM_KEY_VALUE_SEPARATOR);
+                    if (pair.length < 2) {
+                        // ignore info before the first parameter
+                        continue;
+                    }
+                    if (pair.length > 2) {
+                        Log.w(TAG,
+                                "getTransactionId: unexpected parameter" + Arrays.toString(pair));
+                    }
+                    // Trim whitespace in parameter
+                    pair[0] = pair[0].trim();
+                    pair[1] = pair[1].trim();
+                    if (BRANCH_PARAM_KEY.equalsIgnoreCase(pair[0])) {
+                        // There can be multiple "Via" headers in the SIP message, however we want
+                        // to return the first once found, as this corresponds with the transaction
+                        // that is relevant here.
+                        return pair[1];
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private static String[] splitStartLineAndVerify(String startLine) {
+        String[] splitLine = startLine.split(" ");
+        if (isStartLineMalformed(splitLine)) return null;
+        return splitLine;
+    }
+
+    private static boolean isStartLineMalformed(String[] startLine) {
+        if (startLine == null || startLine.length == 0)  {
+            return true;
+        }
+        // start lines contain three segments separated by spaces (SP):
+        // Request-Line  =  Method SP Request-URI SP SIP-Version CRLF
+        // Status-Line  =  SIP-Version SP Status-Code SP Reason-Phrase CRLF
+        return (startLine.length != 3);
+    }
+
+    private static boolean verifySipRequest(String[] request) {
+        // Request-Line  =  Method SP Request-URI SP SIP-Version CRLF
+        boolean verified = request[2].contains(SIP_VERSION_2);
+        verified &= (Uri.parse(request[1]).getScheme() != null);
+        verified &= Arrays.stream(SIP_REQUEST_METHODS).anyMatch(s -> request[0].contains(s));
+        return verified;
+    }
+
+    private static boolean verifySipResponse(String[] response) {
+        // Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
+        boolean verified = response[0].contains(SIP_VERSION_2);
+        int statusCode = Integer.parseInt(response[1]);
+        verified &= (statusCode >= 100  && statusCode < 700);
+        return verified;
+    }
+
+    /**
+     * Parse a String representation of the Header portion of the SIP Message and re-structure it
+     * into a List of key->value pairs representing each header in the order that they appeared in
+     * the message.
+     *
+     * @param headerString The raw string containing all headers
+     * @param stopAtFirstMatch Return early when the first match is found from matching header keys.
+     * @param matchingHeaderKeys An optional list of Strings containing header keys that should be
+     *                           returned if they exist. If none exist, all keys will be returned.
+     *                           (This is internally an equalsIgnoreMatch comparison).
+     * @return the matched header keys and values.
+     */
+    private static List<Pair<String, String>> parseHeaders(String headerString,
+            boolean stopAtFirstMatch, String... matchingHeaderKeys) {
+        // Ensure there is no leading whitespace
+        headerString = removeLeadingWhitespace(headerString);
+
+        List<Pair<String, String>> result = new ArrayList<>();
+        // Split the string line-by-line.
+        String[] headerLines = headerString.split("\\r?\\n");
+        if (headerLines.length == 0) {
+            return Collections.emptyList();
+        }
+
+        String headerKey = null;
+        StringBuilder headerValueSegment = new StringBuilder();
+        // loop through each line, either parsing a "key: value" pair or appending values that span
+        // multiple lines.
+        for (String line : headerLines) {
+            // This line is a continuation of the last line if it starts with whitespace or tab
+            if (line.startsWith("\t") || line.startsWith(" ")) {
+                headerValueSegment.append(removeLeadingWhitespace(line));
+                continue;
+            }
+            // This line is the start of a new key, If headerKey/value is already populated from a
+            // previous key/value pair, add it to list of parsed header pairs.
+            if (headerKey != null) {
+                final String key = headerKey;
+                if (matchingHeaderKeys == null || matchingHeaderKeys.length == 0
+                        || Arrays.stream(matchingHeaderKeys).anyMatch(
+                                (s) -> s.equalsIgnoreCase(key))) {
+                    result.add(new Pair<>(key, headerValueSegment.toString()));
+                    if (stopAtFirstMatch) {
+                        return result;
+                    }
+                }
+                headerKey = null;
+                headerValueSegment = new StringBuilder();
+            }
+
+            // Format is "Key:Value", ignore any ":" after the first.
+            String[] pair = line.split(HEADER_KEY_VALUE_SEPARATOR, 2);
+            if (pair.length < 2) {
+                // malformed line, skip
+                Log.w(TAG, "parseHeaders - received malformed line: " + line);
+                continue;
+            }
+
+            headerKey = pair[0].trim();
+            for (int i = 1; i < pair.length; i++) {
+                headerValueSegment.append(removeLeadingWhitespace(pair[i]));
+            }
+        }
+        // Pick up the last pending header being parsed, if it exists.
+        if (headerKey != null) {
+            final String key = headerKey;
+            if (matchingHeaderKeys == null || matchingHeaderKeys.length == 0
+                    || Arrays.stream(matchingHeaderKeys).anyMatch(
+                            (s) -> s.equalsIgnoreCase(key))) {
+                result.add(new Pair<>(key, headerValueSegment.toString()));
+            }
+        }
+
+        return result;
+    }
+
+    private static String removeLeadingWhitespace(String line) {
+        return line.replaceFirst("^\\s*", "");
+    }
+}
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/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index b785037..6571858 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -28,8 +28,6 @@
 /**
  * Define capability of a modem group. That is, the capabilities
  * are shared between those modems defined by list of modem IDs.
- *
- * @hide
  */
 public final class PhoneCapability implements Parcelable {
     // Hardcoded default DSDS capability.
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index ed09d53..1273aa3a 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -478,7 +478,9 @@
 
     /**
      * Compare phone numbers a and b, return true if they're identical enough for caller ID purposes.
+     * @deprecated use {@link #areSamePhoneNumber(String, String, String)} instead
      */
+    @Deprecated
     public static boolean compare(String a, String b) {
         // We've used loose comparation at least Eclair, which may change in the future.
 
@@ -489,7 +491,9 @@
      * Compare phone numbers a and b, and return true if they're identical
      * enough for caller ID purposes. Checks a resource to determine whether
      * to use a strict or loose comparison algorithm.
+     * @deprecated use {@link #areSamePhoneNumber(String, String, String)} instead
      */
+    @Deprecated
     public static boolean compare(Context context, String a, String b) {
         boolean useStrict = context.getResources().getBoolean(
                com.android.internal.R.bool.config_use_strict_phone_number_comparation);
@@ -3218,7 +3222,7 @@
         }
 
         // The conversion map is not defined (this is default). Skip conversion.
-        if (sConvertToEmergencyMap == null || sConvertToEmergencyMap.length == 0 ) {
+        if (sConvertToEmergencyMap == null || sConvertToEmergencyMap.length == 0) {
             return number;
         }
 
@@ -3254,4 +3258,47 @@
         }
         return number;
     }
+
+    /**
+     * Determines if two phone numbers are the same.
+     * <p>
+     * Matching is based on <a href="https://github.com/google/libphonenumber>libphonenumber</a>.
+     * Unlike {@link #compare(String, String)}, matching takes into account national
+     * dialing plans rather than simply matching the last 7 digits of the two phone numbers. As a
+     * result, it is expected that some numbers which would match using the previous method will no
+     * longer match using this new approach.
+     *
+     * @param number1
+     * @param number2
+     * @param defaultCountryIso The lowercase two letter ISO 3166-1 country code. Used when parsing
+     *                          the phone numbers where it is not possible to determine the country
+     *                          associated with a phone number based on the number alone. It
+     *                          is recommended to pass in
+     *                          {@link TelephonyManager#getNetworkCountryIso()}.
+     * @return True if the two given phone number are same.
+     */
+    public static boolean areSamePhoneNumber(@NonNull String number1,
+            @NonNull String number2, @NonNull String defaultCountryIso) {
+        PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+        PhoneNumber n1;
+        PhoneNumber n2;
+        defaultCountryIso = defaultCountryIso.toUpperCase();
+        try {
+            n1 = util.parseAndKeepRawInput(number1, defaultCountryIso);
+            n2 = util.parseAndKeepRawInput(number2, defaultCountryIso);
+        } catch (NumberParseException e) {
+            return false;
+        }
+
+        PhoneNumberUtil.MatchType matchType = util.isNumberMatch(n1, n2);
+        if (matchType == PhoneNumberUtil.MatchType.EXACT_MATCH
+                || matchType == PhoneNumberUtil.MatchType.NSN_MATCH) {
+            return true;
+        } else if (matchType == PhoneNumberUtil.MatchType.SHORT_NSN_MATCH) {
+            return (n1.getNationalNumber() == n2.getNationalNumber()
+                    && n1.getCountryCode() == n2.getCountryCode());
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index af62ba4..9fb098e 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -17,6 +17,8 @@
 package android.telephony;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.Annotation.NetworkType;
@@ -26,12 +28,10 @@
 import java.util.Arrays;
 import java.util.Objects;
 
-/**
- * @hide
- */
 public final class PhysicalChannelConfig implements Parcelable {
 
     // TODO(b/72993578) consolidate these enums in a central location.
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({CONNECTION_PRIMARY_SERVING, CONNECTION_SECONDARY_SERVING, CONNECTION_UNKNOWN})
     public @interface ConnectionStatus {}
@@ -47,7 +47,25 @@
     public static final int CONNECTION_SECONDARY_SERVING = 2;
 
     /** Connection status is unknown. */
-    public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE;
+    public static final int CONNECTION_UNKNOWN = -1;
+
+    /** Channel number is unknown. */
+    public static final int CHANNEL_NUMBER_UNKNOWN = -1;
+
+    /** 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.
@@ -58,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.
@@ -75,9 +98,24 @@
     private int mFrequencyRange;
 
     /**
-     * The absolute radio frequency channel number, {@link Integer#MAX_VALUE} 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
@@ -86,51 +124,81 @@
     private int[] mContextIds;
 
     /**
-     * The physical cell identifier for this cell - PCI, PSC, {@link Integer#MAX_VALUE} if known.
+     * The physical cell identifier for this cell - PCI, PSC, {@link #PHYSICAL_CELL_ID_UNKNOWN}
      */
     private int mPhysicalCellId;
 
+    /**
+     * This is the band which is being used.
+     */
+    private int mBand;
+
     @Override
     public int describeContents() {
         return 0;
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    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() {
         return mContextIds;
     }
 
     /**
-     * @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}
      * @see {@link ServiceState#FREQUENCY_RANGE_MMWAVE}
+     * @hide
      */
     @ServiceState.FrequencyRange
     public int getFrequencyRange() {
@@ -138,11 +206,48 @@
     }
 
     /**
-     * @return the absolute radio frequency channel number for this physical channel,
-     * {@link Integer#MAX_VALUE} if unknown.
+     * @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;
     }
 
     /**
@@ -152,19 +257,24 @@
      * In EUTRAN, this value is physical layer cell identity. The range is [0, 503].
      * Reference: 3GPP TS 36.211 section 6.11.
      *
-     * In 5G RAN, this value is physical layer cell identity. The range is [0, 1008].
+     * In 5G RAN, this value is physical layer cell identity. The range is [0, 1007].
      * Reference: 3GPP TS 38.211 section 7.4.2.1.
      *
-     * @return the physical cell identifier for this cell, {@link Integer#MAX_VALUE} if unknown.
+     * @return the physical cell identifier for this cell, {@link #PHYSICAL_CELL_ID_UNKNOWN}
+     * if {@link android.telephony.CellInfo#UNAVAILABLE}.
      */
+    @IntRange(from = 0, to = 1007)
     public int getPhysicalCellId() {
         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 getRat() {
-        return mRat;
+    public int getNetworkType() {
+        return mNetworkType;
     }
 
     /**
@@ -174,14 +284,17 @@
      * @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() {
         return mCellConnectionStatus;
     }
 
-    /** @return String representation of the connection status */
+    /**
+     * @return String representation of the connection status
+     * @hide
+     */
     private String getConnectionStatusString() {
         switch(mCellConnectionStatus) {
             case CONNECTION_PRIMARY_SERVING:
@@ -195,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) {
@@ -208,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() {
@@ -240,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();
     }
@@ -257,89 +478,143 @@
     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();
+        }
     }
 
-    /** The builder of {@code PhysicalChannelConfig}. */
+    /**
+     * The builder of {@code PhysicalChannelConfig}.
+     * @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;
 
-        /** @hide */
         public Builder() {
-            mRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+            mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
             mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
-            mChannelNumber = Integer.MAX_VALUE;
-            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 = Integer.MAX_VALUE;
+            mPhysicalCellId = PHYSICAL_CELL_ID_UNKNOWN;
+            mBand = BAND_UNKNOWN;
         }
 
-        /** @hide */
         public PhysicalChannelConfig build() {
             return new PhysicalChannelConfig(this);
         }
 
-        /** @hide */
-        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;
         }
 
-        /** @hide */
-        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;
         }
 
-        /** @hide */
-        public Builder setChannelNumber(int channelNumber) {
-            this.mChannelNumber = channelNumber;
+        public @NonNull Builder setDownlinkChannelNumber(int downlinkChannelNumber) {
+            mDownlinkChannelNumber = downlinkChannelNumber;
             return this;
         }
 
-        /** @hide */
-        public Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) {
-            this.mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
+        public @NonNull Builder setUplinkChannelNumber(int uplinkChannelNumber) {
+            mUplinkChannelNumber = uplinkChannelNumber;
             return this;
         }
 
-        /** @hide */
-        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;
         }
 
-        /** @hide */
-        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;
         }
 
-        /** @hide */
-        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
new file mode 100644
index 0000000..af67ed2
--- /dev/null
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Request used to register {@link SignalThresholdInfo} to be notified when the signal strength
+ * breach the specified thresholds.
+ */
+public final class SignalStrengthUpdateRequest implements Parcelable {
+    /**
+     * List of SignalThresholdInfo for the request.
+     */
+    private final List<SignalThresholdInfo> mSignalThresholdInfos;
+
+    /**
+     * Whether the reporting is required for thresholds in the request while device is idle.
+     */
+    private final boolean mIsReportingRequestedWhileIdle;
+
+    /**
+     * Whether the reporting requested for system thresholds while device is idle.
+     *
+     * System signal thresholds are loaded from carrier config items and mainly used for UI
+     * displaying. By default, they are ignored when device is idle. When setting the value to true,
+     * modem will continue reporting signal strength changes over the system signal thresholds even
+     * device is idle.
+     *
+     * This should only set to true by the system caller.
+     */
+    private final boolean mIsSystemThresholdReportingRequestedWhileIdle;
+
+    /**
+     * A IBinder object as a token for server side to check if the request client is still living.
+     */
+    private final IBinder mLiveToken;
+
+    private SignalStrengthUpdateRequest(
+            @NonNull List<SignalThresholdInfo> signalThresholdInfos,
+            boolean isReportingRequestedWhileIdle,
+            boolean isSystemThresholdReportingRequestedWhileIdle) {
+        validate(signalThresholdInfos);
+
+        mSignalThresholdInfos = signalThresholdInfos;
+        mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
+        mIsSystemThresholdReportingRequestedWhileIdle =
+                isSystemThresholdReportingRequestedWhileIdle;
+        mLiveToken = new Binder();
+    }
+
+    /**
+     * Builder class to create {@link SignalStrengthUpdateRequest} object.
+     */
+    public static final class Builder {
+        private List<SignalThresholdInfo> mSignalThresholdInfos = null;
+        private boolean mIsReportingRequestedWhileIdle = false;
+        private boolean mIsSystemThresholdReportingRequestedWhileIdle = false;
+
+        /**
+         * Set the collection of SignalThresholdInfo for the builder object
+         *
+         * @param signalThresholdInfos the collection of SignalThresholdInfo
+         *
+         * @return the builder to facilitate the chaining
+         */
+        public @NonNull Builder setSignalThresholdInfos(
+                @NonNull Collection<SignalThresholdInfo> signalThresholdInfos) {
+            Objects.requireNonNull(signalThresholdInfos,
+                    "SignalThresholdInfo collection must not be null");
+            for (SignalThresholdInfo info : signalThresholdInfos) {
+                Objects.requireNonNull(info,
+                        "SignalThresholdInfo in the collection must not be null");
+            }
+
+            mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos);
+            // Sort the collection with RAN ascending order, make the ordering not matter for equals
+            mSignalThresholdInfos.sort(
+                    Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType));
+            return this;
+        }
+
+        /**
+         * Set the builder object if require reporting on thresholds in this request when device is
+         * idle.
+         *
+         * @param isReportingRequestedWhileIdle true if request reporting when device is idle
+         *
+         * @return the builder to facilitate the chaining
+         */
+        public @NonNull Builder setReportingRequestedWhileIdle(
+                boolean isReportingRequestedWhileIdle) {
+            mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
+            return this;
+        }
+
+        /**
+         * Set the builder object if require reporting on the system thresholds when device is idle.
+         *
+         * This can only used by the system caller.
+         *
+         * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the
+         *                                                     system thresholds when device is idle
+         * @return the builder to facilitate the chaining
+         * @hide
+         */
+        public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle(
+                boolean isSystemThresholdReportingRequestedWhileIdle) {
+            mIsSystemThresholdReportingRequestedWhileIdle =
+                    isSystemThresholdReportingRequestedWhileIdle;
+            return this;
+        }
+
+        /**
+         * Build a {@link SignalStrengthUpdateRequest} object.
+         *
+         * @return the SignalStrengthUpdateRequest object
+         *
+         * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the
+         * radio access network type in the collection is not unique
+         */
+        public @NonNull SignalStrengthUpdateRequest build() {
+            return new SignalStrengthUpdateRequest(mSignalThresholdInfos,
+                    mIsReportingRequestedWhileIdle, mIsSystemThresholdReportingRequestedWhileIdle);
+        }
+    }
+
+    private SignalStrengthUpdateRequest(Parcel in) {
+        mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR);
+        mIsReportingRequestedWhileIdle = in.readBoolean();
+        mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean();
+        mLiveToken = in.readStrongBinder();
+    }
+
+    /**
+     * Get the collection of SignalThresholdInfo in the request.
+     *
+     * @return the collection of SignalThresholdInfo
+     */
+    @NonNull
+    public Collection<SignalThresholdInfo> getSignalThresholdInfos() {
+        return Collections.unmodifiableList(mSignalThresholdInfos);
+    }
+
+    /**
+     * Get whether reporting is requested for the threshold in the request while device is idle.
+     *
+     * @return true if reporting requested while device is idle
+     */
+    public boolean isReportingRequestedWhileIdle() {
+        return mIsReportingRequestedWhileIdle;
+    }
+
+    /**
+     * @return true if reporting requested for system thresholds while device is idle
+     *
+     * @hide
+     */
+    public boolean isSystemThresholdReportingRequestedWhileIdle() {
+        return mIsSystemThresholdReportingRequestedWhileIdle;
+    }
+
+    /*
+     * @return the live token of the request
+     *
+     * @hide
+     */
+    public @NonNull IBinder getLiveToken() {
+        return mLiveToken;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedList(mSignalThresholdInfos);
+        dest.writeBoolean(mIsReportingRequestedWhileIdle);
+        dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle);
+        dest.writeStrongBinder(mLiveToken);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) return true;
+
+        if (!(other instanceof SignalStrengthUpdateRequest)) {
+            return false;
+        }
+
+        SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other;
+        return mSignalThresholdInfos.equals(request.mSignalThresholdInfos)
+                && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle
+                && mIsSystemThresholdReportingRequestedWhileIdle
+                    == request.mIsSystemThresholdReportingRequestedWhileIdle;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSignalThresholdInfos, mIsReportingRequestedWhileIdle,
+                mIsSystemThresholdReportingRequestedWhileIdle);
+    }
+
+    public static final @NonNull Parcelable.Creator<SignalStrengthUpdateRequest> CREATOR =
+            new Parcelable.Creator<SignalStrengthUpdateRequest>() {
+                @Override
+                public SignalStrengthUpdateRequest createFromParcel(Parcel source) {
+                    return new SignalStrengthUpdateRequest(source);
+                }
+
+                @Override
+                public SignalStrengthUpdateRequest[] newArray(int size) {
+                    return new SignalStrengthUpdateRequest[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return new StringBuilder("SignalStrengthUpdateRequest{")
+                .append("mSignalThresholdInfos=")
+                .append(mSignalThresholdInfos)
+                .append(" mIsReportingRequestedWhileIdle=")
+                .append(mIsReportingRequestedWhileIdle)
+                .append(" mIsSystemThresholdReportingRequestedWhileIdle=")
+                .append(mIsSystemThresholdReportingRequestedWhileIdle)
+                .append(" mLiveToken")
+                .append(mLiveToken)
+                .append("}").toString();
+    }
+
+    /**
+     * Throw IAE when the RAN in the collection is not unique.
+     */
+    private static void validate(Collection<SignalThresholdInfo> infos) {
+        Set<Integer> uniqueRan = new HashSet<>(infos.size());
+        for (SignalThresholdInfo info : infos) {
+            final int ran = info.getRadioAccessNetworkType();
+            if (!uniqueRan.add(ran)) {
+                throw new IllegalArgumentException("RAN: " + ran + " is not unique");
+            }
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
index f6f6d75..0059ad6 100644
--- a/telephony/java/android/telephony/SignalThresholdInfo.java
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -28,101 +28,109 @@
 
 /**
  * Defines the threshold value of the signal strength.
- * @hide
  */
-public class SignalThresholdInfo implements Parcelable {
+public final class SignalThresholdInfo implements Parcelable {
+
+    /**
+     * Unknown signal measurement type.
+     */
+    public static final int SIGNAL_MEASUREMENT_TYPE_UNKNOWN = 0;
+
     /**
      * Received Signal Strength Indication.
      * Range: -113 dBm and -51 dBm
-     * Used RAN: GERAN, CDMA2000
+     * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#GERAN},
+     *           {@link AccessNetworkConstants.AccessNetworkType#CDMA2000}
      * Reference: 3GPP TS 27.007 section 8.5.
      */
-    public static final int SIGNAL_RSSI = 1;
+    public static final int SIGNAL_MEASUREMENT_TYPE_RSSI = 1;
 
     /**
      * Received Signal Code Power.
      * Range: -120 dBm to -25 dBm;
-     * Used RAN: UTRAN
+     * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#UTRAN}
      * Reference: 3GPP TS 25.123, section 9.1.1.1
      */
-    public static final int SIGNAL_RSCP = 2;
+    public static final int SIGNAL_MEASUREMENT_TYPE_RSCP = 2;
 
     /**
      * Reference Signal Received Power.
      * Range: -140 dBm to -44 dBm;
-     * Used RAN: EUTRAN
+     * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
      * Reference: 3GPP TS 36.133 9.1.4
      */
-    public static final int SIGNAL_RSRP = 3;
+    public static final int SIGNAL_MEASUREMENT_TYPE_RSRP = 3;
 
     /**
      * Reference Signal Received Quality
-     * Range: -20 dB to -3 dB;
-     * Used RAN: EUTRAN
+     * Range: -34 dB to 3 dB;
+     * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
      * Reference: 3GPP TS 36.133 9.1.7
      */
-    public static final int SIGNAL_RSRQ = 4;
+    public static final int SIGNAL_MEASUREMENT_TYPE_RSRQ = 4;
 
     /**
      * Reference Signal Signal to Noise Ratio
      * Range: -20 dB to 30 dB;
-     * Used RAN: EUTRAN
+     * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#EUTRAN}
      */
-    public static final int SIGNAL_RSSNR = 5;
+    public static final int SIGNAL_MEASUREMENT_TYPE_RSSNR = 5;
 
     /**
      * 5G SS reference signal received power.
      * Range: -140 dBm to -44 dBm.
-     * Used RAN: NGRAN
+     * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
      * Reference: 3GPP TS 38.215.
      */
-    public static final int SIGNAL_SSRSRP = 6;
+    public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRP = 6;
 
     /**
      * 5G SS reference signal received quality.
-     * Range: -20 dB to -3 dB.
-     * Used RAN: NGRAN
-     * Reference: 3GPP TS 38.215.
+     * Range: -43 dB to 20 dB.
+     * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
+     * Reference: 3GPP TS 38.133 section 10.1.11.1.
      */
-    public static final int SIGNAL_SSRSRQ = 7;
+    public static final int SIGNAL_MEASUREMENT_TYPE_SSRSRQ = 7;
 
     /**
      * 5G SS signal-to-noise and interference ratio.
      * Range: -23 dB to 40 dB
-     * Used RAN: NGRAN
+     * Used RAN: {@link AccessNetworkConstants.AccessNetworkType#NGRAN}
      * Reference: 3GPP TS 38.215 section 5.1.*, 3GPP TS 38.133 section 10.1.16.1.
      */
-    public static final int SIGNAL_SSSINR = 8;
+    public static final int SIGNAL_MEASUREMENT_TYPE_SSSINR = 8;
 
     /** @hide */
-    @IntDef(prefix = { "SIGNAL_" }, value = {
-        SIGNAL_RSSI,
-        SIGNAL_RSCP,
-        SIGNAL_RSRP,
-        SIGNAL_RSRQ,
-        SIGNAL_RSSNR,
-        SIGNAL_SSRSRP,
-        SIGNAL_SSRSRQ,
-        SIGNAL_SSSINR
+    @IntDef(prefix = {"SIGNAL_MEASUREMENT_TYPE_"}, value = {
+            SIGNAL_MEASUREMENT_TYPE_UNKNOWN,
+            SIGNAL_MEASUREMENT_TYPE_RSSI,
+            SIGNAL_MEASUREMENT_TYPE_RSCP,
+            SIGNAL_MEASUREMENT_TYPE_RSRP,
+            SIGNAL_MEASUREMENT_TYPE_RSRQ,
+            SIGNAL_MEASUREMENT_TYPE_RSSNR,
+            SIGNAL_MEASUREMENT_TYPE_SSRSRP,
+            SIGNAL_MEASUREMENT_TYPE_SSRSRQ,
+            SIGNAL_MEASUREMENT_TYPE_SSSINR
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface SignalMeasurementType {}
+    public @interface SignalMeasurementType {
+    }
 
     @SignalMeasurementType
-    private int mSignalMeasurement;
+    private final int mSignalMeasurementType;
 
     /**
      * A hysteresis time in milliseconds to prevent flapping.
      * A value of 0 disables hysteresis
      */
-    private int mHysteresisMs;
+    private final int mHysteresisMs;
 
     /**
      * An interval in dB defining the required magnitude change between reports.
      * hysteresisDb must be smaller than the smallest threshold delta.
      * An interval value of 0 disables hysteresis.
      */
-    private int mHysteresisDb;
+    private final int mHysteresisDb;
 
     /**
      * List of threshold values.
@@ -130,60 +138,399 @@
      * The threshold values for which to apply criteria.
      * A vector size of 0 disables the use of thresholds for reporting.
      */
-    private int[] mThresholds = null;
+    private final int[] mThresholds;
 
     /**
      * {@code true} means modem must trigger the report based on the criteria;
      * {@code false} means modem must not trigger the report based on the criteria.
      */
-    private boolean mIsEnabled = true;
+    private final boolean mIsEnabled;
+
+    /**
+     * The radio access network type associated with the signal thresholds.
+     */
+    @AccessNetworkConstants.RadioAccessNetworkType
+    private final int mRan;
 
     /**
      * Indicates the hysteresisMs is disabled.
+     *
+     * @hide
      */
     public static final int HYSTERESIS_MS_DISABLED = 0;
 
     /**
      * Indicates the hysteresisDb is disabled.
+     *
+     * @hide
      */
     public static final int HYSTERESIS_DB_DISABLED = 0;
 
+
+    /**
+     * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSI}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSSI_MIN_VALUE = -113;
+
+    /**
+     * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSI}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSSI_MAX_VALUE = -51;
+
+    /**
+     * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSCP}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSCP_MIN_VALUE = -120;
+
+    /**
+     * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSCP}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSCP_MAX_VALUE = -25;
+
+    /**
+     * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSRP}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSRP_MIN_VALUE = -140;
+
+    /**
+     * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSRP}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSRP_MAX_VALUE = -44;
+
+    /**
+     * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSRQ}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSRQ_MIN_VALUE = -34;
+
+    /**
+     * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSRQ}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSRQ_MAX_VALUE = 3;
+
+    /**
+     * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSNR}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSSNR_MIN_VALUE = -20;
+
+    /**
+     * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_RSSNR}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_RSSNR_MAX_VALUE = 30;
+
+    /**
+     * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSRSRP}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_SSRSRP_MIN_VALUE = -140;
+
+    /**
+     * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSRSRP}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_SSRSRP_MAX_VALUE = -44;
+
+    /**
+     * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSRSRQ}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_SSRSRQ_MIN_VALUE = -43;
+
+    /**
+     * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSRSRQ}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_SSRSRQ_MAX_VALUE = 20;
+
+    /**
+     * Minimum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSSINR}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_SSSINR_MIN_VALUE = -23;
+
+    /**
+     * Maximum valid value for {@link #SIGNAL_MEASUREMENT_TYPE_SSSINR}.
+     *
+     * @hide
+     */
+    public static final int SIGNAL_SSSINR_MAX_VALUE = 40;
+
+    /**
+     * The minimum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @hide
+     */
+    public static final int MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 1;
+
+    /**
+     * The maximum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @hide
+     */
+    public static final int MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 4;
+
     /**
      * Constructor
      *
-     * @param signalMeasurement Signal Measurement Type
-     * @param hysteresisMs hysteresisMs
-     * @param hysteresisDb hysteresisDb
-     * @param thresholds threshold value
-     * @param isEnabled isEnabled
+     * @param ran               Radio Access Network type
+     * @param signalMeasurementType Signal Measurement Type
+     * @param hysteresisMs      hysteresisMs
+     * @param hysteresisDb      hysteresisDb
+     * @param thresholds        threshold value
+     * @param isEnabled         isEnabled
      */
-    public SignalThresholdInfo(@SignalMeasurementType int signalMeasurement,
-            int hysteresisMs, int hysteresisDb, @NonNull int [] thresholds, boolean isEnabled) {
-        mSignalMeasurement = signalMeasurement;
+    private SignalThresholdInfo(@AccessNetworkConstants.RadioAccessNetworkType int ran,
+            @SignalMeasurementType int signalMeasurementType, int hysteresisMs, int hysteresisDb,
+            @NonNull int[] thresholds, boolean isEnabled) {
+        Objects.requireNonNull(thresholds, "thresholds must not be null");
+        validateRanWithMeasurementType(ran, signalMeasurementType);
+        validateThresholdRange(signalMeasurementType, thresholds);
+
+        mRan = ran;
+        mSignalMeasurementType = signalMeasurementType;
         mHysteresisMs = hysteresisMs < 0 ? HYSTERESIS_MS_DISABLED : hysteresisMs;
         mHysteresisDb = hysteresisDb < 0 ? HYSTERESIS_DB_DISABLED : hysteresisDb;
-        mThresholds = thresholds == null ? null : thresholds.clone();
+        mThresholds = thresholds;
         mIsEnabled = isEnabled;
     }
 
-    public @SignalMeasurementType int getSignalMeasurement() {
-        return mSignalMeasurement;
+    /**
+     * Builder class to create {@link SignalThresholdInfo} objects.
+     */
+    public static final class Builder {
+        private int mRan = AccessNetworkConstants.AccessNetworkType.UNKNOWN;
+        private int mSignalMeasurementType = SIGNAL_MEASUREMENT_TYPE_UNKNOWN;
+        private int mHysteresisMs = HYSTERESIS_MS_DISABLED;
+        private int mHysteresisDb = HYSTERESIS_DB_DISABLED;
+        private int[] mThresholds = null;
+        private boolean mIsEnabled = false;
+
+        /**
+         * Set the radio access network type for the builder instance.
+         *
+         * @param ran The radio access network type
+         * @return the builder to facilitate the chaining
+         */
+        public @NonNull Builder setRadioAccessNetworkType(
+                @AccessNetworkConstants.RadioAccessNetworkType int ran) {
+            mRan = ran;
+            return this;
+        }
+
+        /**
+         * Set the signal measurement type for the builder instance.
+         *
+         * @param signalMeasurementType The signal measurement type
+         * @return the builder to facilitate the chaining
+         */
+        public @NonNull Builder setSignalMeasurementType(
+                @SignalMeasurementType int signalMeasurementType) {
+            mSignalMeasurementType = signalMeasurementType;
+            return this;
+        }
+
+        /**
+         * Set the hysteresis time in milliseconds to prevent flapping. A value of 0 disables
+         * hysteresis.
+         *
+         * @param hysteresisMs the hysteresis time in milliseconds
+         * @return the builder to facilitate the chaining
+         * @hide
+         */
+        public @NonNull Builder setHysteresisMs(int hysteresisMs) {
+            mHysteresisMs = hysteresisMs;
+            return this;
+        }
+
+        /**
+         * Set the interval in dB defining the required magnitude change between reports. A value of
+         * zero disabled dB-based hysteresis restrictions.
+         *
+         * @param hysteresisDb the interval in dB
+         * @return the builder to facilitate the chaining
+         * @hide
+         */
+        public @NonNull Builder setHysteresisDb(int hysteresisDb) {
+            mHysteresisDb = hysteresisDb;
+            return this;
+        }
+
+        /**
+         * Set the signal strength thresholds of the corresponding signal measurement type.
+         *
+         * The range and unit must reference specific SignalMeasurementType. The length of the
+         * thresholds should between the numbers return from
+         * {@link #getMinimumNumberOfThresholdsAllowed()} and
+         * {@link #getMaximumNumberOfThresholdsAllowed()}. An IllegalArgumentException will throw
+         * otherwise.
+         *
+         * @param thresholds array of integer as the signal threshold values
+         * @return the builder to facilitate the chaining
+         *
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSSI
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSCP
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSRP
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSRQ
+         * @see #SIGNAL_MEASUREMENT_TYPE_RSSNR
+         * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP
+         * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ
+         * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR
+         * @see #getThresholds() for more details on signal strength thresholds
+         */
+        public @NonNull Builder setThresholds(@NonNull int[] thresholds) {
+            Objects.requireNonNull(thresholds, "thresholds must not be null");
+            if (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+                    || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED) {
+                throw new IllegalArgumentException(
+                        "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+                                + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED);
+            }
+            mThresholds = thresholds.clone();
+            Arrays.sort(mThresholds);
+            return this;
+        }
+
+        /**
+         * Set the signal strength thresholds for the corresponding signal measurement type without
+         * the length limitation.
+         *
+         * @param thresholds array of integer as the signal threshold values
+         * @return the builder to facilitate the chaining
+         *
+         * @hide
+         */
+        public @NonNull Builder setThresholdsUnlimited(@NonNull int[] thresholds) {
+            Objects.requireNonNull(thresholds, "thresholds must not be null");
+            mThresholds = thresholds.clone();
+            Arrays.sort(mThresholds);
+            return this;
+        }
+
+
+        /**
+         * Set if the modem should trigger the report based on the criteria.
+         *
+         * @param isEnabled true if the modem should trigger the report based on the criteria
+         * @return the builder to facilitate the chaining
+         * @hide
+         */
+        public @NonNull Builder setIsEnabled(boolean isEnabled) {
+            mIsEnabled = isEnabled;
+            return this;
+        }
+
+        /**
+         * Build {@link SignalThresholdInfo} object.
+         *
+         * @return the SignalThresholdInfo object build out
+         *
+         * @throws IllegalArgumentException if the signal measurement type is invalid, any value in
+         * the thresholds is out of range, or the RAN is not allowed to set with the signal
+         * measurement type
+         */
+        public @NonNull SignalThresholdInfo build() {
+            return new SignalThresholdInfo(mRan, mSignalMeasurementType, mHysteresisMs,
+                    mHysteresisDb, mThresholds, mIsEnabled);
+        }
     }
 
+    /**
+     * Get the radio access network type.
+     *
+     * @return radio access network type
+     */
+    public @AccessNetworkConstants.RadioAccessNetworkType int getRadioAccessNetworkType() {
+        return mRan;
+    }
+
+    /**
+     * Get the signal measurement type.
+     *
+     * @return the SignalMeasurementType value
+     */
+    public @SignalMeasurementType int getSignalMeasurementType() {
+        return mSignalMeasurementType;
+    }
+
+    /** @hide */
     public int getHysteresisMs() {
         return mHysteresisMs;
     }
 
+    /** @hide */
     public int getHysteresisDb() {
         return mHysteresisDb;
     }
 
+    /** @hide */
     public boolean isEnabled() {
         return mIsEnabled;
     }
 
-    public int[] getThresholds() {
-        return mThresholds == null ? null : mThresholds.clone();
+    /**
+     * Get the signal strength thresholds.
+     *
+     * Signal strength thresholds are a list of integer used for suggesting signal level and signal
+     * reporting criteria. The range and unit must reference specific SignalMeasurementType.
+     *
+     * Please refer to https://source.android.com/devices/tech/connect/signal-strength on how signal
+     * strength thresholds are used for signal strength reporting.
+     *
+     * @return array of integer of the signal thresholds
+     *
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSSI
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSCP
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSRP
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSRQ
+     * @see #SIGNAL_MEASUREMENT_TYPE_RSSNR
+     * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRP
+     * @see #SIGNAL_MEASUREMENT_TYPE_SSRSRQ
+     * @see #SIGNAL_MEASUREMENT_TYPE_SSSINR
+     */
+    public @NonNull int[] getThresholds() {
+        return mThresholds.clone();
+    }
+
+    /**
+     * Get the minimum number of thresholds allowed in each SignalThresholdInfo.
+     *
+     * @return the minimum number of thresholds allowed
+     */
+    public static int getMinimumNumberOfThresholdsAllowed() {
+        return MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
+    }
+
+    /**
+     * Get the maximum number of threshold allowed in each SignalThresholdInfo.
+     *
+     * @return the maximum number of thresholds allowed
+     */
+    public static int getMaximumNumberOfThresholdsAllowed() {
+        return MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
     }
 
     @Override
@@ -192,8 +539,9 @@
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mSignalMeasurement);
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mRan);
+        out.writeInt(mSignalMeasurementType);
         out.writeInt(mHysteresisMs);
         out.writeInt(mHysteresisDb);
         out.writeIntArray(mThresholds);
@@ -201,7 +549,8 @@
     }
 
     private SignalThresholdInfo(Parcel in) {
-        mSignalMeasurement = in.readInt();
+        mRan = in.readInt();
+        mSignalMeasurementType = in.readInt();
         mHysteresisMs = in.readInt();
         mHysteresisDb = in.readInt();
         mThresholds = in.createIntArray();
@@ -217,7 +566,8 @@
         }
 
         SignalThresholdInfo other = (SignalThresholdInfo) o;
-        return mSignalMeasurement == other.mSignalMeasurement
+        return mRan == other.mRan
+                && mSignalMeasurementType == other.mSignalMeasurementType
                 && mHysteresisMs == other.mHysteresisMs
                 && mHysteresisDb == other.mHysteresisDb
                 && Arrays.equals(mThresholds, other.mThresholds)
@@ -226,8 +576,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(
-                mSignalMeasurement, mHysteresisMs, mHysteresisDb, mThresholds, mIsEnabled);
+        return Objects.hash(mRan, mSignalMeasurementType, mHysteresisMs, mHysteresisDb, mThresholds,
+                mIsEnabled);
     }
 
     public static final @NonNull Parcelable.Creator<SignalThresholdInfo> CREATOR =
@@ -246,11 +596,83 @@
     @Override
     public String toString() {
         return new StringBuilder("SignalThresholdInfo{")
-            .append("mSignalMeasurement=").append(mSignalMeasurement)
-            .append("mHysteresisMs=").append(mSignalMeasurement)
-            .append("mHysteresisDb=").append(mHysteresisDb)
-            .append("mThresholds=").append(Arrays.toString(mThresholds))
-            .append("mIsEnabled=").append(mIsEnabled)
-            .append("}").toString();
+                .append("mRan=").append(mRan)
+                .append(" mSignalMeasurementType=").append(mSignalMeasurementType)
+                .append(" mHysteresisMs=").append(mHysteresisMs)
+                .append(" mHysteresisDb=").append(mHysteresisDb)
+                .append(" mThresholds=").append(Arrays.toString(mThresholds))
+                .append(" mIsEnabled=").append(mIsEnabled)
+                .append("}").toString();
+    }
+
+    /**
+     * Return true if signal measurement type is valid and the threshold value is in range.
+     */
+    private static boolean isValidThreshold(@SignalMeasurementType int type, int threshold) {
+        switch (type) {
+            case SIGNAL_MEASUREMENT_TYPE_RSSI:
+                return threshold >= SIGNAL_RSSI_MIN_VALUE && threshold <= SIGNAL_RSSI_MAX_VALUE;
+            case SIGNAL_MEASUREMENT_TYPE_RSCP:
+                return threshold >= SIGNAL_RSCP_MIN_VALUE && threshold <= SIGNAL_RSCP_MAX_VALUE;
+            case SIGNAL_MEASUREMENT_TYPE_RSRP:
+                return threshold >= SIGNAL_RSRP_MIN_VALUE && threshold <= SIGNAL_RSRP_MAX_VALUE;
+            case SIGNAL_MEASUREMENT_TYPE_RSRQ:
+                return threshold >= SIGNAL_RSRQ_MIN_VALUE && threshold <= SIGNAL_RSRQ_MAX_VALUE;
+            case SIGNAL_MEASUREMENT_TYPE_RSSNR:
+                return threshold >= SIGNAL_RSSNR_MIN_VALUE && threshold <= SIGNAL_RSSNR_MAX_VALUE;
+            case SIGNAL_MEASUREMENT_TYPE_SSRSRP:
+                return threshold >= SIGNAL_SSRSRP_MIN_VALUE && threshold <= SIGNAL_SSRSRP_MAX_VALUE;
+            case SIGNAL_MEASUREMENT_TYPE_SSRSRQ:
+                return threshold >= SIGNAL_SSRSRQ_MIN_VALUE && threshold <= SIGNAL_SSRSRQ_MAX_VALUE;
+            case SIGNAL_MEASUREMENT_TYPE_SSSINR:
+                return threshold >= SIGNAL_SSSINR_MIN_VALUE && threshold <= SIGNAL_SSSINR_MAX_VALUE;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Return true if the radio access type is allowed to set with the measurement type.
+     */
+    private static boolean isValidRanWithMeasurementType(
+            @AccessNetworkConstants.RadioAccessNetworkType int ran,
+            @SignalMeasurementType int type) {
+        switch (type) {
+            case SIGNAL_MEASUREMENT_TYPE_RSSI:
+                return ran == AccessNetworkConstants.AccessNetworkType.GERAN
+                        || ran == AccessNetworkConstants.AccessNetworkType.CDMA2000;
+            case SIGNAL_MEASUREMENT_TYPE_RSCP:
+                return ran == AccessNetworkConstants.AccessNetworkType.UTRAN;
+            case SIGNAL_MEASUREMENT_TYPE_RSRP:
+            case SIGNAL_MEASUREMENT_TYPE_RSRQ:
+            case SIGNAL_MEASUREMENT_TYPE_RSSNR:
+                return ran == AccessNetworkConstants.AccessNetworkType.EUTRAN;
+            case SIGNAL_MEASUREMENT_TYPE_SSRSRP:
+            case SIGNAL_MEASUREMENT_TYPE_SSRSRQ:
+            case SIGNAL_MEASUREMENT_TYPE_SSSINR:
+                return ran == AccessNetworkConstants.AccessNetworkType.NGRAN;
+            default:
+                return false;
+        }
+    }
+
+    private void validateRanWithMeasurementType(
+            @AccessNetworkConstants.RadioAccessNetworkType int ran,
+            @SignalMeasurementType int signalMeasurement) {
+        if (!isValidRanWithMeasurementType(ran, signalMeasurement)) {
+            throw new IllegalArgumentException(
+                    "invalid RAN: " + ran + " with signal measurement type: " + signalMeasurement);
+        }
+    }
+
+    private void validateThresholdRange(@SignalMeasurementType int signalMeasurement,
+            int[] thresholds) {
+        for (int threshold : thresholds) {
+            if (!isValidThreshold(signalMeasurement, threshold)) {
+                throw new IllegalArgumentException(
+                        "invalid signal measurement type: " + signalMeasurement
+                                + " with threshold: " + threshold);
+            }
+        }
     }
 }
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 c05e90b..646744d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -120,10 +120,12 @@
 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;
 import java.util.Objects;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -155,6 +157,7 @@
 public class TelephonyManager {
     private static final String TAG = "TelephonyManager";
 
+    private TelephonyRegistryManager mTelephonyRegistryMgr;
     /**
      * To expand the error codes for {@link TelephonyManager#updateAvailableNetworks} and
      * {@link TelephonyManager#setPreferredOpportunisticDataSubscription}.
@@ -5569,8 +5572,7 @@
     //
 
     /**
-     * Registers a listener object to receive notification of changes
-     * in specified telephony states.
+     * Registers a listener object to receive notification of changes in specified telephony states.
      * <p>
      * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
      * state of interest in the events argument.
@@ -5580,13 +5582,15 @@
      * values.
      * <p>
      * To un-register a listener, pass the listener object and set the events argument to
-     * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
+     * {@link PhoneStateListener#LISTEN_NONE} (0).
      *
      * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
      * applies to the given subId. Otherwise, applies to
-     * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
+     * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}. To listen events for multiple subIds,
      * pass a separate listener object to each TelephonyManager object created with
-     * {@link #createForSubscriptionId}.
+     * {@link #createForSubscriptionId}. Only {@link PhoneStateListener#LISTEN_CALL_STATE} event can
+     * be used to receive changes for all subIds through
+     * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}.
      *
      * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
      * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
@@ -5596,23 +5600,28 @@
      * instability. If a process has registered too many listeners without unregistering them, it
      * may encounter an {@link IllegalStateException} when trying to register more listeners.
      *
-     * @param listener The {@link PhoneStateListener} object to register
-     *                 (or unregister)
-     * @param events The telephony state(s) of interest to the listener,
-     *               as a bitwise-OR combination of {@link PhoneStateListener}
-     *               LISTEN_ flags.
+     * @param listener The {@link PhoneStateListener} object to register (or unregister)
+     * @param events The telephony state(s) of interest to the listener, as a bitwise-OR combination
+     *               of {@link PhoneStateListener} LISTEN_ flags.
+     * @deprecated Use {@link #registerPhoneStateListener(Executor, PhoneStateListener)}.
      */
+    @Deprecated
     public void listen(PhoneStateListener listener, int events) {
-        if (mContext == null) return;
-        boolean notifyNow = (getITelephony() != null);
-        TelephonyRegistryManager telephonyRegistry =
-                (TelephonyRegistryManager)
-                        mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
-        if (telephonyRegistry != null) {
-            telephonyRegistry.listenForSubscriber(mSubId, getOpPackageName(), getAttributionTag(),
-                    listener, events, notifyNow);
+        if (!listener.isExecutorSet()) {
+            throw new IllegalStateException("PhoneStateListener should be created on a thread "
+                    + "with Looper.myLooper() != null");
+        }
+        boolean notifyNow = getITelephony() != null;
+        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+        if (mTelephonyRegistryMgr != null) {
+            if (events != PhoneStateListener.LISTEN_NONE) {
+                mTelephonyRegistryMgr.registerPhoneStateListenerWithEvents(mSubId,
+                        getOpPackageName(), getAttributionTag(), listener, events, notifyNow);
+            } else {
+                unregisterPhoneStateListener(listener);
+            }
         } else {
-            Rlog.w(TAG, "telephony registry not ready.");
+            throw new IllegalStateException("telephony service is null.");
         }
     }
 
@@ -7448,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) {
         }
     }
 
@@ -8689,11 +8703,18 @@
      */
     public static final int CALL_COMPOSER_STATUS_ON = 1;
 
+    /**
+     * Call composer status indicating that sending/receiving pictures is disabled.
+     * All other attachments are still enabled in this state.
+     */
+    public static final int CALL_COMPOSER_STATUS_ON_NO_PICTURES = 2;
+
     /** @hide */
     @IntDef(prefix = {"CALL_COMPOSER_STATUS_"},
             value = {
                 CALL_COMPOSER_STATUS_ON,
                 CALL_COMPOSER_STATUS_OFF,
+                CALL_COMPOSER_STATUS_ON_NO_PICTURES,
             })
     public @interface CallComposerStatus {}
 
@@ -8701,8 +8722,9 @@
      * Set the user-set status for enriched calling with call composer.
      *
      * @param status user-set status for enriched calling with call composer;
-     *               it must be a value of either {@link #CALL_COMPOSER_STATUS_ON}
-     *               or {@link #CALL_COMPOSER_STATUS_OFF}.
+     *               it must be any of {@link #CALL_COMPOSER_STATUS_ON}
+     *               {@link #CALL_COMPOSER_STATUS_OFF},
+     *               or {@link #CALL_COMPOSER_STATUS_ON_NO_PICTURES}
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -8712,7 +8734,8 @@
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void setCallComposerStatus(@CallComposerStatus int status) {
-        if (status != CALL_COMPOSER_STATUS_ON && status != CALL_COMPOSER_STATUS_OFF) {
+        if (status > CALL_COMPOSER_STATUS_ON_NO_PICTURES
+                || status < CALL_COMPOSER_STATUS_OFF) {
             throw new IllegalArgumentException("requested status is invalid");
         }
         try {
@@ -8734,8 +8757,9 @@
      *
      * @throws SecurityException if the caller does not have the permission.
      *
-     * @return the user-set status for enriched calling with call composer either
-     * {@link #CALL_COMPOSER_STATUS_ON} or {@link #CALL_COMPOSER_STATUS_OFF}.
+     * @return the user-set status for enriched calling with call composer, any of
+     * {@link #CALL_COMPOSER_STATUS_ON}, {@link #CALL_COMPOSER_STATUS_OFF}, or
+     * {@link #CALL_COMPOSER_STATUS_ON_NO_PICTURES}.
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @CallComposerStatus int getCallComposerStatus() {
@@ -9438,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;
+        }
     }
 
     /**
@@ -9685,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);
         }
@@ -14313,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.
      *
@@ -14583,4 +14648,165 @@
             e.execute(() -> callback.onAuthenticationFailure(GBA_FAILURE_REASON_FEATURE_NOT_READY));
         }
     }
+
+    /**
+     * Registers a listener object to receive notification of changes in specified telephony states.
+     * <p>
+     * To register a listener, pass a {@link PhoneStateListener} which implements
+     * interfaces of events. For example,
+     * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements
+     * {@link PhoneStateListener.ServiceStateChangedListener}.
+     *
+     * At registration, and when a specified telephony state changes, the telephony manager invokes
+     * the appropriate callback method on the listener object and passes the current (updated)
+     * values.
+     * <p>
+     *
+     * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+     * applies to the given subId. Otherwise, applies to
+     * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}. To listen events for multiple subIds,
+     * pass a separate listener object to each TelephonyManager object created with
+     * {@link #createForSubscriptionId}. Only {@link PhoneStateListener.CallStateChangedListener}
+     * can be used to receive changes for all subIds through
+     * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}.
+     *
+     * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
+     * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
+     * {@link SecurityException} will be thrown otherwise.
+     *
+     * This API should be used sparingly -- large numbers of listeners will cause system
+     * instability. If a process has registered too many listeners without unregistering them, it
+     * may encounter an {@link IllegalStateException} when trying to register more listeners.
+     *
+     * @param executor The executor of where the callback will execute.
+     * @param listener The {@link PhoneStateListener} object to register.
+     */
+    public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull PhoneStateListener listener) {
+        if (executor == null || listener == null) {
+            throw new IllegalArgumentException("PhoneStateListener and executor must be non-null");
+        }
+        mTelephonyRegistryMgr = (TelephonyRegistryManager)
+                mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
+        if (mTelephonyRegistryMgr != null) {
+            mTelephonyRegistryMgr.registerPhoneStateListener(executor, mSubId,
+                    getOpPackageName(), getAttributionTag(), listener, getITelephony() != null);
+        } else {
+            throw new IllegalStateException("telephony service is null.");
+        }
+    }
+
+    /**
+     * Unregister an existing {@link PhoneStateListener}.
+     *
+     * @param listener The {@link PhoneStateListener} object to unregister.
+     */
+    public void unregisterPhoneStateListener(@NonNull PhoneStateListener listener) {
+
+        if (mContext == null) {
+            throw new IllegalStateException("telephony service is null.");
+        }
+
+        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+        if (mTelephonyRegistryMgr != null) {
+            mTelephonyRegistryMgr.unregisterPhoneStateListener(mSubId, getOpPackageName(),
+                    getAttributionTag(), listener, getITelephony() != null);
+        } else {
+            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/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
index 66281ed..fd206c1 100644
--- a/telephony/java/android/telephony/ims/DelegateRegistrationState.java
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
@@ -320,4 +320,11 @@
     public int hashCode() {
         return Objects.hash(mRegisteredTags, mDeregisteringTags, mDeregisteredTags);
     }
+
+    @Override
+    public String toString() {
+        return "DelegateRegistrationState{ registered={" + mRegisteredTags
+                + "}, deregistering={" + mDeregisteringTags + "}, deregistered={"
+                + mDeregisteredTags + "}}";
+    }
 }
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 1539224..9cfa640 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -16,12 +16,16 @@
 
 package android.telephony.ims;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.telephony.SipMessageParsingUtils;
+
 import java.util.Arrays;
 import java.util.Objects;
 
@@ -37,9 +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[] SIP_REQUEST_METHODS = new String[] {"INVITE", "ACK", "OPTIONS",
-            "BYE", "CANCEL", "REGISTER"};
+    private static final String CRLF = "\r\n";
 
     private final String mStartLine;
     private final String mHeaderSection;
@@ -72,6 +74,7 @@
         mContent = new byte[source.readInt()];
         source.readByteArray(mContent);
     }
+
     /**
      * @return The start line of the SIP message, which contains either the request-line or
      * status-line.
@@ -128,34 +131,25 @@
         } else {
             b.append(sanitizeStartLineRequest(mStartLine));
         }
-        b.append("], [");
-        b.append("Header: [");
+        b.append("], Header: [");
         if (IS_DEBUGGING) {
             b.append(mHeaderSection);
         } else {
             // only identify transaction id/call ID when it is available.
             b.append("***");
         }
-        b.append("], ");
-        b.append("Content: [NOT SHOWN]");
+        b.append("], Content: ");
+        b.append(getContent().length == 0 ? "[NONE]" : "[NOT SHOWN]");
         return b.toString();
     }
 
     /**
-     * Start lines containing requests are formatted: METHOD SP Request-URI SP SIP-Version CRLF.
      * Detect if this is a REQUEST and redact Request-URI portion here, as it contains PII.
      */
     private String sanitizeStartLineRequest(String startLine) {
+        if (!SipMessageParsingUtils.isSipRequest(startLine)) return startLine;
         String[] splitLine = startLine.split(" ");
-        if (splitLine == null || splitLine.length == 0)  {
-            return "(INVALID STARTLINE)";
-        }
-        for (String method : SIP_REQUEST_METHODS) {
-            if (splitLine[0].contains(method)) {
-                return splitLine[0] + " <Request-URI> " + splitLine[2];
-            }
-        }
-        return startLine;
+        return splitLine[0] + " <Request-URI> " + splitLine[2];
     }
 
     @Override
@@ -174,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/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 522ad81..9d91901 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -28,6 +28,10 @@
 import android.telephony.ims.SipDelegateManager;
 import android.telephony.ims.SipMessage;
 import android.telephony.ims.stub.SipDelegate;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.SipMessageParsingUtils;
 
 import java.util.ArrayList;
 import java.util.Set;
@@ -40,6 +44,7 @@
  * @hide
  */
 public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMessageCallback {
+    private static final String LOG_TAG = "SipDelegateAW";
 
     private final ISipDelegate.Stub mDelegateBinder = new ISipDelegate.Stub() {
         @Override
@@ -183,11 +188,15 @@
     }
 
     private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
-        //TODO: parse transaction ID or throw IllegalArgumentException if the SipMessage
-        // transaction ID can not be parsed.
+        String transactionId = SipMessageParsingUtils.getTransactionId(m.getHeaderSection());
+        if (TextUtils.isEmpty(transactionId)) {
+            Log.w(LOG_TAG, "failure to parse SipMessage.");
+            throw new IllegalArgumentException("Malformed SipMessage, can not determine "
+                    + "transaction ID.");
+        }
         SipDelegate d = mDelegate;
         if (d != null) {
-            mExecutor.execute(() -> d.notifyMessageReceiveError(null, reason));
+            mExecutor.execute(() -> d.notifyMessageReceiveError(transactionId, reason));
         }
     }
 }
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index a35039b..c877aca 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -28,9 +28,12 @@
 import android.telephony.ims.stub.DelegateConnectionMessageCallback;
 import android.telephony.ims.stub.DelegateConnectionStateCallback;
 import android.telephony.ims.stub.SipDelegate;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.telephony.SipMessageParsingUtils;
+
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.concurrent.Executor;
@@ -265,9 +268,13 @@
     }
 
     private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
-        //TODO: parse transaction ID or throw IllegalArgumentException if the SipMessage
-        // transaction ID can not be parsed.
+        String transactionId = SipMessageParsingUtils.getTransactionId(m.getHeaderSection());
+        if (TextUtils.isEmpty(transactionId)) {
+            Log.w(LOG_TAG, "sendMessage detected a malformed SipMessage and can not get a "
+                    + "transaction ID.");
+            throw new IllegalArgumentException("Could not send SipMessage due to malformed header");
+        }
         mExecutor.execute(() ->
-                mMessageCallback.onMessageSendFailure(null, reason));
+                mMessageCallback.onMessageSendFailure(transactionId, reason));
     }
 }
diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
index d2cb976..d9734a7 100644
--- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
+++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
@@ -18,15 +18,12 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.net.Uri;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.RcsContactUceCapability;
 import android.telephony.ims.RcsUceAdapter;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.RcsFeature;
 
-import java.util.List;
-
 /**
  * The interface of the capabilities event listener for ImsService to notify the framework of the
  * UCE request and status updated.
@@ -84,25 +81,4 @@
      * Telephony stack has crashed.
      */
     void onUnpublish() throws ImsException;
-
-    /**
-     * Inform the framework of a query for this device's UCE capabilities.
-     * <p>
-     * The framework will respond via the
-     * {@link OptionsRequestCallback#onRespondToCapabilityRequest} or
-     * {@link OptionsRequestCallback#onRespondToCapabilityRequestWithError}
-     * @param contactUri The URI associated with the remote contact that is
-     * requesting capabilities.
-     * @param remoteCapabilities The remote contact's capability information.
-     * @param callback The callback of this request which is sent from the remote user.
-     * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not
-     * currently connected to the framework. This can happen if the {@link RcsFeature} is not
-     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received
-     * the {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare
-     * cases when the Telephony stack has crashed.
-     * @hide
-     */
-    void onRemoteCapabilityRequest(@NonNull Uri contactUri,
-            @NonNull List<String> remoteCapabilities,
-            @NonNull OptionsRequestCallback callback) throws ImsException;
 }
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/StagedInstallTest/OWNERS b/tests/StagedInstallTest/OWNERS
index d825dfd..aac68e9 100644
--- a/tests/StagedInstallTest/OWNERS
+++ b/tests/StagedInstallTest/OWNERS
@@ -1 +1,5 @@
 include /services/core/java/com/android/server/pm/OWNERS
+
+dariofreni@google.com
+ioffe@google.com
+olilan@google.com
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index 373aac6..c271f49 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -24,6 +24,7 @@
         "androidx.test.rules",
         "junit",
         "mockito-target-minus-junit4",
+        "modules-utils-build",
         "net-tests-utils",
         "net-utils-framework-common",
         "platform-test-annotations",
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index 8710d23..b2bcfeb 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -18,12 +18,15 @@
 
 import android.os.Build
 import androidx.test.filters.SmallTest
+import com.android.modules.utils.build.SdkLevel
 import com.android.testutils.assertParcelSane
 import com.android.testutils.assertParcelingIsLossless
+import com.android.testutils.DevSdkIgnoreRule
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
 import com.android.testutils.DevSdkIgnoreRunner
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import kotlin.test.assertEquals
@@ -33,6 +36,9 @@
 @RunWith(DevSdkIgnoreRunner::class)
 @IgnoreUpTo(Build.VERSION_CODES.Q)
 class CaptivePortalDataTest {
+    @Rule @JvmField
+    val ignoreRule = DevSdkIgnoreRule()
+
     private val data = CaptivePortalData.Builder()
             .setRefreshTime(123L)
             .setUserPortalUrl(Uri.parse("https://portal.example.com/test"))
@@ -41,14 +47,19 @@
             .setBytesRemaining(456L)
             .setExpiryTime(789L)
             .setCaptive(true)
-            .setVenueFriendlyName("venue friendly name")
+            .apply {
+                if (SdkLevel.isAtLeastS()) {
+                    setVenueFriendlyName("venue friendly name")
+                }
+            }
             .build()
 
     private fun makeBuilder() = CaptivePortalData.Builder(data)
 
     @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())
@@ -67,8 +78,11 @@
         assertNotEqualsAfterChange { it.setBytesRemaining(789L) }
         assertNotEqualsAfterChange { it.setExpiryTime(12L) }
         assertNotEqualsAfterChange { it.setCaptive(false) }
-        assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
-        assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
+
+        if (SdkLevel.isAtLeastS()) {
+            assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
+            assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
+        }
     }
 
     @Test
@@ -111,7 +125,7 @@
         assertFalse(makeBuilder().setCaptive(false).build().isCaptive)
     }
 
-    @Test
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
     fun testVenueFriendlyName() {
         assertEquals("venue friendly name", data.venueFriendlyName)
     }
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 6b7ea66..5d0e016 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -42,9 +42,11 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
 import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+import static android.os.Process.INVALID_UID;
 
 import static com.android.testutils.ParcelUtils.assertParcelSane;
 import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
+import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -53,18 +55,19 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
+import android.net.wifi.WifiInfo;
 import android.net.wifi.aware.DiscoverySession;
 import android.net.wifi.aware.PeerHandle;
 import android.net.wifi.aware.WifiAwareNetworkSpecifier;
 import android.os.Build;
-import android.os.Process;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 
-import androidx.core.os.BuildCompat;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.modules.utils.build.SdkLevel;
 import com.android.testutils.DevSdkIgnoreRule;
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 
@@ -89,10 +92,11 @@
     private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class);
 
     private boolean isAtLeastR() {
-        // BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R.
-        // Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after
-        // releasing Android R.
-        return BuildCompat.isAtLeastR() || Build.VERSION.SDK_INT > Build.VERSION_CODES.Q;
+        return SdkLevel.isAtLeastR();
+    }
+
+    private boolean isAtLeastS() {
+        return SdkLevel.isAtLeastS();
     }
 
     @Test
@@ -324,8 +328,59 @@
         testParcelSane(netCap);
     }
 
+    private NetworkCapabilities createNetworkCapabilitiesWithWifiInfo() {
+        // uses a real WifiInfo to test parceling of sensitive data.
+        final WifiInfo wifiInfo = new WifiInfo.Builder()
+                .setSsid("sssid1234".getBytes())
+                .setBssid("00:11:22:33:44:55")
+                .build();
+        return new NetworkCapabilities()
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .addCapability(NET_CAPABILITY_EIMS)
+                .addCapability(NET_CAPABILITY_NOT_METERED)
+                .setSSID(TEST_SSID)
+                .setTransportInfo(wifiInfo)
+                .setRequestorPackageName("com.android.test")
+                .setRequestorUid(9304);
+    }
+
+    @Test
+    public void testParcelNetworkCapabilitiesWithLocationSensitiveFields() {
+        assumeTrue(isAtLeastS());
+
+        final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
+        final NetworkCapabilities netCapWithLocationSensitiveFields =
+                new NetworkCapabilities(netCap, true);
+
+        assertParcelingIsLossless(netCapWithLocationSensitiveFields);
+        testParcelSane(netCapWithLocationSensitiveFields);
+
+        assertEquals(netCapWithLocationSensitiveFields,
+                parcelingRoundTrip(netCapWithLocationSensitiveFields));
+    }
+
+    @Test
+    public void testParcelNetworkCapabilitiesWithoutLocationSensitiveFields() {
+        assumeTrue(isAtLeastS());
+
+        final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
+        final NetworkCapabilities netCapWithoutLocationSensitiveFields =
+                new NetworkCapabilities(netCap, false);
+
+        final NetworkCapabilities sanitizedNetCap =
+                new NetworkCapabilities(netCapWithoutLocationSensitiveFields);
+        final WifiInfo sanitizedWifiInfo = new WifiInfo.Builder()
+                .setSsid(new byte[0])
+                .setBssid(WifiInfo.DEFAULT_MAC_ADDRESS)
+                .build();
+        sanitizedNetCap.setTransportInfo(sanitizedWifiInfo);
+        assertEquals(sanitizedNetCap, parcelingRoundTrip(netCapWithoutLocationSensitiveFields));
+    }
+
     private void testParcelSane(NetworkCapabilities cap) {
-        if (isAtLeastR()) {
+        if (isAtLeastS()) {
+            assertParcelSane(cap, 16);
+        } else if (isAtLeastR()) {
             assertParcelSane(cap, 15);
         } else {
             assertParcelSane(cap, 11);
@@ -639,26 +694,23 @@
         // Sequence 1: Transport + Transport + TransportInfo
         NetworkCapabilities nc1 = new NetworkCapabilities();
         nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
-                .setTransportInfo(new TransportInfo() {});
+                .setTransportInfo(new TestTransportInfo());
 
         // Sequence 2: Transport + NetworkSpecifier + Transport
         NetworkCapabilities nc2 = new NetworkCapabilities();
-        nc2.addTransportType(TRANSPORT_CELLULAR).setTransportInfo(new TransportInfo() {})
+        nc2.addTransportType(TRANSPORT_CELLULAR).setTransportInfo(new TestTransportInfo())
                 .addTransportType(TRANSPORT_WIFI);
     }
 
     @Test
     public void testCombineTransportInfo() {
         NetworkCapabilities nc1 = new NetworkCapabilities();
-        nc1.setTransportInfo(new TransportInfo() {
-            // empty
-        });
+        nc1.setTransportInfo(new TestTransportInfo());
+
         NetworkCapabilities nc2 = new NetworkCapabilities();
         // new TransportInfo so that object is not #equals to nc1's TransportInfo (that's where
         // combine fails)
-        nc2.setTransportInfo(new TransportInfo() {
-            // empty
-        });
+        nc2.setTransportInfo(new TestTransportInfo());
 
         try {
             nc1.combineCapabilities(nc2);
@@ -761,7 +813,7 @@
         // Test default owner uid.
         // If the owner uid is not set, the default value should be Process.INVALID_UID.
         final NetworkCapabilities nc1 = new NetworkCapabilities.Builder().build();
-        assertEquals(Process.INVALID_UID, nc1.getOwnerUid());
+        assertEquals(INVALID_UID, nc1.getOwnerUid());
         // Test setAdministratorUids and getAdministratorUids.
         final int[] administratorUids = {1001, 10001};
         final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
@@ -906,6 +958,16 @@
     private class TestTransportInfo implements TransportInfo {
         TestTransportInfo() {
         }
+
+        @Override
+        public TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
+            return this;
+        }
+
+        @Override
+        public boolean hasLocationSensitiveFields() {
+            return false;
+        }
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 8e18751..16c4865 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -46,8 +46,6 @@
 import com.android.server.LocalServices
 import com.android.server.NetworkAgentWrapper
 import com.android.server.TestNetIdManager
-import com.android.server.connectivity.DefaultNetworkMetrics
-import com.android.server.connectivity.IpConnectivityMetrics
 import com.android.server.connectivity.MockableSystemProperties
 import com.android.server.connectivity.ProxyTracker
 import com.android.server.net.NetworkPolicyManagerInternal
@@ -92,10 +90,6 @@
     private lateinit var netd: INetd
     @Mock
     private lateinit var dnsResolver: IDnsResolver
-    @Mock
-    private lateinit var metricsLogger: IpConnectivityMetrics.Logger
-    @Mock
-    private lateinit var defaultMetrics: DefaultNetworkMetrics
     @Spy
     private var context = TestableContext(realContext)
 
@@ -149,7 +143,6 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        doReturn(defaultMetrics).`when`(metricsLogger).defaultNetworkMetrics()
         doNothing().`when`(context).sendStickyBroadcastAsUser(any(), any(), any())
 
         networkStackClient = TestNetworkStackClient(realContext)
@@ -173,7 +166,6 @@
     private fun makeDependencies(): ConnectivityService.Dependencies {
         val deps = spy(ConnectivityService.Dependencies())
         doReturn(networkStackClient).`when`(deps).networkStack
-        doReturn(metricsLogger).`when`(deps).metricsLogger
         doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
         doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
         doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
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/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index d74a621..f2dd27e 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import static android.net.ConnectivityManager.TYPE_NONE;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
@@ -31,16 +32,21 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkRequest.Type.REQUEST;
+import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -49,9 +55,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
-import android.net.NetworkCapabilities;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Handler;
@@ -213,9 +217,8 @@
         ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
 
         // register callback
-        when(mService.requestNetwork(
-                any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class)))
-                .thenReturn(request);
+        when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
+                any(), nullable(String.class))).thenReturn(request);
         manager.requestNetwork(request, callback, handler);
 
         // callback triggers
@@ -242,9 +245,8 @@
         ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
 
         // register callback
-        when(mService.requestNetwork(
-                any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class)))
-                .thenReturn(req1);
+        when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
+                any(), nullable(String.class))).thenReturn(req1);
         manager.requestNetwork(req1, callback, handler);
 
         // callback triggers
@@ -261,9 +263,8 @@
         verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
 
         // callback can be registered again
-        when(mService.requestNetwork(
-                any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class)))
-                .thenReturn(req2);
+        when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
+                any(), nullable(String.class))).thenReturn(req2);
         manager.requestNetwork(req2, callback, handler);
 
         // callback triggers
@@ -286,7 +287,7 @@
         info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
 
         when(mCtx.getApplicationInfo()).thenReturn(info);
-        when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any(),
+        when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), any(),
                 nullable(String.class))).thenReturn(request);
 
         Handler handler = new Handler(Looper.getMainLooper());
@@ -340,6 +341,35 @@
         }
     }
 
+    @Test
+    public void testRequestType() throws Exception {
+        final String testPkgName = "MyPackage";
+        final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
+        when(mCtx.getOpPackageName()).thenReturn(testPkgName);
+        final NetworkRequest request = makeRequest(1);
+        final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
+
+        manager.requestNetwork(request, callback);
+        verify(mService).requestNetwork(eq(request.networkCapabilities),
+                eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+                eq(testPkgName), eq(null));
+        reset(mService);
+
+        // Verify that register network callback does not calls requestNetwork at all.
+        manager.registerNetworkCallback(request, callback);
+        verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
+                anyInt(), any(), any());
+        verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
+                eq(testPkgName));
+        reset(mService);
+
+        manager.registerDefaultNetworkCallback(callback);
+        verify(mService).requestNetwork(eq(null),
+                eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+                eq(testPkgName), eq(null));
+        reset(mService);
+    }
+
     static Message makeMessage(NetworkRequest req, int messageType) {
         Bundle bundle = new Bundle();
         bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
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 bf5a265..f893e9e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -21,6 +21,7 @@
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.Intent.ACTION_USER_UNLOCKED;
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -166,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;
@@ -189,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;
@@ -201,6 +206,7 @@
 import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
 import android.net.util.MultinetworkPolicyTracker;
+import android.net.wifi.WifiInfo;
 import android.os.BadParcelableException;
 import android.os.Binder;
 import android.os.Build;
@@ -216,17 +222,21 @@
 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;
 import android.provider.Settings;
+import android.security.Credentials;
 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;
@@ -236,19 +246,19 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
+import com.android.internal.net.VpnProfile;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.WakeupMessage;
 import com.android.internal.util.test.BroadcastInterceptingContext;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
 import com.android.server.connectivity.ConnectivityConstants;
-import com.android.server.connectivity.DefaultNetworkMetrics;
-import com.android.server.connectivity.IpConnectivityMetrics;
 import com.android.server.connectivity.MockableSystemProperties;
 import com.android.server.connectivity.Nat464Xlat;
 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;
@@ -280,6 +290,7 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -289,13 +300,16 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
@@ -362,9 +376,9 @@
     private WrappedMultinetworkPolicyTracker mPolicyTracker;
     private HandlerThread mAlarmManagerThread;
     private TestNetIdManager mNetIdManager;
+    private QosCallbackMockHelper mQosCallbackMockHelper;
+    private QosCallbackTracker mQosCallbackTracker;
 
-    @Mock IpConnectivityMetrics.Logger mMetricsService;
-    @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
     @Mock DeviceIdleInternal mDeviceIdleInternal;
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
@@ -384,6 +398,7 @@
     @Mock MockableSystemProperties mSystemProperties;
     @Mock EthernetManager mEthernetManager;
     @Mock NetworkPolicyManager mNetworkPolicyManager;
+    @Mock KeyStore mKeyStore;
 
     private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
             ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -410,9 +425,6 @@
 
     private class MockContext extends BroadcastInterceptingContext {
         private final MockContentResolver mContentResolver;
-        // Contains all registered receivers since this object was created. Useful to clear
-        // them when needed, as BroadcastInterceptingContext does not provide this facility.
-        private final List<BroadcastReceiver> mRegisteredReceivers = new ArrayList<>();
 
         @Spy private Resources mResources;
         private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
@@ -549,19 +561,6 @@
         public void setPermission(String permission, Integer granted) {
             mMockedPermissions.put(permission, granted);
         }
-
-        @Override
-        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
-            mRegisteredReceivers.add(receiver);
-            return super.registerReceiver(receiver, filter);
-        }
-
-        public void clearRegisteredReceivers() {
-            // super.unregisterReceiver is a no-op for receivers that are not registered (because
-            // they haven't been registered or because they have already been unregistered).
-            // For the same reason, don't bother clearing mRegisteredReceivers.
-            for (final BroadcastReceiver rcv : mRegisteredReceivers) unregisterReceiver(rcv);
-        }
     }
 
     private void waitForIdle() {
@@ -590,10 +589,10 @@
         }
 
         // Bring up a network that we can use to send messages to ConnectivityService.
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
-        waitFor(cv);
+        b.expectBroadcast();
         Network n = mWiFiNetworkAgent.getNetwork();
         assertNotNull(n);
 
@@ -610,10 +609,10 @@
     @Ignore
     public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
         // Bring up a network that we can use to send messages to ConnectivityService.
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
-        waitFor(cv);
+        b.expectBroadcast();
         Network n = mWiFiNetworkAgent.getNetwork();
         assertNotNull(n);
 
@@ -1078,6 +1077,15 @@
         private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
         private VpnInfo mVpnInfo;
 
+        // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
+        // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
+        // test expects two starts in a row, or even if the production code calls start twice in a
+        // row. find a better solution. Simply putting a method to create a LegacyVpnRunner into
+        // Vpn.Dependencies doesn't work because LegacyVpnRunner is not a static class and has
+        // extensive access into the internals of Vpn.
+        private ConditionVariable mStartLegacyVpnCv = new ConditionVariable();
+        private ConditionVariable mStopVpnRunnerCv = new ConditionVariable();
+
         public MockVpn(int userId) {
             super(startHandlerThreadAndReturnLooper(), mServiceContext,
                     new Dependencies() {
@@ -1091,7 +1099,7 @@
                             return mDeviceIdleInternal;
                         }
                     },
-                    mNetworkManagementService, mMockNetd, userId, mock(KeyStore.class));
+                    mNetworkManagementService, mMockNetd, userId, mKeyStore);
         }
 
         public void setUids(Set<UidRange> uids) {
@@ -1203,10 +1211,44 @@
             }
             mAgentRegistered = false;
             setUids(null);
+            // Remove NET_CAPABILITY_INTERNET or MockNetworkAgent will refuse to connect later on.
+            mNetworkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
             mInterface = null;
         }
 
         @Override
+        public void startLegacyVpnRunner() {
+            mStartLegacyVpnCv.open();
+        }
+
+        public void expectStartLegacyVpnRunner() {
+            assertTrue("startLegacyVpnRunner not called after " + TIMEOUT_MS + " ms",
+                    mStartLegacyVpnCv.block(TIMEOUT_MS));
+
+            // startLegacyVpn calls stopVpnRunnerPrivileged, which will open mStopVpnRunnerCv, just
+            // before calling startLegacyVpnRunner. Restore mStopVpnRunnerCv, so the test can expect
+            // that the VpnRunner is stopped and immediately restarted by calling
+            // expectStartLegacyVpnRunner() and expectStopVpnRunnerPrivileged() back-to-back.
+            mStopVpnRunnerCv = new ConditionVariable();
+        }
+
+        @Override
+        public void stopVpnRunnerPrivileged() {
+            if (mVpnRunner != null) {
+                super.stopVpnRunnerPrivileged();
+                disconnect();
+                mStartLegacyVpnCv = new ConditionVariable();
+            }
+            mVpnRunner = null;
+            mStopVpnRunnerCv.open();
+        }
+
+        public void expectStopVpnRunnerPrivileged() {
+            assertTrue("stopVpnRunnerPrivileged not called after " + TIMEOUT_MS + " ms",
+                    mStopVpnRunnerCv.block(TIMEOUT_MS));
+        }
+
+        @Override
         public synchronized VpnInfo getVpnInfo() {
             if (mVpnInfo != null) return mVpnInfo;
 
@@ -1287,10 +1329,19 @@
         }
     }
 
-    private static final int VPN_USER = 0;
-    private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100);
-    private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101);
-    private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043);
+    private static final int PRIMARY_USER = 0;
+    private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
+    private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
+    private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
+    private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
+            UserInfo.FLAG_PRIMARY);
+
+    private static final int RESTRICTED_USER = 1;
+    private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
+            UserInfo.FLAG_RESTRICTED);
+    static {
+        RESTRICTED_USER_INFO.restrictedProfileParentId = PRIMARY_USER;
+    }
 
     @Before
     public void setUp() throws Exception {
@@ -1299,12 +1350,14 @@
         mContext = InstrumentationRegistry.getContext();
 
         MockitoAnnotations.initMocks(this);
-        when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
 
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(VPN_USER, "", 0),
-                }));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+        when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
+        // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
+        // it was started from, i.e., PRIMARY_USER.
+        when(mUserManager.canHaveRestrictedProfile()).thenReturn(true);
+        when(mUserManager.getUserInfo(RESTRICTED_USER)).thenReturn(RESTRICTED_USER_INFO);
+
         final ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
@@ -1352,6 +1405,7 @@
         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);
@@ -1374,9 +1428,9 @@
         doReturn(mNetworkStack).when(deps).getNetworkStack();
         doReturn(mSystemProperties).when(deps).getSystemProperties();
         doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
-        doReturn(mMetricsService).when(deps).getMetricsLogger();
         doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
         doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
+        doReturn(mKeyStore).when(deps).getKeyStore();
         doAnswer(inv -> {
             mPolicyTracker = new WrappedMultinetworkPolicyTracker(
                     inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -1427,6 +1481,11 @@
             mEthernetNetworkAgent.disconnect();
             mEthernetNetworkAgent = null;
         }
+
+        if (mQosCallbackMockHelper != null) {
+            mQosCallbackMockHelper.tearDown();
+            mQosCallbackMockHelper = null;
+        }
         mMockVpn.disconnect();
         waitForIdle();
 
@@ -1513,29 +1572,79 @@
     }
 
     /**
-     * Return a ConditionVariable that opens when {@code count} numbers of CONNECTIVITY_ACTION
-     * broadcasts are received.
+     * Class to simplify expecting broadcasts using BroadcastInterceptingContext.
+     * Ensures that the receiver is unregistered after the expected broadcast is received. This
+     * cannot be done in the BroadcastReceiver itself because BroadcastInterceptingContext runs
+     * the receivers' receive method while iterating over the list of receivers, and unregistering
+     * the receiver during iteration throws ConcurrentModificationException.
      */
-    private ConditionVariable registerConnectivityBroadcast(final int count) {
+    private class ExpectedBroadcast extends CompletableFuture<Intent>  {
+        private final BroadcastReceiver mReceiver;
+
+        ExpectedBroadcast(BroadcastReceiver receiver) {
+            mReceiver = receiver;
+        }
+
+        public Intent expectBroadcast(int timeoutMs) throws Exception {
+            try {
+                return get(timeoutMs, TimeUnit.MILLISECONDS);
+            } catch (TimeoutException e) {
+                fail("Expected broadcast not received after " + timeoutMs + " ms");
+                return null;
+            } finally {
+                mServiceContext.unregisterReceiver(mReceiver);
+            }
+        }
+
+        public Intent expectBroadcast() throws Exception {
+            return expectBroadcast(TIMEOUT_MS);
+        }
+
+        public void expectNoBroadcast(int timeoutMs) throws Exception {
+            waitForIdle();
+            try {
+                final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
+                fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras());
+            } catch (TimeoutException expected) {
+            } finally {
+                mServiceContext.unregisterReceiver(mReceiver);
+            }
+        }
+    }
+
+    /** Expects that {@code count} CONNECTIVITY_ACTION broadcasts are received. */
+    private ExpectedBroadcast registerConnectivityBroadcast(final int count) {
         return registerConnectivityBroadcastThat(count, intent -> true);
     }
 
-    private ConditionVariable registerConnectivityBroadcastThat(final int count,
+    private ExpectedBroadcast registerConnectivityBroadcastThat(final int count,
             @NonNull final Predicate<Intent> filter) {
-        final ConditionVariable cv = new ConditionVariable();
         final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
+        // AtomicReference allows receiver to access expected even though it is constructed later.
+        final AtomicReference<ExpectedBroadcast> expectedRef = new AtomicReference<>();
         final BroadcastReceiver receiver = new BroadcastReceiver() {
-                    private int remaining = count;
-                    public void onReceive(Context context, Intent intent) {
-                        if (!filter.test(intent)) return;
-                        if (--remaining == 0) {
-                            cv.open();
-                            mServiceContext.unregisterReceiver(this);
-                        }
-                    }
-                };
+            private int mRemaining = count;
+            public void onReceive(Context context, Intent intent) {
+                final int type = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1);
+                final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
+                Log.d(TAG, "Received CONNECTIVITY_ACTION type=" + type + " ni=" + ni);
+                if (!filter.test(intent)) return;
+                if (--mRemaining == 0) {
+                    expectedRef.get().complete(intent);
+                }
+            }
+        };
+        final ExpectedBroadcast expected = new ExpectedBroadcast(receiver);
+        expectedRef.set(expected);
         mServiceContext.registerReceiver(receiver, intentFilter);
-        return cv;
+        return expected;
+    }
+
+    private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) {
+        return registerConnectivityBroadcastThat(1, intent ->
+                type == intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) && state.equals(
+                        ((NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO))
+                                .getDetailedState()));
     }
 
     @Test
@@ -1559,10 +1668,9 @@
         // Connect the cell agent and wait for the connected broadcast.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL);
-        final ConditionVariable cv1 = registerConnectivityBroadcastThat(1,
-                intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE);
+        ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
         mCellNetworkAgent.connect(true);
-        waitFor(cv1);
+        b.expectBroadcast();
 
         // Build legacy request for SUPL.
         final NetworkCapabilities legacyCaps = new NetworkCapabilities();
@@ -1572,27 +1680,17 @@
                 ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
 
         // File request, withdraw it and make sure no broadcast is sent
-        final ConditionVariable cv2 = registerConnectivityBroadcast(1);
+        b = registerConnectivityBroadcast(1);
         final TestNetworkCallback callback = new TestNetworkCallback();
         mCm.requestNetwork(legacyRequest, callback);
         callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
         mCm.unregisterNetworkCallback(callback);
-        assertFalse(cv2.block(800)); // 800ms long enough to at least flake if this is sent
-        // As the broadcast did not fire, the receiver was not unregistered. Do this now.
-        mServiceContext.clearRegisteredReceivers();
+        b.expectNoBroadcast(800);  // 800ms long enough to at least flake if this is sent
 
-        // Disconnect the network and expect mobile disconnected broadcast. Use a small hack to
-        // check that has been sent.
-        final AtomicBoolean vanillaAction = new AtomicBoolean(false);
-        final ConditionVariable cv3 = registerConnectivityBroadcastThat(1, intent -> {
-            if (intent.getAction().equals(CONNECTIVITY_ACTION)) {
-                vanillaAction.set(true);
-            }
-            return !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected();
-        });
+        // Disconnect the network and expect mobile disconnected broadcast.
+        b = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
         mCellNetworkAgent.disconnect();
-        waitFor(cv3);
-        assertTrue(vanillaAction.get());
+        b.expectBroadcast();
     }
 
     @Test
@@ -1603,9 +1701,9 @@
         assertNull(mCm.getActiveNetworkInfo());
         assertNull(mCm.getActiveNetwork());
         // Test bringing up validated cellular.
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
         mCellNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         assertLength(2, mCm.getAllNetworks());
         assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
@@ -1613,9 +1711,9 @@
         assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
                 mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
         // Test bringing up validated WiFi.
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         assertLength(2, mCm.getAllNetworks());
         assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
@@ -1630,9 +1728,9 @@
         assertLength(1, mCm.getAllNetworks());
         assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
         // Test WiFi disconnect.
-        cv = registerConnectivityBroadcast(1);
+        b = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.disconnect();
-        waitFor(cv);
+        b.expectBroadcast();
         verifyNoNetwork();
     }
 
@@ -1640,9 +1738,9 @@
     public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
         // Test bringing up unvalidated WiFi
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(false);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up unvalidated cellular
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -1655,19 +1753,19 @@
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mCellNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test cellular disconnect.
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mCellNetworkAgent.disconnect();
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test WiFi disconnect.
-        cv = registerConnectivityBroadcast(1);
+        b = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.disconnect();
-        waitFor(cv);
+        b.expectBroadcast();
         verifyNoNetwork();
     }
 
@@ -1675,25 +1773,25 @@
     public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
         // Test bringing up unvalidated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = registerConnectivityBroadcast(1);
         mCellNetworkAgent.connect(false);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.connect(false);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test WiFi disconnect.
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.disconnect();
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test cellular disconnect.
-        cv = registerConnectivityBroadcast(1);
+        b = registerConnectivityBroadcast(1);
         mCellNetworkAgent.disconnect();
-        waitFor(cv);
+        b.expectBroadcast();
         verifyNoNetwork();
     }
 
@@ -1701,24 +1799,24 @@
     public void testUnlingeringDoesNotValidate() throws Exception {
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(false);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         // Test bringing up validated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mCellNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         // Test cellular disconnect.
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mCellNetworkAgent.disconnect();
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Unlingering a network should not cause it to be marked as validated.
         assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
@@ -1729,25 +1827,25 @@
     public void testCellularOutscoresWeakWifi() throws Exception {
         // Test bringing up validated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = registerConnectivityBroadcast(1);
         mCellNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test WiFi getting really weak.
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.adjustScore(-11);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test WiFi restoring signal strength.
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.adjustScore(11);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
     }
 
@@ -1765,9 +1863,9 @@
         mCellNetworkAgent.expectDisconnected();
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        final ConditionVariable cv = registerConnectivityBroadcast(1);
+        final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
         mWiFiNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up unvalidated cellular.
         // Expect it to be torn down because it could never be the highest scoring network
@@ -1784,33 +1882,33 @@
     public void testCellularFallback() throws Exception {
         // Test bringing up validated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = registerConnectivityBroadcast(1);
         mCellNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Reevaluate WiFi (it'll instantly fail DNS).
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
         // Should quickly fall back to Cellular.
-        waitFor(cv);
+        b.expectBroadcast();
         assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Reevaluate cellular (it'll instantly fail DNS).
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
         // Should quickly fall back to WiFi.
-        waitFor(cv);
+        b.expectBroadcast();
         assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
@@ -1822,23 +1920,23 @@
     public void testWiFiFallback() throws Exception {
         // Test bringing up unvalidated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = registerConnectivityBroadcast(1);
         mWiFiNetworkAgent.connect(false);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular.
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mCellNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
         // Reevaluate cellular (it'll instantly fail DNS).
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
         // Should quickly fall back to WiFi.
-        waitFor(cv);
+        b.expectBroadcast();
         assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
                 NET_CAPABILITY_VALIDATED));
         verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1908,13 +2006,13 @@
         mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
 
         // Test unvalidated networks
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = registerConnectivityBroadcast(1);
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-        waitFor(cv);
+        b.expectBroadcast();
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
         // This should not trigger spurious onAvailable() callbacks, b/21762680.
@@ -1923,28 +2021,28 @@
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(false);
         genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-        waitFor(cv);
+        b.expectBroadcast();
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
-        cv = registerConnectivityBroadcast(2);
+        b = registerConnectivityBroadcast(2);
         mWiFiNetworkAgent.disconnect();
         genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
         cellNetworkCallback.assertNoCallback();
-        waitFor(cv);
+        b.expectBroadcast();
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
-        cv = registerConnectivityBroadcast(1);
+        b = registerConnectivityBroadcast(1);
         mCellNetworkAgent.disconnect();
         genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
         cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
-        waitFor(cv);
+        b.expectBroadcast();
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
 
         // Test validated networks
@@ -2047,10 +2145,6 @@
 
     @Test
     public void testOwnerUidCannotChange() throws Exception {
-        // Owner UIDs are not visible without location permission.
-        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
-                Manifest.permission.ACCESS_FINE_LOCATION);
-
         final NetworkCapabilities ncTemplate = new NetworkCapabilities();
         final int originalOwnerUid = Process.myUid();
         ncTemplate.setOwnerUid(originalOwnerUid);
@@ -2070,6 +2164,10 @@
         mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
         waitForIdle();
 
+        // Owner UIDs are not visible without location permission.
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+
         // Check that the capability change has been applied but the owner UID is not modified.
         NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
         assertEquals(originalOwnerUid, nc.getOwnerUid());
@@ -2665,9 +2763,9 @@
 
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        final ConditionVariable cv = registerConnectivityBroadcast(1);
+        final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
         mWiFiNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
 
         // Register MMS NetworkRequest
@@ -2693,9 +2791,9 @@
     public void testMMSonCell() throws Exception {
         // Test bringing up cellular without MMS
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
         mCellNetworkAgent.connect(false);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_CELLULAR);
 
         // Register MMS NetworkRequest
@@ -3360,8 +3458,8 @@
             NetworkCapabilities networkCapabilities = new NetworkCapabilities();
             networkCapabilities.addTransportType(TRANSPORT_WIFI)
                     .setNetworkSpecifier(new MatchAllNetworkSpecifier());
-            mService.requestNetwork(networkCapabilities, null, 0, null,
-                    ConnectivityManager.TYPE_WIFI, mContext.getPackageName(),
+            mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
+                    null, 0, null, ConnectivityManager.TYPE_WIFI, mContext.getPackageName(),
                     getAttributionTag());
         });
 
@@ -4297,15 +4395,15 @@
     }
 
     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()));
         }
 
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
         mWiFiNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         verifyActiveNetwork(TRANSPORT_WIFI);
         mWiFiNetworkAgent.sendLinkProperties(lp);
         waitForIdle();
@@ -4861,10 +4959,10 @@
         assertNotPinnedToWifi();
 
         // Disconnect cell and wifi.
-        ConditionVariable cv = registerConnectivityBroadcast(3);  // cell down, wifi up, wifi down.
+        ExpectedBroadcast b = registerConnectivityBroadcast(3);  // cell down, wifi up, wifi down.
         mCellNetworkAgent.disconnect();
         mWiFiNetworkAgent.disconnect();
-        waitFor(cv);
+        b.expectBroadcast();
 
         // Pinning takes effect even if the pinned network is the default when the pin is set...
         TestNetworkPinner.pin(mServiceContext, wifiRequest);
@@ -4874,10 +4972,10 @@
         assertPinnedToWifiWithWifiDefault();
 
         // ... and is maintained even when that network is no longer the default.
-        cv = registerConnectivityBroadcast(1);
+        b = registerConnectivityBroadcast(1);
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mCellNetworkAgent.connect(true);
-        waitFor(cv);
+        b.expectBroadcast();
         assertPinnedToWifiWithCellDefault();
     }
 
@@ -4977,7 +5075,7 @@
 
     @Test
     public void testNetworkInfoOfTypeNone() throws Exception {
-        ConditionVariable broadcastCV = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = registerConnectivityBroadcast(1);
 
         verifyNoNetwork();
         TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
@@ -5010,9 +5108,7 @@
         mCm.unregisterNetworkCallback(callback);
 
         verifyNoNetwork();
-        if (broadcastCV.block(10)) {
-            fail("expected no broadcast, but got CONNECTIVITY_ACTION broadcast");
-        }
+        b.expectNoBroadcast(10);
     }
 
     @Test
@@ -5812,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();
@@ -6290,7 +6511,7 @@
     }
 
     @Test
-    public void testVpnRestrictedUsers() throws Exception {
+    public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
         // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
         mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
                 PERMISSION_GRANTED);
@@ -6322,19 +6543,11 @@
         callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
                 -> caps.hasCapability(NET_CAPABILITY_VALIDATED));
 
-        // Create a fake restricted profile whose parent is our user ID.
-        final int userId = UserHandle.getUserId(uid);
-        when(mUserManager.canHaveRestrictedProfile(userId)).thenReturn(true);
-        final int restrictedUserId = userId + 1;
-        final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED);
-        info.restrictedProfileParentId = userId;
-        assertTrue(info.isRestricted());
-        when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info);
-        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, restrictedUserId))
-                .thenReturn(UserHandle.getUid(restrictedUserId, VPN_UID));
+        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
+                .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
 
         final Intent addedIntent = new Intent(ACTION_USER_ADDED);
-        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
 
         // Send a USER_ADDED broadcast for it.
         // The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
@@ -6346,7 +6559,7 @@
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
                 && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+                && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && caps.hasTransport(TRANSPORT_WIFI));
 
@@ -6356,13 +6569,13 @@
         callback.expectCapabilitiesThat(mMockVpn, (caps)
                 -> caps.getUids().size() == 2
                 && caps.getUids().contains(new UidRange(uid, uid))
-                && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+                && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
 
         // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
         final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
-        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
         handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
 
         // Expect that the VPN gains the UID range for the restricted user, and that the capability
@@ -6372,53 +6585,72 @@
                 && caps.getUids().contains(new UidRange(uid, uid))
                 && caps.hasTransport(TRANSPORT_VPN)
                 && !caps.hasTransport(TRANSPORT_WIFI));
+    }
 
-        // Test lockdown with restricted profiles.
+    @Test
+    public void testLockdownVpnWithRestrictedProfiles() throws Exception {
+        // For ConnectivityService#setAlwaysOnVpnPackage.
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
+        // For call Vpn#setAlwaysOnPackage.
         mServiceContext.setPermission(
                 Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+        // Necessary to see the UID ranges in NetworkCapabilities.
         mServiceContext.setPermission(
                 Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
 
+        final NetworkRequest request = new NetworkRequest.Builder()
+                .removeCapability(NET_CAPABILITY_NOT_VPN)
+                .build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+
+        final int uid = Process.myUid();
+
         // Connect wifi and check that UIDs in the main and restricted profiles have network access.
-        mMockVpn.disconnect();
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         mWiFiNetworkAgent.connect(true /* validated */);
-        final int restrictedUid = UserHandle.getUid(restrictedUserId, 42 /* appId */);
+        final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */);
         assertNotNull(mCm.getActiveNetworkForUid(uid));
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
         final ArrayList<String> allowList = new ArrayList<>();
-        mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */,
+                allowList);
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
+        // This is arguably overspecified: a UID that is not running doesn't have an active network.
+        // But it's useful to check that non-default users do not lose network access, and to prove
+        // that the loss of connectivity below is indeed due to the restricted profile coming up.
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Start the restricted profile, and check that the UID within it loses network access.
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(userId, "", 0),
-                        info
-                }));
+        when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
+                .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO,
+                RESTRICTED_USER_INFO));
         // TODO: check that VPN app within restricted profile still has access, etc.
+        final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
+        final Handler handler = new Handler(mCsHandlerThread.getLooper());
         handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
         assertNull(mCm.getActiveNetworkForUid(restrictedUid));
 
         // Stop the restricted profile, and check that the UID within it has network access again.
-        when(mUserManager.getAliveUsers()).thenReturn(
-                Arrays.asList(new UserInfo[] {
-                        new UserInfo(userId, "", 0),
-                }));
+        when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
+
+        // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
+        final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+        removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
         handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
         waitForIdle();
         assertNull(mCm.getActiveNetworkForUid(uid));
         assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
 
-        mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList);
         waitForIdle();
     }
 
@@ -6759,6 +6991,7 @@
         final int userId = UserHandle.getUserId(uid);
         final ArrayList<String> allowList = new ArrayList<>();
         mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        waitForIdle();
 
         UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
         UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999);
@@ -6780,10 +7013,10 @@
 
         // Disable lockdown, expect to see the network unblocked.
         mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
-        expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
         callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
         vpnUidCallback.assertNoCallback();
+        expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -6826,9 +7059,11 @@
         // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
         // Everything should now be blocked.
         mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+        waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
         allowList.clear();
         mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+        waitForIdle();
         expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
         defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
         assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
@@ -6906,6 +7141,200 @@
         mCm.unregisterNetworkCallback(vpnUidCallback);
     }
 
+    private void setupLegacyLockdownVpn() {
+        final String profileName = "testVpnProfile";
+        final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
+        when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true);
+        when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
+
+        final VpnProfile profile = new VpnProfile(profileName);
+        profile.name = "My VPN";
+        profile.server = "192.0.2.1";
+        profile.dnsServers = "8.8.8.8";
+        profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
+        final byte[] encodedProfile = profile.encode();
+        when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
+    }
+
+    @Test
+    public void testLegacyLockdownVpn() throws Exception {
+        mServiceContext.setPermission(
+                Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+
+        final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+        final TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+
+        final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(defaultCallback);
+
+        // Pretend lockdown VPN was configured.
+        setupLegacyLockdownVpn();
+
+        // LockdownVpnTracker disables the Vpn teardown code and enables lockdown.
+        // Check the VPN's state before it does so.
+        assertTrue(mMockVpn.getEnableTeardown());
+        assertFalse(mMockVpn.getLockdown());
+
+        // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker.
+        final int userId = UserHandle.getUserId(Process.myUid());
+        final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        final Handler handler = new Handler(mCsHandlerThread.getLooper());
+        handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+        waitForIdle();
+
+        // Lockdown VPN disables teardown and enables lockdown.
+        assertFalse(mMockVpn.getEnableTeardown());
+        assertTrue(mMockVpn.getLockdown());
+
+        // Bring up a network.
+        // Expect nothing to happen because the network does not have an IPv4 default route: legacy
+        // VPN only supports IPv4.
+        final LinkProperties cellLp = new LinkProperties();
+        cellLp.setInterfaceName("rmnet0");
+        cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+        cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0"));
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(false /* validated */);
+        callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        waitForIdle();
+        assertNull(mMockVpn.getAgent());
+
+        // Add an IPv4 address. Ideally the VPN should start, but it doesn't because nothing calls
+        // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
+        // TODO: consider fixing this.
+        cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25"));
+        cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0"));
+        mCellNetworkAgent.sendLinkProperties(cellLp);
+        callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        waitForIdle();
+        assertNull(mMockVpn.getAgent());
+
+        // Disconnect, then try again with a network that supports IPv4 at connection time.
+        // Expect lockdown VPN to come up.
+        ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        mCellNetworkAgent.disconnect();
+        callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        b1.expectBroadcast();
+
+        // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten
+        // with the state of the VPN network. So expect a CONNECTING broadcast.
+        b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+        mCellNetworkAgent.connect(false /* validated */);
+        callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+        b1.expectBroadcast();
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+
+        // TODO: it would be nice if we could simply rely on the production code here, and have
+        // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with
+        // ConnectivityService, etc. That would require duplicating a fair bit of code from the
+        // Vpn tests around how to mock out LegacyVpnRunner. But even if we did that, this does not
+        // work for at least two reasons:
+        // 1. In this test, calling registerNetworkAgent does not actually result in an agent being
+        //    registered. This is because nothing calls onNetworkMonitorCreated, which is what
+        //    actually ends up causing handleRegisterNetworkAgent to be called. Code in this test
+        //    that wants to register an agent must use TestNetworkAgentWrapper.
+        // 2. Even if we exposed Vpn#agentConnect to the test, and made MockVpn#agentConnect call
+        //    the TestNetworkAgentWrapper code, this would deadlock because the
+        //    TestNetworkAgentWrapper code cannot be called on the handler thread since it calls
+        //    waitForIdle().
+        mMockVpn.expectStartLegacyVpnRunner();
+        b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
+        ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
+        mMockVpn.establishForMyUid();
+        callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+        assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
+        final LinkProperties wifiLp = new LinkProperties();
+        wifiLp.setInterfaceName("wlan0");
+        wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25"));
+        wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0"));
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+
+        b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        // Wifi is CONNECTING because the VPN isn't up yet.
+        b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING);
+        ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
+        mWiFiNetworkAgent.connect(false /* validated */);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+        b3.expectBroadcast();
+        mMockVpn.expectStopVpnRunnerPrivileged();
+        mMockVpn.expectStartLegacyVpnRunner();
+
+        // TODO: why is wifi not blocked? Is it because when this callback is sent, the VPN is still
+        // connected, so the network is not considered blocked by the lockdown UID ranges? But the
+        // fact that a VPN is connected should only result in the VPN itself being unblocked, not
+        // any other network. Bug in isUidBlockedByVpn?
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        callback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
+        callback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        defaultCallback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
+        defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+
+        // While the VPN is reconnecting on the new network, everything is blocked.
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
+
+        // The VPN comes up again on wifi.
+        b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
+        b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
+        mMockVpn.establishForMyUid();
+        callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+        b1.expectBroadcast();
+        b2.expectBroadcast();
+
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        // Disconnect cell. Nothing much happens since it's not the default network.
+        // Whenever LockdownVpnTracker is connected, it will send a connected broadcast any time any
+        // NetworkInfo is updated. This is probably a bug.
+        // TODO: consider fixing this.
+        b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
+        mCellNetworkAgent.disconnect();
+        b1.expectBroadcast();
+        callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+        defaultCallback.assertNoCallback();
+
+        assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+        assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+        assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+
+        b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
+        mWiFiNetworkAgent.disconnect();
+        callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+        b1.expectBroadcast();
+        callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
+        b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
+        mMockVpn.expectStopVpnRunnerPrivileged();
+        callback.expectCallback(CallbackEntry.LOST, mMockVpn);
+        b2.expectBroadcast();
+    }
+
     @Test
     public final void testLoseTrusted() throws Exception {
         final NetworkRequest trustedRequest = new NetworkRequest.Builder()
@@ -7249,11 +7678,11 @@
         // prefix discovery is never started.
         LinkProperties lp = new LinkProperties(baseLp);
         lp.setNat64Prefix(pref64FromRa);
-        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
-        mCellNetworkAgent.connect(false);
-        final Network network = mCellNetworkAgent.getNetwork();
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
+        mWiFiNetworkAgent.connect(false);
+        final Network network = mWiFiNetworkAgent.getNetwork();
         int netId = network.getNetId();
-        callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
         inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
@@ -7262,8 +7691,8 @@
 
         // If the RA prefix is withdrawn, clatd is stopped and prefix discovery is started.
         lp.setNat64Prefix(null);
-        mCellNetworkAgent.sendLinkProperties(lp);
-        expectNat64PrefixChange(callback, mCellNetworkAgent, null);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
+        expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
@@ -7271,8 +7700,8 @@
         // If the RA prefix appears while DNS discovery is in progress, discovery is stopped and
         // clatd is started with the prefix from the RA.
         lp.setNat64Prefix(pref64FromRa);
-        mCellNetworkAgent.sendLinkProperties(lp);
-        expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromRa);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
+        expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
         inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
@@ -7280,21 +7709,21 @@
         // Withdraw the RA prefix so we can test the case where an RA prefix appears after DNS
         // discovery has succeeded.
         lp.setNat64Prefix(null);
-        mCellNetworkAgent.sendLinkProperties(lp);
-        expectNat64PrefixChange(callback, mCellNetworkAgent, null);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
+        expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
 
         mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
                 pref64FromDnsStr, 96);
-        expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromDns);
+        expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
 
         // If an RA advertises the same prefix that was discovered by DNS, nothing happens: prefix
         // discovery is not stopped, and there are no callbacks.
         lp.setNat64Prefix(pref64FromDns);
-        mCellNetworkAgent.sendLinkProperties(lp);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
         callback.assertNoCallback();
         inOrder.verify(mMockNetd, never()).clatdStop(iface);
         inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
@@ -7304,7 +7733,7 @@
 
         // If the RA is later withdrawn, nothing happens again.
         lp.setNat64Prefix(null);
-        mCellNetworkAgent.sendLinkProperties(lp);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
         callback.assertNoCallback();
         inOrder.verify(mMockNetd, never()).clatdStop(iface);
         inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
@@ -7314,8 +7743,8 @@
 
         // If the RA prefix changes, clatd is restarted and prefix discovery is stopped.
         lp.setNat64Prefix(pref64FromRa);
-        mCellNetworkAgent.sendLinkProperties(lp);
-        expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromRa);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
+        expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
 
@@ -7329,8 +7758,8 @@
 
         // If the RA prefix changes, clatd is restarted and prefix discovery is not started.
         lp.setNat64Prefix(newPref64FromRa);
-        mCellNetworkAgent.sendLinkProperties(lp);
-        expectNat64PrefixChange(callback, mCellNetworkAgent, newPref64FromRa);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
+        expectNat64PrefixChange(callback, mWiFiNetworkAgent, newPref64FromRa);
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockNetd).clatdStart(iface, newPref64FromRa.toString());
@@ -7340,7 +7769,7 @@
 
         // If the RA prefix changes to the same value, nothing happens.
         lp.setNat64Prefix(newPref64FromRa);
-        mCellNetworkAgent.sendLinkProperties(lp);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
         callback.assertNoCallback();
         assertEquals(newPref64FromRa, mCm.getLinkProperties(network).getNat64Prefix());
         inOrder.verify(mMockNetd, never()).clatdStop(iface);
@@ -7354,19 +7783,19 @@
         // If the same prefix is learned first by DNS and then by RA, and clat is later stopped,
         // (e.g., because the network disconnects) setPrefix64(netid, "") is never called.
         lp.setNat64Prefix(null);
-        mCellNetworkAgent.sendLinkProperties(lp);
-        expectNat64PrefixChange(callback, mCellNetworkAgent, null);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
+        expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
         inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
         mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */,
                 pref64FromDnsStr, 96);
-        expectNat64PrefixChange(callback, mCellNetworkAgent, pref64FromDns);
+        expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
         inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
         inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any());
 
         lp.setNat64Prefix(pref64FromDns);
-        mCellNetworkAgent.sendLinkProperties(lp);
+        mWiFiNetworkAgent.sendLinkProperties(lp);
         callback.assertNoCallback();
         inOrder.verify(mMockNetd, never()).clatdStop(iface);
         inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
@@ -7377,10 +7806,10 @@
         // When tearing down a network, clat state is only updated after CALLBACK_LOST is fired, but
         // before CONNECTIVITY_ACTION is sent. Wait for CONNECTIVITY_ACTION before verifying that
         // clat has been stopped, or the test will be flaky.
-        ConditionVariable cv = registerConnectivityBroadcast(1);
-        mCellNetworkAgent.disconnect();
-        callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
-        waitFor(cv);
+        ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
+        mWiFiNetworkAgent.disconnect();
+        callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+        b.expectBroadcast();
 
         inOrder.verify(mMockNetd).clatdStop(iface);
         inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
@@ -7455,10 +7884,10 @@
                 .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
 
         // Disconnect wifi
-        ConditionVariable cv = registerConnectivityBroadcast(1);
+        ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
         reset(mNetworkManagementService);
         mWiFiNetworkAgent.disconnect();
-        waitFor(cv);
+        b.expectBroadcast();
         verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
 
         // Clean up
@@ -7580,7 +8009,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -7608,7 +8037,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -7624,7 +8053,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
 
@@ -7639,7 +8068,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(lp, VPN_UID, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
 
@@ -7691,7 +8120,7 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
         // The uid range needs to cover the test app so the network is visible to it.
-        final UidRange vpnRange = UidRange.createForUser(VPN_USER);
+        final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
         final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -7756,8 +8185,22 @@
         naExtraInfo.unregister();
     }
 
+    // To avoid granting location permission bypass.
+    private void denyAllLocationPrivilegedPermissions() {
+        mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+                PERMISSION_DENIED);
+        mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+                PERMISSION_DENIED);
+        mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
+                PERMISSION_DENIED);
+        mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
+                PERMISSION_DENIED);
+    }
+
     private void setupLocationPermissions(
             int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
+        denyAllLocationPrivilegedPermissions();
+
         final ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.targetSdkVersion = targetSdk;
         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
@@ -7778,51 +8221,76 @@
     private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
         final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
 
-        return mService
-                .maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName())
-                .getOwnerUid();
+        return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+                netCap, callerUid, mContext.getPackageName()).getOwnerUid();
+    }
+
+    private void verifyWifiInfoCopyNetCapsForCallerPermission(
+            int callerUid, boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
+        final WifiInfo wifiInfo = mock(WifiInfo.class);
+        when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
+        final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
+
+        mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+                netCap, callerUid, mContext.getPackageName());
+        verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
     }
 
     @Test
-    public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception {
+    public void testCreateForCallerWithLocationInfoSanitizedWithFineLocationAfterQ()
+            throws Exception {
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
         final int myUid = Process.myUid();
         assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+                true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
     }
 
     @Test
-    public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception {
+    public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationPreQ()
+            throws Exception {
         setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
                 Manifest.permission.ACCESS_COARSE_LOCATION);
 
         final int myUid = Process.myUid();
         assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+                true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
     }
 
     @Test
-    public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception {
+    public void testCreateForCallerWithLocationInfoSanitizedLocationOff() throws Exception {
         // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
         setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
         final int myUid = Process.myUid();
         assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+                false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
     }
 
     @Test
-    public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception {
+    public void testCreateForCallerWithLocationInfoSanitizedWrongUid() throws Exception {
         // Test that even with fine location permission, not being the owner leads to sanitization.
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
 
         final int myUid = Process.myUid();
         assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
+
+        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+                true /* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
     }
 
     @Test
-    public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception {
+    public void testCreateForCallerWithLocationInfoSanitizedWithCoarseLocationAfterQ()
+            throws Exception {
         // Test that not having fine location permission leads to sanitization.
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
                 Manifest.permission.ACCESS_COARSE_LOCATION);
@@ -7830,20 +8298,27 @@
         // Test that without the location permission, the owner field is sanitized.
         final int myUid = Process.myUid();
         assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+                false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
     }
 
     @Test
-    public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception {
+    public void testCreateForCallerWithLocationInfoSanitizedWithoutLocationPermission()
+            throws Exception {
         setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
 
         // Test that without the location permission, the owner field is sanitized.
         final int myUid = Process.myUid();
         assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
+
+        verifyWifiInfoCopyNetCapsForCallerPermission(myUid,
+                false/* shouldMakeCopyWithLocationSensitiveFieldsParcelable */);
     }
 
     private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
             throws Exception {
-        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+        final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
         mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
         assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
         mMockVpn.setVpnType(vpnType);
@@ -8047,11 +8522,18 @@
         assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
     }
 
+    public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) {
+        final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
+                ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
+                TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
+        return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
+                nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null,
+                0, INVALID_UID, mQosCallbackTracker);
+    }
+
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(
                 android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
@@ -8064,9 +8546,7 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
 
@@ -8079,9 +8559,7 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
 
@@ -8094,22 +8572,17 @@
 
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
-        final Network network = new Network(NET_ID);
-        final NetworkAgentInfo naiWithoutUid =
-                new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0,
-                        mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
-
-        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
-                Manifest.permission.ACCESS_FINE_LOCATION);
+        final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
 
         mMockVpn.establishForMyUid();
         assertUidRangesUpdatedForMyUid(true);
 
         // Wait for networks to connect and broadcasts to be sent before removing permissions.
         waitForIdle();
-        mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
 
-        assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
+        assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {naiWithoutUid.network}));
         waitForIdle();
         assertTrue(
                 "Active VPN permission not applied",
@@ -8130,9 +8603,7 @@
     public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
         final NetworkCapabilities nc = new NetworkCapabilities();
         nc.setAdministratorUids(new int[] {Process.myUid()});
-        final NetworkAgentInfo naiWithUid =
-                new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
-                        mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
@@ -8149,9 +8620,7 @@
         final NetworkCapabilities nc = new NetworkCapabilities();
         nc.setOwnerUid(Process.myUid());
         nc.setAdministratorUids(new int[] {Process.myUid()});
-        final NetworkAgentInfo naiWithUid =
-                new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null,
-                        mService, null, null, null, 0, INVALID_UID);
+        final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
                 Manifest.permission.ACCESS_FINE_LOCATION);
@@ -8372,6 +8841,7 @@
         mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
         mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
         mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+        waitForIdle();
 
         final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
 
@@ -8417,7 +8887,7 @@
         lp.setInterfaceName("tun0");
         lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
-        final UidRange vpnRange = UidRange.createForUser(VPN_USER);
+        final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER);
         Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
         mMockVpn.establish(lp, VPN_UID, vpnRanges);
         assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -8433,4 +8903,167 @@
         assertVpnUidRangesUpdated(true, newRanges, VPN_UID);
         assertVpnUidRangesUpdated(false, vpnRanges, VPN_UID);
     }
+
+    @Test
+    public void testInvalidRequestTypes() {
+        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);
+
+        for (int reqTypeInt : invalidReqTypeInts) {
+            assertThrows("Expect throws for invalid request type " + reqTypeInt,
+                    IllegalArgumentException.class,
+                    () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
+                            ConnectivityManager.TYPE_NONE, mContext.getPackageName(),
+                            getAttributionTag())
+            );
+        }
+    }
+
+    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 96c56e3..52cb836 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -34,7 +34,9 @@
 import android.net.ConnectivityManager;
 import android.net.IDnsResolver;
 import android.net.INetd;
+import android.net.LinkProperties;
 import android.net.Network;
+import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
@@ -76,6 +78,7 @@
     @Mock Context mCtx;
     @Mock NetworkNotificationManager mNotifier;
     @Mock Resources mResources;
+    @Mock QosCallbackTracker mQosCallbackTracker;
 
     @Before
     public void setUp() {
@@ -353,9 +356,10 @@
         NetworkCapabilities caps = new NetworkCapabilities();
         caps.addCapability(0);
         caps.addTransportType(transport);
-        NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null,
-                caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
-                NetworkProvider.ID_NONE, Binder.getCallingUid());
+        NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
+                new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
+                mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE,
+                Binder.getCallingUid(), mQosCallbackTracker);
         nai.everValidated = true;
         return nai;
     }
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 02a2aad..68aaaed 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -252,6 +252,7 @@
 
     @Test
     public void testRestrictedProfilesAreAddedToVpn() {
+        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
 
         final Vpn vpn = createVpn(primaryUser.id);
@@ -265,6 +266,7 @@
 
     @Test
     public void testManagedProfilesAreNotAddedToVpn() {
+        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         setMockedUsers(primaryUser, managedProfileA);
 
         final Vpn vpn = createVpn(primaryUser.id);
@@ -287,6 +289,7 @@
 
     @Test
     public void testUidAllowAndDenylist() throws Exception {
+        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = PRI_USER_RANGE;
         final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
@@ -312,6 +315,7 @@
 
     @Test
     public void testGetAlwaysAndOnGetLockDown() throws Exception {
+        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
 
         // Default state.
@@ -336,6 +340,7 @@
 
     @Test
     public void testLockdownChangingPackage() throws Exception {
+        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = PRI_USER_RANGE;
 
@@ -363,6 +368,7 @@
 
     @Test
     public void testLockdownAllowlist() throws Exception {
+        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = PRI_USER_RANGE;
 
@@ -437,6 +443,7 @@
 
     @Test
     public void testLockdownRuleRepeatability() throws Exception {
+        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
                 new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)};
@@ -469,6 +476,7 @@
 
     @Test
     public void testLockdownRuleReversibility() throws Exception {
+        if (true) return; // TODO(b/175883995): Test disabled until updated for new UserManager API.
         final Vpn vpn = createVpn(primaryUser.id);
         final UidRangeParcel[] entireUser = {
             new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)
@@ -1174,7 +1182,7 @@
         doAnswer(invocation -> {
             final int id = (int) invocation.getArguments()[0];
             return (userMap.get(id).flags & UserInfo.FLAG_ADMIN) != 0;
-        }).when(mUserManager).canHaveRestrictedProfile(anyInt());
+        }).when(mUserManager).canHaveRestrictedProfile();
     }
 
     /**
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/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
new file mode 100644
index 0000000..3156190
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.vcn;
+
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+
+import android.net.wifi.WifiInfo;
+import android.os.Parcel;
+
+import org.junit.Test;
+
+public class VcnTransportInfoTest {
+    private static final int SUB_ID = 1;
+    private static final int NETWORK_ID = 5;
+    private static final WifiInfo WIFI_INFO =
+            new WifiInfo.Builder().setNetworkId(NETWORK_ID).build();
+
+    private static final VcnTransportInfo CELL_UNDERLYING_INFO = new VcnTransportInfo(SUB_ID);
+    private static final VcnTransportInfo WIFI_UNDERLYING_INFO = new VcnTransportInfo(WIFI_INFO);
+
+    @Test
+    public void testGetWifiInfo() {
+        assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo());
+
+        assertNull(CELL_UNDERLYING_INFO.getWifiInfo());
+    }
+
+    @Test
+    public void testGetSubId() {
+        assertEquals(SUB_ID, CELL_UNDERLYING_INFO.getSubId());
+
+        assertEquals(INVALID_SUBSCRIPTION_ID, WIFI_UNDERLYING_INFO.getSubId());
+    }
+
+    @Test
+    public void testEquals() {
+        assertEquals(CELL_UNDERLYING_INFO, CELL_UNDERLYING_INFO);
+        assertEquals(WIFI_UNDERLYING_INFO, WIFI_UNDERLYING_INFO);
+        assertNotEquals(CELL_UNDERLYING_INFO, WIFI_UNDERLYING_INFO);
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        verifyParcelingIsNull(CELL_UNDERLYING_INFO);
+        verifyParcelingIsNull(WIFI_UNDERLYING_INFO);
+    }
+
+    private void verifyParcelingIsNull(VcnTransportInfo vcnTransportInfo) {
+        Parcel parcel = Parcel.obtain();
+        vcnTransportInfo.writeToParcel(parcel, 0 /* flags */);
+        assertNull(VcnTransportInfo.CREATOR.createFromParcel(parcel));
+    }
+}
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