Merge "Fix ordered background broadcast API"
diff --git a/Android.bp b/Android.bp
index 3046b20..a211d26 100644
--- a/Android.bp
+++ b/Android.bp
@@ -658,7 +658,10 @@
     name: "framework-tethering-annotations",
     srcs: [
         "core/java/android/annotation/NonNull.java",
+        "core/java/android/annotation/Nullable.java",
+        "core/java/android/annotation/RequiresPermission.java",
         "core/java/android/annotation/SystemApi.java",
+        "core/java/android/annotation/TestApi.java",
     ],
 }
 // Build ext.jar
@@ -1061,7 +1064,11 @@
     "--hide MissingPermission --hide BroadcastBehavior " +
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
     "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
-    "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*"
+    "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " +
+    "--api-lint-ignore-prefix android.icu. " +
+    "--api-lint-ignore-prefix java. " +
+    "--api-lint-ignore-prefix junit. " +
+    "--api-lint-ignore-prefix org. "
 
 build = [
     "StubLibraries.bp",
diff --git a/apex/sdkextensions/OWNERS b/apex/sdkextensions/OWNERS
index feb2742..a6e5522 100644
--- a/apex/sdkextensions/OWNERS
+++ b/apex/sdkextensions/OWNERS
@@ -1 +1,2 @@
+dariofreni@google.com
 hansson@google.com
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index dd17473..245a96b 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -32,6 +32,7 @@
     libs: [ "framework-annotations-lib" ],
     permitted_packages: [ "android.os.ext" ],
     installable: true,
+    plugins: ["java_api_finder"],
     visibility: [
         "//frameworks/base/apex/sdkextensions",
         "//frameworks/base/apex/sdkextensions/testing",
diff --git a/api/current.txt b/api/current.txt
index bba6586..c9744c2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9824,6 +9824,7 @@
     field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
     field public static final String CLIPBOARD_SERVICE = "clipboard";
     field public static final String COMPANION_DEVICE_SERVICE = "companiondevice";
+    field public static final String CONNECTIVITY_DIAGNOSTICS_SERVICE = "connectivity_diagnostics";
     field public static final String CONNECTIVITY_SERVICE = "connectivity";
     field public static final String CONSUMER_IR_SERVICE = "consumer_ir";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -9872,6 +9873,7 @@
     field public static final String STORAGE_STATS_SERVICE = "storagestats";
     field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final String TELECOM_SERVICE = "telecom";
+    field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
     field public static final String TELEPHONY_SERVICE = "phone";
     field public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
     field public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
@@ -9882,6 +9884,7 @@
     field public static final String USB_SERVICE = "usb";
     field public static final String USER_SERVICE = "user";
     field public static final String VIBRATOR_SERVICE = "vibrator";
+    field public static final String VPN_MANAGEMENT_SERVICE = "vpn_management";
     field public static final String WALLPAPER_SERVICE = "wallpaper";
     field public static final String WIFI_AWARE_SERVICE = "wifiaware";
     field public static final String WIFI_P2P_SERVICE = "wifip2p";
@@ -28691,8 +28694,6 @@
   public class ConnectivityDiagnosticsManager {
     method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
     method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
-    field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
-    field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
   }
 
   public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
@@ -28702,21 +28703,44 @@
     method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
   }
 
-  public static class ConnectivityDiagnosticsManager.ConnectivityReport {
+  public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
     ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
-    field @NonNull public final android.os.PersistableBundle additionalInfo;
-    field @NonNull public final android.net.LinkProperties linkProperties;
-    field @NonNull public final android.net.Network network;
-    field @NonNull public final android.net.NetworkCapabilities networkCapabilities;
-    field public final long reportTimestamp;
+    method public int describeContents();
+    method @NonNull public android.os.PersistableBundle getAdditionalInfo();
+    method @NonNull public android.net.LinkProperties getLinkProperties();
+    method @NonNull public android.net.Network getNetwork();
+    method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+    method public long getReportTimestamp();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
+    field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttemped";
+    field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
+    field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
+    field public static final int NETWORK_PROBE_DNS = 4; // 0x4
+    field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
+    field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
+    field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
+    field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
+    field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
+    field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
+    field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
+    field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
   }
 
-  public static class ConnectivityDiagnosticsManager.DataStallReport {
+  public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
     ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.os.PersistableBundle);
-    field public final int detectionMethod;
-    field @NonNull public final android.net.Network network;
-    field public final long reportTimestamp;
-    field @NonNull public final android.os.PersistableBundle stallDetails;
+    method public int describeContents();
+    method public int getDetectionMethod();
+    method @NonNull public android.net.Network getNetwork();
+    method public long getReportTimestamp();
+    method @NonNull public android.os.PersistableBundle getStallDetails();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
+    field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+    field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
+    field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
+    field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
+    field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
   }
 
   public class ConnectivityManager {
@@ -28859,6 +28883,35 @@
     field public final int code;
   }
 
+  public final class Ikev2VpnProfile extends android.net.PlatformVpnProfile {
+    method @NonNull public java.util.List<java.lang.String> getAllowedAlgorithms();
+    method public int getMaxMtu();
+    method @Nullable public String getPassword();
+    method @Nullable public byte[] getPresharedKey();
+    method @Nullable public android.net.ProxyInfo getProxyInfo();
+    method @Nullable public java.security.PrivateKey getRsaPrivateKey();
+    method @NonNull public String getServerAddr();
+    method @Nullable public java.security.cert.X509Certificate getServerRootCaCert();
+    method @Nullable public java.security.cert.X509Certificate getUserCert();
+    method @NonNull public String getUserIdentity();
+    method @Nullable public String getUsername();
+    method public boolean isBypassable();
+    method public boolean isMetered();
+  }
+
+  public static final class Ikev2VpnProfile.Builder {
+    ctor public Ikev2VpnProfile.Builder(@NonNull String, @NonNull String);
+    method @NonNull public android.net.Ikev2VpnProfile build();
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setAllowedAlgorithms(@NonNull java.util.List<java.lang.String>);
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey, @Nullable java.security.cert.X509Certificate);
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthPsk(@NonNull byte[]);
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthUsernamePassword(@NonNull String, @NonNull String, @Nullable java.security.cert.X509Certificate);
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setBypassable(boolean);
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setMaxMtu(int);
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setMetered(boolean);
+    method @NonNull public android.net.Ikev2VpnProfile.Builder setProxy(@Nullable android.net.ProxyInfo);
+  }
+
   public class InetAddresses {
     method public static boolean isNumericAddress(@NonNull String);
     method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
@@ -29087,6 +29140,7 @@
     method public int getLinkDownstreamBandwidthKbps();
     method public int getLinkUpstreamBandwidthKbps();
     method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+    method public int getOwnerUid();
     method public int getSignalStrength();
     method @Nullable public android.net.TransportInfo getTransportInfo();
     method public boolean hasCapability(int);
@@ -29096,6 +29150,7 @@
     method @NonNull public android.net.NetworkCapabilities setLinkDownstreamBandwidthKbps(int);
     method @NonNull public android.net.NetworkCapabilities setLinkUpstreamBandwidthKbps(int);
     method @NonNull public android.net.NetworkCapabilities setNetworkSpecifier(@NonNull android.net.NetworkSpecifier);
+    method public void setOwnerUid(int);
     method @NonNull public android.net.NetworkCapabilities setSignalStrength(int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
@@ -29205,6 +29260,14 @@
     field public String response;
   }
 
+  public abstract class PlatformVpnProfile {
+    method public final int getType();
+    method @NonNull public final String getTypeString();
+    field public static final int TYPE_IKEV2_IPSEC_PSK = 7; // 0x7
+    field public static final int TYPE_IKEV2_IPSEC_RSA = 8; // 0x8
+    field public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6; // 0x6
+  }
+
   public final class Proxy {
     ctor public Proxy();
     method @Deprecated public static String getDefaultHost();
@@ -29485,6 +29548,13 @@
     method public String sanitize(String);
   }
 
+  public class VpnManager {
+    method public void deleteProvisionedVpnProfile();
+    method @Nullable public android.content.Intent provisionVpnProfile(@NonNull android.net.PlatformVpnProfile);
+    method public void startProvisionedVpnProfile();
+    method public void stopProvisionedVpnProfile();
+  }
+
   public class VpnService extends android.app.Service {
     ctor public VpnService();
     method public final boolean isAlwaysOn();
@@ -35330,7 +35400,7 @@
     method public boolean isSustainedPerformanceModeSupported();
     method public boolean isWakeLockLevelSupported(int);
     method public android.os.PowerManager.WakeLock newWakeLock(int, String);
-    method public void reboot(@Nullable String);
+    method @RequiresPermission(android.Manifest.permission.REBOOT) public void reboot(@Nullable String);
     method public void removeThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
     field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
     field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
@@ -43500,6 +43570,7 @@
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, String);
+    method public void reject(int);
     method public void removeExtras(java.util.List<java.lang.String>);
     method public void removeExtras(java.lang.String...);
     method public void respondToRttRequest(int, boolean);
@@ -43515,6 +43586,8 @@
     field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
     field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
     field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
+    field public static final int REJECT_REASON_DECLINED = 1; // 0x1
+    field public static final int REJECT_REASON_UNWANTED = 2; // 0x2
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_AUDIO_PROCESSING = 12; // 0xc
     field public static final int STATE_CONNECTING = 9; // 0x9
@@ -43782,6 +43855,7 @@
     method public void onPostDialContinue(boolean);
     method public void onPullExternalCall();
     method public void onReject();
+    method public void onReject(int);
     method public void onReject(String);
     method public void onSeparate();
     method public void onShowIncomingCallUi();
@@ -46317,13 +46391,20 @@
 
   public final class ImsException extends java.lang.Exception {
     method public int getCode();
+    field public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3; // 0x3
     field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1
     field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0
     field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2
   }
 
+  public class ImsManager {
+    method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
+    field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
+    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
+    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
+  }
+
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
-    method @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting();
diff --git a/api/system-current.txt b/api/system-current.txt
index 7b4029c..a92fd51 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -93,6 +93,7 @@
     field public static final String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
     field public static final String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP";
     field public static final String KILL_UID = "android.permission.KILL_UID";
+    field public static final String LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = "android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH";
     field public static final String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
     field public static final String LOCK_DEVICE = "android.permission.LOCK_DEVICE";
     field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO";
@@ -1576,6 +1577,7 @@
     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";
     field public static final String EUICC_CARD_SERVICE = "euicc_card";
     field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final String NETD_SERVICE = "netd";
@@ -1590,7 +1592,6 @@
     field public static final String STATS_MANAGER = "stats";
     field public static final String STATUS_BAR_SERVICE = "statusbar";
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
-    field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
     field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
     field public static final String TETHERING_SERVICE = "tethering";
     field public static final String VR_SERVICE = "vrmanager";
@@ -1641,6 +1642,7 @@
     field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
     field public static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
     field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
+    field @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public static final String ACTION_USER_SWITCHED = "android.intent.action.USER_SWITCHED";
     field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
     field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
     field public static final String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE";
@@ -1945,6 +1947,7 @@
     field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
     field public static final int MATCH_ANY_USER = 4194304; // 0x400000
     field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
+    field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
     field public static final int MATCH_INSTANT = 8388608; // 0x800000
     field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1
     field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2
@@ -3283,10 +3286,12 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
     field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
     field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
+    field public static final long FUNCTION_NCM = 1024L; // 0x400L
     field public static final long FUNCTION_NONE = 0L; // 0x0L
     field public static final long FUNCTION_RNDIS = 32L; // 0x20L
     field public static final String USB_CONFIGURED = "configured";
     field public static final String USB_CONNECTED = "connected";
+    field public static final String USB_FUNCTION_NCM = "ncm";
     field public static final String USB_FUNCTION_RNDIS = "rndis";
   }
 
@@ -4052,8 +4057,8 @@
   public final class DvbDeviceInfo implements android.os.Parcelable {
     ctor public DvbDeviceInfo(int, int);
     method public int describeContents();
-    method public int getAdapterId();
-    method public int getDeviceId();
+    method @IntRange(from=0) public int getAdapterId();
+    method @IntRange(from=0) public int getDeviceId();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR;
   }
@@ -4338,44 +4343,57 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
     method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
     method @Deprecated @RequiresPermission("android.permission.NETWORK_SETTINGS") public String getCaptivePortalServerUrl();
-    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
+    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(android.Manifest.permission.NETWORK_FACTORY) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
-    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
     method @Deprecated public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int, int, @NonNull android.os.Handler);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "android.permission.NETWORK_STACK"}) public boolean shouldAvoidBadWifi();
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
-    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
-    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
+    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(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
-    method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+    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";
     field public static final int TETHERING_BLUETOOTH = 2; // 0x2
     field public static final int TETHERING_USB = 1; // 0x1
     field public static final int TETHERING_WIFI = 0; // 0x0
-    field public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
-    field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
-    field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
+    field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+    field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
     field public static final int TYPE_NONE = -1; // 0xffffffff
     field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
   }
 
-  public abstract static class ConnectivityManager.OnStartTetheringCallback {
-    ctor public ConnectivityManager.OnStartTetheringCallback();
-    method public void onTetheringFailed();
-    method public void onTetheringStarted();
+  @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
+    ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
+    method @Deprecated public void onTetheringFailed();
+    method @Deprecated public void onTetheringStarted();
   }
 
-  public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
-    method public void onTetheringEntitlementResult(int);
+  @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
+    method @Deprecated public void onTetheringEntitlementResult(int);
   }
 
-  public abstract static class ConnectivityManager.OnTetheringEventCallback {
-    ctor public ConnectivityManager.OnTetheringEventCallback();
-    method public void onUpstreamChanged(@Nullable android.net.Network);
+  @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
+    ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
+    method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
+  }
+
+  public class EthernetManager {
+    method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+  }
+
+  public static interface EthernetManager.TetheredInterfaceCallback {
+    method public void onAvailable(@NonNull String);
+    method public void onUnavailable();
+  }
+
+  public static class EthernetManager.TetheredInterfaceRequest {
+    method public void release();
   }
 
   public class InvalidPacketException extends java.lang.Exception {
@@ -4447,13 +4465,18 @@
 
   public class LinkAddress implements android.os.Parcelable {
     ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
     ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public LinkAddress(@NonNull String);
     ctor public LinkAddress(@NonNull String, int, int);
+    method public long getDeprecationTime();
+    method public long getExpirationTime();
     method public boolean isGlobalPreferred();
     method public boolean isIpv4();
     method public boolean isIpv6();
     method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
+    field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
+    field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
   }
 
   public final class LinkProperties implements android.os.Parcelable {
@@ -4533,9 +4556,11 @@
 
   public final class NetworkCapabilities implements android.os.Parcelable {
     method public boolean deduceRestrictedCapability();
+    method @NonNull public java.util.List<java.lang.Integer> getAdministratorUids();
     method @Nullable public String getSSID();
     method @NonNull public int[] getTransportTypes();
     method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+    method public void setAdministratorUids(@NonNull java.util.List<java.lang.Integer>);
     method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String);
     method @NonNull public android.net.NetworkCapabilities setTransportInfo(@NonNull android.net.TransportInfo);
     field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
@@ -4708,19 +4733,105 @@
     method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
   }
 
-  public final class StringNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
-    ctor public StringNetworkSpecifier(@NonNull String);
-    method public int describeContents();
-    method public boolean satisfiedBy(android.net.NetworkSpecifier);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.StringNetworkSpecifier> CREATOR;
-    field @NonNull public final String specifier;
-  }
-
   public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
     method public boolean satisfiedBy(android.net.NetworkSpecifier);
   }
 
+  public final class TetheredClient implements android.os.Parcelable {
+    ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
+    method public int describeContents();
+    method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
+    method @NonNull public android.net.MacAddress getMacAddress();
+    method public int getTetheringType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
+  }
+
+  public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.net.LinkAddress getAddress();
+    method @Nullable public String getHostname();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
+  }
+
+  public class TetheringManager {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
+    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
+    field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
+    field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
+    field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+    field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+    field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+    field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+    field public static final int TETHERING_ETHERNET = 5; // 0x5
+    field public static final int TETHERING_INVALID = -1; // 0xffffffff
+    field public static final int TETHERING_NCM = 4; // 0x4
+    field public static final int TETHERING_USB = 1; // 0x1
+    field public static final int TETHERING_WIFI = 0; // 0x0
+    field public static final int TETHERING_WIFI_P2P = 3; // 0x3
+    field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
+    field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
+    field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+    field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
+    field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
+    field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+    field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
+    field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
+    field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+    field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
+    field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
+    field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
+    field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+    field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
+    field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+  }
+
+  public static interface TetheringManager.OnTetheringEntitlementResultListener {
+    method public void onTetheringEntitlementResult(int);
+  }
+
+  public abstract static class TetheringManager.StartTetheringCallback {
+    ctor public TetheringManager.StartTetheringCallback();
+    method public void onTetheringFailed(int);
+    method public void onTetheringStarted();
+  }
+
+  public abstract static class TetheringManager.TetheringEventCallback {
+    ctor public TetheringManager.TetheringEventCallback();
+    method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+    method public void onError(@NonNull String, int);
+    method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+    method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public void onTetheringSupported(boolean);
+    method public void onUpstreamChanged(@Nullable android.net.Network);
+  }
+
+  @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
+    ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+  }
+
+  public static class TetheringManager.TetheringRequest {
+  }
+
+  public static class TetheringManager.TetheringRequest.Builder {
+    ctor public TetheringManager.TetheringRequest.Builder(int);
+    method @NonNull public android.net.TetheringManager.TetheringRequest build();
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+  }
+
   public class TrafficStats {
     method public static void setThreadStatsTagApp();
     method public static void setThreadStatsTagBackup();
@@ -4910,7 +5021,7 @@
   }
 
   public final class IkeSessionConfiguration {
-    ctor public IkeSessionConfiguration();
+    method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
     method @NonNull public String getRemoteApplicationVersion();
     method @NonNull public java.util.List<byte[]> getRemoteVendorIDs();
     method public boolean isIkeExtensionEnabled(int);
@@ -4919,6 +5030,7 @@
   }
 
   public final class IkeSessionParams {
+    method @NonNull public java.util.List<android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest> getConfigurationRequests();
     method public long getHardLifetime();
     method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig();
     method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification();
@@ -4932,6 +5044,8 @@
 
   public static final class IkeSessionParams.Builder {
     ctor public IkeSessionParams.Builder();
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(@NonNull java.net.InetAddress);
+    method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(int);
     method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
     method @NonNull public android.net.ipsec.ike.IkeSessionParams build();
     method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
@@ -4945,6 +5059,14 @@
     method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
   }
 
+  public static interface IkeSessionParams.ConfigRequestIpv4PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
+    method @Nullable public java.net.Inet4Address getAddress();
+  }
+
+  public static interface IkeSessionParams.ConfigRequestIpv6PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
+    method @Nullable public java.net.Inet6Address getAddress();
+  }
+
   public abstract static class IkeSessionParams.IkeAuthConfig {
   }
 
@@ -4966,6 +5088,9 @@
     method @NonNull public byte[] getPsk();
   }
 
+  public static interface IkeSessionParams.IkeConfigRequest {
+  }
+
   public final class IkeTrafficSelector {
     ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
     field public final int endPort;
@@ -5013,7 +5138,7 @@
   }
 
   public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
-    method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest> getConfigurationRequests();
+    method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest> getConfigurationRequests();
   }
 
   public static final class TunnelModeChildSessionParams.Builder {
@@ -5030,33 +5155,33 @@
     method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder setLifetime(long, long);
   }
 
-  public static interface TunnelModeChildSessionParams.ConfigRequest {
-  }
-
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
     method @Nullable public java.net.Inet4Address getAddress();
   }
 
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
     method @Nullable public java.net.Inet4Address getAddress();
   }
 
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
     method @Nullable public java.net.Inet4Address getAddress();
   }
 
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+  public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
   }
 
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+  public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
     method @Nullable public java.net.Inet6Address getAddress();
     method public int getPrefixLength();
   }
 
-  public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+  public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
     method @Nullable public java.net.Inet6Address getAddress();
   }
 
+  public static interface TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
+  }
+
 }
 
 package android.net.ipsec.ike.exceptions {
@@ -5540,7 +5665,7 @@
     method public boolean isPortableHotspotSupported();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
-    method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
+    method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
     method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
@@ -6957,6 +7082,7 @@
     field public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
     field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
     field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
+    field public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
     field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
     field public static final String DOZE_ALWAYS_ON = "doze_always_on";
     field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
@@ -7076,7 +7202,73 @@
   }
 
   public static final class Telephony.SimInfo {
+    field public static final String ACCESS_RULES = "access_rules";
+    field public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS = "access_rules_from_carrier_configs";
+    field public static final String ALLOWED_NETWORK_TYPES = "allowed_network_types";
+    field public static final String CARD_ID = "card_id";
+    field public static final String CARRIER_ID = "carrier_id";
+    field public static final String CARRIER_NAME = "carrier_name";
+    field public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+    field public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+    field public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+    field public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+    field public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+    field public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+    field public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+    field public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+    field public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+    field public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+    field public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+    field public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+    field public static final String COLOR = "color";
     field @NonNull public static final android.net.Uri CONTENT_URI;
+    field public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+    field public static final String DATA_ROAMING = "data_roaming";
+    field public static final int DATA_ROAMING_DEFAULT = 0; // 0x0
+    field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
+    field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+    field public static final String DISPLAY_NAME = "display_name";
+    field public static final String EHPLMNS = "ehplmns";
+    field public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+    field public static final String GROUP_OWNER = "group_owner";
+    field public static final String GROUP_UUID = "group_uuid";
+    field public static final String HPLMNS = "hplmns";
+    field public static final String ICC_ID = "icc_id";
+    field public static final String IMSI = "imsi";
+    field public static final String IMS_RCS_UCE_ENABLED = "ims_rcs_uce_enabled";
+    field public static final String ISO_COUNTRY_CODE = "iso_country_code";
+    field public static final String IS_EMBEDDED = "is_embedded";
+    field public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+    field public static final String IS_REMOVABLE = "is_removable";
+    field public static final String MCC = "mcc";
+    field public static final String MCC_STRING = "mcc_string";
+    field public static final String MNC = "mnc";
+    field public static final String MNC_STRING = "mnc_string";
+    field public static final String NAME_SOURCE = "name_source";
+    field public static final int NAME_SOURCE_CARRIER = 3; // 0x3
+    field public static final int NAME_SOURCE_DEFAULT = 0; // 0x0
+    field public static final int NAME_SOURCE_SIM_PNN = 4; // 0x4
+    field public static final int NAME_SOURCE_SIM_SPN = 1; // 0x1
+    field public static final int NAME_SOURCE_USER_INPUT = 2; // 0x2
+    field public static final String NUMBER = "number";
+    field public static final String PROFILE_CLASS = "profile_class";
+    field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
+    field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
+    field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
+    field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
+    field public static final int PROFILE_CLASS_UNSET = -1; // 0xffffffff
+    field public static final int SIM_NOT_INSERTED = -1; // 0xffffffff
+    field public static final String SIM_SLOT_INDEX = "sim_id";
+    field public static final String SUBSCRIPTION_TYPE = "subscription_type";
+    field public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0; // 0x0
+    field public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1; // 0x1
+    field public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+    field public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+    field public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+    field public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+    field public static final String WFC_IMS_MODE = "wfc_ims_mode";
+    field public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+    field public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
   }
 
   public static final class Telephony.Sms.Intents {
@@ -7101,6 +7293,14 @@
 
 }
 
+package android.se.omapi {
+
+  public final class Reader {
+    method @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED) public boolean reset();
+  }
+
+}
+
 package android.security.keystore {
 
   public abstract class AttestationUtils {
@@ -8805,6 +9005,7 @@
     method public int getSleepTimeMillis();
     method public long getTimestamp();
     method @NonNull public java.util.List<android.telephony.ModemActivityInfo.TransmitPower> getTransmitPowerInfo();
+    method public boolean isValid();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
     field public static final int TX_POWER_LEVELS = 5; // 0x5
@@ -8902,6 +9103,7 @@
     method public void onRadioPowerStateChanged(int);
     method public void onSrvccStateChanged(int);
     method public void onVoiceActivationStateChanged(int);
+    field @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 512; // 0x200
     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
@@ -9274,6 +9476,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -9347,9 +9550,12 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
     method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAlwaysReportSignalStrength(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
@@ -9376,6 +9582,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String);
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
     field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE";
+    field public static final String ACTION_SERVICE_PROVIDERS_UPDATED = "android.telephony.action.SERVICE_PROVIDERS_UPDATED";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
@@ -9388,7 +9595,12 @@
     field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
     field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
     field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
+    field public static final String EXTRA_DATA_SPN = "android.telephony.extra.DATA_SPN";
+    field public static final String EXTRA_PLMN = "android.telephony.extra.PLMN";
+    field public static final String EXTRA_SHOW_PLMN = "android.telephony.extra.SHOW_PLMN";
+    field public static final String EXTRA_SHOW_SPN = "android.telephony.extra.SHOW_SPN";
     field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
+    field public static final String EXTRA_SPN = "android.telephony.extra.SPN";
     field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
     field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
     field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff
@@ -9977,15 +10189,12 @@
   }
 
   public class ImsManager {
-    method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
     method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int);
     field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
-    field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
-    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
-    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
   }
 
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
+    method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
@@ -10353,8 +10562,8 @@
     method public int describeContents();
     method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags();
     method @NonNull public android.net.Uri getContactUri();
-    method @Nullable public android.net.Uri getServiceUri(int);
-    method public boolean isCapable(int);
+    method @Nullable public android.net.Uri getServiceUri(long);
+    method public boolean isCapable(long);
     method public boolean isCapable(@NonNull String);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000
@@ -10376,6 +10585,7 @@
     field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100
     field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000
     field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000
+    field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000
     field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000
     field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000
     field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000
@@ -10384,6 +10594,7 @@
     field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000
     field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000
     field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800
+    field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000
     field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400
     field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
@@ -10391,12 +10602,43 @@
 
   public static class RcsContactUceCapability.Builder {
     ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int, @NonNull android.net.Uri);
-    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long);
     method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String);
     method @NonNull public android.telephony.ims.RcsContactUceCapability build();
   }
 
+  public class RcsUceAdapter {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+    field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd
+    field public static final int ERROR_FORBIDDEN = 6; // 0x6
+    field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+    field public static final int ERROR_INSUFFICIENT_MEMORY = 11; // 0xb
+    field public static final int ERROR_LOST_NETWORK = 12; // 0xc
+    field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+    field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+    field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+    field public static final int ERROR_NOT_FOUND = 7; // 0x7
+    field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+    field public static final int ERROR_REQUEST_TIMEOUT = 10; // 0xa
+    field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+    field public static final int PUBLISH_STATE_200_OK = 1; // 0x1
+    field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
+    field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
+    field public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; // 0x4
+    field public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3
+  }
+
+  public static class RcsUceAdapter.CapabilitiesCallback {
+    ctor public RcsUceAdapter.CapabilitiesCallback();
+    method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+    method public void onError(int);
+  }
+
 }
 
 package android.telephony.ims.feature {
@@ -10486,6 +10728,8 @@
   public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
     ctor public RcsFeature();
     method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+    method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl();
+    method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl();
     method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
@@ -10658,6 +10902,7 @@
     method public int transact(android.os.Bundle);
     method public int updateCallBarring(int, int, String[]);
     method public int updateCallBarringForServiceClass(int, int, String[], int);
+    method public int updateCallBarringWithPassword(int, int, @Nullable String[], int, @NonNull String);
     method public int updateCallForward(int, int, String, int, int);
     method public int updateCallWaiting(boolean, int);
     method public int updateClip(boolean);
@@ -10677,6 +10922,71 @@
     field public static final int INVALID_RESULT = -1; // 0xffffffff
   }
 
+  public class RcsCapabilityExchange {
+    ctor public RcsCapabilityExchange();
+    method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException;
+    field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4
+    field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2
+    field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6
+    field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3
+    field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7
+    field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9
+    field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8
+    field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb
+    field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa
+    field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0
+    field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1
+  }
+
+  public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+    ctor public RcsPresenceExchangeImplBase();
+    method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException;
+    method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException;
+    method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException;
+    method public final void onUnpublish() throws android.telephony.ims.ImsException;
+    method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int);
+    method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int);
+    field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7
+    field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9
+    field public static final int RESPONSE_FORBIDDEN = 3; // 0x3
+    field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2
+    field public static final int RESPONSE_NOT_FOUND = 4; // 0x4
+    field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1
+    field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7
+    field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8
+    field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff
+    field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6
+    field public static final int RESPONSE_SUCCESS = 0; // 0x0
+  }
+
+  public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+    ctor public RcsSipOptionsImplBase();
+    method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+    method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+    method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+    method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int);
+    method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+    field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5
+    field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4
+    field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff
+    field public static final int RESPONSE_NOT_FOUND = 3; // 0x3
+    field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2
+    field public static final int RESPONSE_SUCCESS = 0; // 0x0
+    field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1
+  }
+
 }
 
 package android.telephony.mbms {
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 432a5fd..306b8af 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -1,4 +1,14 @@
 // Baseline format: 1.0
+// Tethering broadcast action / extras cannot change name for backwards compatibility
+ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
+    Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED`
+ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
+    Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray`
+ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
+    Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray`
+ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
+    Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray`
+
 ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
     
 
diff --git a/api/test-current.txt b/api/test-current.txt
index b5915d5..b9d53db 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -653,11 +653,11 @@
     method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
     field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
+    field public static final String ETHERNET_SERVICE = "ethernet";
     field public static final String NETWORK_STACK_SERVICE = "network_stack";
     field public static final String PERMISSION_SERVICE = "permission";
     field public static final String ROLLBACK_SERVICE = "rollback";
     field public static final String STATUS_BAR_SERVICE = "statusbar";
-    field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
     field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
@@ -1393,6 +1393,19 @@
     field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
   }
 
+  public class EthernetManager {
+    method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+  }
+
+  public static interface EthernetManager.TetheredInterfaceCallback {
+    method public void onAvailable(@NonNull String);
+    method public void onUnavailable();
+  }
+
+  public static class EthernetManager.TetheredInterfaceRequest {
+    method public void release();
+  }
+
   public final class IpPrefix implements android.os.Parcelable {
     ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public IpPrefix(@NonNull String);
@@ -1404,9 +1417,12 @@
 
   public class LinkAddress implements android.os.Parcelable {
     ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+    ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
     ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
     ctor public LinkAddress(@NonNull String);
     ctor public LinkAddress(@NonNull String, int, int);
+    method public long getDeprecationTime();
+    method public long getExpirationTime();
     method public boolean isGlobalPreferred();
     method public boolean isIpv4();
     method public boolean isIpv6();
@@ -1506,6 +1522,101 @@
     method public void teardownTestNetwork(@NonNull android.net.Network);
   }
 
+  public final class TetheredClient implements android.os.Parcelable {
+    ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
+    method public int describeContents();
+    method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
+    method @NonNull public android.net.MacAddress getMacAddress();
+    method public int getTetheringType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
+  }
+
+  public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.net.LinkAddress getAddress();
+    method @Nullable public String getHostname();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
+  }
+
+  public class TetheringManager {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
+    method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
+    method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+    method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+    method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
+    method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+    method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
+    field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
+    field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
+    field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+    field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+    field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+    field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+    field public static final int TETHERING_ETHERNET = 5; // 0x5
+    field public static final int TETHERING_INVALID = -1; // 0xffffffff
+    field public static final int TETHERING_NCM = 4; // 0x4
+    field public static final int TETHERING_USB = 1; // 0x1
+    field public static final int TETHERING_WIFI = 0; // 0x0
+    field public static final int TETHERING_WIFI_P2P = 3; // 0x3
+    field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
+    field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
+    field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+    field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
+    field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
+    field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+    field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
+    field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
+    field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+    field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
+    field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
+    field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
+    field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+    field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
+    field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+  }
+
+  public static interface TetheringManager.OnTetheringEntitlementResultListener {
+    method public void onTetheringEntitlementResult(int);
+  }
+
+  public abstract static class TetheringManager.StartTetheringCallback {
+    ctor public TetheringManager.StartTetheringCallback();
+    method public void onTetheringFailed(int);
+    method public void onTetheringStarted();
+  }
+
+  public abstract static class TetheringManager.TetheringEventCallback {
+    ctor public TetheringManager.TetheringEventCallback();
+    method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+    method public void onError(@NonNull String, int);
+    method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+    method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public void onTetheringSupported(boolean);
+    method public void onUpstreamChanged(@Nullable android.net.Network);
+  }
+
+  @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
+    ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+  }
+
+  public static class TetheringManager.TetheringRequest {
+  }
+
+  public static class TetheringManager.TetheringRequest.Builder {
+    ctor public TetheringManager.TetheringRequest.Builder(int);
+    method @NonNull public android.net.TetheringManager.TetheringRequest build();
+    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
+    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
+    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+  }
+
   public class TrafficStats {
     method public static long getLoopbackRxBytes();
     method public static long getLoopbackRxPackets();
@@ -3304,15 +3415,12 @@
   }
 
   public class ImsManager {
-    method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
     method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int);
     field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
-    field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
-    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
-    field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
   }
 
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
+    method @Deprecated @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting();
@@ -3672,6 +3780,87 @@
     method public void onProvisioningStringChanged(int, @NonNull String);
   }
 
+  public final class RcsContactUceCapability implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags();
+    method @NonNull public android.net.Uri getContactUri();
+    method @Nullable public android.net.Uri getServiceUri(long);
+    method public boolean isCapable(long);
+    method public boolean isCapable(@NonNull String);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000
+    field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000
+    field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000
+    field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2
+    field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4
+    field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1
+    field public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = 4096; // 0x1000
+    field public static final int CAPABILITY_FILE_TRANSFER = 8; // 0x8
+    field public static final int CAPABILITY_FILE_TRANSFER_HTTP = 64; // 0x40
+    field public static final int CAPABILITY_FILE_TRANSFER_SMS = 128; // 0x80
+    field public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = 32; // 0x20
+    field public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = 16; // 0x10
+    field public static final int CAPABILITY_GEOLOCATION_PULL = 131072; // 0x20000
+    field public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = 262144; // 0x40000
+    field public static final int CAPABILITY_GEOLOCATION_PUSH = 32768; // 0x8000
+    field public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = 65536; // 0x10000
+    field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100
+    field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000
+    field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000
+    field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000
+    field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000
+    field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000
+    field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000
+    field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000
+    field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000
+    field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000
+    field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000
+    field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800
+    field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000
+    field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400
+    field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
+  }
+
+  public static class RcsContactUceCapability.Builder {
+    ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String);
+    method @NonNull public android.telephony.ims.RcsContactUceCapability build();
+  }
+
+  public class RcsUceAdapter {
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getUcePublishState() throws android.telephony.ims.ImsException;
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+    field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd
+    field public static final int ERROR_FORBIDDEN = 6; // 0x6
+    field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+    field public static final int ERROR_INSUFFICIENT_MEMORY = 11; // 0xb
+    field public static final int ERROR_LOST_NETWORK = 12; // 0xc
+    field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+    field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+    field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+    field public static final int ERROR_NOT_FOUND = 7; // 0x7
+    field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+    field public static final int ERROR_REQUEST_TIMEOUT = 10; // 0xa
+    field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+    field public static final int PUBLISH_STATE_200_OK = 1; // 0x1
+    field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
+    field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
+    field public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; // 0x4
+    field public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3
+  }
+
+  public static class RcsUceAdapter.CapabilitiesCallback {
+    ctor public RcsUceAdapter.CapabilitiesCallback();
+    method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+    method public void onError(int);
+  }
+
 }
 
 package android.telephony.ims.feature {
@@ -3761,6 +3950,8 @@
   public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
     ctor public RcsFeature();
     method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+    method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl();
+    method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl();
     method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
     method public void onFeatureReady();
     method public void onFeatureRemoved();
@@ -3933,6 +4124,7 @@
     method public int transact(android.os.Bundle);
     method public int updateCallBarring(int, int, String[]);
     method public int updateCallBarringForServiceClass(int, int, String[], int);
+    method public int updateCallBarringWithPassword(int, int, @Nullable String[], int, @NonNull String);
     method public int updateCallForward(int, int, String, int, int);
     method public int updateCallWaiting(boolean, int);
     method public int updateClip(boolean);
@@ -3952,6 +4144,71 @@
     field public static final int INVALID_RESULT = -1; // 0xffffffff
   }
 
+  public class RcsCapabilityExchange {
+    ctor public RcsCapabilityExchange();
+    method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException;
+    field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4
+    field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2
+    field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6
+    field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3
+    field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7
+    field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9
+    field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8
+    field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb
+    field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa
+    field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0
+    field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1
+  }
+
+  public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+    ctor public RcsPresenceExchangeImplBase();
+    method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException;
+    method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException;
+    method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException;
+    method public final void onUnpublish() throws android.telephony.ims.ImsException;
+    method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int);
+    method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int);
+    field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
+    field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7
+    field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9
+    field public static final int RESPONSE_FORBIDDEN = 3; // 0x3
+    field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2
+    field public static final int RESPONSE_NOT_FOUND = 4; // 0x4
+    field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1
+    field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7
+    field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5
+    field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8
+    field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff
+    field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6
+    field public static final int RESPONSE_SUCCESS = 0; // 0x0
+  }
+
+  public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+    ctor public RcsSipOptionsImplBase();
+    method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+    method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+    method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+    method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int);
+    method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+    field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5
+    field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4
+    field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff
+    field public static final int RESPONSE_NOT_FOUND = 3; // 0x3
+    field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2
+    field public static final int RESPONSE_SUCCESS = 0; // 0x0
+    field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1
+  }
+
 }
 
 package android.telephony.mbms {
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index 3af392c..46f3aeb 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -5,6 +5,16 @@
     
 
 
+// Tethering broadcast action / extras cannot change name for backwards compatibility
+ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
+    Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED`
+ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
+    Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray`
+ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
+    Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray`
+ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
+    Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray`
+
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_ADDITIONAL_CALL_INFO:
     Inconsistent extra value; expected `android.telephony.ims.extra.ADDITIONAL_CALL_INFO`, was `AdditionalCallInfo`
 ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CALL_RAT_TYPE:
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 1987440..9707405 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -366,12 +366,8 @@
     }
 
     private void runGetMaxPhones() throws RemoteException {
-        // This assumes the max number of SIMs is 2, which it currently is
-        if (TelephonyManager.MULTISIM_ALLOWED == mTelephonyManager.isMultiSimSupported()) {
-            System.out.println("2");
-        } else {
-            System.out.println("1");
-        }
+        // how many logical modems can be potentially active simultaneously
+        System.out.println(mTelephonyManager.getSupportedModemCount());
     }
 
     private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException {
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
index 2cb93e4..ecbfed9 100644
--- a/core/java/android/annotation/SystemApi.java
+++ b/core/java/android/annotation/SystemApi.java
@@ -23,6 +23,7 @@
 import static java.lang.annotation.ElementType.PACKAGE;
 import static java.lang.annotation.ElementType.TYPE;
 
+import java.lang.annotation.Repeatable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
@@ -40,39 +41,48 @@
  */
 @Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
 @Retention(RetentionPolicy.RUNTIME)
+@Repeatable(SystemApi.Container.class) // TODO(b/146727827): make this non-repeatable
 public @interface SystemApi {
     enum Client {
         /**
          * Specifies that the intended clients of a SystemApi are privileged apps.
-         * This is the default value for {@link #client}. This implies
-         * MODULE_APPS and MODULE_LIBRARIES as well, which means that APIs will also
-         * be available to module apps and jars.
+         * This is the default value for {@link #client}.
+         * TODO Update the javadoc according to the final spec
          */
         PRIVILEGED_APPS,
 
         /**
-         * Specifies that the intended clients of a SystemApi are modules implemented
-         * as apps, like the NetworkStack app. This implies MODULE_LIBRARIES as well,
-         * which means that APIs will also be available to module jars.
+         * DO NOT USE. Use PRIVILEGED_APPS instead.
+         * (This would provide no further protection over PRIVILEGED_APPS; do not rely on it)
+         * @deprecated Use #PRIVILEGED_APPS instead
          */
+        @Deprecated
         MODULE_APPS,
 
         /**
          * Specifies that the intended clients of a SystemApi are modules implemented
          * as libraries, like the conscrypt.jar in the conscrypt APEX.
+         * TODO Update the javadoc according to the final spec
          */
-        MODULE_LIBRARIES
+        MODULE_LIBRARIES,
+
+        /**
+         * Specifies that the system API is available only in the system server process.
+         * Use this to expose APIs from code loaded by the system server process <em>but</em>
+         * not in <pre>BOOTCLASSPATH</pre>.
+         * TODO(b/148177503) Update "services-stubs" and actually use it.
+         */
+        SYSTEM_SERVER
     }
 
+    /** @deprecated do not use */
+    @Deprecated
     enum Process {
-        /**
-         * Specifies that the SystemAPI is available in every Java processes.
-         * This is the default value for {@link #process}.
-         */
+        /** @deprecated do not use */
         ALL,
 
         /**
-         * Specifies that the SystemAPI is available only in the system server process.
+         * @deprecated use Client#SYSTEM_SERVER instead
          */
         SYSTEM_SERVER
     }
@@ -83,7 +93,18 @@
     Client client() default android.annotation.SystemApi.Client.PRIVILEGED_APPS;
 
     /**
-     * The process(es) that this SystemAPI is available
+     * @deprecated use Client#SYSTEM_SERVER instead for system_server APIs
      */
+    @Deprecated
     Process process() default android.annotation.SystemApi.Process.ALL;
+
+
+    /**
+     * Container for {@link SystemApi} that allows it to be applied repeatedly to types.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(TYPE)
+    @interface Container {
+        SystemApi[] value();
+    }
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 88976e1..81f6d28 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -98,6 +98,7 @@
 import android.media.soundtrigger.SoundTriggerManager;
 import android.media.tv.ITvInputManager;
 import android.media.tv.TvInputManager;
+import android.net.ConnectivityDiagnosticsManager;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityThread;
 import android.net.EthernetManager;
@@ -112,6 +113,7 @@
 import android.net.NetworkWatchlistManager;
 import android.net.TestNetworkManager;
 import android.net.TetheringManager;
+import android.net.VpnManager;
 import android.net.lowpan.ILowpanManager;
 import android.net.lowpan.LowpanManager;
 import android.net.nsd.INsdManager;
@@ -369,6 +371,27 @@
                 return new IpSecManager(ctx, service);
             }});
 
+        registerService(Context.VPN_MANAGEMENT_SERVICE, VpnManager.class,
+                new CachedServiceFetcher<VpnManager>() {
+            @Override
+            public VpnManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+                return new VpnManager(ctx, service);
+            }});
+
+        registerService(Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
+                ConnectivityDiagnosticsManager.class,
+                new CachedServiceFetcher<ConnectivityDiagnosticsManager>() {
+            @Override
+            public ConnectivityDiagnosticsManager createService(ContextImpl ctx)
+                    throws ServiceNotFoundException {
+                // ConnectivityDiagnosticsManager is backed by ConnectivityService
+                IBinder b = ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
+                IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+                return new ConnectivityDiagnosticsManager(ctx, service);
+            }});
+
         registerService(
                 Context.TEST_NETWORK_SERVICE,
                 TestNetworkManager.class,
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 8993de0..ee2cc6d 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -297,7 +297,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(@Nullable BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
         if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothA2dpSink service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -345,7 +346,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(@Nullable BluetoothDevice device) {
+    public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothA2dpSink service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index bd0a39c..8415ecd 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3236,18 +3236,6 @@
     }
 
     /**
-     * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
-     * API name, listenUsingL2capChannel.
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothServerSocket listenUsingL2capCoc(int transport)
-            throws IOException {
-        Log.e(TAG, "listenUsingL2capCoc: PLEASE USE THE OFFICIAL API, listenUsingL2capChannel");
-        return listenUsingL2capChannel();
-    }
-
-    /**
      * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
      * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The
      * supported Bluetooth transport is LE only.
@@ -3294,19 +3282,6 @@
     }
 
     /**
-     * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
-     * API name, listenUsingInsecureL2capChannel.
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport)
-            throws IOException {
-        Log.e(TAG, "listenUsingInsecureL2capCoc: PLEASE USE THE OFFICIAL API, "
-                    + "listenUsingInsecureL2capChannel");
-        return listenUsingInsecureL2capChannel();
-    }
-
-    /**
      * Register a {@link #OnMetadataChangedListener} to receive update about metadata
      * changes for this {@link BluetoothDevice}.
      * Registration must be done when Bluetooth is ON and will last until
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 9fe4dd6..12dc814c 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -2172,17 +2172,6 @@
     }
 
     /**
-     * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
-     * API name, createL2capChannel.
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException {
-        Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createL2capChannel");
-        return createL2capChannel(psm);
-    }
-
-    /**
      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
      * be used to start a secure outgoing connection to the remote device with the same dynamic
      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
@@ -2213,17 +2202,6 @@
     }
 
     /**
-     * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
-     * API name, createInsecureL2capChannel.
-     * @hide
-     */
-    @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException {
-        Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createInsecureL2capChannel");
-        return createInsecureL2capChannel(psm);
-    }
-
-    /**
      * Set a keyed metadata of this {@link BluetoothDevice} to a
      * {@link String} value.
      * Only bonded devices's metadata will be persisted across Bluetooth
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 6de1ffb..fbda9e9 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -584,7 +584,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
         if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothHeadsetClient service =
                 getService();
@@ -633,7 +634,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(BluetoothDevice device) {
+    public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothHeadsetClient service =
                 getService();
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index c1233b8..26e3e27 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -416,7 +416,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(@Nullable BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
         if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothHidHost service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -464,7 +465,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(@Nullable BluetoothDevice device) {
+    public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothHidHost service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 4674706..1c62faa 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -340,7 +340,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(@Nullable BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
         if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothMap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -388,7 +389,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(@Nullable BluetoothDevice device) {
+    public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothMap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 0aa5aac..8d2aadd 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -271,7 +271,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
         if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothMapClient service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -319,7 +320,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(BluetoothDevice device) {
+    public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
         if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")");
         final IBluetoothMapClient service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index 9618ba0..9563c68 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -271,7 +271,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
         if (DBG) {
             log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         }
@@ -323,7 +324,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(BluetoothDevice device) {
+    public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
         if (VDBG) {
             log("getConnectionPolicy(" + device + ")");
         }
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 8bf1b58..bfc3a4d 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -330,7 +330,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
-    public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+    public boolean setConnectionPolicy(BluetoothDevice device,
+            @ConnectionPolicy int connectionPolicy) {
         if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
         final IBluetoothSap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
@@ -378,7 +379,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionPolicy(BluetoothDevice device) {
+    public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
         final IBluetoothSap service = getService();
         if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index cd4af96..c3c7f97 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3296,6 +3296,7 @@
             CONNECTIVITY_SERVICE,
             //@hide: IP_MEMORY_STORE_SERVICE,
             IPSEC_SERVICE,
+            VPN_MANAGEMENT_SERVICE,
             TEST_NETWORK_SERVICE,
             //@hide: UPDATE_LOCK_SERVICE,
             //@hide: NETWORKMANAGEMENT_SERVICE,
@@ -3880,6 +3881,24 @@
     public static final String IPSEC_SERVICE = "ipsec";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.VpnManager} to
+     * manage profiles for the platform built-in VPN.
+     *
+     * @see #getSystemService(String)
+     */
+    public static final String VPN_MANAGEMENT_SERVICE = "vpn_management";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
+     * android.net.ConnectivityDiagnosticsManager} for performing network connectivity diagnostics
+     * as well as receiving network connectivity information from the system.
+     *
+     * @see #getSystemService(String)
+     * @see android.net.ConnectivityDiagnosticsManager
+     */
+    public static final String CONNECTIVITY_DIAGNOSTICS_SERVICE = "connectivity_diagnostics";
+
+    /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.net.TestNetworkManager} for building TUNs and limited-use Networks
      *
@@ -4003,16 +4022,16 @@
     public static final String LOWPAN_SERVICE = "lowpan";
 
     /**
-     * Use with {@link #getSystemService(String)} to retrieve a {@link
-     * android.net.EthernetManager} for handling management of
-     * Ethernet access.
+     * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.EthernetManager}
+     * for handling management of Ethernet access.
      *
      * @see #getSystemService(String)
      * @see android.net.EthernetManager
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @TestApi
     public static final String ETHERNET_SERVICE = "ethernet";
 
     /**
@@ -4835,10 +4854,7 @@
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.telephony.ims.ImsManager}.
-     * @hide
      */
-    @SystemApi
-    @TestApi
     public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9cba7aa..d859a3af 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3619,7 +3619,9 @@
      * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
      * @hide
      */
-    @UnsupportedAppUsage
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @SystemApi
     public static final String ACTION_USER_SWITCHED =
             "android.intent.action.USER_SWITCHED";
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0ae00fb..93b90b4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -545,9 +545,10 @@
     public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO;
 
     /**
-     * Internal flag used to indicate that a package is a hidden system app.
+     * Internal {@link PackageInfo} flag used to indicate that a package is a hidden system app.
      * @hide
      */
+    @SystemApi
     public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS =  0x20000000;
 
     /**
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 67fdda3..b0d0b4c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -262,6 +262,15 @@
     public static final String USB_FUNCTION_ACCESSORY = "accessory";
 
     /**
+     * Name of the NCM USB function.
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
+     */
+    @SystemApi
+    public static final String USB_FUNCTION_NCM = "ncm";
+
+    /**
      * Name of extra for {@link #ACTION_USB_PORT_CHANGED}
      * containing the {@link UsbPort} object for the port.
      *
@@ -367,8 +376,15 @@
      */
     public static final long FUNCTION_ADB = GadgetFunction.ADB;
 
+    /**
+     * Code for the ncm source usb function.
+     * {@hide}
+     */
+    @SystemApi
+    public static final long FUNCTION_NCM = 1 << 10;
+
     private static final long SETTABLE_FUNCTIONS = FUNCTION_MTP | FUNCTION_PTP | FUNCTION_RNDIS
-            | FUNCTION_MIDI;
+            | FUNCTION_MIDI | FUNCTION_NCM;
 
     private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>();
 
@@ -380,6 +396,7 @@
         FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ACCESSORY, FUNCTION_ACCESSORY);
         FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_AUDIO_SOURCE, FUNCTION_AUDIO_SOURCE);
         FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ADB, FUNCTION_ADB);
+        FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_NCM, FUNCTION_NCM);
     }
 
     private final Context mContext;
@@ -935,6 +952,9 @@
         if ((functions & FUNCTION_AUDIO_SOURCE) != 0) {
             joiner.add(UsbManager.USB_FUNCTION_AUDIO_SOURCE);
         }
+        if ((functions & FUNCTION_NCM) != 0) {
+            joiner.add(UsbManager.USB_FUNCTION_NCM);
+        }
         if ((functions & FUNCTION_ADB) != 0) {
             joiner.add(UsbManager.USB_FUNCTION_ADB);
         }
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.aidl b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
new file mode 100644
index 0000000..82ba0ca
--- /dev/null
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.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 ConnectivityDiagnosticsManager.ConnectivityReport;
+parcelable ConnectivityDiagnosticsManager.DataStallReport;
\ No newline at end of file
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index 6afdb5e..b13e4b7 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -18,10 +18,20 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.PersistableBundle;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -47,38 +57,169 @@
  * </ul>
  */
 public class ConnectivityDiagnosticsManager {
-    public static final int DETECTION_METHOD_DNS_EVENTS = 1;
-    public static final int DETECTION_METHOD_TCP_METRICS = 2;
+    private final Context mContext;
+    private final IConnectivityManager mService;
 
     /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(
-            prefix = {"DETECTION_METHOD_"},
-            value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
-    public @interface DetectionMethod {}
+    public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
+        mContext = Preconditions.checkNotNull(context, "missing context");
+        mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+    }
 
     /** @hide */
-    public ConnectivityDiagnosticsManager() {}
+    @VisibleForTesting
+    public static boolean persistableBundleEquals(
+            @Nullable PersistableBundle a, @Nullable PersistableBundle b) {
+        if (a == b) return true;
+        if (a == null || b == null) return false;
+        if (!Objects.equals(a.keySet(), b.keySet())) return false;
+        for (String key : a.keySet()) {
+            if (!Objects.equals(a.get(key), b.get(key))) return false;
+        }
+        return true;
+    }
 
     /** Class that includes connectivity information for a specific Network at a specific time. */
-    public static class ConnectivityReport {
+    public static final class ConnectivityReport implements Parcelable {
+        /**
+         * The overall status of the network is that it is invalid; it neither provides
+         * connectivity nor has been exempted from validation.
+         */
+        public static final int NETWORK_VALIDATION_RESULT_INVALID = 0;
+
+        /**
+         * The overall status of the network is that it is valid, this may be because it provides
+         * full Internet access (all probes succeeded), or because other properties of the network
+         * caused probes not to be run.
+         */
+        // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID
+        public static final int NETWORK_VALIDATION_RESULT_VALID = 1;
+
+        /**
+         * The overall status of the network is that it provides partial connectivity; some
+         * probed services succeeded but others failed.
+         */
+        // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
+        public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2;
+
+        /**
+         * Due to the properties of the network, validation was not performed.
+         */
+        public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3;
+
+        /** @hide */
+        @IntDef(
+                prefix = {"NETWORK_VALIDATION_RESULT_"},
+                value = {
+                        NETWORK_VALIDATION_RESULT_INVALID,
+                        NETWORK_VALIDATION_RESULT_VALID,
+                        NETWORK_VALIDATION_RESULT_PARTIALLY_VALID,
+                        NETWORK_VALIDATION_RESULT_SKIPPED
+                })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface NetworkValidationResult {}
+
+        /**
+         * The overall validation result for the Network being reported on.
+         *
+         * <p>The possible values for this key are:
+         * {@link #NETWORK_VALIDATION_RESULT_INVALID},
+         * {@link #NETWORK_VALIDATION_RESULT_VALID},
+         * {@link #NETWORK_VALIDATION_RESULT_PARTIALLY_VALID},
+         * {@link #NETWORK_VALIDATION_RESULT_SKIPPED}.
+         *
+         * @see android.net.NetworkCapabilities#CAPABILITY_VALIDATED
+         */
+        @NetworkValidationResult
+        public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
+
+        /** DNS probe. */
+        // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS
+        public static final int NETWORK_PROBE_DNS = 0x04;
+
+        /** HTTP probe. */
+        // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP
+        public static final int NETWORK_PROBE_HTTP = 0x08;
+
+        /** HTTPS probe. */
+        // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
+        public static final int NETWORK_PROBE_HTTPS = 0x10;
+
+        /** Captive portal fallback probe. */
+        // TODO: link to INetworkMonitor.NETWORK_VALIDATION_FALLBACK
+        public static final int NETWORK_PROBE_FALLBACK = 0x20;
+
+        /** Private DNS (DNS over TLS) probd. */
+        // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS
+        public static final int NETWORK_PROBE_PRIVATE_DNS = 0x40;
+
+        /** @hide */
+        @IntDef(
+                prefix = {"NETWORK_PROBE_"},
+                value = {
+                        NETWORK_PROBE_DNS,
+                        NETWORK_PROBE_HTTP,
+                        NETWORK_PROBE_HTTPS,
+                        NETWORK_PROBE_FALLBACK,
+                        NETWORK_PROBE_PRIVATE_DNS
+                })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface NetworkProbe {}
+
+        /**
+         * A bitmask of network validation probes that succeeded.
+         *
+         * <p>The possible bits values reported by this key are:
+         * {@link #NETWORK_PROBE_DNS},
+         * {@link #NETWORK_PROBE_HTTP},
+         * {@link #NETWORK_PROBE_HTTPS},
+         * {@link #NETWORK_PROBE_FALLBACK},
+         * {@link #NETWORK_PROBE_PRIVATE_DNS}.
+         */
+        @NetworkProbe
+        public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK =
+                "networkProbesSucceeded";
+
+        /**
+         * A bitmask of network validation probes that were attempted.
+         *
+         * <p>These probes may have failed or may be incomplete at the time of this report.
+         *
+         * <p>The possible bits values reported by this key are:
+         * {@link #NETWORK_PROBE_DNS},
+         * {@link #NETWORK_PROBE_HTTP},
+         * {@link #NETWORK_PROBE_HTTPS},
+         * {@link #NETWORK_PROBE_FALLBACK},
+         * {@link #NETWORK_PROBE_PRIVATE_DNS}.
+         */
+        @NetworkProbe
+        public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK =
+                "networkProbesAttemped";
+
+        /** @hide */
+        @StringDef(prefix = {"KEY_"}, value = {
+                KEY_NETWORK_VALIDATION_RESULT, KEY_NETWORK_PROBES_SUCCEEDED_BITMASK,
+                KEY_NETWORK_PROBES_ATTEMPTED_BITMASK})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface ConnectivityReportBundleKeys {}
+
         /** The Network for which this ConnectivityReport applied */
-        @NonNull public final Network network;
+        @NonNull private final Network mNetwork;
 
         /**
          * The timestamp for the report. The timestamp is taken from {@link
          * System#currentTimeMillis}.
          */
-        public final long reportTimestamp;
+        private final long mReportTimestamp;
 
         /** LinkProperties available on the Network at the reported timestamp */
-        @NonNull public final LinkProperties linkProperties;
+        @NonNull private final LinkProperties mLinkProperties;
 
         /** NetworkCapabilities available on the Network at the reported timestamp */
-        @NonNull public final NetworkCapabilities networkCapabilities;
+        @NonNull private final NetworkCapabilities mNetworkCapabilities;
 
         /** PersistableBundle that may contain additional info about the report */
-        @NonNull public final PersistableBundle additionalInfo;
+        @NonNull private final PersistableBundle mAdditionalInfo;
 
         /**
          * Constructor for ConnectivityReport.
@@ -101,30 +242,191 @@
                 @NonNull LinkProperties linkProperties,
                 @NonNull NetworkCapabilities networkCapabilities,
                 @NonNull PersistableBundle additionalInfo) {
-            this.network = network;
-            this.reportTimestamp = reportTimestamp;
-            this.linkProperties = linkProperties;
-            this.networkCapabilities = networkCapabilities;
-            this.additionalInfo = additionalInfo;
+            mNetwork = network;
+            mReportTimestamp = reportTimestamp;
+            mLinkProperties = linkProperties;
+            mNetworkCapabilities = networkCapabilities;
+            mAdditionalInfo = additionalInfo;
         }
+
+        /**
+         * Returns the Network for this ConnectivityReport.
+         *
+         * @return The Network for which this ConnectivityReport applied
+         */
+        @NonNull
+        public Network getNetwork() {
+            return mNetwork;
+        }
+
+        /**
+         * Returns the epoch timestamp (milliseconds) for when this report was taken.
+         *
+         * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
+         */
+        public long getReportTimestamp() {
+            return mReportTimestamp;
+        }
+
+        /**
+         * Returns the LinkProperties available when this report was taken.
+         *
+         * @return LinkProperties available on the Network at the reported timestamp
+         */
+        @NonNull
+        public LinkProperties getLinkProperties() {
+            return new LinkProperties(mLinkProperties);
+        }
+
+        /**
+         * Returns the NetworkCapabilities when this report was taken.
+         *
+         * @return NetworkCapabilities available on the Network at the reported timestamp
+         */
+        @NonNull
+        public NetworkCapabilities getNetworkCapabilities() {
+            return new NetworkCapabilities(mNetworkCapabilities);
+        }
+
+        /**
+         * Returns a PersistableBundle with additional info for this report.
+         *
+         * @return PersistableBundle that may contain additional info about the report
+         */
+        @NonNull
+        public PersistableBundle getAdditionalInfo() {
+            return new PersistableBundle(mAdditionalInfo);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object o) {
+            if (this == o) return true;
+            if (!(o instanceof ConnectivityReport)) return false;
+            final ConnectivityReport that = (ConnectivityReport) o;
+
+            // PersistableBundle is optimized to avoid unparcelling data unless fields are
+            // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
+            // {@link PersistableBundle#kindofEquals}.
+            return mReportTimestamp == that.mReportTimestamp
+                    && mNetwork.equals(that.mNetwork)
+                    && mLinkProperties.equals(that.mLinkProperties)
+                    && mNetworkCapabilities.equals(that.mNetworkCapabilities)
+                    && persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(
+                    mNetwork,
+                    mReportTimestamp,
+                    mLinkProperties,
+                    mNetworkCapabilities,
+                    mAdditionalInfo);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeParcelable(mNetwork, flags);
+            dest.writeLong(mReportTimestamp);
+            dest.writeParcelable(mLinkProperties, flags);
+            dest.writeParcelable(mNetworkCapabilities, flags);
+            dest.writeParcelable(mAdditionalInfo, flags);
+        }
+
+        /** Implement the Parcelable interface */
+        public static final @NonNull Creator<ConnectivityReport> CREATOR =
+                new Creator<ConnectivityReport>() {
+                    public ConnectivityReport createFromParcel(Parcel in) {
+                        return new ConnectivityReport(
+                                in.readParcelable(null),
+                                in.readLong(),
+                                in.readParcelable(null),
+                                in.readParcelable(null),
+                                in.readParcelable(null));
+                    }
+
+                    public ConnectivityReport[] newArray(int size) {
+                        return new ConnectivityReport[size];
+                    }
+                };
     }
 
     /** Class that includes information for a suspected data stall on a specific Network */
-    public static class DataStallReport {
+    public static final class DataStallReport implements Parcelable {
+        public static final int DETECTION_METHOD_DNS_EVENTS = 1;
+        public static final int DETECTION_METHOD_TCP_METRICS = 2;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(
+                prefix = {"DETECTION_METHOD_"},
+                value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
+        public @interface DetectionMethod {}
+
+        /**
+         * This key represents the period in milliseconds over which other included TCP metrics
+         * were measured.
+         *
+         * <p>This key will be included if the data stall detection method is
+         * {@link #DETECTION_METHOD_TCP_METRICS}.
+         *
+         * <p>This value is an int.
+         */
+        public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS =
+                "tcpMetricsCollectionPeriodMillis";
+
+        /**
+         * This key represents the fail rate of TCP packets when the suspected data stall was
+         * detected.
+         *
+         * <p>This key will be included if the data stall detection method is
+         * {@link #DETECTION_METHOD_TCP_METRICS}.
+         *
+         * <p>This value is an int percentage between 0 and 100.
+         */
+        public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
+
+        /**
+         * This key represents the consecutive number of DNS timeouts that have occurred.
+         *
+         * <p>The consecutive count will be reset any time a DNS response is received.
+         *
+         * <p>This key will be included if the data stall detection method is
+         * {@link #DETECTION_METHOD_DNS_EVENTS}.
+         *
+         * <p>This value is an int.
+         */
+        public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @StringDef(prefix = {"KEY_"}, value = {
+                KEY_TCP_PACKET_FAIL_RATE,
+                KEY_DNS_CONSECUTIVE_TIMEOUTS
+        })
+        public @interface DataStallReportBundleKeys {}
+
         /** The Network for which this DataStallReport applied */
-        @NonNull public final Network network;
+        @NonNull private final Network mNetwork;
 
         /**
          * The timestamp for the report. The timestamp is taken from {@link
          * System#currentTimeMillis}.
          */
-        public final long reportTimestamp;
+        private long mReportTimestamp;
 
         /** The detection method used to identify the suspected data stall */
-        @DetectionMethod public final int detectionMethod;
+        @DetectionMethod private final int mDetectionMethod;
 
         /** PersistableBundle that may contain additional information on the suspected data stall */
-        @NonNull public final PersistableBundle stallDetails;
+        @NonNull private final PersistableBundle mStallDetails;
 
         /**
          * Constructor for DataStallReport.
@@ -143,10 +445,150 @@
                 long reportTimestamp,
                 @DetectionMethod int detectionMethod,
                 @NonNull PersistableBundle stallDetails) {
-            this.network = network;
-            this.reportTimestamp = reportTimestamp;
-            this.detectionMethod = detectionMethod;
-            this.stallDetails = stallDetails;
+            mNetwork = network;
+            mReportTimestamp = reportTimestamp;
+            mDetectionMethod = detectionMethod;
+            mStallDetails = stallDetails;
+        }
+
+        /**
+         * Returns the Network for this DataStallReport.
+         *
+         * @return The Network for which this DataStallReport applied
+         */
+        @NonNull
+        public Network getNetwork() {
+            return mNetwork;
+        }
+
+        /**
+         * Returns the epoch timestamp (milliseconds) for when this report was taken.
+         *
+         * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
+         */
+        public long getReportTimestamp() {
+            return mReportTimestamp;
+        }
+
+        /**
+         * Returns the detection method used to identify this suspected data stall.
+         *
+         * @return The detection method used to identify the suspected data stall
+         */
+        public int getDetectionMethod() {
+            return mDetectionMethod;
+        }
+
+        /**
+         * Returns a PersistableBundle with additional info for this report.
+         *
+         * <p>Gets a bundle with details about the suspected data stall including information
+         * specific to the monitoring method that detected the data stall.
+         *
+         * @return PersistableBundle that may contain additional information on the suspected data
+         *     stall
+         */
+        @NonNull
+        public PersistableBundle getStallDetails() {
+            return new PersistableBundle(mStallDetails);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object o) {
+            if (this == o) return true;
+            if (!(o instanceof DataStallReport)) return false;
+            final DataStallReport that = (DataStallReport) o;
+
+            // PersistableBundle is optimized to avoid unparcelling data unless fields are
+            // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
+            // {@link PersistableBundle#kindofEquals}.
+            return mReportTimestamp == that.mReportTimestamp
+                    && mDetectionMethod == that.mDetectionMethod
+                    && mNetwork.equals(that.mNetwork)
+                    && persistableBundleEquals(mStallDetails, that.mStallDetails);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mNetwork, mReportTimestamp, mDetectionMethod, mStallDetails);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeParcelable(mNetwork, flags);
+            dest.writeLong(mReportTimestamp);
+            dest.writeInt(mDetectionMethod);
+            dest.writeParcelable(mStallDetails, flags);
+        }
+
+        /** Implement the Parcelable interface */
+        public static final @NonNull Creator<DataStallReport> CREATOR =
+                new Creator<DataStallReport>() {
+                    public DataStallReport createFromParcel(Parcel in) {
+                        return new DataStallReport(
+                                in.readParcelable(null),
+                                in.readLong(),
+                                in.readInt(),
+                                in.readParcelable(null));
+                    }
+
+                    public DataStallReport[] newArray(int size) {
+                        return new DataStallReport[size];
+                    }
+                };
+    }
+
+    /** @hide */
+    @VisibleForTesting
+    public static class ConnectivityDiagnosticsBinder
+            extends IConnectivityDiagnosticsCallback.Stub {
+        @NonNull private final ConnectivityDiagnosticsCallback mCb;
+        @NonNull private final Executor mExecutor;
+
+        /** @hide */
+        @VisibleForTesting
+        public ConnectivityDiagnosticsBinder(
+                @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) {
+            this.mCb = cb;
+            this.mExecutor = executor;
+        }
+
+        /** @hide */
+        @VisibleForTesting
+        public void onConnectivityReport(@NonNull ConnectivityReport report) {
+            Binder.withCleanCallingIdentity(() -> {
+                mExecutor.execute(() -> {
+                    mCb.onConnectivityReport(report);
+                });
+            });
+        }
+
+        /** @hide */
+        @VisibleForTesting
+        public void onDataStallSuspected(@NonNull DataStallReport report) {
+            Binder.withCleanCallingIdentity(() -> {
+                mExecutor.execute(() -> {
+                    mCb.onDataStallSuspected(report);
+                });
+            });
+        }
+
+        /** @hide */
+        @VisibleForTesting
+        public void onNetworkConnectivityReported(
+                @NonNull Network network, boolean hasConnectivity) {
+            Binder.withCleanCallingIdentity(() -> {
+                mExecutor.execute(() -> {
+                    mCb.onNetworkConnectivityReported(network, hasConnectivity);
+                });
+            });
         }
     }
 
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 11c1a9c..94eda01 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -33,6 +33,9 @@
 import android.content.Intent;
 import android.net.IpSecManager.UdpEncapsulationSocket;
 import android.net.SocketKeepalive.Callback;
+import android.net.TetheringManager.StartTetheringCallback;
+import android.net.TetheringManager.TetheringEventCallback;
+import android.net.TetheringManager.TetheringRequest;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
@@ -58,6 +61,7 @@
 import android.util.Log;
 import android.util.SparseIntArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
 
@@ -75,6 +79,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -484,34 +489,35 @@
      * enable if any.
      * @hide
      */
-    public static final String EXTRA_ADD_TETHER_TYPE = TetheringManager.EXTRA_ADD_TETHER_TYPE;
+    public static final String EXTRA_ADD_TETHER_TYPE = TetheringConstants.EXTRA_ADD_TETHER_TYPE;
 
     /**
      * Extra used for communicating with the TetherService. Includes the type of tethering for
      * which to cancel provisioning.
      * @hide
      */
-    public static final String EXTRA_REM_TETHER_TYPE = TetheringManager.EXTRA_REM_TETHER_TYPE;
+    public static final String EXTRA_REM_TETHER_TYPE = TetheringConstants.EXTRA_REM_TETHER_TYPE;
 
     /**
      * Extra used for communicating with the TetherService. True to schedule a recheck of tether
      * provisioning.
      * @hide
      */
-    public static final String EXTRA_SET_ALARM = TetheringManager.EXTRA_SET_ALARM;
+    public static final String EXTRA_SET_ALARM = TetheringConstants.EXTRA_SET_ALARM;
 
     /**
      * Tells the TetherService to run a provision check now.
      * @hide
      */
-    public static final String EXTRA_RUN_PROVISION = TetheringManager.EXTRA_RUN_PROVISION;
+    public static final String EXTRA_RUN_PROVISION = TetheringConstants.EXTRA_RUN_PROVISION;
 
     /**
      * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
      * which will receive provisioning results. Can be left empty.
      * @hide
      */
-    public static final String EXTRA_PROVISION_CALLBACK = TetheringManager.EXTRA_PROVISION_CALLBACK;
+    public static final String EXTRA_PROVISION_CALLBACK =
+            TetheringConstants.EXTRA_PROVISION_CALLBACK;
 
     /**
      * The absence of a connection type.
@@ -2369,10 +2375,12 @@
      *
      * @return an array of 0 or more Strings of tetherable interface names.
      *
+     * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead.
      * {@hide}
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     @UnsupportedAppUsage
+    @Deprecated
     public String[] getTetherableIfaces() {
         return getTetheringManager().getTetherableIfaces();
     }
@@ -2382,10 +2390,12 @@
      *
      * @return an array of 0 or more String of currently tethered interface names.
      *
+     * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead.
      * {@hide}
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     @UnsupportedAppUsage
+    @Deprecated
     public String[] getTetheredIfaces() {
         return getTetheringManager().getTetheredIfaces();
     }
@@ -2401,10 +2411,12 @@
      * @return an array of 0 or more String indicating the interface names
      *        which failed to tether.
      *
+     * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead.
      * {@hide}
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     @UnsupportedAppUsage
+    @Deprecated
     public String[] getTetheringErroredIfaces() {
         return getTetheringManager().getTetheringErroredIfaces();
     }
@@ -2413,9 +2425,11 @@
      * Get the set of tethered dhcp ranges.
      *
      * @return an array of 0 or more {@code String} of tethered dhcp ranges.
+     * @deprecated This API just return the default value which is not used in DhcpServer.
      * {@hide}
      */
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    @Deprecated
     public String[] getTetheredDhcpRanges() {
         return getTetheringManager().getTetheredDhcpRanges();
     }
@@ -2441,10 +2455,12 @@
      *
      * @param iface the interface name to tether.
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     * @deprecated Use {@link TetheringManager#startTethering} instead
      *
      * {@hide}
      */
     @UnsupportedAppUsage
+    @Deprecated
     public int tether(String iface) {
         return getTetheringManager().tether(iface);
     }
@@ -2468,6 +2484,7 @@
      * {@hide}
      */
     @UnsupportedAppUsage
+    @Deprecated
     public int untether(String iface) {
         return getTetheringManager().untether(iface);
     }
@@ -2488,6 +2505,7 @@
      *
      * @return a boolean - {@code true} indicating Tethering is supported.
      *
+     * @deprecated Use {@link TetheringEventCallback#onTetheringSupported(boolean)} instead.
      * {@hide}
      */
     @SystemApi
@@ -2499,9 +2517,12 @@
 
     /**
      * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
+     *
+     * @deprecated Use {@link TetheringManager.StartTetheringCallback} instead.
      * @hide
      */
     @SystemApi
+    @Deprecated
     public static abstract class OnStartTetheringCallback {
         /**
          * Called when tethering has been successfully started.
@@ -2518,9 +2539,12 @@
      * Convenient overload for
      * {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null
      * handler to run on the current thread's {@link Looper}.
+     *
+     * @deprecated Use {@link TetheringManager#startTethering} instead.
      * @hide
      */
     @SystemApi
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
     public void startTethering(int type, boolean showProvisioningUi,
             final OnStartTetheringCallback callback) {
@@ -2544,26 +2568,44 @@
      * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
      *         of the result of trying to tether.
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     *
+     * @deprecated Use {@link TetheringManager#startTethering} instead.
      * @hide
      */
     @SystemApi
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
     public void startTethering(int type, boolean showProvisioningUi,
             final OnStartTetheringCallback callback, Handler handler) {
         Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
 
-        ResultReceiver wrappedCallback = new ResultReceiver(handler) {
+        final Executor executor = new Executor() {
             @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (resultCode == TETHER_ERROR_NO_ERROR) {
-                    callback.onTetheringStarted();
+            public void execute(Runnable command) {
+                if (handler == null) {
+                    command.run();
                 } else {
-                    callback.onTetheringFailed();
+                    handler.post(command);
                 }
             }
         };
 
-        getTetheringManager().startTethering(type, wrappedCallback, showProvisioningUi);
+        final StartTetheringCallback tetheringCallback = new StartTetheringCallback() {
+            @Override
+            public void onTetheringStarted() {
+                callback.onTetheringStarted();
+            }
+
+            @Override
+            public void onTetheringFailed(final int resultCode) {
+                callback.onTetheringFailed();
+            }
+        };
+
+        final TetheringRequest request = new TetheringRequest.Builder(type)
+                .setSilentProvisioning(!showProvisioningUi).build();
+
+        getTetheringManager().startTethering(request, executor, tetheringCallback);
     }
 
     /**
@@ -2574,9 +2616,12 @@
      *         {@link ConnectivityManager.TETHERING_WIFI},
      *         {@link ConnectivityManager.TETHERING_USB}, or
      *         {@link ConnectivityManager.TETHERING_BLUETOOTH}.
+     *
+     * @deprecated Use {@link TetheringManager#stopTethering} instead.
      * @hide
      */
     @SystemApi
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
     public void stopTethering(int type) {
         getTetheringManager().stopTethering(type);
@@ -2586,9 +2631,11 @@
      * Callback for use with {@link registerTetheringEventCallback} to find out tethering
      * upstream status.
      *
-     *@hide
+     * @deprecated Use {@link TetheringManager#OnTetheringEventCallback} instead.
+     * @hide
      */
     @SystemApi
+    @Deprecated
     public abstract static class OnTetheringEventCallback {
 
         /**
@@ -2601,6 +2648,10 @@
         public void onUpstreamChanged(@Nullable Network network) {}
     }
 
+    @GuardedBy("mTetheringEventCallbacks")
+    private final ArrayMap<OnTetheringEventCallback, TetheringEventCallback>
+            mTetheringEventCallbacks = new ArrayMap<>();
+
     /**
      * Start listening to tethering change events. Any new added callback will receive the last
      * tethering status right away. If callback is registered when tethering has no upstream or
@@ -2609,16 +2660,30 @@
      *
      * @param executor the executor on which callback will be invoked.
      * @param callback the callback to be called when tethering has change events.
+     *
+     * @deprecated Use {@link TetheringManager#registerTetheringEventCallback} instead.
      * @hide
      */
     @SystemApi
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
     public void registerTetheringEventCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull final OnTetheringEventCallback callback) {
         Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null.");
 
-        getTetheringManager().registerTetheringEventCallback(executor, callback);
+        final TetheringEventCallback tetherCallback =
+                new TetheringEventCallback() {
+                    @Override
+                    public void onUpstreamChanged(@Nullable Network network) {
+                        callback.onUpstreamChanged(network);
+                    }
+                };
+
+        synchronized (mTetheringEventCallbacks) {
+            mTetheringEventCallbacks.put(callback, tetherCallback);
+            getTetheringManager().registerTetheringEventCallback(executor, tetherCallback);
+        }
     }
 
     /**
@@ -2626,13 +2691,21 @@
      * {@link #registerTetheringEventCallback}.
      *
      * @param callback previously registered callback.
+     *
+     * @deprecated Use {@link TetheringManager#unregisterTetheringEventCallback} instead.
      * @hide
      */
     @SystemApi
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
     public void unregisterTetheringEventCallback(
             @NonNull final OnTetheringEventCallback callback) {
-        getTetheringManager().unregisterTetheringEventCallback(callback);
+        Objects.requireNonNull(callback, "The callback must be non-null");
+        synchronized (mTetheringEventCallbacks) {
+            final TetheringEventCallback tetherCallback =
+                    mTetheringEventCallbacks.remove(callback);
+            getTetheringManager().unregisterTetheringEventCallback(tetherCallback);
+        }
     }
 
 
@@ -2644,10 +2717,12 @@
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable usb interfaces.
      *
+     * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead.
      * {@hide}
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     @UnsupportedAppUsage
+    @Deprecated
     public String[] getTetherableUsbRegexs() {
         return getTetheringManager().getTetherableUsbRegexs();
     }
@@ -2660,10 +2735,12 @@
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable wifi interfaces.
      *
+     * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead.
      * {@hide}
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     @UnsupportedAppUsage
+    @Deprecated
     public String[] getTetherableWifiRegexs() {
         return getTetheringManager().getTetherableWifiRegexs();
     }
@@ -2676,10 +2753,13 @@
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable bluetooth interfaces.
      *
+     * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged(
+     *TetheringManager.TetheringInterfaceRegexps)} instead.
      * {@hide}
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     @UnsupportedAppUsage
+    @Deprecated
     public String[] getTetherableBluetoothRegexs() {
         return getTetheringManager().getTetherableBluetoothRegexs();
     }
@@ -2698,45 +2778,114 @@
      *
      * @param enable a boolean - {@code true} to enable tethering
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     * @deprecated Use {@link TetheringManager#startTethering} instead
      *
      * {@hide}
      */
     @UnsupportedAppUsage
+    @Deprecated
     public int setUsbTethering(boolean enable) {
         return getTetheringManager().setUsbTethering(enable);
     }
 
-    /** {@hide} */
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_NO_ERROR}.
+     * {@hide}
+     */
     @SystemApi
-    public static final int TETHER_ERROR_NO_ERROR           = 0;
-    /** {@hide} */
-    public static final int TETHER_ERROR_UNKNOWN_IFACE      = 1;
-    /** {@hide} */
-    public static final int TETHER_ERROR_SERVICE_UNAVAIL    = 2;
-    /** {@hide} */
-    public static final int TETHER_ERROR_UNSUPPORTED        = 3;
-    /** {@hide} */
-    public static final int TETHER_ERROR_UNAVAIL_IFACE      = 4;
-    /** {@hide} */
-    public static final int TETHER_ERROR_MASTER_ERROR       = 5;
-    /** {@hide} */
-    public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
-    /** {@hide} */
-    public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
-    /** {@hide} */
-    public static final int TETHER_ERROR_ENABLE_NAT_ERROR     = 8;
-    /** {@hide} */
-    public static final int TETHER_ERROR_DISABLE_NAT_ERROR    = 9;
-    /** {@hide} */
-    public static final int TETHER_ERROR_IFACE_CFG_ERROR      = 10;
-    /** {@hide} */
+    @Deprecated
+    public static final int TETHER_ERROR_NO_ERROR = TetheringManager.TETHER_ERROR_NO_ERROR;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNKNOWN_IFACE}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_UNKNOWN_IFACE =
+            TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_SERVICE_UNAVAIL}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_SERVICE_UNAVAIL =
+            TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNSUPPORTED}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_UNSUPPORTED = TetheringManager.TETHER_ERROR_UNSUPPORTED;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNAVAIL_IFACE}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_UNAVAIL_IFACE =
+            TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_MASTER_ERROR}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_MASTER_ERROR = TetheringManager.TETHER_ERROR_MASTER_ERROR;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_TETHER_IFACE_ERROR}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_TETHER_IFACE_ERROR =
+            TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNTETHER_IFACE_ERROR}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR =
+            TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_NAT_ERROR}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_ENABLE_NAT_ERROR =
+            TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_NAT_ERROR}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_DISABLE_NAT_ERROR =
+            TetheringManager.TETHER_ERROR_DISABLE_NAT_ERROR;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_IFACE_CFG_ERROR}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_IFACE_CFG_ERROR =
+            TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISION_FAILED}.
+     * {@hide}
+     */
     @SystemApi
-    public static final int TETHER_ERROR_PROVISION_FAILED     = 11;
-    /** {@hide} */
-    public static final int TETHER_ERROR_DHCPSERVER_ERROR     = 12;
-    /** {@hide} */
+    @Deprecated
+    public static final int TETHER_ERROR_PROVISION_FAILED =
+            TetheringManager.TETHER_ERROR_PROVISION_FAILED;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}.
+     * {@hide}
+     */
+    @Deprecated
+    public static final int TETHER_ERROR_DHCPSERVER_ERROR =
+            TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
+    /**
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
+     * {@hide}
+     */
     @SystemApi
-    public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN  = 13;
+    @Deprecated
+    public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN =
+            TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
 
     /**
      * Get a more detailed error code after a Tethering or Untethering
@@ -2746,10 +2895,12 @@
      * @return error The error code of the last error tethering or untethering the named
      *               interface
      *
+     * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead.
      * {@hide}
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     @UnsupportedAppUsage
+    @Deprecated
     public int getLastTetherError(String iface) {
         return getTetheringManager().getLastTetherError(iface);
     }
@@ -2767,9 +2918,12 @@
     /**
      * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
      * entitlement succeeded.
+     *
+     * @deprecated Use {@link TetheringManager#OnTetheringEntitlementResultListener} instead.
      * @hide
      */
     @SystemApi
+    @Deprecated
     public interface OnTetheringEntitlementResultListener  {
         /**
          * Called to notify entitlement result.
@@ -2799,9 +2953,11 @@
      * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
      *         notify the caller of the result of entitlement check. The listener may be called zero
      *         or one time.
+     * @deprecated Use {@link TetheringManager#requestLatestTetheringEntitlementResult} instead.
      * {@hide}
      */
     @SystemApi
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
     public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
             @NonNull @CallbackExecutor Executor executor,
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index fd015b4..a3899b7 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -16,7 +16,10 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Handler;
@@ -24,12 +27,15 @@
 import android.os.RemoteException;
 
 import java.util.ArrayList;
+import java.util.Objects;
 
 /**
  * A class representing the IP configuration of the Ethernet network.
  *
  * @hide
  */
+@SystemApi
+@TestApi
 @SystemService(Context.ETHERNET_SERVICE)
 public class EthernetManager {
     private static final String TAG = "EthernetManager";
@@ -37,7 +43,7 @@
 
     private final Context mContext;
     private final IEthernetManager mService;
-    private final Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) {
         @Override
         public void handleMessage(Message msg) {
             if (msg.what == MSG_AVAILABILITY_CHANGED) {
@@ -60,12 +66,14 @@
 
     /**
      * A listener interface to receive notification on changes in Ethernet.
+     * @hide
      */
     public interface Listener {
         /**
          * Called when Ethernet port's availability is changed.
          * @param iface Ethernet interface name
          * @param isAvailable {@code true} if Ethernet port exists.
+         * @hide
          */
         @UnsupportedAppUsage
         void onAvailabilityChanged(String iface, boolean isAvailable);
@@ -76,6 +84,7 @@
      * Applications will almost always want to use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
      * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}.
+     * @hide
      */
     public EthernetManager(Context context, IEthernetManager service) {
         mContext = context;
@@ -85,6 +94,7 @@
     /**
      * Get Ethernet configuration.
      * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
+     * @hide
      */
     @UnsupportedAppUsage
     public IpConfiguration getConfiguration(String iface) {
@@ -97,6 +107,7 @@
 
     /**
      * Set Ethernet configuration.
+     * @hide
      */
     @UnsupportedAppUsage
     public void setConfiguration(String iface, IpConfiguration config) {
@@ -109,6 +120,7 @@
 
     /**
      * Indicates whether the system currently has one or more Ethernet interfaces.
+     * @hide
      */
     @UnsupportedAppUsage
     public boolean isAvailable() {
@@ -119,6 +131,7 @@
      * Indicates whether the system has given interface.
      *
      * @param iface Ethernet interface name
+     * @hide
      */
     @UnsupportedAppUsage
     public boolean isAvailable(String iface) {
@@ -133,6 +146,7 @@
      * Adds a listener.
      * @param listener A {@link Listener} to add.
      * @throws IllegalArgumentException If the listener is null.
+     * @hide
      */
     @UnsupportedAppUsage
     public void addListener(Listener listener) {
@@ -151,6 +165,7 @@
 
     /**
      * Returns an array of available Ethernet interface names.
+     * @hide
      */
     @UnsupportedAppUsage
     public String[] getAvailableInterfaces() {
@@ -165,6 +180,7 @@
      * Removes a listener.
      * @param listener A {@link Listener} to remove.
      * @throws IllegalArgumentException If the listener is null.
+     * @hide
      */
     @UnsupportedAppUsage
     public void removeListener(Listener listener) {
@@ -180,4 +196,78 @@
             }
         }
     }
+
+    /**
+     * A request for a tethered interface.
+     */
+    public static class TetheredInterfaceRequest {
+        private final IEthernetManager mService;
+        private final ITetheredInterfaceCallback mCb;
+
+        private TetheredInterfaceRequest(@NonNull IEthernetManager service,
+                @NonNull ITetheredInterfaceCallback cb) {
+            this.mService = service;
+            this.mCb = cb;
+        }
+
+        /**
+         * Release the request, causing the interface to revert back from tethering mode if there
+         * is no other requestor.
+         */
+        public void release() {
+            try {
+                mService.releaseTetheredInterface(mCb);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}.
+     */
+    public interface TetheredInterfaceCallback {
+        /**
+         * Called when the tethered interface is available.
+         * @param iface The name of the interface.
+         */
+        void onAvailable(@NonNull String iface);
+
+        /**
+         * Called when the tethered interface is now unavailable.
+         */
+        void onUnavailable();
+    }
+
+    /**
+     * Request a tethered interface in tethering mode.
+     *
+     * <p>When this method is called and there is at least one ethernet interface available, the
+     * system will designate one to act as a tethered interface. If there is already a tethered
+     * interface, the existing interface will be used.
+     * @param callback A callback to be called once the request has been fulfilled.
+     */
+    @NonNull
+    public TetheredInterfaceRequest requestTetheredInterface(
+            @NonNull TetheredInterfaceCallback callback) {
+        Objects.requireNonNull(callback, "Callback must be non-null");
+        final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() {
+            @Override
+            public void onAvailable(String iface) {
+                callback.onAvailable(iface);
+            }
+
+            @Override
+            public void onUnavailable() {
+                callback.onUnavailable();
+            }
+        };
+
+        try {
+            mService.requestTetheredInterface(cbInternal);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return new TetheredInterfaceRequest(mService, cbInternal);
+    }
 }
diff --git a/core/java/android/net/IConnectivityDiagnosticsCallback.aidl b/core/java/android/net/IConnectivityDiagnosticsCallback.aidl
new file mode 100644
index 0000000..3a161bf
--- /dev/null
+++ b/core/java/android/net/IConnectivityDiagnosticsCallback.aidl
@@ -0,0 +1,28 @@
+/**
+ *
+ * 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.net;
+
+import android.net.ConnectivityDiagnosticsManager;
+import android.net.Network;
+
+/** @hide */
+oneway interface IConnectivityDiagnosticsCallback {
+    void onConnectivityReport(in ConnectivityDiagnosticsManager.ConnectivityReport report);
+    void onDataStallSuspected(in ConnectivityDiagnosticsManager.DataStallReport report);
+    void onNetworkConnectivityReported(in Network n, boolean hasConnectivity);
+}
\ No newline at end of file
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 186196bd..3e9e7fa 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent;
 import android.net.ConnectionInfo;
+import android.net.IConnectivityDiagnosticsCallback;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkAgentConfig;
@@ -211,5 +212,9 @@
     boolean isCallerCurrentAlwaysOnVpnApp();
     boolean isCallerCurrentAlwaysOnVpnLockdownApp();
 
+    void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
+            in NetworkRequest request);
+    void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
+
     IBinder startOrGetTestNetworkService();
 }
diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl
index 94960b5..ccc6e35 100644
--- a/core/java/android/net/IEthernetManager.aidl
+++ b/core/java/android/net/IEthernetManager.aidl
@@ -18,6 +18,7 @@
 
 import android.net.IpConfiguration;
 import android.net.IEthernetServiceListener;
+import android.net.ITetheredInterfaceCallback;
 
 /**
  * Interface that answers queries about, and allows changing
@@ -32,4 +33,6 @@
     boolean isAvailable(String iface);
     void addListener(in IEthernetServiceListener listener);
     void removeListener(in IEthernetServiceListener listener);
+    void requestTetheredInterface(in ITetheredInterfaceCallback callback);
+    void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
 }
diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl
new file mode 100644
index 0000000..e3d0759
--- /dev/null
+++ b/core/java/android/net/ITetheredInterfaceCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+/** @hide */
+interface ITetheredInterfaceCallback {
+    void onAvailable(in String iface);
+    void onUnavailable();
+}
\ No newline at end of file
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
new file mode 100644
index 0000000..42b4da1
--- /dev/null
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -0,0 +1,728 @@
+/*
+ * 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.net;
+
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_PSK;
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_RSA;
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+import static com.android.internal.util.Preconditions.checkStringNotEmpty;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.security.Credentials;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.VpnProfile;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The Ikev2VpnProfile is a configuration for the platform setup of IKEv2/IPsec VPNs.
+ *
+ * <p>Together with VpnManager, this allows apps to provision IKEv2/IPsec VPNs that do not require
+ * the VPN app to constantly run in the background.
+ *
+ * @see VpnManager
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296 - Internet Key
+ *     Exchange, Version 2 (IKEv2)</a>
+ */
+public final class Ikev2VpnProfile extends PlatformVpnProfile {
+    private static final String MISSING_PARAM_MSG_TMPL = "Required parameter was not provided: %s";
+    private static final String EMPTY_CERT = "";
+
+    @NonNull private final String mServerAddr;
+    @NonNull private final String mUserIdentity;
+
+    // PSK authentication
+    @Nullable private final byte[] mPresharedKey;
+
+    // Username/Password, RSA authentication
+    @Nullable private final X509Certificate mServerRootCaCert;
+
+    // Username/Password authentication
+    @Nullable private final String mUsername;
+    @Nullable private final String mPassword;
+
+    // RSA Certificate authentication
+    @Nullable private final PrivateKey mRsaPrivateKey;
+    @Nullable private final X509Certificate mUserCert;
+
+    @Nullable private final ProxyInfo mProxyInfo;
+    @NonNull private final List<String> mAllowedAlgorithms;
+    private final boolean mIsBypassable; // Defaults in builder
+    private final boolean mIsMetered; // Defaults in builder
+    private final int mMaxMtu; // Defaults in builder
+
+    private Ikev2VpnProfile(
+            int type,
+            @NonNull String serverAddr,
+            @NonNull String userIdentity,
+            @Nullable byte[] presharedKey,
+            @Nullable X509Certificate serverRootCaCert,
+            @Nullable String username,
+            @Nullable String password,
+            @Nullable PrivateKey rsaPrivateKey,
+            @Nullable X509Certificate userCert,
+            @Nullable ProxyInfo proxyInfo,
+            @NonNull List<String> allowedAlgorithms,
+            boolean isBypassable,
+            boolean isMetered,
+            int maxMtu) {
+        super(type);
+
+        checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
+        checkNotNull(userIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
+        checkNotNull(allowedAlgorithms, MISSING_PARAM_MSG_TMPL, "Allowed Algorithms");
+
+        mServerAddr = serverAddr;
+        mUserIdentity = userIdentity;
+        mPresharedKey =
+                presharedKey == null ? null : Arrays.copyOf(presharedKey, presharedKey.length);
+        mServerRootCaCert = serverRootCaCert;
+        mUsername = username;
+        mPassword = password;
+        mRsaPrivateKey = rsaPrivateKey;
+        mUserCert = userCert;
+        mProxyInfo = new ProxyInfo(proxyInfo);
+
+        // UnmodifiableList doesn't make a defensive copy by default.
+        mAllowedAlgorithms = Collections.unmodifiableList(new ArrayList<>(allowedAlgorithms));
+
+        mIsBypassable = isBypassable;
+        mIsMetered = isMetered;
+        mMaxMtu = maxMtu;
+
+        validate();
+    }
+
+    private void validate() {
+        // Server Address not validated except to check an address was provided. This allows for
+        // dual-stack servers and hostname based addresses.
+        checkStringNotEmpty(mServerAddr, MISSING_PARAM_MSG_TMPL, "Server Address");
+        checkStringNotEmpty(mUserIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
+
+        // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
+        // networks, the VPN must provide a link fulfilling the stricter of the two conditions
+        // (at least that of the IPv6 MTU).
+        if (mMaxMtu < LinkProperties.MIN_MTU_V6) {
+            throw new IllegalArgumentException(
+                    "Max MTU must be at least" + LinkProperties.MIN_MTU_V6);
+        }
+
+        switch (mType) {
+            case TYPE_IKEV2_IPSEC_USER_PASS:
+                checkNotNull(mUsername, MISSING_PARAM_MSG_TMPL, "Username");
+                checkNotNull(mPassword, MISSING_PARAM_MSG_TMPL, "Password");
+
+                if (mServerRootCaCert != null) checkCert(mServerRootCaCert);
+
+                break;
+            case TYPE_IKEV2_IPSEC_PSK:
+                checkNotNull(mPresharedKey, MISSING_PARAM_MSG_TMPL, "Preshared Key");
+                break;
+            case TYPE_IKEV2_IPSEC_RSA:
+                checkNotNull(mUserCert, MISSING_PARAM_MSG_TMPL, "User cert");
+                checkNotNull(mRsaPrivateKey, MISSING_PARAM_MSG_TMPL, "RSA Private key");
+
+                checkCert(mUserCert);
+                if (mServerRootCaCert != null) checkCert(mServerRootCaCert);
+
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid auth method set");
+        }
+
+        VpnProfile.validateAllowedAlgorithms(mAllowedAlgorithms);
+    }
+
+    /** Retrieves the server address string. */
+    @NonNull
+    public String getServerAddr() {
+        return mServerAddr;
+    }
+
+    /** Retrieves the user identity. */
+    @NonNull
+    public String getUserIdentity() {
+        return mUserIdentity;
+    }
+
+    /**
+     * Retrieves the pre-shared key.
+     *
+     * <p>May be null if the profile is not using Pre-shared key authentication.
+     */
+    @Nullable
+    public byte[] getPresharedKey() {
+        return mPresharedKey == null ? null : Arrays.copyOf(mPresharedKey, mPresharedKey.length);
+    }
+
+    /**
+     * Retrieves the certificate for the server's root CA.
+     *
+     * <p>May be null if the profile is not using RSA Digital Signature Authentication or
+     * Username/Password authentication
+     */
+    @Nullable
+    public X509Certificate getServerRootCaCert() {
+        return mServerRootCaCert;
+    }
+
+    /**
+     * Retrieves the username.
+     *
+     * <p>May be null if the profile is not using Username/Password authentication
+     */
+    @Nullable
+    public String getUsername() {
+        return mUsername;
+    }
+
+    /**
+     * Retrieves the password.
+     *
+     * <p>May be null if the profile is not using Username/Password authentication
+     */
+    @Nullable
+    public String getPassword() {
+        return mPassword;
+    }
+
+    /**
+     * Retrieves the RSA private key.
+     *
+     * <p>May be null if the profile is not using RSA Digital Signature authentication
+     */
+    @Nullable
+    public PrivateKey getRsaPrivateKey() {
+        return mRsaPrivateKey;
+    }
+
+    /** Retrieves the user certificate, if any was set. */
+    @Nullable
+    public X509Certificate getUserCert() {
+        return mUserCert;
+    }
+
+    /** Retrieves the proxy information if any was set */
+    @Nullable
+    public ProxyInfo getProxyInfo() {
+        return mProxyInfo;
+    }
+
+    /** Returns all the algorithms allowed by this VPN profile. */
+    @NonNull
+    public List<String> getAllowedAlgorithms() {
+        return mAllowedAlgorithms;
+    }
+
+    /** Returns whether or not the VPN profile should be bypassable. */
+    public boolean isBypassable() {
+        return mIsBypassable;
+    }
+
+    /** Returns whether or not the VPN profile should be always considered metered. */
+    public boolean isMetered() {
+        return mIsMetered;
+    }
+
+    /** Retrieves the maximum MTU set for this VPN profile. */
+    public int getMaxMtu() {
+        return mMaxMtu;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mType,
+                mServerAddr,
+                mUserIdentity,
+                Arrays.hashCode(mPresharedKey),
+                mServerRootCaCert,
+                mUsername,
+                mPassword,
+                mRsaPrivateKey,
+                mUserCert,
+                mProxyInfo,
+                mAllowedAlgorithms,
+                mIsBypassable,
+                mIsMetered,
+                mMaxMtu);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Ikev2VpnProfile)) {
+            return false;
+        }
+
+        final Ikev2VpnProfile other = (Ikev2VpnProfile) obj;
+        return mType == other.mType
+                && Objects.equals(mServerAddr, other.mServerAddr)
+                && Objects.equals(mUserIdentity, other.mUserIdentity)
+                && Arrays.equals(mPresharedKey, other.mPresharedKey)
+                && Objects.equals(mServerRootCaCert, other.mServerRootCaCert)
+                && Objects.equals(mUsername, other.mUsername)
+                && Objects.equals(mPassword, other.mPassword)
+                && Objects.equals(mRsaPrivateKey, other.mRsaPrivateKey)
+                && Objects.equals(mUserCert, other.mUserCert)
+                && Objects.equals(mProxyInfo, other.mProxyInfo)
+                && Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms)
+                && mIsBypassable == other.mIsBypassable
+                && mIsMetered == other.mIsMetered
+                && mMaxMtu == other.mMaxMtu;
+    }
+
+    /**
+     * Builds a VpnProfile instance for internal use, based on the stored IKEv2/IPsec parameters.
+     *
+     * <p>Redundant authentication information (from previous calls to other setAuth* methods) will
+     * be discarded.
+     *
+     * @hide
+     */
+    @NonNull
+    public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
+        final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */);
+        profile.type = mType;
+        profile.server = mServerAddr;
+        profile.ipsecIdentifier = mUserIdentity;
+        profile.proxy = mProxyInfo;
+        profile.setAllowedAlgorithms(mAllowedAlgorithms);
+        profile.isBypassable = mIsBypassable;
+        profile.isMetered = mIsMetered;
+        profile.maxMtu = mMaxMtu;
+        profile.areAuthParamsInline = true;
+        profile.saveLogin = true;
+
+        switch (mType) {
+            case TYPE_IKEV2_IPSEC_USER_PASS:
+                profile.username = mUsername;
+                profile.password = mPassword;
+                profile.ipsecCaCert =
+                        mServerRootCaCert == null ? "" : certificateToPemString(mServerRootCaCert);
+                break;
+            case TYPE_IKEV2_IPSEC_PSK:
+                profile.ipsecSecret = encodeForIpsecSecret(mPresharedKey);
+                break;
+            case TYPE_IKEV2_IPSEC_RSA:
+                profile.ipsecUserCert = certificateToPemString(mUserCert);
+                profile.ipsecSecret = encodeForIpsecSecret(mRsaPrivateKey.getEncoded());
+                profile.ipsecCaCert =
+                        mServerRootCaCert == null ? "" : certificateToPemString(mServerRootCaCert);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid auth method set");
+        }
+
+        return profile;
+    }
+
+    /**
+     * Constructs a Ikev2VpnProfile from an internal-use VpnProfile instance.
+     *
+     * <p>Redundant authentication information (not related to profile type) will be discarded.
+     *
+     * @hide
+     */
+    @NonNull
+    public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
+            throws IOException, GeneralSecurityException {
+        final Builder builder = new Builder(profile.server, profile.ipsecIdentifier);
+        builder.setProxy(profile.proxy);
+        builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
+        builder.setBypassable(profile.isBypassable);
+        builder.setMetered(profile.isMetered);
+        builder.setMaxMtu(profile.maxMtu);
+
+        switch (profile.type) {
+            case TYPE_IKEV2_IPSEC_USER_PASS:
+                builder.setAuthUsernamePassword(
+                        profile.username,
+                        profile.password,
+                        certificateFromPemString(profile.ipsecCaCert));
+                break;
+            case TYPE_IKEV2_IPSEC_PSK:
+                builder.setAuthPsk(decodeFromIpsecSecret(profile.ipsecSecret));
+                break;
+            case TYPE_IKEV2_IPSEC_RSA:
+                final X509Certificate userCert = certificateFromPemString(profile.ipsecUserCert);
+                final PrivateKey key = getPrivateKey(profile.ipsecSecret);
+                final X509Certificate serverRootCa = certificateFromPemString(profile.ipsecCaCert);
+                builder.setAuthDigitalSignature(userCert, key, serverRootCa);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid auth method set");
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Converts a X509 Certificate to a PEM-formatted string.
+     *
+     * <p>Must be public due to runtime-package restrictions.
+     *
+     * @hide
+     */
+    @NonNull
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static String certificateToPemString(@Nullable X509Certificate cert)
+            throws IOException, CertificateEncodingException {
+        if (cert == null) {
+            return EMPTY_CERT;
+        }
+
+        // Credentials.convertToPem outputs ASCII bytes.
+        return new String(Credentials.convertToPem(cert), StandardCharsets.US_ASCII);
+    }
+
+    /**
+     * Decodes the provided Certificate(s).
+     *
+     * <p>Will use the first one if the certStr encodes more than one certificate.
+     */
+    @Nullable
+    private static X509Certificate certificateFromPemString(@Nullable String certStr)
+            throws CertificateException {
+        if (certStr == null || EMPTY_CERT.equals(certStr)) {
+            return null;
+        }
+
+        try {
+            final List<X509Certificate> certs =
+                    Credentials.convertFromPem(certStr.getBytes(StandardCharsets.US_ASCII));
+            return certs.isEmpty() ? null : certs.get(0);
+        } catch (IOException e) {
+            throw new CertificateException(e);
+        }
+    }
+
+    /** @hide */
+    @NonNull
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static String encodeForIpsecSecret(@NonNull byte[] secret) {
+        checkNotNull(secret, MISSING_PARAM_MSG_TMPL, "secret");
+
+        return Base64.getEncoder().encodeToString(secret);
+    }
+
+    @NonNull
+    private static byte[] decodeFromIpsecSecret(@NonNull String encoded) {
+        checkNotNull(encoded, MISSING_PARAM_MSG_TMPL, "encoded");
+
+        return Base64.getDecoder().decode(encoded);
+    }
+
+    @NonNull
+    private static PrivateKey getPrivateKey(@NonNull String keyStr)
+            throws InvalidKeySpecException, NoSuchAlgorithmException {
+        final PKCS8EncodedKeySpec privateKeySpec =
+                new PKCS8EncodedKeySpec(decodeFromIpsecSecret(keyStr));
+        final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        return keyFactory.generatePrivate(privateKeySpec);
+    }
+
+    private static void checkCert(@NonNull X509Certificate cert) {
+        try {
+            certificateToPemString(cert);
+        } catch (GeneralSecurityException | IOException e) {
+            throw new IllegalArgumentException("Certificate could not be encoded");
+        }
+    }
+
+    private static @NonNull <T> T checkNotNull(
+            final T reference, final String messageTemplate, final Object... messageArgs) {
+        return Objects.requireNonNull(reference, String.format(messageTemplate, messageArgs));
+    }
+
+    /** A incremental builder for IKEv2 VPN profiles */
+    public static final class Builder {
+        private int mType = -1;
+        @NonNull private final String mServerAddr;
+        @NonNull private final String mUserIdentity;
+
+        // PSK authentication
+        @Nullable private byte[] mPresharedKey;
+
+        // Username/Password, RSA authentication
+        @Nullable private X509Certificate mServerRootCaCert;
+
+        // Username/Password authentication
+        @Nullable private String mUsername;
+        @Nullable private String mPassword;
+
+        // RSA Certificate authentication
+        @Nullable private PrivateKey mRsaPrivateKey;
+        @Nullable private X509Certificate mUserCert;
+
+        @Nullable private ProxyInfo mProxyInfo;
+        @NonNull private List<String> mAllowedAlgorithms = new ArrayList<>();
+        private boolean mIsBypassable = false;
+        private boolean mIsMetered = true;
+        private int mMaxMtu = 1360;
+
+        /**
+         * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
+         *
+         * @param serverAddr the server that the VPN should connect to
+         * @param identity the identity string to be used for IKEv2 authentication
+         */
+        public Builder(@NonNull String serverAddr, @NonNull String identity) {
+            checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "serverAddr");
+            checkNotNull(identity, MISSING_PARAM_MSG_TMPL, "identity");
+
+            mServerAddr = serverAddr;
+            mUserIdentity = identity;
+        }
+
+        private void resetAuthParams() {
+            mPresharedKey = null;
+            mServerRootCaCert = null;
+            mUsername = null;
+            mPassword = null;
+            mRsaPrivateKey = null;
+            mUserCert = null;
+        }
+
+        /**
+         * Set the IKEv2 authentication to use the provided username/password.
+         *
+         * <p>Setting this will configure IKEv2 authentication using EAP-MSCHAPv2. Only one
+         * authentication method may be set. This method will overwrite any previously set
+         * authentication method.
+         *
+         * @param user the username to be used for EAP-MSCHAPv2 authentication
+         * @param pass the password to be used for EAP-MSCHAPv2 authentication
+         * @param serverRootCa the root certificate to be used for verifying the identity of the
+         *     server
+         * @return this {@link Builder} object to facilitate chaining of method calls
+         * @throws IllegalArgumentException if any of the certificates were invalid or of an
+         *     unrecognized format
+         */
+        @NonNull
+        public Builder setAuthUsernamePassword(
+                @NonNull String user,
+                @NonNull String pass,
+                @Nullable X509Certificate serverRootCa) {
+            checkNotNull(user, MISSING_PARAM_MSG_TMPL, "user");
+            checkNotNull(pass, MISSING_PARAM_MSG_TMPL, "pass");
+
+            // Test to make sure all auth params can be encoded safely.
+            if (serverRootCa != null) checkCert(serverRootCa);
+
+            resetAuthParams();
+            mUsername = user;
+            mPassword = pass;
+            mServerRootCaCert = serverRootCa;
+            mType = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+            return this;
+        }
+
+        /**
+         * Set the IKEv2 authentication to use Digital Signature Authentication with the given key.
+         *
+         * <p>Setting this will configure IKEv2 authentication using a Digital Signature scheme.
+         * Only one authentication method may be set. This method will overwrite any previously set
+         * authentication method.
+         *
+         * @param userCert the username to be used for RSA Digital signiture authentication
+         * @param key the PrivateKey instance associated with the user ceritificate, used for
+         *     constructing the signature
+         * @param serverRootCa the root certificate to be used for verifying the identity of the
+         *     server
+         * @return this {@link Builder} object to facilitate chaining of method calls
+         * @throws IllegalArgumentException if any of the certificates were invalid or of an
+         *     unrecognized format
+         */
+        @NonNull
+        public Builder setAuthDigitalSignature(
+                @NonNull X509Certificate userCert,
+                @NonNull PrivateKey key,
+                @Nullable X509Certificate serverRootCa) {
+            checkNotNull(userCert, MISSING_PARAM_MSG_TMPL, "userCert");
+            checkNotNull(key, MISSING_PARAM_MSG_TMPL, "key");
+
+            // Test to make sure all auth params can be encoded safely.
+            checkCert(userCert);
+            if (serverRootCa != null) checkCert(serverRootCa);
+
+            resetAuthParams();
+            mUserCert = userCert;
+            mRsaPrivateKey = key;
+            mServerRootCaCert = serverRootCa;
+            mType = VpnProfile.TYPE_IKEV2_IPSEC_RSA;
+            return this;
+        }
+
+        /**
+         * Set the IKEv2 authentication to use Preshared keys.
+         *
+         * <p>Setting this will configure IKEv2 authentication using a Preshared Key. Only one
+         * authentication method may be set. This method will overwrite any previously set
+         * authentication method.
+         *
+         * @param psk the key to be used for Pre-Shared Key authentication
+         * @return this {@link Builder} object to facilitate chaining of method calls
+         */
+        @NonNull
+        public Builder setAuthPsk(@NonNull byte[] psk) {
+            checkNotNull(psk, MISSING_PARAM_MSG_TMPL, "psk");
+
+            resetAuthParams();
+            mPresharedKey = psk;
+            mType = VpnProfile.TYPE_IKEV2_IPSEC_PSK;
+            return this;
+        }
+
+        /**
+         * Sets whether apps can bypass this VPN connection.
+         *
+         * <p>By default, all traffic from apps are forwarded through the VPN interface and it is
+         * not possible for unprivileged apps to side-step the VPN. If a VPN is set to bypassable,
+         * apps may use methods such as {@link Network#getSocketFactory} or {@link
+         * Network#openConnection} to instead send/receive directly over the underlying network or
+         * any other network they have permissions for.
+         *
+         * @param isBypassable Whether or not the VPN should be considered bypassable. Defaults to
+         *     {@code false}.
+         * @return this {@link Builder} object to facilitate chaining of method calls
+         */
+        @NonNull
+        public Builder setBypassable(boolean isBypassable) {
+            mIsBypassable = isBypassable;
+            return this;
+        }
+
+        /**
+         * Sets a proxy for the VPN network.
+         *
+         * <p>Note that this proxy is only a recommendation and it may be ignored by apps.
+         *
+         * @param proxy the ProxyInfo to be set for the VPN network
+         * @return this {@link Builder} object to facilitate chaining of method calls
+         */
+        @NonNull
+        public Builder setProxy(@Nullable ProxyInfo proxy) {
+            mProxyInfo = proxy;
+            return this;
+        }
+
+        /**
+         * Set the upper bound of the maximum transmission unit (MTU) of the VPN interface.
+         *
+         * <p>If it is not set, a safe value will be used. Additionally, the actual link MTU will be
+         * dynamically calculated/updated based on the underlying link's mtu.
+         *
+         * @param mtu the MTU (in bytes) of the VPN interface
+         * @return this {@link Builder} object to facilitate chaining of method calls
+         * @throws IllegalArgumentException if the value is not at least the minimum IPv6 MTU (1280)
+         */
+        @NonNull
+        public Builder setMaxMtu(int mtu) {
+            // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
+            // networks, the VPN must provide a link fulfilling the stricter of the two conditions
+            // (at least that of the IPv6 MTU).
+            if (mtu < LinkProperties.MIN_MTU_V6) {
+                throw new IllegalArgumentException(
+                        "Max MTU must be at least " + LinkProperties.MIN_MTU_V6);
+            }
+            mMaxMtu = mtu;
+            return this;
+        }
+
+        /**
+         * Marks the VPN network as metered.
+         *
+         * <p>A VPN network is classified as metered when the user is sensitive to heavy data usage
+         * due to monetary costs and/or data limitations. In such cases, you should set this to
+         * {@code true} so that apps on the system can avoid doing large data transfers. Otherwise,
+         * set this to {@code false}. Doing so would cause VPN network to inherit its meteredness
+         * from the underlying network.
+         *
+         * @param isMetered {@code true} if the VPN network should be treated as metered regardless
+         *     of underlying network meteredness. Defaults to {@code true}.
+         * @return this {@link Builder} object to facilitate chaining of method calls
+         * @see NetworkCapabilities.NET_CAPABILITY_NOT_METERED
+         */
+        @NonNull
+        public Builder setMetered(boolean isMetered) {
+            mIsMetered = isMetered;
+            return this;
+        }
+
+        /**
+         * Sets the allowable set of IPsec algorithms
+         *
+         * <p>A list of allowed IPsec algorithms as defined in {@link IpSecAlgorithm}
+         *
+         * @param algorithmNames the list of supported IPsec algorithms
+         * @return this {@link Builder} object to facilitate chaining of method calls
+         * @see IpSecAlgorithm
+         */
+        @NonNull
+        public Builder setAllowedAlgorithms(@NonNull List<String> algorithmNames) {
+            checkNotNull(algorithmNames, MISSING_PARAM_MSG_TMPL, "algorithmNames");
+            VpnProfile.validateAllowedAlgorithms(algorithmNames);
+
+            mAllowedAlgorithms = algorithmNames;
+            return this;
+        }
+
+        /**
+         * Validates, builds and provisions the VpnProfile.
+         *
+         * @throws IllegalArgumentException if any of the required keys or values were invalid
+         */
+        @NonNull
+        public Ikev2VpnProfile build() {
+            return new Ikev2VpnProfile(
+                    mType,
+                    mServerAddr,
+                    mUserIdentity,
+                    mPresharedKey,
+                    mServerRootCaCert,
+                    mUsername,
+                    mPassword,
+                    mRsaPrivateKey,
+                    mUserCert,
+                    mProxyInfo,
+                    mAllowedAlgorithms,
+                    mIsBypassable,
+                    mIsMetered,
+                    mMaxMtu);
+        }
+    }
+}
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index bf8b38f..a9d7f17 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -19,6 +19,7 @@
 import static android.system.OsConstants.IFA_F_DADFAILED;
 import static android.system.OsConstants.IFA_F_DEPRECATED;
 import static android.system.OsConstants.IFA_F_OPTIMISTIC;
+import static android.system.OsConstants.IFA_F_PERMANENT;
 import static android.system.OsConstants.IFA_F_TENTATIVE;
 import static android.system.OsConstants.RT_SCOPE_HOST;
 import static android.system.OsConstants.RT_SCOPE_LINK;
@@ -34,6 +35,7 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 import android.util.Pair;
 
 import java.net.Inet4Address;
@@ -41,6 +43,7 @@
 import java.net.InetAddress;
 import java.net.InterfaceAddress;
 import java.net.UnknownHostException;
+import java.util.Objects;
 
 /**
  * Identifies an IP address on a network link.
@@ -58,6 +61,21 @@
  * </ul>
  */
 public class LinkAddress implements Parcelable {
+
+    /**
+     * Indicates the deprecation or expiration time is unknown
+     * @hide
+     */
+    @SystemApi
+    public static final long LIFETIME_UNKNOWN = -1;
+
+    /**
+     * Indicates this address is permanent.
+     * @hide
+     */
+    @SystemApi
+    public static final long LIFETIME_PERMANENT = Long.MAX_VALUE;
+
     /**
      * IPv4 or IPv6 address.
      */
@@ -71,7 +89,9 @@
     private int prefixLength;
 
     /**
-     * Address flags. A bitmask of IFA_F_* values.
+     * Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not
+     * return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED}
+     * flag depending on the current preferred lifetime.
      */
     private int flags;
 
@@ -81,6 +101,23 @@
     private int scope;
 
     /**
+     * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be
+     * or was deprecated. At the time existing connections can still use this address until it
+     * expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates
+     * this information is not available. {@link #LIFETIME_PERMANENT} indicates this
+     * {@link LinkAddress} will never be deprecated.
+     */
+    private long deprecationTime;
+
+    /**
+     * The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress}
+     * will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this
+     * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+     * will never expire.
+     */
+    private long expirationTime;
+
+    /**
      * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
      * RFC 6724 section 3.2.
      * @hide
@@ -152,7 +189,8 @@
     /**
      * Utility function for the constructors.
      */
-    private void init(InetAddress address, int prefixLength, int flags, int scope) {
+    private void init(InetAddress address, int prefixLength, int flags, int scope,
+                      long deprecationTime, long expirationTime) {
         if (address == null ||
                 address.isMulticastAddress() ||
                 prefixLength < 0 ||
@@ -161,15 +199,42 @@
             throw new IllegalArgumentException("Bad LinkAddress params " + address +
                     "/" + prefixLength);
         }
+
+        // deprecation time and expiration time must be both provided, or neither.
+        if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) {
+            throw new IllegalArgumentException(
+                    "Must not specify only one of deprecation time and expiration time");
+        }
+
+        // deprecation time needs to be a positive value.
+        if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) {
+            throw new IllegalArgumentException("invalid deprecation time " + deprecationTime);
+        }
+
+        // expiration time needs to be a positive value.
+        if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) {
+            throw new IllegalArgumentException("invalid expiration time " + expirationTime);
+        }
+
+        // expiration time can't be earlier than deprecation time
+        if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN
+                && expirationTime < deprecationTime) {
+            throw new IllegalArgumentException("expiration earlier than deprecation ("
+                    + deprecationTime + ", " + expirationTime + ")");
+        }
+
         this.address = address;
         this.prefixLength = prefixLength;
         this.flags = flags;
         this.scope = scope;
+        this.deprecationTime = deprecationTime;
+        this.expirationTime = expirationTime;
     }
 
     /**
      * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
      * the specified flags and scope. Flags and scope are not checked for validity.
+     *
      * @param address The IP address.
      * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
      * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
@@ -181,7 +246,39 @@
     @TestApi
     public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
             int flags, int scope) {
-        init(address, prefixLength, flags, scope);
+        init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
+    }
+
+    /**
+     * Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with
+     * the specified flags, scope, deprecation time, and expiration time. Flags and scope are not
+     * checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT}
+     * flag will be adjusted based on the passed-in lifetimes.
+     *
+     * @param address The IP address.
+     * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
+     * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
+     * @param scope An integer defining the scope in which the address is unique (e.g.,
+     *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
+     * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when
+     *                        this {@link LinkAddress} will be or was deprecated. At the time
+     *                        existing connections can still use this address until it expires, but
+     *                        new connections should use the new address. {@link #LIFETIME_UNKNOWN}
+     *                        indicates this information is not available.
+     *                        {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
+     *                        never be deprecated.
+     * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this
+     *                       {@link LinkAddress} will expire and be removed from the interface.
+     *                       {@link #LIFETIME_UNKNOWN} indicates this information is not available.
+     *                       {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
+     *                       never expire.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
+                       int flags, int scope, long deprecationTime, long expirationTime) {
+        init(address, prefixLength, flags, scope, deprecationTime, expirationTime);
     }
 
     /**
@@ -237,7 +334,7 @@
         // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
         // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
         Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
-        init(ipAndMask.first, ipAndMask.second, flags, scope);
+        init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
     }
 
     /**
@@ -265,10 +362,12 @@
             return false;
         }
         LinkAddress linkAddress = (LinkAddress) obj;
-        return this.address.equals(linkAddress.address) &&
-            this.prefixLength == linkAddress.prefixLength &&
-            this.flags == linkAddress.flags &&
-            this.scope == linkAddress.scope;
+        return this.address.equals(linkAddress.address)
+                && this.prefixLength == linkAddress.prefixLength
+                && this.flags == linkAddress.flags
+                && this.scope == linkAddress.scope
+                && this.deprecationTime == linkAddress.deprecationTime
+                && this.expirationTime == linkAddress.expirationTime;
     }
 
     /**
@@ -276,7 +375,7 @@
      */
     @Override
     public int hashCode() {
-        return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope;
+        return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime);
     }
 
     /**
@@ -329,6 +428,25 @@
      * Returns the flags of this {@code LinkAddress}.
      */
     public int getFlags() {
+        int flags = this.flags;
+        if (deprecationTime != LIFETIME_UNKNOWN) {
+            if (SystemClock.elapsedRealtime() >= deprecationTime) {
+                flags |= IFA_F_DEPRECATED;
+            } else {
+                // If deprecation time is in the future, or permanent.
+                flags &= ~IFA_F_DEPRECATED;
+            }
+        }
+
+        if (expirationTime == LIFETIME_PERMANENT) {
+            flags |= IFA_F_PERMANENT;
+        } else if (expirationTime != LIFETIME_UNKNOWN) {
+            // If we know this address expired or will expire in the future, then this address
+            // should not be permanent.
+            flags &= ~IFA_F_PERMANENT;
+        }
+
+        // Do no touch the original flags. Return the adjusted flags here.
         return flags;
     }
 
@@ -340,7 +458,42 @@
     }
 
     /**
-     * Returns true if this {@code LinkAddress} is global scope and preferred.
+     * Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this
+     * {@link LinkAddress} will be or was deprecated. At the time existing connections can still use
+     * this address until it expires, but new connections should use the new address.
+     *
+     * @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
+     * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+     * will never be deprecated.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public long getDeprecationTime() {
+        return deprecationTime;
+    }
+
+    /**
+     * Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this
+     * {@link LinkAddress} will expire and be removed from the interface.
+     *
+     * @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
+     * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+     * will never expire.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public long getExpirationTime() {
+        return expirationTime;
+    }
+
+    /**
+     * Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently
+     * deprecated).
+     *
      * @hide
      */
     @TestApi
@@ -352,6 +505,7 @@
          * state has cleared either DAD has succeeded or failed, and both
          * flags are cleared regardless).
          */
+        int flags = getFlags();
         return (scope == RT_SCOPE_UNIVERSE
                 && !isIpv6ULA()
                 && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
@@ -373,6 +527,8 @@
         dest.writeInt(prefixLength);
         dest.writeInt(this.flags);
         dest.writeInt(scope);
+        dest.writeLong(deprecationTime);
+        dest.writeLong(expirationTime);
     }
 
     /**
@@ -392,7 +548,10 @@
                 int prefixLength = in.readInt();
                 int flags = in.readInt();
                 int scope = in.readInt();
-                return new LinkAddress(address, prefixLength, flags, scope);
+                long deprecationTime = in.readLong();
+                long expirationTime = in.readLong();
+                return new LinkAddress(address, prefixLength, flags, scope, deprecationTime,
+                        expirationTime);
             }
 
             public LinkAddress[] newArray(int size) {
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index ec773ef..d25ee0e 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -80,7 +80,8 @@
     private final transient boolean mParcelSensitiveFields;
 
     private static final int MIN_MTU    = 68;
-    private static final int MIN_MTU_V6 = 1280;
+    /* package-visibility - Used in other files (such as Ikev2VpnProfile) as minimum iface MTU. */
+    static final int MIN_MTU_V6 = 1280;
     private static final int MAX_MTU    = 10000;
 
     private static final int INET6_ADDR_LENGTH = 16;
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8ebd139..f94bdb7 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -26,6 +26,7 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Process;
 import android.util.ArraySet;
 import android.util.proto.ProtoOutputStream;
 
@@ -35,6 +36,9 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.StringJoiner;
@@ -55,7 +59,6 @@
  */
 public final class NetworkCapabilities implements Parcelable {
     private static final String TAG = "NetworkCapabilities";
-    private static final int INVALID_UID = -1;
 
     // Set to true when private DNS is broken.
     private boolean mPrivateDnsBroken;
@@ -82,7 +85,8 @@
         mTransportInfo = null;
         mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
         mUids = null;
-        mEstablishingVpnAppUid = INVALID_UID;
+        mAdministratorUids.clear();
+        mOwnerUid = Process.INVALID_UID;
         mSSID = null;
         mPrivateDnsBroken = false;
     }
@@ -100,7 +104,8 @@
         mTransportInfo = nc.mTransportInfo;
         mSignalStrength = nc.mSignalStrength;
         setUids(nc.mUids); // Will make the defensive copy
-        mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
+        setAdministratorUids(nc.mAdministratorUids);
+        mOwnerUid = nc.mOwnerUid;
         mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
         mSSID = nc.mSSID;
         mPrivateDnsBroken = nc.mPrivateDnsBroken;
@@ -805,31 +810,76 @@
     }
 
     /**
-     * UID of the app that manages this network, or INVALID_UID if none/unknown.
+     * UID of the app that owns this network, or INVALID_UID if none/unknown.
      *
-     * This field keeps track of the UID of the app that created this network and is in charge
-     * of managing it. In the practice, it is used to store the UID of VPN apps so it is named
-     * accordingly, but it may be renamed if other mechanisms are offered for third party apps
-     * to create networks.
-     *
-     * Because this field is only used in the services side (and to avoid apps being able to
-     * set this to whatever they want), this field is not parcelled and will not be conserved
-     * across the IPC boundary.
-     * @hide
+     * <p>This field keeps track of the UID of the app that created this network and is in charge of
+     * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
+     * VPN, or Carrier Service app managing a cellular data connection.
      */
-    private int mEstablishingVpnAppUid = INVALID_UID;
+    private int mOwnerUid = Process.INVALID_UID;
 
     /**
-     * Set the UID of the managing app.
-     * @hide
+     * Set the UID of the owner app.
      */
-    public void setEstablishingVpnAppUid(final int uid) {
-        mEstablishingVpnAppUid = uid;
+    public void setOwnerUid(final int uid) {
+        mOwnerUid = uid;
     }
 
-    /** @hide */
-    public int getEstablishingVpnAppUid() {
-        return mEstablishingVpnAppUid;
+    /**
+     * Retrieves the UID of the owner app.
+     */
+    public int getOwnerUid() {
+        return mOwnerUid;
+    }
+
+    /**
+     * UIDs of packages that are administrators of this network, or empty if none.
+     *
+     * <p>This field tracks the UIDs of packages that have permission to manage this network.
+     *
+     * <p>Network owners will also be listed as administrators.
+     *
+     * <p>For NetworkCapability instances being sent from the System Server, this value MUST be
+     * empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the
+     * receiving entity must have the ACCESS_FINE_LOCATION permission and target R+.
+     */
+    private final List<Integer> mAdministratorUids = new ArrayList<>();
+
+    /**
+     * Sets the list of UIDs that are administrators of this network.
+     *
+     * <p>UIDs included in administratorUids gain administrator privileges over this Network.
+     * Examples of UIDs that should be included in administratorUids are:
+     * <ul>
+     *     <li>Carrier apps with privileges for the relevant subscription
+     *     <li>Active VPN apps
+     *     <li>Other application groups with a particular Network-related role
+     * </ul>
+     *
+     * <p>In general, user-supplied networks (such as WiFi networks) do not have an administrator.
+     *
+     * <p>An app is granted owner privileges over Networks that it supplies. Owner privileges
+     * implicitly include administrator privileges.
+     *
+     * @param administratorUids the UIDs to be set as administrators of this Network.
+     * @hide
+     */
+    @SystemApi
+    public void setAdministratorUids(@NonNull final List<Integer> administratorUids) {
+        mAdministratorUids.clear();
+        mAdministratorUids.addAll(administratorUids);
+    }
+
+    /**
+     * Retrieves the list of UIDs that are administrators of this Network.
+     *
+     * @return the List of UIDs that are administrators of this Network
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    public List<Integer> getAdministratorUids() {
+        return Collections.unmodifiableList(mAdministratorUids);
     }
 
     /**
@@ -1102,7 +1152,7 @@
      * member is null, then the network is not restricted by app UID. If it's an empty list, then
      * it means nobody can use it.
      * As a special exception, the app managing this network (as identified by its UID stored in
-     * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in
+     * mOwnerUid) can always see this network. This is embodied by a special check in
      * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
      * to the app that manages it as determined by #appliesToUid.
      * <p>
@@ -1209,7 +1259,7 @@
      * in the passed nc (representing the UIDs that this network is available to).
      * <p>
      * As a special exception, the UID that created the passed network (as represented by its
-     * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN
+     * mOwnerUid field) always satisfies a NetworkRequest requiring it (of LISTEN
      * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
      * can see its own network when it listens for it.
      * <p>
@@ -1220,7 +1270,7 @@
     public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) {
         if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
         for (UidRange requiredRange : mUids) {
-            if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
+            if (requiredRange.contains(nc.mOwnerUid)) return true;
             if (!nc.appliesToUidRange(requiredRange)) {
                 return false;
             }
@@ -1471,6 +1521,7 @@
     public int describeContents() {
         return 0;
     }
+
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(mNetworkCapabilities);
@@ -1484,6 +1535,8 @@
         dest.writeArraySet(mUids);
         dest.writeString(mSSID);
         dest.writeBoolean(mPrivateDnsBroken);
+        dest.writeList(mAdministratorUids);
+        dest.writeInt(mOwnerUid);
     }
 
     public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1504,6 +1557,8 @@
                         null /* ClassLoader, null for default */);
                 netCap.mSSID = in.readString();
                 netCap.mPrivateDnsBroken = in.readBoolean();
+                netCap.setAdministratorUids(in.readArrayList(null));
+                netCap.mOwnerUid = in.readInt();
                 return netCap;
             }
             @Override
@@ -1553,8 +1608,12 @@
                 sb.append(" Uids: <").append(mUids).append(">");
             }
         }
-        if (mEstablishingVpnAppUid != INVALID_UID) {
-            sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
+        if (mOwnerUid != Process.INVALID_UID) {
+            sb.append(" OwnerUid: ").append(mOwnerUid);
+        }
+
+        if (!mAdministratorUids.isEmpty()) {
+            sb.append(" AdministratorUids: ").append(mAdministratorUids);
         }
 
         if (null != mSSID) {
diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java
new file mode 100644
index 0000000..fbae637
--- /dev/null
+++ b/core/java/android/net/PlatformVpnProfile.java
@@ -0,0 +1,107 @@
+/*
+ * 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.net;
+
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_PSK;
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_RSA;
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import com.android.internal.net.VpnProfile;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.GeneralSecurityException;
+
+/**
+ * PlatformVpnProfile represents a configuration for a platform-based VPN implementation.
+ *
+ * <p>Platform-based VPNs allow VPN applications to provide configuration and authentication options
+ * to leverage the Android OS' implementations of well-defined control plane (authentication, key
+ * negotiation) and data plane (per-packet encryption) protocols to simplify the creation of VPN
+ * tunnels. In contrast, {@link VpnService} based VPNs must implement both the control and data
+ * planes on a per-app basis.
+ *
+ * @see Ikev2VpnProfile
+ */
+public abstract class PlatformVpnProfile {
+    /**
+     * Alias to platform VPN related types from VpnProfile, for API use.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        TYPE_IKEV2_IPSEC_USER_PASS,
+        TYPE_IKEV2_IPSEC_PSK,
+        TYPE_IKEV2_IPSEC_RSA,
+    })
+    public static @interface PlatformVpnType {}
+
+    public static final int TYPE_IKEV2_IPSEC_USER_PASS = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+    public static final int TYPE_IKEV2_IPSEC_PSK = VpnProfile.TYPE_IKEV2_IPSEC_PSK;
+    public static final int TYPE_IKEV2_IPSEC_RSA = VpnProfile.TYPE_IKEV2_IPSEC_RSA;
+
+    /** @hide */
+    @PlatformVpnType protected final int mType;
+
+    /** @hide */
+    PlatformVpnProfile(@PlatformVpnType int type) {
+        mType = type;
+    }
+    /** Returns the profile integer type. */
+    @PlatformVpnType
+    public final int getType() {
+        return mType;
+    }
+
+    /** Returns a type string describing the VPN profile type */
+    @NonNull
+    public final String getTypeString() {
+        switch (mType) {
+            case TYPE_IKEV2_IPSEC_USER_PASS:
+                return "IKEv2/IPsec Username/Password";
+            case TYPE_IKEV2_IPSEC_PSK:
+                return "IKEv2/IPsec Preshared key";
+            case TYPE_IKEV2_IPSEC_RSA:
+                return "IKEv2/IPsec RSA Digital Signature";
+            default:
+                return "Unknown VPN profile type";
+        }
+    }
+
+    /** @hide */
+    @NonNull
+    public abstract VpnProfile toVpnProfile() throws IOException, GeneralSecurityException;
+
+    /** @hide */
+    @NonNull
+    public static PlatformVpnProfile fromVpnProfile(@NonNull VpnProfile profile)
+            throws IOException, GeneralSecurityException {
+        switch (profile.type) {
+            case TYPE_IKEV2_IPSEC_USER_PASS: // fallthrough
+            case TYPE_IKEV2_IPSEC_PSK: // fallthrough
+            case TYPE_IKEV2_IPSEC_RSA:
+                return Ikev2VpnProfile.fromVpnProfile(profile);
+            default:
+                throw new IllegalArgumentException("Unknown VPN Profile type");
+        }
+    }
+}
diff --git a/core/java/android/net/StringNetworkSpecifier.java b/core/java/android/net/StringNetworkSpecifier.java
index 83dbc63..6ae5971 100644
--- a/core/java/android/net/StringNetworkSpecifier.java
+++ b/core/java/android/net/StringNetworkSpecifier.java
@@ -17,7 +17,6 @@
 package android.net;
 
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -27,7 +26,6 @@
 import java.util.Objects;
 
 /** @hide */
-@SystemApi
 public final class StringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
     /**
      * Arbitrary string used to pass (additional) information to the network factory.
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
new file mode 100644
index 0000000..f95807a
--- /dev/null
+++ b/core/java/android/net/VpnManager.java
@@ -0,0 +1,88 @@
+/*
+ * 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.net;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * This class provides an interface for apps to manage platform VPN profiles
+ *
+ * <p>Apps can use this API to provide profiles with which the platform can set up a VPN without
+ * further app intermediation. When a VPN profile is present and the app is selected as an always-on
+ * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the
+ * app (unlike VpnService).
+ *
+ * <p>VPN apps using supported protocols should preferentially use this API over the {@link
+ * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user
+ * the guarantee that VPN network traffic is not subjected to on-device packet interception.
+ *
+ * @see Ikev2VpnProfile
+ */
+public class VpnManager {
+    @NonNull private final Context mContext;
+    @NonNull private final IConnectivityManager mService;
+
+    /**
+     * Create an instance of the VpnManger with the given context.
+     *
+     * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the
+     * {@link Context.getSystemService()} method call.
+     *
+     * @hide
+     */
+    public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
+        mContext = checkNotNull(ctx, "missing Context");
+        mService = checkNotNull(service, "missing IConnectivityManager");
+    }
+
+    /**
+     * Install a VpnProfile configuration keyed on the calling app's package name.
+     *
+     * @param profile the PlatformVpnProfile provided by this package. Will override any previous
+     *     PlatformVpnProfile stored for this package.
+     * @return an intent to request user consent if needed (null otherwise).
+     */
+    @Nullable
+    public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    /** Delete the VPN profile configuration that was provisioned by the calling app */
+    public void deleteProvisionedVpnProfile() {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    /**
+     * Request the startup of a previously provisioned VPN.
+     *
+     * @throws SecurityException exception if user or device settings prevent this VPN from being
+     *     setup, or if user consent has not been granted
+     */
+    public void startProvisionedVpnProfile() {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+
+    /** Tear down the VPN provided by the calling app (if any) */
+    public void stopProvisionedVpnProfile() {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index febc36c..68c2764 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1409,6 +1409,7 @@
      * @throws UnsupportedOperationException if userspace reboot was requested on a device that
      *                                       doesn't support it.
      */
+    @RequiresPermission(permission.REBOOT)
     public void reboot(@Nullable String reason) {
         if (REBOOT_USERSPACE.equals(reason) && !isRebootingUserspaceSupported()) {
             throw new UnsupportedOperationException(
@@ -1428,6 +1429,7 @@
      * </p>
      * @hide
      */
+    @RequiresPermission(permission.REBOOT)
     public void rebootSafeMode() {
         try {
             mService.rebootSafeMode(false, true);
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 92fecad..bbc936d 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -193,4 +193,5 @@
     void startCheckpoint(int numTries) = 85;
     boolean needsCheckpoint() = 86;
     void abortChanges(in String message, boolean retry) = 87;
+    void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1f3ae09..b22db2e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -81,7 +81,6 @@
 import android.os.UserHandle;
 import android.provider.SettingsValidators.Validator;
 import android.speech.tts.TextToSpeech;
-import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.util.AndroidException;
 import android.util.ArrayMap;
@@ -8571,6 +8570,7 @@
          *
          * @hide
          */
+        @SystemApi
         public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
 
         /**
@@ -13320,16 +13320,17 @@
 
         /**
          * Whether the Volte is enabled. If this setting is not set then we use the Carrier Config
-         * value {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+         * value
+         * {@link android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
          * <p>
          * Type: int (0 for false, 1 for true)
          * @hide
-         * @deprecated Use {@link android.telephony.SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+         * @deprecated Use {@link android.provider.Telephony.SimInfo#ENHANCED_4G_MODE_ENABLED}
          * instead.
          */
         @Deprecated
         public static final String ENHANCED_4G_MODE_ENABLED =
-                SubscriptionManager.ENHANCED_4G_MODE_ENABLED;
+                Telephony.SimInfo.ENHANCED_4G_MODE_ENABLED;
 
         /**
          * Whether VT (Video Telephony over IMS) is enabled
@@ -13337,10 +13338,10 @@
          * Type: int (0 for false, 1 for true)
          *
          * @hide
-         * @deprecated Use {@link android.telephony.SubscriptionManager#VT_IMS_ENABLED} instead.
+         * @deprecated Use {@link android.provider.Telephony.SimInfo#VT_IMS_ENABLED} instead.
          */
         @Deprecated
-        public static final String VT_IMS_ENABLED = SubscriptionManager.VT_IMS_ENABLED;
+        public static final String VT_IMS_ENABLED = Telephony.SimInfo.VT_IMS_ENABLED;
 
         /**
          * Whether WFC is enabled
@@ -13348,10 +13349,10 @@
          * Type: int (0 for false, 1 for true)
          *
          * @hide
-         * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ENABLED} instead.
+         * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ENABLED} instead.
          */
         @Deprecated
-        public static final String WFC_IMS_ENABLED = SubscriptionManager.WFC_IMS_ENABLED;
+        public static final String WFC_IMS_ENABLED = Telephony.SimInfo.WFC_IMS_ENABLED;
 
         /**
          * WFC mode on home/non-roaming network.
@@ -13359,10 +13360,10 @@
          * Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
          *
          * @hide
-         * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_MODE} instead.
+         * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_MODE} instead.
          */
         @Deprecated
-        public static final String WFC_IMS_MODE = SubscriptionManager.WFC_IMS_MODE;
+        public static final String WFC_IMS_MODE = Telephony.SimInfo.WFC_IMS_MODE;
 
         /**
          * WFC mode on roaming network.
@@ -13370,11 +13371,11 @@
          * Type: int - see {@link #WFC_IMS_MODE} for values
          *
          * @hide
-         * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_MODE}
+         * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_MODE}
          * instead.
          */
         @Deprecated
-        public static final String WFC_IMS_ROAMING_MODE = SubscriptionManager.WFC_IMS_ROAMING_MODE;
+        public static final String WFC_IMS_ROAMING_MODE = Telephony.SimInfo.WFC_IMS_ROAMING_MODE;
 
         /**
          * Whether WFC roaming is enabled
@@ -13382,12 +13383,12 @@
          * Type: int (0 for false, 1 for true)
          *
          * @hide
-         * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_ENABLED}
+         * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_ENABLED}
          * instead
          */
         @Deprecated
         public static final String WFC_IMS_ROAMING_ENABLED =
-                SubscriptionManager.WFC_IMS_ROAMING_ENABLED;
+                Telephony.SimInfo.WFC_IMS_ROAMING_ENABLED;
 
         /**
          * Whether user can enable/disable LTE as a preferred network. A carrier might control
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 90ac821..1611d28 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -37,11 +37,13 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
+import android.telephony.CarrierConfigManager;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SmsMessage;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.UiccAccessRule;
 import android.text.TextUtils;
 import android.util.Patterns;
 
@@ -4928,5 +4930,414 @@
          */
         @NonNull
         public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+        /**
+         * TelephonyProvider unique key column name is the subscription id.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+
+        /**
+         * TelephonyProvider column name for a unique identifier for the subscription within the
+         * specific subscription type. For example, it contains SIM ICC Identifier subscriptions
+         * on Local SIMs. and Mac-address for Remote-SIM Subscriptions for Bluetooth devices.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String ICC_ID = "icc_id";
+
+        /**
+         * TelephonyProvider column name for user SIM_SlOT_INDEX
+         * <P>Type: INTEGER (int)</P>
+         */
+        public static final String SIM_SLOT_INDEX = "sim_id";
+
+        /**
+         * SIM is not inserted
+         */
+        public static final int SIM_NOT_INSERTED = -1;
+
+        /**
+         * TelephonyProvider column name Subscription-type.
+         * <P>Type: INTEGER (int)</P> {@link #SUBSCRIPTION_TYPE_LOCAL_SIM} for Local-SIM
+         * Subscriptions, {@link #SUBSCRIPTION_TYPE_REMOTE_SIM} for Remote-SIM Subscriptions.
+         * Default value is 0.
+         */
+        public static final String SUBSCRIPTION_TYPE = "subscription_type";
+
+        /**
+         * This constant is to designate a subscription as a Local-SIM Subscription.
+         * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on
+         * the device.
+         * </p>
+         */
+        public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+
+        /**
+         * This constant is to designate a subscription as a Remote-SIM Subscription.
+         * <p>
+         * A Remote-SIM subscription is for a SIM on a phone connected to this device via some
+         * connectivity mechanism, for example bluetooth. Similar to Local SIM, this subscription
+         * can be used for SMS, Voice and data by proxying data through the connected device.
+         * Certain data of the SIM, such as IMEI, are not accessible for Remote SIMs.
+         * </p>
+         *
+         * <p>
+         * A Remote-SIM is available only as long the phone stays connected to this device.
+         * When the phone disconnects, Remote-SIM subscription is removed from this device and is
+         * no longer known. All data associated with the subscription, such as stored SMS, call
+         * logs, contacts etc, are removed from this device.
+         * </p>
+         *
+         * <p>
+         * If the phone re-connects to this device, a new Remote-SIM subscription is created for
+         * the phone. The Subscription Id associated with the new subscription is different from
+         * the Subscription Id of the previous Remote-SIM subscription created (and removed) for the
+         * phone; i.e., new Remote-SIM subscription treats the reconnected phone as a Remote-SIM
+         * that was never seen before.
+         * </p>
+         */
+        public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
+
+        /**
+         * TelephonyProvider column name data_enabled_override_rules.
+         * It's a list of rules for overriding data enabled settings. The syntax is
+         * For example, "mms=nonDefault" indicates enabling data for mms in non-default
+         * subscription.
+         * "default=nonDefault&inVoiceCall" indicates enabling data for internet in non-default
+         * subscription and while is in voice call.
+         *
+         * Default value is empty string.
+         */
+        public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+
+        /**
+         * TelephonyProvider column name for user displayed name.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String DISPLAY_NAME = "display_name";
+
+        /**
+         * TelephonyProvider column name for the service provider name for the SIM.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String CARRIER_NAME = "carrier_name";
+
+        /**
+         * TelephonyProvider column name for source of the user displayed name.
+         * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below
+         */
+        public static final String NAME_SOURCE = "name_source";
+
+        /** The name_source is the default, which is from the carrier id. */
+        public static final int NAME_SOURCE_DEFAULT = 0;
+
+        /**
+         * The name_source is from SIM EF_SPN.
+         */
+        public static final int NAME_SOURCE_SIM_SPN = 1;
+
+        /**
+         * The name_source is from user input
+         */
+        public static final int NAME_SOURCE_USER_INPUT = 2;
+
+        /**
+         * The name_source is carrier (carrier app, carrier config, etc.)
+         */
+        public static final int NAME_SOURCE_CARRIER = 3;
+
+        /**
+         * The name_source is from SIM EF_PNN.
+         */
+        public static final int NAME_SOURCE_SIM_PNN = 4;
+
+        /**
+         * TelephonyProvider column name for the color of a SIM.
+         * <P>Type: INTEGER (int)</P>
+         */
+        public static final String COLOR = "color";
+
+        /** TelephonyProvider column name for the default color of a SIM {@hide} */
+        public static final int COLOR_DEFAULT = 0;
+
+        /**
+         * TelephonyProvider column name for the phone number of a SIM.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String NUMBER = "number";
+
+        /**
+         * TelephonyProvider column name for the number display format of a SIM.
+         * <P>Type: INTEGER (int)</P>
+         * @hide
+         */
+        public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+        /**
+         * TelephonyProvider column name for the default display format of a SIM
+         * @hide
+         */
+        public static final int DISPLAY_NUMBER_DEFAULT = 1;
+
+        /**
+         * TelephonyProvider column name for whether data roaming is enabled.
+         * <P>Type: INTEGER (int)</P>
+         */
+        public static final String DATA_ROAMING = "data_roaming";
+
+        /** Indicates that data roaming is enabled for a subscription */
+        public static final int DATA_ROAMING_ENABLE = 1;
+
+        /** Indicates that data roaming is disabled for a subscription */
+        public static final int DATA_ROAMING_DISABLE = 0;
+
+        /** TelephonyProvider column name for default data roaming setting: disable */
+        public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+        /**
+         * TelephonyProvider column name for subscription carrier id.
+         * @see TelephonyManager#getSimCarrierId()
+         * <p>Type: INTEGER (int) </p>
+         */
+        public static final String CARRIER_ID = "carrier_id";
+
+        /**
+         * A comma-separated list of EHPLMNs associated with the subscription
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String EHPLMNS = "ehplmns";
+
+        /**
+         * A comma-separated list of HPLMNs associated with the subscription
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String HPLMNS = "hplmns";
+
+        /**
+         * TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String MCC_STRING = "mcc_string";
+
+        /**
+         * TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String MNC_STRING = "mnc_string";
+
+        /**
+         * TelephonyProvider column name for the MCC associated with a SIM.
+         * <P>Type: INTEGER (int)</P>
+         */
+        public static final String MCC = "mcc";
+
+        /**
+         * TelephonyProvider column name for the MNC associated with a SIM.
+         * <P>Type: INTEGER (int)</P>
+         */
+        public static final String MNC = "mnc";
+
+        /**
+         * TelephonyProvider column name for the iso country code associated with a SIM.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String ISO_COUNTRY_CODE = "iso_country_code";
+
+        /**
+         * TelephonyProvider column name for the sim provisioning status associated with a SIM.
+         * <P>Type: INTEGER (int)</P>
+         * @hide
+         */
+        public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+
+        /** The sim is provisioned {@hide} */
+        public static final int SIM_PROVISIONED = 0;
+
+        /**
+         * TelephonyProvider column name for whether a subscription is embedded (that is, present on
+         * an eSIM).
+         * <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
+         */
+        public static final String IS_EMBEDDED = "is_embedded";
+
+        /**
+         * TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of
+         * the current enabled profile on the card, while for eUICC card it is the EID of the card.
+         * <P>Type: TEXT (String)</P>
+         */
+        public static final String CARD_ID = "card_id";
+
+        /**
+         * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+         * {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1.
+         * <p>TYPE: BLOB
+         */
+        public static final String ACCESS_RULES = "access_rules";
+
+        /**
+         * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+         * {@link UiccAccessRule#encodeRules} but for the rules that come from CarrierConfigs.
+         * Only present if there are access rules in CarrierConfigs
+         * <p>TYPE: BLOB
+         */
+        public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
+                "access_rules_from_carrier_configs";
+
+        /**
+         * TelephonyProvider column name identifying whether an embedded subscription is on a
+         * removable card. Such subscriptions are marked inaccessible as soon as the current card
+         * is removed. Otherwise, they will remain accessible unless explicitly deleted. Only
+         * present if {@link #IS_EMBEDDED} is 1.
+         * <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
+         */
+        public static final String IS_REMOVABLE = "is_removable";
+
+        /** TelephonyProvider column name for extreme threat in CB settings */
+        public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+
+        /** TelephonyProvider column name for severe threat in CB settings */
+        public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+
+        /** TelephonyProvider column name for amber alert in CB settings */
+        public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+
+        /** TelephonyProvider column name for emergency alert in CB settings */
+        public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+
+        /** TelephonyProvider column name for alert sound duration in CB settings */
+        public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+
+        /** TelephonyProvider column name for alert reminder interval in CB settings */
+        public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+
+        /** TelephonyProvider column name for enabling vibrate in CB settings */
+        public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+
+        /** TelephonyProvider column name for enabling alert speech in CB settings */
+        public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+
+        /** TelephonyProvider column name for ETWS test alert in CB settings */
+        public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+
+        /** TelephonyProvider column name for enable channel50 alert in CB settings */
+        public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+        /** TelephonyProvider column name for CMAS test alert in CB settings */
+        public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+
+        /** TelephonyProvider column name for Opt out dialog in CB settings */
+        public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
+        /**
+         * TelephonyProvider column name for enable Volte.
+         *
+         * If this setting is not initialized (set to -1)  then we use the Carrier Config value
+         * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+         */
+        public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+
+        /** TelephonyProvider column name for enable VT (Video Telephony over IMS) */
+        public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+        /** TelephonyProvider column name for enable Wifi calling */
+        public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+
+        /** TelephonyProvider column name for Wifi calling mode */
+        public static final String WFC_IMS_MODE = "wfc_ims_mode";
+
+        /** TelephonyProvider column name for Wifi calling mode in roaming */
+        public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+
+        /** TelephonyProvider column name for enable Wifi calling in roaming */
+        public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+
+        /**
+         * Determines if the user has enabled IMS RCS User Capability Exchange (UCE) for this
+         * subscription.
+         */
+        public static final String IMS_RCS_UCE_ENABLED = "ims_rcs_uce_enabled";
+
+        /**
+         * TelephonyProvider column name for whether a subscription is opportunistic, that is,
+         * whether the network it connects to is limited in functionality or coverage.
+         * For example, CBRS.
+         * <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
+         */
+        public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+
+        /**
+         * TelephonyProvider column name for group ID. Subscriptions with same group ID
+         * are considered bundled together, and should behave as a single subscription at
+         * certain scenarios.
+         */
+        public static final String GROUP_UUID = "group_uuid";
+
+        /**
+         * TelephonyProvider column name for group owner. It's the package name who created
+         * the subscription group.
+         */
+        public static final String GROUP_OWNER = "group_owner";
+
+        /**
+         * TelephonyProvider column name for whether a subscription is metered or not, that is,
+         * whether the network it connects to charges for subscription or not. For example, paid
+         * CBRS or unpaid.
+         * @hide
+         */
+        public static final String IS_METERED = "is_metered";
+
+        /**
+         * TelephonyProvider column name for the profile class of a subscription
+         * Only present if {@link #IS_EMBEDDED} is 1.
+         * <P>Type: INTEGER (int)</P>
+         */
+        public static final String PROFILE_CLASS = "profile_class";
+
+        /**
+         * A testing profile can be pre-loaded or downloaded onto
+         * the eUICC and provides connectivity to test equipment
+         * for the purpose of testing the device and the eUICC. It
+         * is not intended to store any operator credentials.
+         */
+        public static final int PROFILE_CLASS_TESTING = 0;
+
+        /**
+         * A provisioning profile is pre-loaded onto the eUICC and
+         * provides connectivity to a mobile network solely for the
+         * purpose of provisioning profiles.
+         */
+        public static final int PROFILE_CLASS_PROVISIONING = 1;
+
+        /**
+         * An operational profile can be pre-loaded or downloaded
+         * onto the eUICC and provides services provided by the
+         * operator.
+         */
+        public static final int PROFILE_CLASS_OPERATIONAL = 2;
+
+        /**
+         * The profile class is unset. This occurs when profile class
+         * info is not available. The subscription either has no profile
+         * metadata or the profile metadata did not encode profile class.
+         */
+        public static final int PROFILE_CLASS_UNSET = -1;
+
+        /** Default profile class */
+        public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+
+        /**
+         * IMSI (International Mobile Subscriber Identity).
+         * <P>Type: TEXT </P>
+         */
+        public static final String IMSI = "imsi";
+
+        /** Whether uicc applications is set to be enabled or disabled. By default it's enabled. */
+        public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+
+        /**
+         * TelephonyProvider column name for allowed network types. Indicate which network types
+         * are allowed. Default is -1.
+         */
+        public static final String ALLOWED_NETWORK_TYPES = "allowed_network_types";
     }
 }
diff --git a/core/java/android/se/omapi/ISecureElementReader.aidl b/core/java/android/se/omapi/ISecureElementReader.aidl
index a312c44..41244ab 100644
--- a/core/java/android/se/omapi/ISecureElementReader.aidl
+++ b/core/java/android/se/omapi/ISecureElementReader.aidl
@@ -48,4 +48,10 @@
      */
     void closeSessions();
 
+    /**
+     * Closes all the sessions opened on this reader and resets the reader.
+     * All the channels opened by all these sessions will be closed.
+     * @return true if the reset is successful, false otherwise.
+     */
+    boolean reset();
 }
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 80262f7..7f68d91 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -23,6 +23,8 @@
 package android.se.omapi;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.util.Log;
@@ -150,4 +152,25 @@
             } catch (RemoteException ignore) { }
         }
     }
+
+    /**
+     * Close all the sessions opened on this reader and reset the reader.
+     * All the channels opened by all these sessions will be closed.
+     * @return <code>true</code> if reset success, <code>false</code> otherwise.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED)
+    public boolean reset() {
+        if (!mService.isConnected()) {
+            Log.e(TAG, "service is not connected");
+            return false;
+        }
+        synchronized (mLock) {
+            try {
+                closeSessions();
+                return mReader.reset();
+            } catch (RemoteException ignore) {return false;}
+        }
+    }
 }
diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index 5330cff..f67af85 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -212,20 +212,16 @@
 
     private int getUiOptionsAsFlags() {
         int uiOptionsAsFlags = 0;
-        try {
-            ContentResolver contentResolver = mContext.getContentResolver();
-            int inversionEnabled = Settings.Secure.getInt(contentResolver,
-                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
-            if (inversionEnabled == 1) {
-                uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
-            }
-            float fontScale = Settings.System.getFloat(contentResolver,
-                    Settings.System.FONT_SCALE);
-            if (fontScale > 1.0) {
-                uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
-            }
-        } catch (SettingNotFoundException e) {
-            Log.w(TAG, "Unexpected SettingNotFoundException");
+        ContentResolver contentResolver = mContext.getContentResolver();
+        int inversionEnabled = Settings.Secure.getInt(contentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0);
+        if (inversionEnabled == 1) {
+            uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
+        }
+        float fontScale = Settings.System.getFloat(contentResolver,
+                Settings.System.FONT_SCALE, (float) 1.0);
+        if (fontScale > 1.0) {
+            uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
         }
         return uiOptionsAsFlags;
     }
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index f886cf5..03e7361 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -168,6 +168,16 @@
     public static final int LISTEN_SIGNAL_STRENGTHS                         = 0x00000100;
 
     /**
+     * Listen for always reported changes of the network signal strengths (cellular),
+     * even in some situations such as the screen of the device is off.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+    @SystemApi
+    public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH          = 0x00000200;
+
+    /**
      * Listen for changes to observed cell info.
      *
      * @see #onCellInfoChanged
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 4bb012a..bbae027 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.net;
 
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.net.ProxyInfo;
 import android.os.Build;
@@ -23,21 +24,34 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.net.InetAddress;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
 
 /**
- * Parcel-like entity class for VPN profiles. To keep things simple, all
- * fields are package private. Methods are provided for serialization, so
- * storage can be implemented easily. Two rules are set for this class.
- * First, all fields must be kept non-null. Second, always make a copy
- * using clone() before modifying.
+ * Profile storage class for a platform VPN.
+ *
+ * <p>This class supports both the Legacy VPN, as well as application-configurable platform VPNs
+ * (such as IKEv2/IPsec).
+ *
+ * <p>This class is serialized and deserialized via the {@link #encode()} and {@link #decode()}
+ * functions for persistent storage in the Android Keystore. The encoding is entirely custom, but
+ * must be kept for backward compatibility for devices upgrading between Android versions.
  *
  * @hide
  */
-public class VpnProfile implements Cloneable, Parcelable {
+public final class VpnProfile implements Cloneable, Parcelable {
     private static final String TAG = "VpnProfile";
 
+    @VisibleForTesting static final String VALUE_DELIMITER = "\0";
+    @VisibleForTesting static final String LIST_DELIMITER = ",";
+
     // Match these constants with R.array.vpn_types.
     public static final int TYPE_PPTP = 0;
     public static final int TYPE_L2TP_IPSEC_PSK = 1;
@@ -45,39 +59,85 @@
     public static final int TYPE_IPSEC_XAUTH_PSK = 3;
     public static final int TYPE_IPSEC_XAUTH_RSA = 4;
     public static final int TYPE_IPSEC_HYBRID_RSA = 5;
-    public static final int TYPE_MAX = 5;
+    public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6;
+    public static final int TYPE_IKEV2_IPSEC_PSK = 7;
+    public static final int TYPE_IKEV2_IPSEC_RSA = 8;
+    public static final int TYPE_MAX = 8;
 
     // Match these constants with R.array.vpn_proxy_settings.
     public static final int PROXY_NONE = 0;
     public static final int PROXY_MANUAL = 1;
 
+    private static final String ENCODED_NULL_PROXY_INFO = "\0\0\0\0";
+
     // Entity fields.
     @UnsupportedAppUsage
-    public final String key;           // -1
+    public final String key;                                   // -1
+
     @UnsupportedAppUsage
-    public String name = "";           // 0
+    public String name = "";                                   // 0
+
     @UnsupportedAppUsage
-    public int type = TYPE_PPTP;       // 1
+    public int type = TYPE_PPTP;                               // 1
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public String server = "";         // 2
+    public String server = "";                                 // 2
+
     @UnsupportedAppUsage
-    public String username = "";       // 3
-    public String password = "";       // 4
-    public String dnsServers = "";     // 5
-    public String searchDomains = "";  // 6
-    public String routes = "";         // 7
-    public boolean mppe = true;        // 8
-    public String l2tpSecret = "";     // 9
-    public String ipsecIdentifier = "";// 10
-    public String ipsecSecret = "";    // 11
-    public String ipsecUserCert = "";  // 12
-    public String ipsecCaCert = "";    // 13
-    public String ipsecServerCert = "";// 14
-    public ProxyInfo proxy = null;     // 15~18
+    public String username = "";                               // 3
+    public String password = "";                               // 4
+    public String dnsServers = "";                             // 5
+    public String searchDomains = "";                          // 6
+    public String routes = "";                                 // 7
+    public boolean mppe = true;                                // 8
+    public String l2tpSecret = "";                             // 9
+    public String ipsecIdentifier = "";                        // 10
+
+    /**
+     * The RSA private key or pre-shared key used for authentication.
+     *
+     * <p>If areAuthParamsInline is {@code true}, this String will be either:
+     *
+     * <ul>
+     *   <li>If this is an IKEv2 RSA profile: a PKCS#8 encoded {@link java.security.PrivateKey}
+     *   <li>If this is an IKEv2 PSK profile: a string value representing the PSK.
+     * </ul>
+     */
+    public String ipsecSecret = "";                            // 11
+
+    /**
+     * The RSA certificate to be used for digital signature authentication.
+     *
+     * <p>If areAuthParamsInline is {@code true}, this String will be a pem-encoded {@link
+     * java.security.X509Certificate}
+     */
+    public String ipsecUserCert = "";                          // 12
+
+    /**
+     * The RSA certificate that should be used to verify the server's end/target certificate.
+     *
+     * <p>If areAuthParamsInline is {@code true}, this String will be a pem-encoded {@link
+     * java.security.X509Certificate}
+     */
+    public String ipsecCaCert = "";                            // 13
+    public String ipsecServerCert = "";                        // 14
+    public ProxyInfo proxy = null;                             // 15~18
+
+    /**
+     * The list of allowable algorithms.
+     *
+     * <p>This list is validated in the setter to ensure that encoding characters (list, value
+     * delimiters) are not present in the algorithm names. See {@link #validateAllowedAlgorithms()}
+     */
+    private List<String> mAllowedAlgorithms = new ArrayList<>(); // 19
+    public boolean isBypassable = false;                       // 20
+    public boolean isMetered = false;                          // 21
+    public int maxMtu = 1400;                                  // 22
+    public boolean areAuthParamsInline = false;                   // 23
 
     // Helper fields.
     @UnsupportedAppUsage
-    public boolean saveLogin = false;
+    public transient boolean saveLogin = false;
 
     public VpnProfile(String key) {
         this.key = key;
@@ -103,6 +163,34 @@
         ipsecServerCert = in.readString();
         saveLogin = in.readInt() != 0;
         proxy = in.readParcelable(null);
+        mAllowedAlgorithms = new ArrayList<>();
+        in.readList(mAllowedAlgorithms, null);
+        isBypassable = in.readBoolean();
+        isMetered = in.readBoolean();
+        maxMtu = in.readInt();
+        areAuthParamsInline = in.readBoolean();
+    }
+
+    /**
+     * Retrieves the list of allowed algorithms.
+     *
+     * <p>The contained elements are as listed in {@link IpSecAlgorithm}
+     */
+    public List<String> getAllowedAlgorithms() {
+        return Collections.unmodifiableList(mAllowedAlgorithms);
+    }
+
+    /**
+     * Validates and sets the list of algorithms that can be used for the IPsec transforms.
+     *
+     * @param allowedAlgorithms the list of allowable algorithms, as listed in {@link
+     *     IpSecAlgorithm}.
+     * @throws IllegalArgumentException if any delimiters are used in algorithm names. See {@link
+     *     #VALUE_DELIMITER} and {@link LIST_DELIMITER}.
+     */
+    public void setAllowedAlgorithms(List<String> allowedAlgorithms) {
+        validateAllowedAlgorithms(allowedAlgorithms);
+        mAllowedAlgorithms = allowedAlgorithms;
     }
 
     @Override
@@ -125,8 +213,18 @@
         out.writeString(ipsecServerCert);
         out.writeInt(saveLogin ? 1 : 0);
         out.writeParcelable(proxy, flags);
+        out.writeList(mAllowedAlgorithms);
+        out.writeBoolean(isBypassable);
+        out.writeBoolean(isMetered);
+        out.writeInt(maxMtu);
+        out.writeBoolean(areAuthParamsInline);
     }
 
+    /**
+     * Decodes a VpnProfile instance from the encoded byte array.
+     *
+     * <p>See {@link #encode()}
+     */
     @UnsupportedAppUsage
     public static VpnProfile decode(String key, byte[] value) {
         try {
@@ -134,9 +232,11 @@
                 return null;
             }
 
-            String[] values = new String(value, StandardCharsets.UTF_8).split("\0", -1);
-            // There can be 14 - 19 Bytes in values.length.
-            if (values.length < 14 || values.length > 19) {
+            String[] values = new String(value, StandardCharsets.UTF_8).split(VALUE_DELIMITER, -1);
+            // Acceptable numbers of values are:
+            // 14-19: Standard profile, with option for serverCert, proxy
+            // 24: Standard profile with serverCert, proxy and platform-VPN parameters.
+            if ((values.length < 14 || values.length > 19) && values.length != 24) {
                 return null;
             }
 
@@ -164,13 +264,23 @@
                 String port = (values.length > 16) ? values[16] : "";
                 String exclList = (values.length > 17) ? values[17] : "";
                 String pacFileUrl = (values.length > 18) ? values[18] : "";
-                if (pacFileUrl.isEmpty()) {
+                if (!host.isEmpty() || !port.isEmpty() || !exclList.isEmpty()) {
                     profile.proxy = new ProxyInfo(host, port.isEmpty() ?
                             0 : Integer.parseInt(port), exclList);
-                } else {
+                } else if (!pacFileUrl.isEmpty()) {
                     profile.proxy = new ProxyInfo(pacFileUrl);
                 }
-            } // else profle.proxy = null
+            } // else profile.proxy = null
+
+            // Either all must be present, or none must be.
+            if (values.length >= 24) {
+                profile.mAllowedAlgorithms = Arrays.asList(values[19].split(LIST_DELIMITER));
+                profile.isBypassable = Boolean.parseBoolean(values[20]);
+                profile.isMetered = Boolean.parseBoolean(values[21]);
+                profile.maxMtu = Integer.parseInt(values[22]);
+                profile.areAuthParamsInline = Boolean.parseBoolean(values[23]);
+            }
+
             profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
             return profile;
         } catch (Exception e) {
@@ -179,36 +289,52 @@
         return null;
     }
 
+    /**
+     * Encodes a VpnProfile instance to a byte array for storage.
+     *
+     * <p>See {@link #decode(String, byte[])}
+     */
     public byte[] encode() {
         StringBuilder builder = new StringBuilder(name);
-        builder.append('\0').append(type);
-        builder.append('\0').append(server);
-        builder.append('\0').append(saveLogin ? username : "");
-        builder.append('\0').append(saveLogin ? password : "");
-        builder.append('\0').append(dnsServers);
-        builder.append('\0').append(searchDomains);
-        builder.append('\0').append(routes);
-        builder.append('\0').append(mppe);
-        builder.append('\0').append(l2tpSecret);
-        builder.append('\0').append(ipsecIdentifier);
-        builder.append('\0').append(ipsecSecret);
-        builder.append('\0').append(ipsecUserCert);
-        builder.append('\0').append(ipsecCaCert);
-        builder.append('\0').append(ipsecServerCert);
+        builder.append(VALUE_DELIMITER).append(type);
+        builder.append(VALUE_DELIMITER).append(server);
+        builder.append(VALUE_DELIMITER).append(saveLogin ? username : "");
+        builder.append(VALUE_DELIMITER).append(saveLogin ? password : "");
+        builder.append(VALUE_DELIMITER).append(dnsServers);
+        builder.append(VALUE_DELIMITER).append(searchDomains);
+        builder.append(VALUE_DELIMITER).append(routes);
+        builder.append(VALUE_DELIMITER).append(mppe);
+        builder.append(VALUE_DELIMITER).append(l2tpSecret);
+        builder.append(VALUE_DELIMITER).append(ipsecIdentifier);
+        builder.append(VALUE_DELIMITER).append(ipsecSecret);
+        builder.append(VALUE_DELIMITER).append(ipsecUserCert);
+        builder.append(VALUE_DELIMITER).append(ipsecCaCert);
+        builder.append(VALUE_DELIMITER).append(ipsecServerCert);
         if (proxy != null) {
-            builder.append('\0').append(proxy.getHost() != null ? proxy.getHost() : "");
-            builder.append('\0').append(proxy.getPort());
-            builder.append('\0').append(proxy.getExclusionListAsString() != null ?
-                    proxy.getExclusionListAsString() : "");
-            builder.append('\0').append(proxy.getPacFileUrl().toString());
+            builder.append(VALUE_DELIMITER).append(proxy.getHost() != null ? proxy.getHost() : "");
+            builder.append(VALUE_DELIMITER).append(proxy.getPort());
+            builder.append(VALUE_DELIMITER)
+                    .append(
+                            proxy.getExclusionListAsString() != null
+                                    ? proxy.getExclusionListAsString()
+                                    : "");
+            builder.append(VALUE_DELIMITER).append(proxy.getPacFileUrl().toString());
+        } else {
+            builder.append(ENCODED_NULL_PROXY_INFO);
         }
+
+        builder.append(VALUE_DELIMITER).append(String.join(LIST_DELIMITER, mAllowedAlgorithms));
+        builder.append(VALUE_DELIMITER).append(isBypassable);
+        builder.append(VALUE_DELIMITER).append(isMetered);
+        builder.append(VALUE_DELIMITER).append(maxMtu);
+        builder.append(VALUE_DELIMITER).append(areAuthParamsInline);
+
         return builder.toString().getBytes(StandardCharsets.UTF_8);
     }
 
     /**
-     * Tests if profile is valid for lockdown, which requires IPv4 address for
-     * both server and DNS. Server hostnames would require using DNS before
-     * connection.
+     * Tests if profile is valid for lockdown, which requires IPv4 address for both server and DNS.
+     * Server hostnames would require using DNS before connection.
      */
     public boolean isValidLockdownProfile() {
         return isTypeValidForLockdown()
@@ -238,10 +364,7 @@
         return !TextUtils.isEmpty(dnsServers);
     }
 
-    /**
-     * Returns {@code true} if all DNS servers have numeric addresses,
-     * e.g. 8.8.8.8
-     */
+    /** Returns {@code true} if all DNS servers have numeric addresses, e.g. 8.8.8.8 */
     public boolean areDnsAddressesNumeric() {
         try {
             for (String dnsServer : dnsServers.split(" +")) {
@@ -253,6 +376,62 @@
         return true;
     }
 
+    /**
+     * Validates that the provided list of algorithms does not contain illegal characters.
+     *
+     * @param allowedAlgorithms The list to be validated
+     */
+    public static void validateAllowedAlgorithms(List<String> allowedAlgorithms) {
+        for (final String alg : allowedAlgorithms) {
+            if (alg.contains(VALUE_DELIMITER) || alg.contains(LIST_DELIMITER)) {
+                throw new IllegalArgumentException(
+                        "Algorithm contained illegal ('\0' or ',') character");
+            }
+        }
+    }
+
+    /** Generates a hashcode over the VpnProfile. */
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+            key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
+            l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
+            proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline);
+    }
+
+    /** Checks VPN profiles for interior equality. */
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof VpnProfile)) {
+            return false;
+        }
+
+        final VpnProfile other = (VpnProfile) obj;
+        return Objects.equals(key, other.key)
+                && Objects.equals(name, other.name)
+                && type == other.type
+                && Objects.equals(server, other.server)
+                && Objects.equals(username, other.username)
+                && Objects.equals(password, other.password)
+                && Objects.equals(dnsServers, other.dnsServers)
+                && Objects.equals(searchDomains, other.searchDomains)
+                && Objects.equals(routes, other.routes)
+                && mppe == other.mppe
+                && Objects.equals(l2tpSecret, other.l2tpSecret)
+                && Objects.equals(ipsecIdentifier, other.ipsecIdentifier)
+                && Objects.equals(ipsecSecret, other.ipsecSecret)
+                && Objects.equals(ipsecUserCert, other.ipsecUserCert)
+                && Objects.equals(ipsecCaCert, other.ipsecCaCert)
+                && Objects.equals(ipsecServerCert, other.ipsecServerCert)
+                && Objects.equals(proxy, other.proxy)
+                && Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms)
+                && isBypassable == other.isBypassable
+                && isMetered == other.isMetered
+                && maxMtu == other.maxMtu
+                && areAuthParamsInline == other.areAuthParamsInline;
+    }
+
+    @NonNull
     public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
         @Override
         public VpnProfile createFromParcel(Parcel in) {
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 13d0c5c..7adb27c 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -19,6 +19,8 @@
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.type.DefaultMimeMapFactory;
 import android.os.Build;
@@ -34,6 +36,7 @@
 import com.android.internal.logging.AndroidConfig;
 import com.android.server.NetworkManagementSocketTagger;
 
+import dalvik.annotation.compat.VersionCodes;
 import dalvik.system.RuntimeHooks;
 import dalvik.system.ThreadPrioritySetter;
 import dalvik.system.VMRuntime;
@@ -64,8 +67,17 @@
 
     private static volatile boolean mCrashing = false;
 
+    /*
+     * Native heap allocations will now have a non-zero tag in the most significant byte.
+     * See {@linktourl https://source.android.com/devices/tech/debug/tagged-pointers}.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = VersionCodes.Q)
+    private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
+
     private static final native void nativeFinishInit();
     private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
+    private static native void nativeDisableHeapPointerTagging();
 
     private static int Clog_e(String tag, String msg, Throwable tr) {
         return Log.printlns(Log.LOG_ID_CRASH, Log.ERROR, tag, msg, tr);
@@ -398,6 +410,20 @@
         if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
     }
 
+    private static void maybeDisableHeapPointerTagging(long[] disabledCompatChanges) {
+        // Heap tagging needs to be disabled before any additional threads are created, but the
+        // AppCompat framework is not initialized enough at this point.
+        // Check if the change is enabled manually.
+        if (disabledCompatChanges != null) {
+            for (int i = 0; i < disabledCompatChanges.length; i++) {
+                if (disabledCompatChanges[i] == NATIVE_HEAP_POINTER_TAGGING) {
+                    nativeDisableHeapPointerTagging();
+                    break;
+                }
+            }
+        }
+    }
+
     protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
             String[] argv, ClassLoader classLoader) {
         // If the application calls System.exit(), terminate the process
@@ -410,6 +436,8 @@
         VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
         VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
 
+        maybeDisableHeapPointerTagging(disabledCompatChanges);
+
         final Arguments args = new Arguments(argv);
 
         // The end of of the RuntimeInit event (see #zygoteInit).
diff --git a/core/java/com/android/internal/util/ConnectivityUtil.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
similarity index 71%
rename from core/java/com/android/internal/util/ConnectivityUtil.java
rename to core/java/com/android/internal/util/LocationPermissionChecker.java
index b1d4fa0..dc318b4 100644
--- a/core/java/com/android/internal/util/ConnectivityUtil.java
+++ b/core/java/com/android/internal/util/LocationPermissionChecker.java
@@ -33,28 +33,59 @@
 
 
 /**
- * Utility methods for common functionality using by different networks.
+ * The methods used for location permission and location mode checking.
  *
  * @hide
  */
-public class ConnectivityUtil {
+public class LocationPermissionChecker {
 
-    private static final String TAG = "ConnectivityUtil";
+    private static final String TAG = "LocationPermissionChecker";
 
     private final Context mContext;
-    private final AppOpsManager mAppOps;
+    private final AppOpsManager mAppOpsManager;
     private final UserManager mUserManager;
+    private final LocationManager mLocationManager;
 
-    public ConnectivityUtil(Context context) {
+    public LocationPermissionChecker(Context context) {
         mContext = context;
-        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        mLocationManager =
+            (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
     }
 
     /**
-     * API to determine if the caller has fine/coarse location permission (depending on
-     * config/targetSDK level) and the location mode is enabled for the user. SecurityException is
-     * thrown if the caller has no permission or the location mode is disabled.
+     * Check location permission granted by the caller.
+     *
+     * This API check if the location mode enabled for the caller and the caller has
+     * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
+     *
+     * @param pkgName package name of the application requesting access
+     * @param featureId The feature in the package
+     * @param uid The uid of the package
+     * @param message A message describing why the permission was checked. Only needed if this is
+     *                not inside of a two-way binder call from the data receiver
+     *
+     * @return {@code true} returns if the caller has location permission and the location mode is
+     *         enabled.
+     */
+    public boolean checkLocationPermission(String pkgName, @Nullable String featureId,
+            int uid, @Nullable String message) {
+        try {
+            enforceLocationPermission(pkgName, featureId, uid, message);
+            return true;
+        } catch (SecurityException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Enforce the caller has location permission.
+     *
+     * This API determines if the location mode enabled for the caller and the caller has
+     * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
+     * SecurityException is thrown if the caller has no permission or the location mode is disabled.
+     *
      * @param pkgName package name of the application requesting access
      * @param featureId The feature in the package
      * @param uid The uid of the package
@@ -62,31 +93,21 @@
      *                not inside of a two-way binder call from the data receiver
      */
     public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid,
-            @Nullable String message)
-            throws SecurityException {
+            @Nullable String message) throws SecurityException {
+
         checkPackage(uid, pkgName);
 
         // Location mode must be enabled
         if (!isLocationModeEnabled()) {
-            // Location mode is disabled, scan results cannot be returned
             throw new SecurityException("Location mode is disabled for the device");
         }
 
         // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to
         // location information.
-        boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId,
-                uid, /* coarseForTargetSdkLessThanQ */ true, message);
-
-        // If neither caller or app has location access, there is no need to check
-        // any other permissions. Deny access to scan results.
-        if (!canAppPackageUseLocation) {
+        if (!checkCallersLocationPermission(pkgName, featureId,
+                uid, /* coarseForTargetSdkLessThanQ */ true, message)) {
             throw new SecurityException("UID " + uid + " has no location permission");
         }
-        // If the User or profile is current, permission is granted
-        // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
-        if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
-            throw new SecurityException("UID " + uid + " profile not permitted");
-        }
     }
 
     /**
@@ -104,6 +125,7 @@
      */
     public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId,
             int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) {
+
         boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
 
         String permissionType = Manifest.permission.ACCESS_FINE_LOCATION;
@@ -111,8 +133,7 @@
             // Having FINE permission implies having COARSE permission (but not the reverse)
             permissionType = Manifest.permission.ACCESS_COARSE_LOCATION;
         }
-        if (getUidPermission(permissionType, uid)
-                == PackageManager.PERMISSION_DENIED) {
+        if (getUidPermission(permissionType, uid) == PackageManager.PERMISSION_DENIED) {
             return false;
         }
 
@@ -134,10 +155,8 @@
      * Retrieves a handle to LocationManager (if not already done) and check if location is enabled.
      */
     public boolean isLocationModeEnabled() {
-        LocationManager locationManager =
-                (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
         try {
-            return locationManager.isLocationEnabledForUser(UserHandle.of(
+            return mLocationManager.isLocationEnabledForUser(UserHandle.of(
                     getCurrentUser()));
         } catch (Exception e) {
             Log.e(TAG, "Failure to get location mode via API, falling back to settings", e);
@@ -166,28 +185,15 @@
 
     private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId,
             int uid, @Nullable String message) {
-        return mAppOps.noteOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED;
+        return mAppOpsManager.noteOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED;
     }
 
-    private void checkPackage(int uid, String pkgName) throws SecurityException {
+    private void checkPackage(int uid, String pkgName)
+            throws SecurityException {
         if (pkgName == null) {
             throw new SecurityException("Checking UID " + uid + " but Package Name is Null");
         }
-        mAppOps.checkPackage(uid, pkgName);
-    }
-
-    private boolean isCurrentProfile(int uid) {
-        UserHandle currentUser = UserHandle.of(getCurrentUser());
-        UserHandle callingUser = UserHandle.getUserHandleForUid(uid);
-        return currentUser.equals(callingUser)
-                || mUserManager.isSameProfileGroup(
-                        currentUser.getIdentifier(), callingUser.getIdentifier());
-    }
-
-    private boolean checkInteractAcrossUsersFull(int uid) {
-        return getUidPermission(
-                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid)
-                == PackageManager.PERMISSION_GRANTED;
+        mAppOpsManager.checkPackage(uid, pkgName);
     }
 
     @VisibleForTesting
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8e0e1c6..551541e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -47,6 +47,7 @@
 #include <signal.h>
 #include <dirent.h>
 #include <assert.h>
+#include <bionic/malloc.h>
 
 #include <string>
 #include <vector>
@@ -279,6 +280,14 @@
     gCurRuntime->setExitWithoutCleanup(exitWithoutCleanup);
 }
 
+static void com_android_internal_os_RuntimeInit_nativeDisableHeapPointerTagging(
+        JNIEnv* env, jobject clazz) {
+    HeapTaggingLevel tag_level = M_HEAP_TAGGING_LEVEL_NONE;
+    if (!android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &tag_level, sizeof(tag_level))) {
+        ALOGE("ERROR: could not disable heap pointer tagging\n");
+    }
+}
+
 /*
  * JNI registration.
  */
@@ -286,10 +295,12 @@
 int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
 {
     const JNINativeMethod methods[] = {
-        { "nativeFinishInit", "()V",
-            (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
-        { "nativeSetExitWithoutCleanup", "(Z)V",
-            (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
+            {"nativeFinishInit", "()V",
+             (void*)com_android_internal_os_RuntimeInit_nativeFinishInit},
+            {"nativeSetExitWithoutCleanup", "(Z)V",
+             (void*)com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup},
+            {"nativeDisableHeapPointerTagging", "()V",
+             (void*)com_android_internal_os_RuntimeInit_nativeDisableHeapPointerTagging},
     };
     return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
         methods, NELEM(methods));
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 74ced89..4892faa 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -14,6 +14,7 @@
 # Frameworks
 ogunwale@google.com
 jjaggi@google.com
+per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
 
 # Launcher
 hyunyoungs@google.com
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5c204ab..6960aef 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2082,6 +2082,11 @@
     <permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows listen permission to always reported signal strength.
+         @hide Used internally. -->
+    <permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
+        android:protectionLevel="signature|telephony" />
+
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
          corresponds to a device SIM.
@@ -4695,6 +4700,19 @@
     <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
                 android:protectionLevel="signature|installer" />
 
+    <!-- Allows an app to log compat change usage.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.LOG_COMPAT_CHANGE"
+                android:protectionLevel="signature" />
+    <!-- Allows an app to read compat change config.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
+                android:protectionLevel="signature" />
+    <!-- Allows an app to override compat change config.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
+                android:protectionLevel="signature" />
+
     <!-- Allows input events to be monitored. Very dangerous!  @hide -->
     <permission android:name="android.permission.MONITOR_INPUT"
                 android:protectionLevel="signature" />
diff --git a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
similarity index 83%
rename from core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java
rename to core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
index 5564712..6a0a3dc 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -47,8 +48,8 @@
 
 import java.util.HashMap;
 
-/** Unit tests for {@link ConnectivityUtil}. */
-public class ConnectivityUtilTest {
+/** Unit tests for {@link LocationPermissionChecker}. */
+public class LocationPermissionCheckerTest {
 
     public static final String TAG = "ConnectivityUtilTest";
 
@@ -84,18 +85,7 @@
     private boolean mThrowSecurityException;
     private Answer<Integer> mReturnPermission;
     private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
-
-    private class TestConnectivityUtil extends ConnectivityUtil {
-
-        TestConnectivityUtil(Context context) {
-            super(context);
-        }
-
-        @Override
-        protected int getCurrentUser() {
-            return mCurrentUser;
-        }
-    }
+    private LocationPermissionChecker mChecker;
 
     @Before
     public void setUp() {
@@ -140,11 +130,12 @@
         mThrowSecurityException = true;
         mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M;
         mIsLocationEnabled = false;
-        mCurrentUser = UserHandle.USER_SYSTEM;
+        mCurrentUser = ActivityManager.getCurrentUser();
         mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
         mFineLocationPermission = PackageManager.PERMISSION_DENIED;
         mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
         mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
+        mChecker = new LocationPermissionChecker(mMockContext);
     }
 
     private void setupMockInterface() {
@@ -188,8 +179,7 @@
         mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
         mUid = mCurrentUser;
         setupTestCase();
-        new TestConnectivityUtil(mMockContext)
-                .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+        mChecker.enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
     }
 
     @Test
@@ -202,8 +192,7 @@
         mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED;
         mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
         setupTestCase();
-        new TestConnectivityUtil(mMockContext)
-                .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+        mChecker.enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
     }
 
     @Test
@@ -216,22 +205,8 @@
         setupTestCase();
 
         assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
-    }
-
-    @Test
-    public void testenforceCanAccessScanResults_UserOrProfileNotCurrent() throws Exception {
-        mIsLocationEnabled = true;
-        mThrowSecurityException = false;
-        mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
-        mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
-        mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
-        setupTestCase();
-
-        assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+                () -> mChecker.enforceLocationPermission(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
     }
 
     @Test
@@ -240,8 +215,8 @@
         mIsLocationEnabled = true;
         setupTestCase();
         assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+                () -> mChecker.enforceLocationPermission(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
     }
 
     @Test
@@ -255,8 +230,8 @@
         setupTestCase();
 
         assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+                () -> mChecker.enforceLocationPermission(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
         verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString());
     }
 
@@ -271,8 +246,8 @@
         setupTestCase();
 
         assertThrows(SecurityException.class,
-                () -> new TestConnectivityUtil(mMockContext)
-                        .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+                () -> mChecker.enforceLocationPermission(
+                        TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
     }
 
     private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
diff --git a/media/java/android/media/tv/DvbDeviceInfo.java b/media/java/android/media/tv/DvbDeviceInfo.java
index 96c8528..54fc39e 100644
--- a/media/java/android/media/tv/DvbDeviceInfo.java
+++ b/media/java/android/media/tv/DvbDeviceInfo.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
@@ -23,9 +24,13 @@
 import android.util.Log;
 
 /**
- * Simple container for information about DVB device.
- * Not for third-party developers.
+ * A digital video broadcasting (DVB) device.
  *
+ * <p> Simple wrapper around a <a href="https://www.linuxtv.org/docs/dvbapi/dvbapi.html">Linux DVB
+ * v3</a> device.
+ *
+ * @see TvInputManager#getDvbDeviceList()
+ * @see TvInputManager#openDvbDevice(DvbDeviceInfo, int)
  * @hide
  */
 @SystemApi
@@ -67,17 +72,19 @@
     }
 
     /**
-     * Returns the adapter ID of DVB device, in terms of enumerating the DVB device adapters
-     * installed in the system. The adapter ID counts from zero.
+     * Returns the adapter ID.
+     *
+     * <p>DVB Adapters contain one or more devices.
      */
+    @IntRange(from = 0)
     public int getAdapterId() {
         return mAdapterId;
     }
 
     /**
-     * Returns the device ID of DVB device, in terms of enumerating the DVB devices attached to
-     * the same device adapter. The device ID counts from zero.
+     * Returns the device ID.
      */
+    @IntRange(from = 0)
     public int getDeviceId() {
         return mDeviceId;
     }
diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java
index 6197c70..5babb16 100644
--- a/media/java/android/media/tv/TvContentRating.java
+++ b/media/java/android/media/tv/TvContentRating.java
@@ -17,7 +17,6 @@
 package android.media.tv;
 
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.text.TextUtils;
 
 import com.android.internal.util.Preconditions;
@@ -179,6 +178,10 @@
  *         <td>TV content rating system for Canada (French)</td>
  *     </tr>
  *     <tr>
+ *         <td>DTMB</td>
+ *         <td>DTMB content rating system</td>
+ *     </tr>
+ *     <tr>
  *         <td>DVB</td>
  *         <td>DVB content rating system</td>
  *     </tr>
@@ -199,10 +202,18 @@
  *         <td>TV content rating system for South Korea</td>
  *     </tr>
  *     <tr>
+ *         <td>NZ_TV</td>
+ *         <td>TV content rating system for New Zealand</td>
+ *     </tr>
+ *     <tr>
  *         <td>SG_TV</td>
  *         <td>TV content rating system for Singapore</td>
  *     </tr>
  *     <tr>
+ *         <td>TH_TV</td>
+ *         <td>TV content rating system for Thailand</td>
+ *     </tr>
+ *     <tr>
  *         <td>US_MV</td>
  *         <td>Movie content rating system for the United States</td>
  *     </tr>
@@ -356,6 +367,67 @@
  *         <td>Only to be viewed by adults</td>
  *     </tr>
  *     <tr>
+ *         <td valign="top" rowspan="15">DTMB</td>
+ *         <td>DTMB_4</td>
+ *         <td>Recommended for ages 4 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_5</td>
+ *         <td>Recommended for ages 5 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_6</td>
+ *         <td>Recommended for ages 6 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_7</td>
+ *         <td>Recommended for ages 7 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_8</td>
+ *         <td>Recommended for ages 8 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_9</td>
+ *         <td>Recommended for ages 9 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_10</td>
+ *         <td>Recommended for ages 10 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_11</td>
+ *         <td>Recommended for ages 11 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_12</td>
+ *         <td>Recommended for ages 12 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_13</td>
+ *         <td>Recommended for ages 13 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_14</td>
+ *         <td>Recommended for ages 14 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_15</td>
+ *         <td>Recommended for ages 15 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_16</td>
+ *         <td>Recommended for ages 16 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_17</td>
+ *         <td>Recommended for ages 17 and over</td>
+ *     </tr>
+ *     <tr>
+ *         <td>DTMB_18</td>
+ *         <td>Recommended for ages 18 and over</td>
+ *     </tr>
+ *     <tr>
  *         <td valign="top" rowspan="15">DVB</td>
  *         <td>DVB_4</td>
  *         <td>Recommended for ages 4 and over</td>
@@ -648,6 +720,22 @@
  *         <td>For adults only</td>
  *     </tr>
  *     <tr>
+ *         <td valign="top" rowspan="3">NZ_TV</td>
+ *         <td>NZ_TV_G</td>
+ *         <td>Programmes which exclude material likely to be unsuitable for children. Programmes
+ *         may not necessarily be designed for child viewers but should not contain material likely
+ *         to alarm or distress them</td>
+ *     </tr>
+ *     <tr>
+ *         <td>NZ_TV_PGR</td>
+ *         <td>Programmes containing material more suited for mature audiences but not necessarily
+ *         unsuitable for child viewers when subject to the guidance of a parent or an adult</td>
+ *     </tr>
+ *     <tr>
+ *         <td>NZ_TV_AO</td>
+ *         <td>Programmes containing adult themes and directed primarily at mature audiences</td>
+ *     </tr>
+ *     <tr>
  *         <td valign="top" rowspan="6">SG_TV</td>
  *         <td>SG_TV_G</td>
  *         <td>Suitable for all ages</td>
@@ -674,6 +762,31 @@
  *         <td>Suitable for adults aged 21 and above</td>
  *     </tr>
  *     <tr>
+ *         <td valign="top" rowspan="6">TH_TV</td>
+ *         <td>TH_TV_4</td>
+ *         <td>Suitable for audiences 3 to 5 years of age</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_6</td>
+ *         <td>Suitable for audiences 6 to 12 years of age</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_10</td>
+ *         <td>Suitable for all audiences</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_13</td>
+ *         <td>Parental guidance suggested for viewers age below 13</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_18</td>
+ *         <td>Parental guidance suggested for viewers age below 18</td>
+ *     </tr>
+ *     <tr>
+ *         <td>TH_TV_19</td>
+ *         <td>Not suitable for children and teenagers</td>
+ *     </tr>
+ *     <tr>
  *         <td valign="top" rowspan="5">US_MV</td>
  *         <td>US_MV_G</td>
  *         <td>General audiences</td>
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 854ea43..ed4fe4b 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1664,7 +1664,7 @@
     }
 
     /**
-     * Returns the list of currently available DVB devices on the system.
+     * Returns the list of currently available DVB frontend devices on the system.
      *
      * @return the list of {@link DvbDeviceInfo} objects representing available DVB devices.
      * @hide
@@ -1681,16 +1681,17 @@
     }
 
     /**
-     * Returns a {@link ParcelFileDescriptor} of a specified DVB device for a given
-     * {@link DvbDeviceInfo}
+     * Returns a {@link ParcelFileDescriptor} of a specified DVB device of a given type for a given
+     * {@link DvbDeviceInfo}.
      *
      * @param info A {@link DvbDeviceInfo} to open a DVB device.
-     * @param deviceType A DVB device type. The type can be {@link #DVB_DEVICE_DEMUX},
-     *            {@link #DVB_DEVICE_DVR} or {@link #DVB_DEVICE_FRONTEND}.
+     * @param deviceType A DVB device type.
      * @return a {@link ParcelFileDescriptor} of a specified DVB device for a given
-     *         {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo}
-     *         failed to open.
+     * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo}
+     * failed to open.
      * @throws IllegalArgumentException if {@code deviceType} is invalid or the device is not found.
+
+     * @see <a href="https://www.linuxtv.org/docs/dvbapi/dvbapi.html">Linux DVB API v3</a>
      * @hide
      */
     @SystemApi
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index 4318a0a..d4c4a62 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -352,8 +352,7 @@
         if (!TextUtils.equals(mId, obj.mId) || mType != obj.mType
                 || !TextUtils.equals(mLanguage, obj.mLanguage)
                 || !TextUtils.equals(mDescription, obj.mDescription)
-                || mEncrypted != obj.mEncrypted
-                || !Objects.equals(mExtra, obj.mExtra)) {
+                || mEncrypted != obj.mEncrypted) {
             return false;
         }
 
@@ -381,7 +380,16 @@
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(mId);
+        int result = Objects.hash(mId, mType, mLanguage, mDescription);
+
+        if (mType == TYPE_AUDIO) {
+            result = Objects.hash(result, mAudioChannelCount, mAudioSampleRate);
+        } else if (mType == TYPE_VIDEO) {
+            result = Objects.hash(result, mVideoWidth, mVideoHeight, mVideoFrameRate,
+                    mVideoPixelAspectRatio);
+        }
+
+        return result;
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<TvTrackInfo> CREATOR =
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index af2569d..14c7795 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -108,6 +108,7 @@
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.CREATE_USERS" />
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 8631e86..d330732 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -19,16 +19,12 @@
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
 import static android.telephony.PhoneStateListener.LISTEN_NONE;
 
-import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
-
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
-import android.os.SystemProperties;
-import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
@@ -37,20 +33,18 @@
 import android.text.TextUtils;
 import android.util.Log;
 
-import androidx.annotation.VisibleForTesting;
-
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.settingslib.WirelessUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
+import androidx.annotation.VisibleForTesting;
+
 /**
  * Controller that generates text including the carrier names and/or the status of all the SIM
  * interfaces in the device. Through a callback, the updates can be retrieved either as a list or
@@ -73,8 +67,6 @@
     private Context mContext;
     private CharSequence mSeparator;
     private WakefulnessLifecycle mWakefulnessLifecycle;
-    @VisibleForTesting
-    protected boolean mDisplayOpportunisticSubscriptionCarrierText;
     private final WakefulnessLifecycle.Observer mWakefulnessObserver =
             new WakefulnessLifecycle.Observer() {
                 @Override
@@ -173,9 +165,6 @@
         mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
         mSimSlotsNumber = getTelephonyManager().getSupportedModemCount();
         mSimErrorState = new boolean[mSimSlotsNumber];
-        updateDisplayOpportunisticSubscriptionCarrierText(SystemProperties.getBoolean(
-                TelephonyProperties.DISPLAY_OPPORTUNISTIC_SUBSCRIPTION_CARRIER_TEXT_PROPERTY_NAME,
-                false));
     }
 
     private TelephonyManager getTelephonyManager() {
@@ -255,63 +244,8 @@
         }
     }
 
-    /**
-     * @param subscriptions
-     */
-    private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
-        if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
-            SubscriptionInfo info1 = subscriptions.get(0);
-            SubscriptionInfo info2 = subscriptions.get(1);
-            if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
-                // If both subscriptions are primary, show both.
-                if (!info1.isOpportunistic() && !info2.isOpportunistic()) return;
-
-                // If carrier required, always show signal bar of primary subscription.
-                // Otherwise, show whichever subscription is currently active for Internet.
-                boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
-                        .getBoolean(CarrierConfigManager
-                        .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
-                if (alwaysShowPrimary) {
-                    subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
-                } else {
-                    subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
-                            ? info2 : info1);
-                }
-
-            }
-        }
-    }
-
-    /**
-     * updates if opportunistic sub carrier text should be displayed or not
-     *
-     */
-    @VisibleForTesting
-    public void updateDisplayOpportunisticSubscriptionCarrierText(boolean isEnable) {
-        mDisplayOpportunisticSubscriptionCarrierText = isEnable;
-    }
-
     protected List<SubscriptionInfo> getSubscriptionInfo() {
-        List<SubscriptionInfo> subs;
-        if (mDisplayOpportunisticSubscriptionCarrierText) {
-            SubscriptionManager subscriptionManager = ((SubscriptionManager) mContext
-                    .getSystemService(
-                    Context.TELEPHONY_SUBSCRIPTION_SERVICE));
-            subs = subscriptionManager.getActiveSubscriptionInfoList(false);
-            if (subs == null) {
-                subs = new ArrayList<>();
-            } else {
-                filterMobileSubscriptionInSameGroup(subs);
-            }
-        } else {
-            subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
-            if (subs == null) {
-                subs = new ArrayList<>();
-            } else {
-                filterMobileSubscriptionInSameGroup(subs);
-            }
-        }
-        return subs;
+        return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
     }
 
     protected void updateCarrierText() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1fb50a9..0ede50d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -30,6 +30,7 @@
 import static android.os.BatteryManager.EXTRA_STATUS;
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
 
+import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -77,6 +78,7 @@
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
@@ -257,6 +259,7 @@
     private boolean mLogoutEnabled;
     // If the user long pressed the lock icon, disabling face auth for the current session.
     private boolean mLockIconPressed;
+    private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
     /**
      * Short delay before restarting biometric authentication after a successful try
@@ -392,9 +395,11 @@
         }
     };
 
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+    @VisibleForTesting
+    public PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
         @Override
         public void onActiveDataSubscriptionIdChanged(int subId) {
+            mActiveMobileDataSubscription = subId;
             mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED);
         }
     };
@@ -496,7 +501,9 @@
         }
     }
 
-    /** @return List of SubscriptionInfo records, maybe empty but never null */
+    /**
+     * @return List of SubscriptionInfo records, maybe empty but never null.
+     */
     public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
         List<SubscriptionInfo> sil = mSubscriptionInfo;
         if (sil == null || forceReload) {
@@ -508,7 +515,42 @@
         } else {
             mSubscriptionInfo = sil;
         }
-        return mSubscriptionInfo;
+        return new ArrayList<>(mSubscriptionInfo);
+    }
+
+    /**
+     * This method returns filtered list of SubscriptionInfo from {@link #getSubscriptionInfo}.
+     * above. Maybe empty but never null.
+     *
+     * In DSDS mode if both subscriptions are grouped and one is opportunistic, we filter out one
+     * of them based on carrier config. e.g. In this case we should only show one carrier name
+     * on the status bar and quick settings.
+     */
+    public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) {
+        List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false);
+        if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
+            SubscriptionInfo info1 = subscriptions.get(0);
+            SubscriptionInfo info2 = subscriptions.get(1);
+            if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
+                // If both subscriptions are primary, show both.
+                if (!info1.isOpportunistic() && !info2.isOpportunistic()) return subscriptions;
+
+                // If carrier required, always show signal bar of primary subscription.
+                // Otherwise, show whichever subscription is currently active for Internet.
+                boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
+                        .getBoolean(CarrierConfigManager
+                        .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
+                if (alwaysShowPrimary) {
+                    subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
+                } else {
+                    subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
+                            ? info2 : info1);
+                }
+
+            }
+        }
+
+        return subscriptions;
     }
 
     @Override
@@ -2637,6 +2679,7 @@
                 pw.println("    " + mSubscriptionInfo.get(i));
             }
         }
+        pw.println("  Current active data subId=" + mActiveMobileDataSubscription);
         pw.println("  Service states:");
         for (int subId : mServiceStates.keySet()) {
             pw.println("    " + subId + "=" + mServiceStates.get(subId));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index d1b3c3c..2a5ccdb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -134,7 +134,7 @@
 
     private void updateText() {
         CharSequence displayText = null;
-        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
         final int N = subs.size();
         for (int i = 0; i < N; i++) {
             int subId = subs.get(i).getSubscriptionId();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index 0d6178b..f2c0434 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -97,7 +97,7 @@
         boolean allSimsMissing = true;
         CharSequence displayText = null;
 
-        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
         final int N = subs.size();
         for (int i = 0; i < N; i++) {
             int subId = subs.get(i).getSubscriptionId();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 4d9ea29..5a8ff4b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -19,7 +19,7 @@
 
 import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
 import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE;
-import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
 
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.TestCase.assertFalse;
@@ -77,21 +77,16 @@
     private static final CharSequence AIRPLANE_MODE_TEXT = "Airplane mode";
     private static final String TEST_CARRIER = "TEST_CARRIER";
     private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
-    private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
     private static final int TEST_CARRIER_ID = 1;
     private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0,
-            TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
-            DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
-            TEST_CARRIER_ID, 0);
-    private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(0, "", 0,
-            TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
-            DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
+            TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
+            DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, null,
             TEST_CARRIER_ID, 0);
     private static final SubscriptionInfo TEST_SUBSCRIPTION_NULL = new SubscriptionInfo(0, "", 0,
-            TEST_CARRIER, null, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
+            TEST_CARRIER, null, NAME_SOURCE_DEFAULT, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
             null, null, null, null, false, null, "");
     private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0,
-            TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+            TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
             DATA_ROAMING_ENABLE, null, null, null, null, false, null, "");
     @Mock
     private WifiManager mWifiManager;
@@ -136,7 +131,6 @@
                 mKeyguardUpdateMonitor);
         // This should not start listening on any of the real dependencies
         mCarrierTextController.setListening(mCarrierTextCallback);
-        mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText(false);
     }
 
     @Test
@@ -145,7 +139,7 @@
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
         when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -165,7 +159,7 @@
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
         when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn(
                 IccCardConstants.State.CARD_IO_ERROR);
@@ -198,7 +192,7 @@
     @Test
     public void testWrongSlots() {
         reset(mCarrierTextCallback);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
                 new ArrayList<>());
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
                 IccCardConstants.State.CARD_IO_ERROR);
@@ -212,7 +206,7 @@
     @Test
     public void testMoreSlotsThanSubs() {
         reset(mCarrierTextCallback);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
                 new ArrayList<>());
 
         // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
@@ -262,7 +256,7 @@
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -286,7 +280,7 @@
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION_ROAMING);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -366,7 +360,7 @@
     @Test
     public void testCreateInfo_noSubscriptions() {
         reset(mCarrierTextCallback);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
                 new ArrayList<>());
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -390,7 +384,7 @@
         list.add(TEST_SUBSCRIPTION);
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -415,7 +409,7 @@
         when(mKeyguardUpdateMonitor.getSimState(anyInt()))
                 .thenReturn(IccCardConstants.State.READY)
                 .thenReturn(IccCardConstants.State.NOT_READY);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -440,7 +434,7 @@
         when(mKeyguardUpdateMonitor.getSimState(anyInt()))
                 .thenReturn(IccCardConstants.State.NOT_READY)
                 .thenReturn(IccCardConstants.State.READY);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -467,7 +461,7 @@
                 .thenReturn(IccCardConstants.State.READY)
                 .thenReturn(IccCardConstants.State.NOT_READY)
                 .thenReturn(IccCardConstants.State.READY);
-        when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -482,30 +476,6 @@
                 captor.getValue().carrierText);
     }
 
-    @Test
-    public void testCarrierText_GroupedSubWithOpportunisticCarrierText() {
-        reset(mCarrierTextCallback);
-        List<SubscriptionInfo> list = new ArrayList<>();
-        list.add(TEST_SUBSCRIPTION);
-        list.add(TEST_SUBSCRIPTION_2);
-        when(mKeyguardUpdateMonitor.getSimState(anyInt()))
-            .thenReturn(IccCardConstants.State.READY);
-
-        mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
-        mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText(true);
-        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
-        ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
-                ArgumentCaptor.forClass(
-                CarrierTextController.CarrierTextCallbackInfo.class);
-
-        mCarrierTextController.updateCarrierText();
-        mTestableLooper.processAllMessages();
-        verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
-
-        assertEquals(TEST_CARRIER_2, captor.getValue().carrierText);
-    }
-
     public static class TestCarrierTextController extends CarrierTextController {
         private KeyguardUpdateMonitor mKUM;
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 21585ed..cfffcbc 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -16,15 +16,18 @@
 
 package com.android.keyguard;
 
+import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -42,6 +45,7 @@
 import android.os.Bundle;
 import android.os.UserManager;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -62,6 +66,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 @SmallTest
@@ -73,7 +79,18 @@
 // new tests.
 @RunWithLooper(setAsMainLooper = true)
 public class KeyguardUpdateMonitorTest extends SysuiTestCase {
-
+    private static final String TEST_CARRIER = "TEST_CARRIER";
+    private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
+    private static final int TEST_CARRIER_ID = 1;
+    private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
+    private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(1, "", 0,
+            TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
+            DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
+            TEST_CARRIER_ID, 0);
+    private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(2, "", 0,
+            TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
+            DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
+            TEST_CARRIER_ID, 0);
     @Mock
     private KeyguardUpdateMonitor.StrongAuthTracker mStrongAuthTracker;
     @Mock
@@ -92,6 +109,8 @@
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
     private KeyguardBypassController mKeyguardBypassController;
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
     private TestableLooper mTestableLooper;
     private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
@@ -119,6 +138,7 @@
         context.addMockSystemService(FaceManager.class, mFaceManager);
         context.addMockSystemService(UserManager.class, mUserManager);
         context.addMockSystemService(DevicePolicyManager.class, mDevicePolicyManager);
+        context.addMockSystemService(SubscriptionManager.class, mSubscriptionManager);
 
         mTestableLooper = TestableLooper.get(this);
         mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(context);
@@ -441,6 +461,22 @@
         assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
     }
 
+    @Test
+    public void testGetSubscriptionInfo_whenInGroupedSubWithOpportunistic() {
+        List<SubscriptionInfo> list = new ArrayList<>();
+        list.add(TEST_SUBSCRIPTION);
+        list.add(TEST_SUBSCRIPTION_2);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+        mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
+                TEST_SUBSCRIPTION_2.getSubscriptionId());
+        mTestableLooper.processAllMessages();
+
+        List<SubscriptionInfo> listToVerify = mKeyguardUpdateMonitor
+                .getFilteredSubscriptionInfo(false);
+        assertThat(listToVerify.size()).isEqualTo(1);
+        assertThat(listToVerify.get(0)).isEqualTo(TEST_SUBSCRIPTION_2);
+    }
+
     private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
         int subscription = simInited
                 ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 264ce44..e0adb34d 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -19,7 +19,15 @@
     local_include_dir: "src",
     include_dirs: ["frameworks/base/core/java"], // For framework parcelables.
     srcs: [
-        "src/android/net/*.aidl",
+        // @JavaOnlyStableParcelable aidl declarations must not be listed here, as this would cause
+        // compilation to fail (b/148001843).
+        "src/android/net/IIntResultListener.aidl",
+        "src/android/net/ITetheringConnector.aidl",
+        "src/android/net/ITetheringEventCallback.aidl",
+        "src/android/net/TetheringCallbackStartedParcel.aidl",
+        "src/android/net/TetheringConfigurationParcel.aidl",
+        "src/android/net/TetheringRequestParcel.aidl",
+        "src/android/net/TetherStatesParcel.aidl",
     ],
     backend: {
         ndk: {
@@ -35,7 +43,9 @@
     name: "framework-tethering",
     sdk_version: "system_current",
     srcs: [
+        "src/android/net/TetheredClient.java",
         "src/android/net/TetheringManager.java",
+        "src/android/net/TetheringConstants.java",
         ":framework-tethering-annotations",
     ],
     static_libs: [
@@ -62,11 +72,16 @@
 filegroup {
     name: "framework-tethering-srcs",
     srcs: [
+        "src/android/net/TetheredClient.aidl",
+        "src/android/net/TetheredClient.java",
         "src/android/net/TetheringManager.java",
+        "src/android/net/TetheringConstants.java",
         "src/android/net/IIntResultListener.aidl",
         "src/android/net/ITetheringEventCallback.aidl",
         "src/android/net/ITetheringConnector.aidl",
+        "src/android/net/TetheringCallbackStartedParcel.aidl",
         "src/android/net/TetheringConfigurationParcel.aidl",
+        "src/android/net/TetheringRequestParcel.aidl",
         "src/android/net/TetherStatesParcel.aidl",
     ],
     path: "src"
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
index d30c399..5febe73 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
@@ -17,6 +17,7 @@
 
 import android.net.IIntResultListener;
 import android.net.ITetheringEventCallback;
+import android.net.TetheringRequestParcel;
 import android.os.ResultReceiver;
 
 /** @hide */
@@ -27,8 +28,8 @@
 
     void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver);
 
-    void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi,
-            String callerPkg);
+    void startTethering(in TetheringRequestParcel request, String callerPkg,
+            IIntResultListener receiver);
 
     void stopTethering(int type, String callerPkg, IIntResultListener receiver);
 
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
index 2836195..28a810d 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
@@ -18,6 +18,7 @@
 
 import android.net.Network;
 import android.net.TetheringConfigurationParcel;
+import android.net.TetheringCallbackStartedParcel;
 import android.net.TetherStatesParcel;
 
 /**
@@ -26,8 +27,8 @@
  */
 oneway interface ITetheringEventCallback
 {
-    void onCallbackStarted(in Network network, in TetheringConfigurationParcel config,
-            in TetherStatesParcel states);
+    /** Called immediately after the callbacks are registered */
+    void onCallbackStarted(in TetheringCallbackStartedParcel parcel);
     void onCallbackStopped(int errorCode);
     void onUpstreamChanged(in Network network);
     void onConfigurationChanged(in TetheringConfigurationParcel config);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
new file mode 100644
index 0000000..0b279b8
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
@@ -0,0 +1,18 @@
+/**
+ * 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;
+
+@JavaOnlyStableParcelable parcelable TetheredClient;
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
new file mode 100644
index 0000000..6514688
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
@@ -0,0 +1,212 @@
+/*
+ * 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.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Information on a tethered downstream client.
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class TetheredClient implements Parcelable {
+    @NonNull
+    private final MacAddress mMacAddress;
+    @NonNull
+    private final List<AddressInfo> mAddresses;
+    // TODO: use an @IntDef here
+    private final int mTetheringType;
+
+    public TetheredClient(@NonNull MacAddress macAddress,
+            @NonNull Collection<AddressInfo> addresses, int tetheringType) {
+        mMacAddress = macAddress;
+        mAddresses = new ArrayList<>(addresses);
+        mTetheringType = tetheringType;
+    }
+
+    private TetheredClient(@NonNull Parcel in) {
+        this(in.readParcelable(null), in.createTypedArrayList(AddressInfo.CREATOR), in.readInt());
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelable(mMacAddress, flags);
+        dest.writeTypedList(mAddresses);
+        dest.writeInt(mTetheringType);
+    }
+
+    @NonNull
+    public MacAddress getMacAddress() {
+        return mMacAddress;
+    }
+
+    @NonNull
+    public List<AddressInfo> getAddresses() {
+        return new ArrayList<>(mAddresses);
+    }
+
+    public int getTetheringType() {
+        return mTetheringType;
+    }
+
+    /**
+     * Return a new {@link TetheredClient} that has all the attributes of this instance, plus the
+     * {@link AddressInfo} of the provided {@link TetheredClient}.
+     *
+     * <p>Duplicate addresses are removed.
+     * @hide
+     */
+    public TetheredClient addAddresses(@NonNull TetheredClient other) {
+        final HashSet<AddressInfo> newAddresses = new HashSet<>(
+                mAddresses.size() + other.mAddresses.size());
+        newAddresses.addAll(mAddresses);
+        newAddresses.addAll(other.mAddresses);
+        return new TetheredClient(mMacAddress, newAddresses, mTetheringType);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mMacAddress, mAddresses, mTetheringType);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (!(obj instanceof TetheredClient)) return false;
+        final TetheredClient other = (TetheredClient) obj;
+        return mMacAddress.equals(other.mMacAddress)
+                && mAddresses.equals(other.mAddresses)
+                && mTetheringType == other.mTetheringType;
+    }
+
+    /**
+     * Information on an lease assigned to a tethered client.
+     */
+    public static final class AddressInfo implements Parcelable {
+        @NonNull
+        private final LinkAddress mAddress;
+        @Nullable
+        private final String mHostname;
+        // TODO: use LinkAddress expiration time once it is supported
+        private final long mExpirationTime;
+
+        /** @hide */
+        public AddressInfo(@NonNull LinkAddress address, @Nullable String hostname) {
+            this(address, hostname, 0);
+        }
+
+        /** @hide */
+        public AddressInfo(@NonNull LinkAddress address, String hostname, long expirationTime) {
+            this.mAddress = address;
+            this.mHostname = hostname;
+            this.mExpirationTime = expirationTime;
+        }
+
+        private AddressInfo(Parcel in) {
+            this(in.readParcelable(null),  in.readString(), in.readLong());
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeParcelable(mAddress, flags);
+            dest.writeString(mHostname);
+            dest.writeLong(mExpirationTime);
+        }
+
+        @NonNull
+        public LinkAddress getAddress() {
+            return mAddress;
+        }
+
+        @Nullable
+        public String getHostname() {
+            return mHostname;
+        }
+
+        /** @hide TODO: use expiration time in LinkAddress */
+        public long getExpirationTime() {
+            return mExpirationTime;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mAddress, mHostname, mExpirationTime);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (!(obj instanceof AddressInfo)) return false;
+            final AddressInfo other = (AddressInfo) obj;
+            // Use .equals() for addresses as all changes, including address expiry changes,
+            // should be included.
+            return other.mAddress.equals(mAddress)
+                    && Objects.equals(mHostname, other.mHostname)
+                    && mExpirationTime == other.mExpirationTime;
+        }
+
+        @NonNull
+        public static final Creator<AddressInfo> CREATOR = new Creator<AddressInfo>() {
+            @NonNull
+            @Override
+            public AddressInfo createFromParcel(@NonNull Parcel in) {
+                return new AddressInfo(in);
+            }
+
+            @NonNull
+            @Override
+            public AddressInfo[] newArray(int size) {
+                return new AddressInfo[size];
+            }
+        };
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Creator<TetheredClient> CREATOR = new Creator<TetheredClient>() {
+        @NonNull
+        @Override
+        public TetheredClient createFromParcel(@NonNull Parcel in) {
+            return new TetheredClient(in);
+        }
+
+        @NonNull
+        @Override
+        public TetheredClient[] newArray(int size) {
+            return new TetheredClient[size];
+        }
+    };
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
new file mode 100644
index 0000000..14ee2d3
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.net.Network;
+import android.net.TetheringConfigurationParcel;
+import android.net.TetherStatesParcel;
+
+/**
+ * Initial information reported by tethering upon callback registration.
+ * @hide
+ */
+parcelable TetheringCallbackStartedParcel {
+    boolean tetheringSupported;
+    Network upstreamNetwork;
+    TetheringConfigurationParcel config;
+    TetherStatesParcel states;
+}
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
new file mode 100644
index 0000000..00cf98e
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -0,0 +1,66 @@
+/*
+ * 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.ResultReceiver;
+
+/**
+ * Collections of constants for internal tethering usage.
+ *
+ * <p>These hidden constants are not in TetheringManager as they are not part of the API stubs
+ * generated for TetheringManager, which prevents the tethering module from linking them at
+ * build time.
+ * TODO: investigate changing the tethering build rules so that Tethering can reference hidden
+ * symbols from framework-tethering even when they are in a non-hidden class.
+ * @hide
+ */
+public class TetheringConstants {
+    /**
+     * Extra used for communicating with the TetherService. Includes the type of tethering to
+     * enable if any.
+     *
+     * {@hide}
+     */
+    public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+    /**
+     * Extra used for communicating with the TetherService. Includes the type of tethering for
+     * which to cancel provisioning.
+     *
+     * {@hide}
+     */
+    public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+    /**
+     * Extra used for communicating with the TetherService. True to schedule a recheck of tether
+     * provisioning.
+     *
+     * {@hide}
+     */
+    public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+    /**
+     * Tells the TetherService to run a provision check now.
+     *
+     * {@hide}
+     */
+    public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+    /**
+     * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
+     * which will receive provisioning results. Can be left empty.
+     *
+     * {@hide}
+     */
+    public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 11e5718..37ce1d57 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -15,9 +15,14 @@
  */
 package android.net;
 
+import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.Context;
-import android.net.ConnectivityManager.OnTetheringEventCallback;
+import android.os.Bundle;
 import android.os.ConditionVariable;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -25,6 +30,12 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -34,7 +45,8 @@
  *
  * @hide
  */
-// TODO: make it @SystemApi
+@SystemApi
+@TestApi
 public class TetheringManager {
     private static final String TAG = TetheringManager.class.getSimpleName();
     private static final int DEFAULT_TIMEOUT_MS = 60_000;
@@ -44,7 +56,7 @@
     private final ITetheringConnector mConnector;
     private final TetheringCallbackInternal mCallback;
     private final Context mContext;
-    private final ArrayMap<OnTetheringEventCallback, ITetheringEventCallback>
+    private final ArrayMap<TetheringEventCallback, ITetheringEventCallback>
             mTetheringEventCallbacks = new ArrayMap<>();
 
     private TetheringConfigurationParcel mTetheringConfiguration;
@@ -72,7 +84,7 @@
      * gives a String[] listing all the interfaces currently in local-only
      * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
      */
-    public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";
+    public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
 
     /**
      * gives a String[] listing all the interfaces currently tethered
@@ -119,33 +131,16 @@
     public static final int TETHERING_WIFI_P2P = 3;
 
     /**
-     * Extra used for communicating with the TetherService. Includes the type of tethering to
-     * enable if any.
+     * Ncm local tethering type.
+     * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
      */
-    public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+    public static final int TETHERING_NCM = 4;
 
     /**
-     * Extra used for communicating with the TetherService. Includes the type of tethering for
-     * which to cancel provisioning.
+     * Ethernet tethering type.
+     * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
      */
-    public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
-
-    /**
-     * Extra used for communicating with the TetherService. True to schedule a recheck of tether
-     * provisioning.
-     */
-    public static final String EXTRA_SET_ALARM = "extraSetAlarm";
-
-    /**
-     * Tells the TetherService to run a provision check now.
-     */
-    public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
-
-    /**
-     * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
-     * which will receive provisioning results. Can be left empty.
-     */
-    public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+    public static final int TETHERING_ETHERNET = 5;
 
     public static final int TETHER_ERROR_NO_ERROR           = 0;
     public static final int TETHER_ERROR_UNKNOWN_IFACE      = 1;
@@ -160,12 +155,14 @@
     public static final int TETHER_ERROR_IFACE_CFG_ERROR      = 10;
     public static final int TETHER_ERROR_PROVISION_FAILED     = 11;
     public static final int TETHER_ERROR_DHCPSERVER_ERROR     = 12;
-    public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN  = 13;
+    public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13;
     public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
     public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
 
     /**
      * Create a TetheringManager object for interacting with the tethering service.
+     *
+     * {@hide}
      */
     public TetheringManager(@NonNull final Context context, @NonNull final IBinder service) {
         mContext = context;
@@ -229,10 +226,9 @@
         private final ConditionVariable mWaitForCallback = new ConditionVariable();
 
         @Override
-        public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
-                TetherStatesParcel states) {
-            mTetheringConfiguration = config;
-            mTetherStatesParcel = states;
+        public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
+            mTetheringConfiguration = parcel.config;
+            mTetherStatesParcel = parcel.states;
             mWaitForCallback.open();
         }
 
@@ -275,6 +271,8 @@
      *
      * @param iface the interface name to tether.
      * @return error a {@code TETHER_ERROR} value indicating success or failure type
+     *
+     * {@hide}
      */
     @Deprecated
     public int tether(@NonNull final String iface) {
@@ -296,6 +294,8 @@
      *
      * @deprecated The only usages is PanService. It uses this for legacy reasons
      * and will migrate away as soon as possible.
+     *
+     * {@hide}
      */
     @Deprecated
     public int untether(@NonNull final String iface) {
@@ -320,6 +320,8 @@
      * #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
      * used and an entitlement check is needed, downstream USB tethering will be enabled but will
      * not have any upstream.
+     *
+     * {@hide}
      */
     @Deprecated
     public int setUsbTethering(final boolean enable) {
@@ -338,27 +340,171 @@
     }
 
     /**
+     *  Use with {@link #startTethering} to specify additional parameters when starting tethering.
+     */
+    public static class TetheringRequest {
+        /** A configuration set for TetheringRequest. */
+        private final TetheringRequestParcel mRequestParcel;
+
+        private TetheringRequest(final TetheringRequestParcel request) {
+            mRequestParcel = request;
+        }
+
+        /** Builder used to create TetheringRequest. */
+        public static class Builder {
+            private final TetheringRequestParcel mBuilderParcel;
+
+            /** Default constructor of Builder. */
+            public Builder(final int type) {
+                mBuilderParcel = new TetheringRequestParcel();
+                mBuilderParcel.tetheringType = type;
+                mBuilderParcel.localIPv4Address = null;
+                mBuilderParcel.exemptFromEntitlementCheck = false;
+                mBuilderParcel.showProvisioningUi = true;
+            }
+
+            /**
+             * Configure tethering with static IPv4 assignment (with DHCP disabled).
+             *
+             * @param localIPv4Address The preferred local IPv4 address to use.
+             */
+            @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+            @NonNull
+            public Builder useStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address) {
+                mBuilderParcel.localIPv4Address = localIPv4Address;
+                return this;
+            }
+
+            /** Start tethering without entitlement checks. */
+            @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+            @NonNull
+            public Builder setExemptFromEntitlementCheck(boolean exempt) {
+                mBuilderParcel.exemptFromEntitlementCheck = exempt;
+                return this;
+            }
+
+            /** Start tethering without showing the provisioning UI. */
+            @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+            @NonNull
+            public Builder setSilentProvisioning(boolean silent) {
+                mBuilderParcel.showProvisioningUi = silent;
+                return this;
+            }
+
+            /** Build {@link TetheringRequest] with the currently set configuration. */
+            @NonNull
+            public TetheringRequest build() {
+                return new TetheringRequest(mBuilderParcel);
+            }
+        }
+
+        /**
+         * Get a TetheringRequestParcel from the configuration
+         * @hide
+         */
+        public TetheringRequestParcel getParcel() {
+            return mRequestParcel;
+        }
+
+        /** String of TetheringRequest detail. */
+        public String toString() {
+            return "TetheringRequest [ type= " + mRequestParcel.tetheringType
+                    + ", localIPv4Address= " + mRequestParcel.localIPv4Address
+                    + ", exemptFromEntitlementCheck= "
+                    + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= "
+                    + mRequestParcel.showProvisioningUi + " ]";
+        }
+    }
+
+    /**
+     * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
+     */
+    public abstract static class StartTetheringCallback {
+        /**
+         * Called when tethering has been successfully started.
+         */
+        public void onTetheringStarted() {}
+
+        /**
+         * Called when starting tethering failed.
+         *
+         * @param resultCode One of the {@code TETHER_ERROR_*} constants.
+         */
+        public void onTetheringFailed(final int resultCode) {}
+    }
+
+    /**
      * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
      * fails, stopTethering will be called automatically.
      *
+     * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+     * fail if a tethering entitlement check is required.
+     *
+     * @param request a {@link TetheringRequest} which can specify the preferred configuration.
+     * @param executor {@link Executor} to specify the thread upon which the callback of
+     *         TetheringRequest will be invoked.
+     * @param callback A callback that will be called to indicate the success status of the
+     *                 tethering start request.
      */
-    // TODO: improve the usage of ResultReceiver, b/145096122
-    public void startTethering(final int type, @NonNull final ResultReceiver receiver,
-            final boolean showProvisioningUi) {
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.TETHER_PRIVILEGED,
+            android.Manifest.permission.WRITE_SETTINGS
+    })
+    public void startTethering(@NonNull final TetheringRequest request,
+            @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) {
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "startTethering caller:" + callerPkg);
 
+        final IIntResultListener listener = new IIntResultListener.Stub() {
+            @Override
+            public void onResult(final int resultCode) {
+                executor.execute(() -> {
+                    if (resultCode == TETHER_ERROR_NO_ERROR) {
+                        callback.onTetheringStarted();
+                    } else {
+                        callback.onTetheringFailed(resultCode);
+                    }
+                });
+            }
+        };
         try {
-            mConnector.startTethering(type, receiver, showProvisioningUi, callerPkg);
+            mConnector.startTethering(request.getParcel(), callerPkg, listener);
         } catch (RemoteException e) {
             throw new IllegalStateException(e);
         }
     }
 
     /**
+     * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
+     * fails, stopTethering will be called automatically.
+     *
+     * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+     * fail if a tethering entitlement check is required.
+     *
+     * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants.
+     * @param executor {@link Executor} to specify the thread upon which the callback of
+     *         TetheringRequest will be invoked.
+     */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.TETHER_PRIVILEGED,
+            android.Manifest.permission.WRITE_SETTINGS
+    })
+    public void startTethering(int type, @NonNull final Executor executor,
+            @NonNull final StartTetheringCallback callback) {
+        startTethering(new TetheringRequest.Builder(type).build(), executor, callback);
+    }
+
+    /**
      * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
      * applicable.
+     *
+     * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+     * fail if a tethering entitlement check is required.
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.TETHER_PRIVILEGED,
+            android.Manifest.permission.WRITE_SETTINGS
+    })
     public void stopTethering(final int type) {
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "stopTethering caller:" + callerPkg);
@@ -375,11 +521,69 @@
     }
 
     /**
+     * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
+     * entitlement succeeded.
+     */
+    public interface OnTetheringEntitlementResultListener  {
+        /**
+         * Called to notify entitlement result.
+         *
+         * @param resultCode an int value of entitlement result. It may be one of
+         *         {@link #TETHER_ERROR_NO_ERROR},
+         *         {@link #TETHER_ERROR_PROVISION_FAILED}, or
+         *         {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
+         */
+        void onTetheringEntitlementResult(int resultCode);
+    }
+
+    /**
      * Request the latest value of the tethering entitlement check.
      *
-     * Note: Allow privileged apps who have TETHER_PRIVILEGED permission to access. If it turns
-     * out some such apps are observed to abuse this API, change to per-UID limits on this API
-     * if it's really needed.
+     * <p>This method will only return the latest entitlement result if it is available. If no
+     * cached entitlement result is available, and {@code showEntitlementUi} is false,
+     * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN} will be returned. If {@code showEntitlementUi} is
+     * true, entitlement will be run.
+     *
+     * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+     * fail if a tethering entitlement check is required.
+     *
+     * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants.
+     * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check.
+     * @param executor the executor on which callback will be invoked.
+     * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
+     *         notify the caller of the result of entitlement check. The listener may be called zero
+     *         or one time.
+     */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.TETHER_PRIVILEGED,
+            android.Manifest.permission.WRITE_SETTINGS
+    })
+    public void requestLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
+            @NonNull Executor executor,
+            @NonNull final OnTetheringEntitlementResultListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException(
+                    "OnTetheringEntitlementResultListener cannot be null.");
+        }
+
+        ResultReceiver wrappedListener = new ResultReceiver(null /* handler */) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                executor.execute(() -> {
+                    listener.onTetheringEntitlementResult(resultCode);
+                });
+            }
+        };
+
+        requestLatestTetheringEntitlementResult(type, wrappedListener,
+                    showEntitlementUi);
+    }
+
+    /**
+     * Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
+     * with ConnectivityManager#getLatestTetheringEntitlementResult
+     *
+     * {@hide}
      */
     // TODO: improve the usage of ResultReceiver, b/145096122
     public void requestLatestTetheringEntitlementResult(final int type,
@@ -396,25 +600,161 @@
     }
 
     /**
+     * Callback for use with {@link registerTetheringEventCallback} to find out tethering
+     * upstream status.
+     */
+    public abstract static class TetheringEventCallback {
+        /**
+         * Called when tethering supported status changed.
+         *
+         * <p>This will be called immediately after the callback is registered, and may be called
+         * multiple times later upon changes.
+         *
+         * <p>Tethering may be disabled via system properties, device configuration, or device
+         * policy restrictions.
+         *
+         * @param supported The new supported status
+         */
+        public void onTetheringSupported(boolean supported) {}
+
+        /**
+         * Called when tethering upstream changed.
+         *
+         * <p>This will be called immediately after the callback is registered, and may be called
+         * multiple times later upon changes.
+         *
+         * @param network the {@link Network} of tethering upstream. Null means tethering doesn't
+         * have any upstream.
+         */
+        public void onUpstreamChanged(@Nullable Network network) {}
+
+        /**
+         * Called when there was a change in tethering interface regular expressions.
+         *
+         * <p>This will be called immediately after the callback is registered, and may be called
+         * multiple times later upon changes.
+         * @param reg The new regular expressions.
+         * @deprecated Referencing interfaces by regular expressions is a deprecated mechanism.
+         */
+        @Deprecated
+        public void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
+
+        /**
+         * Called when there was a change in the list of tetherable interfaces.
+         *
+         * <p>This will be called immediately after the callback is registered, and may be called
+         * multiple times later upon changes.
+         * @param interfaces The list of tetherable interfaces.
+         */
+        public void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
+
+        /**
+         * Called when there was a change in the list of tethered interfaces.
+         *
+         * <p>This will be called immediately after the callback is registered, and may be called
+         * multiple times later upon changes.
+         * @param interfaces The list of tethered interfaces.
+         */
+        public void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
+
+        /**
+         * Called when an error occurred configuring tethering.
+         *
+         * <p>This will be called immediately after the callback is registered if the latest status
+         * on the interface is an error, and may be called multiple times later upon changes.
+         * @param ifName Name of the interface.
+         * @param error One of {@code TetheringManager#TETHER_ERROR_*}.
+         */
+        public void onError(@NonNull String ifName, int error) {}
+
+        /**
+         * Called when the list of tethered clients changes.
+         *
+         * <p>This callback provides best-effort information on connected clients based on state
+         * known to the system, however the list cannot be completely accurate (and should not be
+         * used for security purposes). For example, clients behind a bridge and using static IP
+         * assignments are not visible to the tethering device; or even when using DHCP, such
+         * clients may still be reported by this callback after disconnection as the system cannot
+         * determine if they are still connected.
+         * @param clients The new set of tethered clients; the collection is not ordered.
+         */
+        public void onClientsChanged(@NonNull Collection<TetheredClient> clients) {}
+    }
+
+    /**
+     * Regular expressions used to identify tethering interfaces.
+     * @deprecated Referencing interfaces by regular expressions is a deprecated mechanism.
+     */
+    @Deprecated
+    public static class TetheringInterfaceRegexps {
+        private final String[] mTetherableBluetoothRegexs;
+        private final String[] mTetherableUsbRegexs;
+        private final String[] mTetherableWifiRegexs;
+
+        public TetheringInterfaceRegexps(@NonNull String[] tetherableBluetoothRegexs,
+                @NonNull String[] tetherableUsbRegexs, @NonNull String[] tetherableWifiRegexs) {
+            mTetherableBluetoothRegexs = tetherableBluetoothRegexs.clone();
+            mTetherableUsbRegexs = tetherableUsbRegexs.clone();
+            mTetherableWifiRegexs = tetherableWifiRegexs.clone();
+        }
+
+        @NonNull
+        public List<String> getTetherableBluetoothRegexs() {
+            return Collections.unmodifiableList(Arrays.asList(mTetherableBluetoothRegexs));
+        }
+
+        @NonNull
+        public List<String> getTetherableUsbRegexs() {
+            return Collections.unmodifiableList(Arrays.asList(mTetherableUsbRegexs));
+        }
+
+        @NonNull
+        public List<String> getTetherableWifiRegexs() {
+            return Collections.unmodifiableList(Arrays.asList(mTetherableWifiRegexs));
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mTetherableBluetoothRegexs, mTetherableUsbRegexs,
+                    mTetherableWifiRegexs);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object obj) {
+            if (!(obj instanceof TetheringInterfaceRegexps)) return false;
+            final TetheringInterfaceRegexps other = (TetheringInterfaceRegexps) obj;
+            return Arrays.equals(mTetherableBluetoothRegexs, other.mTetherableBluetoothRegexs)
+                    && Arrays.equals(mTetherableUsbRegexs, other.mTetherableUsbRegexs)
+                    && Arrays.equals(mTetherableWifiRegexs, other.mTetherableWifiRegexs);
+        }
+    }
+
+    /**
      * Start listening to tethering change events. Any new added callback will receive the last
      * tethering status right away. If callback is registered,
-     * {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
+     * {@link TetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
      * has no upstream or disabled, the argument of callback will be null. The same callback object
      * cannot be registered twice.
      *
      * @param executor the executor on which callback will be invoked.
      * @param callback the callback to be called when tethering has change events.
      */
+    @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
     public void registerTetheringEventCallback(@NonNull Executor executor,
-            @NonNull OnTetheringEventCallback callback) {
+            @NonNull TetheringEventCallback callback) {
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "registerTetheringEventCallback caller:" + callerPkg);
 
         synchronized (mTetheringEventCallbacks) {
-            if (!mTetheringEventCallbacks.containsKey(callback)) {
+            if (mTetheringEventCallbacks.containsKey(callback)) {
                 throw new IllegalArgumentException("callback was already registered.");
             }
             final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
+                // Only accessed with a lock on this object
+                private final HashMap<String, Integer> mErrorStates = new HashMap<>();
+                private String[] mLastTetherableInterfaces = null;
+                private String[] mLastTetheredInterfaces = null;
+
                 @Override
                 public void onUpstreamChanged(Network network) throws RemoteException {
                     executor.execute(() -> {
@@ -422,11 +762,45 @@
                     });
                 }
 
+                private synchronized void sendErrorCallbacks(final TetherStatesParcel newStates) {
+                    for (int i = 0; i < newStates.erroredIfaceList.length; i++) {
+                        final String iface = newStates.erroredIfaceList[i];
+                        final Integer lastError = mErrorStates.get(iface);
+                        final int newError = newStates.lastErrorList[i];
+                        if (newError != TETHER_ERROR_NO_ERROR
+                                && !Objects.equals(lastError, newError)) {
+                            callback.onError(iface, newError);
+                        }
+                        mErrorStates.put(iface, newError);
+                    }
+                }
+
+                private synchronized void maybeSendTetherableIfacesChangedCallback(
+                        final TetherStatesParcel newStates) {
+                    if (Arrays.equals(mLastTetherableInterfaces, newStates.availableList)) return;
+                    mLastTetherableInterfaces = newStates.availableList.clone();
+                    callback.onTetherableInterfacesChanged(
+                            Collections.unmodifiableList(Arrays.asList(mLastTetherableInterfaces)));
+                }
+
+                private synchronized void maybeSendTetheredIfacesChangedCallback(
+                        final TetherStatesParcel newStates) {
+                    if (Arrays.equals(mLastTetheredInterfaces, newStates.tetheredList)) return;
+                    mLastTetheredInterfaces = newStates.tetheredList.clone();
+                    callback.onTetheredInterfacesChanged(
+                            Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
+                }
+
+                // Called immediately after the callbacks are registered.
                 @Override
-                public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
-                        TetherStatesParcel states) {
+                public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
                     executor.execute(() -> {
-                        callback.onUpstreamChanged(network);
+                        callback.onTetheringSupported(parcel.tetheringSupported);
+                        callback.onUpstreamChanged(parcel.upstreamNetwork);
+                        sendErrorCallbacks(parcel.states);
+                        sendRegexpsChanged(parcel.config);
+                        maybeSendTetherableIfacesChangedCallback(parcel.states);
+                        maybeSendTetheredIfacesChangedCallback(parcel.states);
                     });
                 }
 
@@ -437,11 +811,26 @@
                     });
                 }
 
-                @Override
-                public void onConfigurationChanged(TetheringConfigurationParcel config) { }
+                private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
+                    callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
+                            parcel.tetherableBluetoothRegexs,
+                            parcel.tetherableUsbRegexs,
+                            parcel.tetherableWifiRegexs));
+                }
 
                 @Override
-                public void onTetherStatesChanged(TetherStatesParcel states) { }
+                public void onConfigurationChanged(TetheringConfigurationParcel config) {
+                    executor.execute(() -> sendRegexpsChanged(config));
+                }
+
+                @Override
+                public void onTetherStatesChanged(TetherStatesParcel states) {
+                    executor.execute(() -> {
+                        sendErrorCallbacks(states);
+                        maybeSendTetherableIfacesChangedCallback(states);
+                        maybeSendTetheredIfacesChangedCallback(states);
+                    });
+                }
             };
             try {
                 mConnector.registerTetheringEventCallback(remoteCallback, callerPkg);
@@ -458,7 +847,11 @@
      *
      * @param callback previously registered callback.
      */
-    public void unregisterTetheringEventCallback(@NonNull final OnTetheringEventCallback callback) {
+    @RequiresPermission(anyOf = {
+            Manifest.permission.TETHER_PRIVILEGED,
+            Manifest.permission.ACCESS_NETWORK_STATE
+    })
+    public void unregisterTetheringEventCallback(@NonNull final TetheringEventCallback callback) {
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "unregisterTetheringEventCallback caller:" + callerPkg);
 
@@ -482,6 +875,7 @@
      * @param iface The name of the interface of interest
      * @return error The error code of the last error tethering or untethering the named
      *               interface
+     * @hide
      */
     public int getLastTetherError(@NonNull final String iface) {
         mCallback.waitForStarted();
@@ -503,6 +897,7 @@
      *
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable usb interfaces.
+     * @hide
      */
     public @NonNull String[] getTetherableUsbRegexs() {
         mCallback.waitForStarted();
@@ -516,6 +911,7 @@
      *
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable wifi interfaces.
+     * @hide
      */
     public @NonNull String[] getTetherableWifiRegexs() {
         mCallback.waitForStarted();
@@ -529,6 +925,7 @@
      *
      * @return an array of 0 or more regular expression Strings defining
      *        what interfaces are considered tetherable bluetooth interfaces.
+     * @hide
      */
     public @NonNull String[] getTetherableBluetoothRegexs() {
         mCallback.waitForStarted();
@@ -540,6 +937,7 @@
      * device configuration and current interface existence.
      *
      * @return an array of 0 or more Strings of tetherable interface names.
+     * @hide
      */
     public @NonNull String[] getTetherableIfaces() {
         mCallback.waitForStarted();
@@ -552,6 +950,7 @@
      * Get the set of tethered interfaces.
      *
      * @return an array of 0 or more String of currently tethered interface names.
+     * @hide
      */
     public @NonNull String[] getTetheredIfaces() {
         mCallback.waitForStarted();
@@ -570,6 +969,7 @@
      *
      * @return an array of 0 or more String indicating the interface names
      *        which failed to tether.
+     * @hide
      */
     public @NonNull String[] getTetheringErroredIfaces() {
         mCallback.waitForStarted();
@@ -582,6 +982,7 @@
      * Get the set of tethered dhcp ranges.
      *
      * @deprecated This API just return the default value which is not used in DhcpServer.
+     * @hide
      */
     @Deprecated
     public @NonNull String[] getTetheredDhcpRanges() {
@@ -595,6 +996,7 @@
      * due to device configuration.
      *
      * @return a boolean - {@code true} indicating Tethering is supported.
+     * @hide
      */
     public boolean isTetheringSupported() {
         final String callerPkg = mContext.getOpPackageName();
@@ -613,7 +1015,14 @@
 
     /**
      * Stop all active tethering.
+     *
+     * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+     * fail if a tethering entitlement check is required.
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.TETHER_PRIVILEGED,
+            android.Manifest.permission.WRITE_SETTINGS
+    })
     public void stopAllTethering() {
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "stopAllTethering caller:" + callerPkg);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
new file mode 100644
index 0000000..bf19d85
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
@@ -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.net.LinkAddress;
+
+/**
+ * Configuration details for requesting tethering.
+ * @hide
+ */
+parcelable TetheringRequestParcel {
+    int tetheringType;
+    LinkAddress localIPv4Address;
+    boolean exemptFromEntitlementCheck;
+    boolean showProvisioningUi;
+}
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index 6fa1f77..379cd18 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -29,6 +29,12 @@
     </string-array>
 
     <!-- List of regexpressions describing the interface (if any) that represent tetherable
+         NCM interfaces.  If the device doesn't want to support tethering over NCM this should
+         be empty. -->
+    <string-array translatable="false" name="config_tether_ncm_regexs">
+    </string-array>
+
+    <!-- List of regexpressions describing the interface (if any) that represent tetherable
          Wifi interfaces.  If the device doesn't want to support tethering over Wifi this
          should be empty.  An example would be "softap.*" -->
     <string-array translatable="false" name="config_tether_wifi_regexs">
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index e089d9d..fe025c7 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -17,6 +17,7 @@
     <overlayable name="TetheringConfig">
         <policy type="product|system|vendor">
             <item type="array" name="config_tether_usb_regexs"/>
+            <item type="array" name="config_tether_ncm_regexs" />
             <item type="array" name="config_tether_wifi_regexs"/>
             <item type="array" name="config_tether_wifi_p2p_regexs"/>
             <item type="array" name="config_tether_bluetooth_regexs"/>
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 0491ad7..190d2509 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -93,6 +93,8 @@
     private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
     private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1";
     private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24;
+    private static final String ETHERNET_IFACE_ADDR = "192.168.50.1";
+    private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24;
 
     // TODO: have PanService use some visible version of this constant
     private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
@@ -416,7 +418,8 @@
         final Inet4Address srvAddr;
         int prefixLen = 0;
         try {
-            if (mInterfaceType == TetheringManager.TETHERING_USB) {
+            if (mInterfaceType == TetheringManager.TETHERING_USB
+                    || mInterfaceType == TetheringManager.TETHERING_NCM) {
                 srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR);
                 prefixLen = USB_PREFIX_LENGTH;
             } else if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
@@ -425,6 +428,10 @@
             } else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
                 srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR);
                 prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
+            } else if (mInterfaceType == TetheringManager.TETHERING_ETHERNET) {
+                // TODO: randomize address for tethering too, similarly to wifi
+                srvAddr = (Inet4Address) parseNumericAddress(ETHERNET_IFACE_ADDR);
+                prefixLen = ETHERNET_IFACE_PREFIX_LENGTH;
             } else {
                 // BT configures the interface elsewhere: only start DHCP.
                 // TODO: make all tethering types behave the same way, and delete the bluetooth
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index 1cabc8d..e81d6ac 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -16,14 +16,14 @@
 
 package com.android.server.connectivity.tethering;
 
-import static android.net.TetheringManager.EXTRA_ADD_TETHER_TYPE;
-import static android.net.TetheringManager.EXTRA_PROVISION_CALLBACK;
-import static android.net.TetheringManager.EXTRA_RUN_PROVISION;
+import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
+import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
+import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
 import static android.net.TetheringManager.TETHERING_BLUETOOTH;
 import static android.net.TetheringManager.TETHERING_INVALID;
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
-import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
 
@@ -577,7 +577,7 @@
 
     private static String errorString(int value) {
         switch (value) {
-            case TETHER_ERROR_ENTITLEMENT_UNKONWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
+            case TETHER_ERROR_ENTITLEMENT_UNKNOWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
             case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR";
             case TETHER_ERROR_PROVISION_FAILED: return "TETHER_ERROR_PROVISION_FAILED";
             default:
@@ -657,7 +657,7 @@
         }
 
         final int cacheValue = mEntitlementCacheValue.get(
-                downstream, TETHER_ERROR_ENTITLEMENT_UNKONWN);
+                downstream, TETHER_ERROR_ENTITLEMENT_UNKNOWN);
         if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
             receiver.send(cacheValue, null);
         } else {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 5bf41ce..5b35bb6 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.hardware.usb.UsbManager.USB_CONFIGURED;
 import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
 import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
 import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
@@ -29,7 +30,9 @@
 import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
 import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
 import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
 import static android.net.TetheringManager.TETHERING_INVALID;
+import static android.net.TetheringManager.TETHERING_NCM;
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHERING_WIFI_P2P;
@@ -66,6 +69,8 @@
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.IIntResultListener;
 import android.net.INetd;
 import android.net.ITetheringEventCallback;
 import android.net.IpPrefix;
@@ -74,7 +79,9 @@
 import android.net.Network;
 import android.net.NetworkInfo;
 import android.net.TetherStatesParcel;
+import android.net.TetheringCallbackStartedParcel;
 import android.net.TetheringConfigurationParcel;
+import android.net.TetheringRequestParcel;
 import android.net.ip.IpServer;
 import android.net.shared.NetdUtils;
 import android.net.util.BaseNetdUnsolicitedEventListener;
@@ -107,6 +114,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.MessageUtils;
@@ -209,6 +217,13 @@
     private boolean mDataSaverEnabled = false;
     private String mWifiP2pTetherInterface = null;
 
+    @GuardedBy("mPublicSync")
+    private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
+    @GuardedBy("mPublicSync")
+    private String mConfiguredEthernetIface;
+    @GuardedBy("mPublicSync")
+    private EthernetCallback mEthernetCallback;
+
     public Tethering(TetheringDependencies deps) {
         mLog.mark("Tethering.constructed");
         mDeps = deps;
@@ -405,6 +420,8 @@
             return TETHERING_USB;
         } else if (cfg.isBluetooth(iface)) {
             return TETHERING_BLUETOOTH;
+        } else if (cfg.isNcm(iface)) {
+            return TETHERING_NCM;
         }
         return TETHERING_INVALID;
     }
@@ -423,9 +440,10 @@
         }
     }
 
-    void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
-        mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi);
-        enableTetheringInternal(type, true /* enabled */, receiver);
+    void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) {
+        mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
+                request.showProvisioningUi);
+        enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
     }
 
     void stopTethering(int type) {
@@ -437,29 +455,40 @@
      * Enables or disables tethering for the given type. If provisioning is required, it will
      * schedule provisioning rechecks for the specified interface.
      */
-    private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
+    private void enableTetheringInternal(int type, boolean enable,
+            final IIntResultListener listener) {
         int result;
         switch (type) {
             case TETHERING_WIFI:
                 result = setWifiTethering(enable);
-                sendTetherResult(receiver, result);
+                sendTetherResult(listener, result);
                 break;
             case TETHERING_USB:
                 result = setUsbTethering(enable);
-                sendTetherResult(receiver, result);
+                sendTetherResult(listener, result);
                 break;
             case TETHERING_BLUETOOTH:
-                setBluetoothTethering(enable, receiver);
+                setBluetoothTethering(enable, listener);
+                break;
+            case TETHERING_NCM:
+                result = setNcmTethering(enable);
+                sendTetherResult(listener, result);
+                break;
+            case TETHERING_ETHERNET:
+                result = setEthernetTethering(enable);
+                sendTetherResult(listener, result);
                 break;
             default:
                 Log.w(TAG, "Invalid tether type.");
-                sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
+                sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
         }
     }
 
-    private void sendTetherResult(ResultReceiver receiver, int result) {
-        if (receiver != null) {
-            receiver.send(result, null);
+    private void sendTetherResult(final IIntResultListener listener, int result) {
+        if (listener != null) {
+            try {
+                listener.onResult(result);
+            } catch (RemoteException e) { }
         }
     }
 
@@ -485,12 +514,12 @@
         return TETHER_ERROR_MASTER_ERROR;
     }
 
-    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
+    private void setBluetoothTethering(final boolean enable, final IIntResultListener listener) {
         final BluetoothAdapter adapter = mDeps.getBluetoothAdapter();
         if (adapter == null || !adapter.isEnabled()) {
             Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
                     + (adapter == null));
-            sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
+            sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL);
             return;
         }
 
@@ -519,12 +548,63 @@
                 final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
                         ? TETHER_ERROR_NO_ERROR
                         : TETHER_ERROR_MASTER_ERROR;
-                sendTetherResult(receiver, result);
+                sendTetherResult(listener, result);
                 adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
             }
         }, BluetoothProfile.PAN);
     }
 
+    private int setEthernetTethering(final boolean enable) {
+        final EthernetManager em = (EthernetManager) mContext.getSystemService(
+                Context.ETHERNET_SERVICE);
+        synchronized (mPublicSync) {
+            if (enable) {
+                mEthernetCallback = new EthernetCallback();
+                mEthernetIfaceRequest = em.requestTetheredInterface(mEthernetCallback);
+            } else {
+                if (mConfiguredEthernetIface != null) {
+                    stopEthernetTetheringLocked();
+                    mEthernetIfaceRequest.release();
+                }
+                mEthernetCallback = null;
+            }
+        }
+        return TETHER_ERROR_NO_ERROR;
+    }
+
+    private void stopEthernetTetheringLocked() {
+        if (mConfiguredEthernetIface == null) return;
+        changeInterfaceState(mConfiguredEthernetIface, IpServer.STATE_AVAILABLE);
+        stopTrackingInterfaceLocked(mConfiguredEthernetIface);
+        mConfiguredEthernetIface = null;
+    }
+
+    private class EthernetCallback implements EthernetManager.TetheredInterfaceCallback {
+        @Override
+        public void onAvailable(String iface) {
+            synchronized (mPublicSync) {
+                if (this != mEthernetCallback) {
+                    // Ethernet callback arrived after Ethernet tethering stopped. Ignore.
+                    return;
+                }
+                maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET);
+                changeInterfaceState(iface, IpServer.STATE_TETHERED);
+                mConfiguredEthernetIface = iface;
+            }
+        }
+
+        @Override
+        public void onUnavailable() {
+            synchronized (mPublicSync) {
+                if (this != mEthernetCallback) {
+                    // onAvailable called after stopping Ethernet tethering.
+                    return;
+                }
+                stopEthernetTetheringLocked();
+            }
+        }
+    }
+
     int tether(String iface) {
         return tether(iface, IpServer.STATE_TETHERED);
     }
@@ -575,6 +655,7 @@
         stopTethering(TETHERING_WIFI_P2P);
         stopTethering(TETHERING_USB);
         stopTethering(TETHERING_BLUETOOTH);
+        stopTethering(TETHERING_ETHERNET);
     }
 
     int getLastTetherError(String iface) {
@@ -798,6 +879,7 @@
             final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
             final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
             final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
+            final boolean ncmEnabled = intent.getBooleanExtra(USB_FUNCTION_NCM, false);
 
             mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
                     usbConnected, usbConfigured, rndisEnabled));
@@ -825,6 +907,8 @@
                 } else if (usbConfigured && rndisEnabled) {
                     // Tether if rndis is enabled and usb is configured.
                     tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
+                } else if (usbConnected && ncmEnabled) {
+                    tetherMatchingInterfaces(IpServer.STATE_LOCAL_ONLY, TETHERING_NCM);
                 }
                 mRndisEnabled = usbConfigured && rndisEnabled;
             }
@@ -951,6 +1035,7 @@
                 mWrapper.showTetheredNotification(
                         R.drawable.stat_sys_tether_general, false);
                 mWrapper.untetherAll();
+                // TODO(b/148139325): send tetheringSupported on restriction change
             }
         }
     }
@@ -1125,6 +1210,16 @@
         return TETHER_ERROR_NO_ERROR;
     }
 
+    private int setNcmTethering(boolean enable) {
+        if (VDBG) Log.d(TAG, "setNcmTethering(" + enable + ")");
+        UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
+        synchronized (mPublicSync) {
+            usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_NCM
+                    : UsbManager.FUNCTION_NONE);
+        }
+        return TETHER_ERROR_NO_ERROR;
+    }
+
     // TODO review API - figure out how to delete these entirely.
     String[] getTetheredIfaces() {
         ArrayList<String> list = new ArrayList<String>();
@@ -1844,9 +1939,13 @@
     void registerTetheringEventCallback(ITetheringEventCallback callback) {
         mHandler.post(() -> {
             mTetheringEventCallbacks.register(callback);
+            final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
+            parcel.tetheringSupported = mDeps.isTetheringSupported();
+            parcel.upstreamNetwork = mTetherUpstream;
+            parcel.config = mConfig.toStableParcelable();
+            parcel.states = mTetherStatesParcel;
             try {
-                callback.onCallbackStarted(mTetherUpstream, mConfig.toStableParcelable(),
-                        mTetherStatesParcel);
+                callback.onCallbackStarted(parcel);
             } catch (RemoteException e) {
                 // Not really very much to do here.
             }
@@ -1881,6 +1980,7 @@
             for (int i = 0; i < length; i++) {
                 try {
                     mTetheringEventCallbacks.getBroadcastItem(i).onConfigurationChanged(config);
+                    // TODO(b/148139325): send tetheringSupported on configuration change
                 } catch (RemoteException e) {
                     // Not really very much to do here.
                 }
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 068c346..7e9e26f 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -83,6 +83,7 @@
     public final String[] tetherableWifiRegexs;
     public final String[] tetherableWifiP2pRegexs;
     public final String[] tetherableBluetoothRegexs;
+    public final String[] tetherableNcmRegexs;
     public final boolean isDunRequired;
     public final boolean chooseUpstreamAutomatically;
     public final Collection<Integer> preferredUpstreamIfaceTypes;
@@ -103,6 +104,7 @@
         Resources res = getResources(ctx, activeDataSubId);
 
         tetherableUsbRegexs = getResourceStringArray(res, R.array.config_tether_usb_regexs);
+        tetherableNcmRegexs = getResourceStringArray(res, R.array.config_tether_ncm_regexs);
         // TODO: Evaluate deleting this altogether now that Wi-Fi always passes
         // us an interface name. Careful consideration needs to be given to
         // implications for Settings and for provisioning checks.
@@ -156,6 +158,11 @@
         return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
     }
 
+    /** Check if interface is ncm */
+    public boolean isNcm(String iface) {
+        return matchesDownstreamRegexs(iface, tetherableNcmRegexs);
+    }
+
     /** Check whether no ui entitlement application is available.*/
     public boolean hasMobileHotspotProvisionApp() {
         return !TextUtils.isEmpty(provisioningAppNoUi);
@@ -170,6 +177,7 @@
         dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
         dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
         dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
+        dumpStringArray(pw, "tetherableNcmRegexs", tetherableNcmRegexs);
 
         pw.print("isDunRequired: ");
         pw.println(isDunRequired);
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
index cb7d392..7dc5c5f 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -33,6 +33,7 @@
 import android.net.ITetheringEventCallback;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.TetheringRequestParcel;
 import android.net.dhcp.DhcpServerCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.ip.IpServer;
@@ -143,11 +144,11 @@
         }
 
         @Override
-        public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
-                String callerPkg) {
-            if (checkAndNotifyCommonError(callerPkg, receiver)) return;
+        public void startTethering(TetheringRequestParcel request, String callerPkg,
+                IIntResultListener listener) {
+            if (checkAndNotifyCommonError(callerPkg, listener)) return;
 
-            mTethering.startTethering(type, receiver, showProvisioningUi);
+            mTethering.startTethering(request, listener);
         }
 
         @Override
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index 53782fed..13174c5 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -19,6 +19,7 @@
     certificate: "platform",
     srcs: [
         "src/**/*.java",
+        "src/**/*.kt",
     ],
     test_suites: [
         "device-tests",
diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml
index 0a1cdd3..530bc07 100644
--- a/packages/Tethering/tests/unit/AndroidManifest.xml
+++ b/packages/Tethering/tests/unit/AndroidManifest.xml
@@ -16,6 +16,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.networkstack.tethering.tests.unit">
 
+    <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
+
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt b/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt
new file mode 100644
index 0000000..83c19ec
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.net.InetAddresses.parseNumericAddress
+import android.net.TetheredClient.AddressInfo
+import android.net.TetheringManager.TETHERING_BLUETOOTH
+import android.net.TetheringManager.TETHERING_USB
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+
+private val TEST_MACADDR = MacAddress.fromBytes(byteArrayOf(12, 23, 34, 45, 56, 67))
+private val TEST_OTHER_MACADDR = MacAddress.fromBytes(byteArrayOf(23, 34, 45, 56, 67, 78))
+private val TEST_ADDR1 = LinkAddress(parseNumericAddress("192.168.113.3"), 24)
+private val TEST_ADDR2 = LinkAddress(parseNumericAddress("fe80::1:2:3"), 64)
+private val TEST_ADDRINFO1 = AddressInfo(TEST_ADDR1, "test_hostname")
+private val TEST_ADDRINFO2 = AddressInfo(TEST_ADDR2, null)
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TetheredClientTest {
+    @Test
+    fun testParceling() {
+        assertParcelSane(makeTestClient(), fieldCount = 3)
+    }
+
+    @Test
+    fun testEquals() {
+        assertEquals(makeTestClient(), makeTestClient())
+
+        // Different mac address
+        assertNotEquals(makeTestClient(), TetheredClient(
+                TEST_OTHER_MACADDR,
+                listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
+                TETHERING_BLUETOOTH))
+
+        // Different hostname
+        assertNotEquals(makeTestClient(), TetheredClient(
+                TEST_MACADDR,
+                listOf(AddressInfo(TEST_ADDR1, "test_other_hostname"), TEST_ADDRINFO2),
+                TETHERING_BLUETOOTH))
+
+        // Null hostname
+        assertNotEquals(makeTestClient(), TetheredClient(
+                TEST_MACADDR,
+                listOf(AddressInfo(TEST_ADDR1, null), TEST_ADDRINFO2),
+                TETHERING_BLUETOOTH))
+
+        // Missing address
+        assertNotEquals(makeTestClient(), TetheredClient(
+                TEST_MACADDR,
+                listOf(TEST_ADDRINFO2),
+                TETHERING_BLUETOOTH))
+
+        // Different type
+        assertNotEquals(makeTestClient(), TetheredClient(
+                TEST_MACADDR,
+                listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
+                TETHERING_BLUETOOTH))
+    }
+
+    @Test
+    fun testAddAddresses() {
+        val client1 = TetheredClient(TEST_MACADDR, listOf(TEST_ADDRINFO1), TETHERING_USB)
+        val client2 = TetheredClient(TEST_OTHER_MACADDR, listOf(TEST_ADDRINFO2), TETHERING_USB)
+        assertEquals(TetheredClient(
+                TEST_MACADDR,
+                listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
+                TETHERING_USB), client1.addAddresses(client2))
+    }
+
+    private fun makeTestClient() = TetheredClient(
+            TEST_MACADDR,
+            listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
+            TETHERING_BLUETOOTH)
+}
\ No newline at end of file
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 4f07461..3a1d4a6 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -19,7 +19,7 @@
 import static android.net.TetheringManager.TETHERING_BLUETOOTH;
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
-import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
@@ -110,7 +110,7 @@
     }
 
     public class WrappedEntitlementManager extends EntitlementManager {
-        public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+        public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKNOWN;
         public int uiProvisionCount = 0;
         public int silentProvisionCount = 0;
 
@@ -120,7 +120,7 @@
         }
 
         public void reset() {
-            fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+            fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKNOWN;
             uiProvisionCount = 0;
             silentProvisionCount = 0;
         }
@@ -274,7 +274,7 @@
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
-                assertEquals(TETHER_ERROR_ENTITLEMENT_UNKONWN, resultCode);
+                assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode);
                 mCallbacklatch.countDown();
             }
         };
@@ -343,7 +343,7 @@
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
-                assertEquals(TETHER_ERROR_ENTITLEMENT_UNKONWN, resultCode);
+                assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode);
                 mCallbacklatch.countDown();
             }
         };
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index affd691..e7c3e55 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -18,6 +18,7 @@
 
 import static android.hardware.usb.UsbManager.USB_CONFIGURED;
 import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
 import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
 import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
@@ -27,6 +28,7 @@
 import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
 import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
 import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.TetheringManager.TETHERING_NCM;
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
@@ -86,7 +88,9 @@
 import android.net.NetworkRequest;
 import android.net.RouteInfo;
 import android.net.TetherStatesParcel;
+import android.net.TetheringCallbackStartedParcel;
 import android.net.TetheringConfigurationParcel;
+import android.net.TetheringRequestParcel;
 import android.net.dhcp.DhcpServerCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpServer;
@@ -149,6 +153,7 @@
     private static final String TEST_USB_IFNAME = "test_rndis0";
     private static final String TEST_WLAN_IFNAME = "test_wlan0";
     private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
+    private static final String TEST_NCM_IFNAME = "test_ncm0";
     private static final String TETHERING_NAME = "Tethering";
 
     private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
@@ -250,9 +255,11 @@
                     ifName.equals(TEST_USB_IFNAME)
                             || ifName.equals(TEST_WLAN_IFNAME)
                             || ifName.equals(TEST_MOBILE_IFNAME)
-                            || ifName.equals(TEST_P2P_IFNAME));
+                            || ifName.equals(TEST_P2P_IFNAME)
+                            || ifName.equals(TEST_NCM_IFNAME));
             final String[] ifaces = new String[] {
-                    TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME};
+                    TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME,
+                    TEST_NCM_IFNAME};
             return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
                     MacAddress.ALL_ZEROS_ADDRESS);
         }
@@ -426,13 +433,16 @@
                 .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
         when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
                 .thenReturn(new String[0]);
+        when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
+                .thenReturn(new String[] { "test_ncm\\d" });
         when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
         when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
         when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
                 false);
         when(mNetd.interfaceGetList())
                 .thenReturn(new String[] {
-                        TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
+                        TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME,
+                        TEST_NCM_IFNAME});
         when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn("");
         mInterfaceConfiguration = new InterfaceConfigurationParcel();
         mInterfaceConfiguration.flags = new String[0];
@@ -467,6 +477,16 @@
         return new Tethering(mTetheringDependencies);
     }
 
+    private TetheringRequestParcel createTetheringRquestParcel(final int type) {
+        final TetheringRequestParcel request = new TetheringRequestParcel();
+        request.tetheringType = type;
+        request.localIPv4Address = null;
+        request.exemptFromEntitlementCheck = false;
+        request.showProvisioningUi = false;
+
+        return request;
+    }
+
     @After
     public void tearDown() {
         mServiceContext.unregisterReceiver(mBroadcastReceiver);
@@ -512,11 +532,16 @@
                 P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
     }
 
-    private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
+    private void sendUsbBroadcast(boolean connected, boolean configured, boolean function,
+            int type) {
         final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
         intent.putExtra(USB_CONNECTED, connected);
         intent.putExtra(USB_CONFIGURED, configured);
-        intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
+        if (type == TETHERING_USB) {
+            intent.putExtra(USB_FUNCTION_RNDIS, function);
+        } else {
+            intent.putExtra(USB_FUNCTION_NCM, function);
+        }
         mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
@@ -566,13 +591,22 @@
         verifyNoMoreInteractions(mWifiManager);
     }
 
+    private void prepareNcmTethering() {
+        // Emulate startTethering(TETHERING_NCM) called
+        mTethering.startTethering(createTetheringRquestParcel(TETHERING_NCM), null);
+        mLooper.dispatchAll();
+        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NCM);
+
+        mTethering.interfaceStatusChanged(TEST_NCM_IFNAME, true);
+    }
+
     private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
         when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
         when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
                 .thenReturn(upstreamState);
 
         // Emulate pressing the USB tethering button in Settings UI.
-        mTethering.startTethering(TETHERING_USB, null, false);
+        mTethering.startTethering(createTetheringRquestParcel(TETHERING_USB), null);
         mLooper.dispatchAll();
         verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
 
@@ -588,7 +622,7 @@
         verifyNoMoreInteractions(mNetd);
 
         // Pretend we then receive USB configured broadcast.
-        sendUsbBroadcast(true, true, true);
+        sendUsbBroadcast(true, true, true, TETHERING_USB);
         mLooper.dispatchAll();
         // Now we should see the start of tethering mechanics (in this case:
         // tetherMatchingInterfaces() which starts by fetching all interfaces).
@@ -679,7 +713,7 @@
 
     private void runUsbTethering(UpstreamNetworkState upstreamState) {
         prepareUsbTethering(upstreamState);
-        sendUsbBroadcast(true, true, true);
+        sendUsbBroadcast(true, true, true, TETHERING_USB);
         mLooper.dispatchAll();
     }
 
@@ -802,6 +836,29 @@
         verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
     }
 
+    private void runNcmTethering() {
+        prepareNcmTethering();
+        sendUsbBroadcast(true, true, true, TETHERING_NCM);
+        mLooper.dispatchAll();
+    }
+
+    @Test
+    public void workingNcmTethering() throws Exception {
+        runNcmTethering();
+
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
+    }
+
+    @Test
+    public void workingNcmTethering_LegacyDhcp() {
+        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
+                true);
+        sendConfigurationChanged();
+        runNcmTethering();
+
+        verify(mIpServerDependencies, never()).makeDhcpServer(any(), any(), any());
+    }
+
     @Test
     public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
         workingLocalOnlyHotspotEnrichedApBroadcast(true);
@@ -818,7 +875,7 @@
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(TETHERING_WIFI, null, false);
+        mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
@@ -845,7 +902,7 @@
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(TETHERING_WIFI, null, false);
+        mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
@@ -922,7 +979,7 @@
         doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(TETHERING_WIFI, null, false);
+        mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
@@ -1113,11 +1170,10 @@
         }
 
         @Override
-        public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
-                TetherStatesParcel states) {
-            mActualUpstreams.add(network);
-            mTetheringConfigs.add(config);
-            mTetherStates.add(states);
+        public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
+            mActualUpstreams.add(parcel.upstreamNetwork);
+            mTetheringConfigs.add(parcel.config);
+            mTetherStates.add(parcel.states);
         }
 
         @Override
@@ -1188,7 +1244,7 @@
         tetherState = callback.pollTetherStatesChanged();
         assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
 
-        mTethering.startTethering(TETHERING_WIFI, null, false);
+        mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
         mLooper.dispatchAll();
         tetherState = callback.pollTetherStatesChanged();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 76c119d..478b87c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -66,6 +66,7 @@
 import android.net.ConnectionInfo;
 import android.net.ConnectivityManager;
 import android.net.ICaptivePortal;
+import android.net.IConnectivityDiagnosticsCallback;
 import android.net.IConnectivityManager;
 import android.net.IDnsResolver;
 import android.net.IIpConnectivityMetrics;
@@ -212,6 +213,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.ConcurrentModificationException;
 import java.util.HashMap;
@@ -1624,7 +1626,8 @@
         return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
     }
 
-    private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
+    @VisibleForTesting
+    NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
             NetworkCapabilities nc, int callerPid, int callerUid) {
         final NetworkCapabilities newNc = new NetworkCapabilities(nc);
         if (!checkSettingsPermission(callerPid, callerUid)) {
@@ -1634,9 +1637,24 @@
         if (newNc.getNetworkSpecifier() != null) {
             newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
         }
+        newNc.setAdministratorUids(Collections.EMPTY_LIST);
+
+        maybeSanitizeLocationInfoForCaller(newNc, callerUid);
+
         return newNc;
     }
 
+    private void maybeSanitizeLocationInfoForCaller(
+            NetworkCapabilities nc, int callerUid) {
+        // TODO(b/142072839): Conditionally reset the owner UID if the following
+        // conditions are not met:
+        // 1. The destination app is the network owner
+        // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted
+        // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted
+        // 3. The user's location toggle is on
+        nc.setOwnerUid(INVALID_UID);
+    }
+
     private LinkProperties linkPropertiesRestrictedForCallerPermissions(
             LinkProperties lp, int callerPid, int callerUid) {
         if (lp == null) return new LinkProperties();
@@ -1664,6 +1682,10 @@
         if (!checkSettingsPermission()) {
             nc.setSingleUid(Binder.getCallingUid());
         }
+        nc.setAdministratorUids(Collections.EMPTY_LIST);
+
+        // Clear owner UID; this can never come from an app.
+        nc.setOwnerUid(INVALID_UID);
     }
 
     private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
@@ -5791,7 +5813,7 @@
         }
 
         final Set<UidRange> ranges = nai.networkCapabilities.getUids();
-        final int vpnAppUid = nai.networkCapabilities.getEstablishingVpnAppUid();
+        final int vpnAppUid = nai.networkCapabilities.getOwnerUid();
         // TODO: this create a window of opportunity for apps to receive traffic between the time
         // when the old rules are removed and the time when new rules are added. To fix this,
         // make eBPF support two whitelisted interfaces so here new rules can be added before the
@@ -5990,7 +6012,7 @@
         if (nc == null || lp == null) return false;
         return nai.isVPN()
                 && !nai.networkAgentConfig.allowBypass
-                && nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID
+                && nc.getOwnerUid() != Process.SYSTEM_UID
                 && lp.getInterfaceName() != null
                 && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
     }
@@ -6038,12 +6060,10 @@
             // TODO Fix this window by computing an accurate diff on Set<UidRange>, so the old range
             // to be removed will never overlap with the new range to be added.
             if (wasFiltering && !prevRanges.isEmpty()) {
-                mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges,
-                        prevNc.getEstablishingVpnAppUid());
+                mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, prevNc.getOwnerUid());
             }
             if (shouldFilter && !newRanges.isEmpty()) {
-                mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges,
-                        newNc.getEstablishingVpnAppUid());
+                mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, newNc.getOwnerUid());
             }
         } catch (Exception e) {
             // Never crash!
@@ -7304,4 +7324,20 @@
             return mTNS;
         }
     }
+
+    @Override
+    public void registerConnectivityDiagnosticsCallback(
+            @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) {
+        // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality
+        throw new UnsupportedOperationException(
+                "registerConnectivityDiagnosticsCallback not yet implemented");
+    }
+
+    @Override
+    public void unregisterConnectivityDiagnosticsCallback(
+            @NonNull IConnectivityDiagnosticsCallback callback) {
+        // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality
+        throw new UnsupportedOperationException(
+                "unregisterConnectivityDiagnosticsCallback not yet implemented");
+    }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 90b0c11..39ad354 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2788,6 +2788,24 @@
     }
 
     /*
+     * Clear disk encryption key bound to the associated token / secret pair. Removing the user
+     * binding of the Disk encryption key is done in two phases: first, this call will retrieve
+     * the disk encryption key using the provided token / secret pair and store it by
+     * encrypting it with a keymaster key not bound to the user, then fixateNewestUserKeyAuth
+     * is called to delete all other bindings of the disk encryption key.
+     */
+    @Override
+    public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
+        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+
+        try {
+            mVold.clearUserKeyAuth(userId, serialNumber, encodeBytes(token), encodeBytes(secret));
+        } catch (Exception e) {
+            Slog.wtf(TAG, e);
+        }
+    }
+
+    /*
      * Delete all disk encryption token/secret pairs except the most recently added one
      */
     @Override
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 62743aa..5eacb28 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -882,6 +882,10 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+                            != 0) {
+                        updateReportSignalStrengthDecision(r.subId);
+                    }
                     if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
                         try {
                             if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
@@ -1005,6 +1009,27 @@
         }
     }
 
+    private void updateReportSignalStrengthDecision(int subscriptionId) {
+        synchronized (mRecords) {
+            TelephonyManager telephonyManager = (TelephonyManager) mContext
+                    .getSystemService(Context.TELEPHONY_SERVICE);
+            for (Record r : mRecords) {
+                // 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)) {
+                    telephonyManager.createForSubscriptionId(subscriptionId)
+                            .setAlwaysReportSignalStrength(true);
+                    return;
+                }
+            }
+            // If none of the system clients wants to always listen to signal strength,
+            // we need to set it off.
+            telephonyManager.createForSubscriptionId(subscriptionId)
+                    .setAlwaysReportSignalStrength(false);
+        }
+    }
+
     private String getCallIncomingNumber(Record record, int phoneId) {
         // Only reveal the incoming number if the record has read call log permission.
         return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : "";
@@ -1062,6 +1087,14 @@
                     }
 
                     mRecords.remove(i);
+
+                    // Every time a client that is registrating to always receive the signal
+                    // 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)) {
+                        updateReportSignalStrengthDecision(r.subId);
+                    }
                     return;
                 }
             }
@@ -2415,6 +2448,11 @@
                     android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
         }
 
+        if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
+        }
+
         if ((events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f021008..5833d16 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -272,6 +272,7 @@
 
         static final int MSG_BG_START_TIMEOUT = 1;
         static final int MSG_UPDATE_FOREGROUND_APPS = 2;
+        static final int MSG_ENSURE_NOT_START_BG = 3;
 
         ServiceMap(Looper looper, int userId) {
             super(looper);
@@ -289,6 +290,11 @@
                 case MSG_UPDATE_FOREGROUND_APPS: {
                     updateForegroundApps(this);
                 } break;
+                case MSG_ENSURE_NOT_START_BG: {
+                    synchronized (mAm) {
+                        rescheduleDelayedStartsLocked();
+                    }
+                } break;
             }
         }
 
@@ -296,7 +302,9 @@
             if (mStartingBackground.remove(r)) {
                 if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                         "No longer background starting: " + r);
-                rescheduleDelayedStartsLocked();
+                removeMessages(MSG_ENSURE_NOT_START_BG);
+                Message msg = obtainMessage(MSG_ENSURE_NOT_START_BG);
+                sendMessage(msg);
             }
             if (mDelayedStartList.remove(r)) {
                 if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b311233..1452e25 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1538,6 +1538,9 @@
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                             | Intent.FLAG_RECEIVER_FOREGROUND);
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
+                    // Also, add the UserHandle for mainline modules which can't use the @hide
+                    // EXTRA_USER_HANDLE.
+                    intent.putExtra(Intent.EXTRA_USER, UserHandle.of(profileUserId));
                     mInjector.broadcastIntent(intent,
                             null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                             null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
@@ -1554,6 +1557,9 @@
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                             | Intent.FLAG_RECEIVER_FOREGROUND);
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
+                    // Also, add the UserHandle for mainline modules which can't use the @hide
+                    // EXTRA_USER_HANDLE.
+                    intent.putExtra(Intent.EXTRA_USER, UserHandle.of(profileUserId));
                     mInjector.broadcastIntent(intent,
                             null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                             null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
@@ -1563,6 +1569,9 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_FOREGROUND);
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
+                // Also, add the UserHandle for mainline modules which can't use the @hide
+                // EXTRA_USER_HANDLE.
+                intent.putExtra(Intent.EXTRA_USER, UserHandle.of(newUserId));
                 mInjector.broadcastIntent(intent,
                         null, null, 0, null, null,
                         new String[] {android.Manifest.permission.MANAGE_USERS},
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 029b7bc..e48169f 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,6 +16,11 @@
 
 package com.android.server.compat;
 
+import static android.Manifest.permission.LOG_COMPAT_CHANGE;
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
+import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.content.Context;
@@ -67,12 +72,14 @@
 
     @Override
     public void reportChange(long changeId, ApplicationInfo appInfo) {
+        checkCompatChangeLogPermission();
         reportChange(changeId, appInfo.uid,
                 StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
     }
 
     @Override
     public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+        checkCompatChangeLogPermission();
         ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
         if (appInfo == null) {
             return;
@@ -82,11 +89,13 @@
 
     @Override
     public void reportChangeByUid(long changeId, int uid) {
+        checkCompatChangeLogPermission();
         reportChange(changeId, uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
     }
 
     @Override
     public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
+        checkCompatChangeReadPermission();
         if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
             reportChange(changeId, appInfo.uid,
                     StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
@@ -99,6 +108,7 @@
 
     @Override
     public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+        checkCompatChangeReadPermission();
         ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
         if (appInfo == null) {
             return true;
@@ -108,6 +118,7 @@
 
     @Override
     public boolean isChangeEnabledByUid(long changeId, int uid) {
+        checkCompatChangeReadPermission();
         String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
         if (packages == null || packages.length == 0) {
             return true;
@@ -140,6 +151,7 @@
     @Override
     public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
             throws RemoteException, SecurityException {
+        checkCompatChangeOverridePermission();
         mCompatConfig.addOverrides(overrides, packageName);
         killPackage(packageName);
     }
@@ -147,11 +159,13 @@
     @Override
     public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
             throws RemoteException, SecurityException {
+        checkCompatChangeOverridePermission();
         mCompatConfig.addOverrides(overrides, packageName);
     }
 
     @Override
     public void clearOverrides(String packageName) throws RemoteException, SecurityException {
+        checkCompatChangeOverridePermission();
         mCompatConfig.removePackageOverrides(packageName);
         killPackage(packageName);
     }
@@ -159,12 +173,14 @@
     @Override
     public void clearOverridesForTest(String packageName)
             throws RemoteException, SecurityException {
+        checkCompatChangeOverridePermission();
         mCompatConfig.removePackageOverrides(packageName);
     }
 
     @Override
     public boolean clearOverride(long changeId, String packageName)
             throws RemoteException, SecurityException {
+        checkCompatChangeOverridePermission();
         boolean existed = mCompatConfig.removeOverride(changeId, packageName);
         killPackage(packageName);
         return existed;
@@ -172,11 +188,13 @@
 
     @Override
     public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
+        checkCompatChangeReadPermission();
         return mCompatConfig.getAppConfig(appInfo);
     }
 
     @Override
     public CompatibilityChangeInfo[] listAllChanges() {
+        checkCompatChangeReadPermission();
         return mCompatConfig.dumpChanges();
     }
 
@@ -215,6 +233,7 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        checkCompatChangeReadPermission();
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
         mCompatConfig.dumpConfig(pw);
     }
@@ -276,4 +295,25 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
+
+    private void checkCompatChangeLogPermission() throws SecurityException {
+        if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE)
+                != PERMISSION_GRANTED) {
+            throw new SecurityException("Cannot log compat change usage");
+        }
+    }
+
+    private void checkCompatChangeReadPermission() throws SecurityException {
+        if (mContext.checkCallingOrSelfPermission(READ_COMPAT_CHANGE_CONFIG)
+                != PERMISSION_GRANTED) {
+            throw new SecurityException("Cannot read compat change");
+        }
+    }
+
+    private void checkCompatChangeOverridePermission() throws SecurityException {
+        if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
+                != PERMISSION_GRANTED) {
+            throw new SecurityException("Cannot override compat change");
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 69ab47a..2933fab 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -950,7 +950,7 @@
         NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
         networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
 
-        mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid());
+        mNetworkCapabilities.setOwnerUid(Binder.getCallingUid());
         mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
                 mConfig.allowedApplications, mConfig.disallowedApplications));
         long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/lights/OWNERS b/services/core/java/com/android/server/lights/OWNERS
index c7c6d56..0e795b9 100644
--- a/services/core/java/com/android/server/lights/OWNERS
+++ b/services/core/java/com/android/server/lights/OWNERS
@@ -1,2 +1,3 @@
 michaelwr@google.com
-dangittik@google.com
+santoscordon@google.com
+flc@google.com
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9510db0..288484f 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -25,7 +25,6 @@
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
 import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
-import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
 import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.USER_FRP;
@@ -1511,7 +1510,7 @@
             if (credential != null) {
                 Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
             }
-            clearUserKeyProtection(userId);
+            clearUserKeyProtection(userId, null);
             getGateKeeperService().clearSecureUserId(userId);
             mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
             setKeystorePassword(null, userId);
@@ -1688,9 +1687,17 @@
         addUserKeyAuth(userId, token, secretFromCredential(credential));
     }
 
-    private void clearUserKeyProtection(int userId) throws RemoteException {
+    private void clearUserKeyProtection(int userId, byte[] secret) {
         if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
-        addUserKeyAuth(userId, null, null);
+        final UserInfo userInfo = mUserManager.getUserInfo(userId);
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            mStorageManager.clearUserKeyAuth(userId, userInfo.serialNumber, null, secret);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("clearUserKeyAuth failed user=" + userId);
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
     }
 
     private static byte[] secretFromCredential(byte[] credential) throws RemoteException {
@@ -2512,7 +2519,7 @@
             setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
             setKeystorePassword(auth.deriveKeyStorePassword(), userId);
         } else {
-            clearUserKeyProtection(userId);
+            clearUserKeyProtection(userId, null);
             setKeystorePassword(null, userId);
             getGateKeeperService().clearSecureUserId(userId);
         }
@@ -2532,23 +2539,12 @@
             return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
         }
         long handle = getSyntheticPasswordHandleLocked(userId);
-        // This is a global setting
-        long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
-                SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
-      return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
+        return handle != SyntheticPasswordManager.DEFAULT_HANDLE;
     }
 
     @VisibleForTesting
     protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
-        long handle = getSyntheticPasswordHandleLocked(userId);
-        // This is a global setting
-        long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
-                SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
-        return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
-    }
-
-    private void enableSyntheticPasswordLocked() {
-        setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
+        return true;
     }
 
     private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential,
@@ -2698,7 +2694,7 @@
             // during boot. Vold storage needs to be unlocked before manipulation of the keys can
             // succeed.
             unlockUserKey(userId, null, auth.deriveDiskEncryptionKey());
-            clearUserKeyProtection(userId);
+            clearUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
             fixateNewestUserKeyAuth(userId);
             unlockKeystore(auth.deriveKeyStorePassword(), userId);
             setKeystorePassword(null, userId);
@@ -2829,7 +2825,6 @@
             throws RemoteException {
         if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
         synchronized (mSpManager) {
-            enableSyntheticPasswordLocked();
             // Migrate to synthetic password based credentials if the user has no password,
             // the token can then be activated immediately.
             AuthenticationToken auth = null;
diff --git a/services/core/java/com/android/server/policy/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
index e08c004..157f825 100644
--- a/services/core/java/com/android/server/policy/GlobalKeyManager.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -74,7 +74,7 @@
                 Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
                         .setComponent(component)
                         .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                        .putExtra(Intent.EXTRA_KEY_EVENT, event);
+                        .putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(event));
                 context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
                 return true;
             }
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 61fe01f..1e623e0 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -65,6 +65,8 @@
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.SUSPEND_APPS"/>
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
+    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
+    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
     <uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
     <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
diff --git a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
index 4d229ef..625766a 100644
--- a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
+++ b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
@@ -157,6 +157,8 @@
             String expected =
                     "TestThread2 annotated stack trace:\n" +
                     "    at java.lang.Object.wait(Native Method)\n" +
+                    "    at java.lang.Object.wait(Object.java:442)\n" +
+                    "    at java.lang.Object.wait(Object.java:568)\n" +
                     "    at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" +
                             "WatchdogDiagnosticsTest.java:91)\n" +
                     "    - locked <HASH> (a java.lang.String)\n" +
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 842cdd5..2aaf759 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -215,6 +215,18 @@
             }
         }).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any());
 
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                mStorageManager.clearUserKeyAuth((int) args[0] /* userId */,
+                        (int) args[1] /* serialNumber */,
+                        (byte[]) args[2] /* token */,
+                        (byte[]) args[3] /* secret */);
+                return null;
+            }
+        }).when(sm).clearUserKeyAuth(anyInt(), anyInt(), any(), any());
+
         doAnswer(
                 new Answer<Void>() {
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
index 1ae1fa6..102bac1 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
@@ -36,6 +36,15 @@
         getUserAuth(userId).add(new Pair<>(token, secret));
     }
 
+    public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
+        ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
+        if (token == null && secret == null) {
+            return;
+        }
+        auths.remove(new Pair<>(token, secret));
+        auths.add(new Pair<>(null, null));
+    }
+
     public void fixateNewestUserKeyAuth(int userId) {
         ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId);
         Pair<byte[], byte[]> latest = auths.get(auths.size() - 1);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index d9b1320..33f7924 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -103,31 +103,6 @@
         return mService.getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId) != 0;
     }
 
-    @Test
-    public void testPasswordMigration() throws RemoteException {
-        final byte[] password = "testPasswordMigration-password".getBytes();
-
-        disableSyntheticPassword();
-        mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
-        long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
-        final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
-        enableSyntheticPassword();
-        // Performs migration
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
-                    .getResponseCode());
-        assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
-        assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
-
-        // SP-based verification
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
-                LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-        assertArrayNotEquals(primaryStorageKey,
-                mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
-    }
-
     protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException {
         enableSyntheticPassword();
         int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
@@ -270,86 +245,6 @@
     }
 
     @Test
-    public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
-        final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
-        disableSyntheticPassword();
-        mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
-        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
-        final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
-        final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
-        final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
-        final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
-        assertTrue(primarySid != 0);
-        assertTrue(profileSid != 0);
-        assertTrue(profileSid != primarySid);
-
-        // do migration
-        enableSyntheticPassword();
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-
-        // verify
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-        assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
-        assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
-        assertArrayNotEquals(primaryStorageKey,
-                mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
-        assertArrayNotEquals(profileStorageKey,
-                mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
-        assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
-        assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
-    }
-
-    @Test
-    public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
-        final byte[] primaryPassword =
-                "testManagedProfileSeparateChallengeMigration-primary".getBytes();
-        final byte[] profilePassword =
-                "testManagedProfileSeparateChallengeMigration-profile".getBytes();
-        disableSyntheticPassword();
-        mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
-        mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
-                PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
-        final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
-        final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
-        final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
-        final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
-        assertTrue(primarySid != 0);
-        assertTrue(profileSid != 0);
-        assertTrue(profileSid != primarySid);
-
-        // do migration
-        enableSyntheticPassword();
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                0, MANAGED_PROFILE_USER_ID).getResponseCode());
-
-        // verify
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
-                        .getResponseCode());
-        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
-                profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
-                0, MANAGED_PROFILE_USER_ID).getResponseCode());
-        assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
-        assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
-        assertArrayNotEquals(primaryStorageKey,
-                mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
-        assertArrayNotEquals(profileStorageKey,
-                mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
-        assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
-        assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
-    }
-
-    @Test
     public void testTokenBasedResetPassword() throws RemoteException {
         final byte[] password = "password".getBytes();
         final byte[] pattern = "123654".getBytes();
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index acf51f3..f54f8d1 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -265,6 +265,29 @@
     public static final String EVENT_HANDOVER_FAILED =
             "android.telecom.event.HANDOVER_FAILED";
 
+
+    /**
+     * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
+     * call because they have declined to answer it.  This typically means that they are unable
+     * to answer the call at this time and would prefer it be sent to voicemail.
+     */
+    public static final int REJECT_REASON_DECLINED = 1;
+
+    /**
+     * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
+     * call because it is an unwanted call.  This allows the user to indicate that they are
+     * rejecting a call because it is likely a nuisance call.
+     */
+    public static final int REJECT_REASON_UNWANTED = 2;
+
+    /**
+     * @hide
+     */
+    @IntDef(prefix = { "REJECT_REASON_" },
+            value = {REJECT_REASON_DECLINED, REJECT_REASON_UNWANTED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RejectReason {};
+
     public static class Details {
         /** @hide */
         @Retention(RetentionPolicy.SOURCE)
@@ -1520,6 +1543,16 @@
     }
 
     /**
+     * Instructs the {@link ConnectionService} providing this {@link #STATE_RINGING} call that the
+     * user has chosen to reject the call and has indicated a reason why the call is being rejected.
+     *
+     * @param rejectReason the reason the call is being rejected.
+     */
+    public void reject(@RejectReason int rejectReason) {
+        mInCallAdapter.rejectCall(mTelecomCallId, rejectReason);
+    }
+
+    /**
      * Instructs this {@code Call} to disconnect.
      */
     public void disconnect() {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index c934625..72c66d2 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -3037,6 +3037,17 @@
     public void onReject() {}
 
     /**
+     * Notifies this Connection, which is in {@link #STATE_RINGING}, of a request to reject.
+     * <p>
+     * For managed {@link ConnectionService}s, this will be called when the user rejects a call via
+     * the default dialer's {@link InCallService} using {@link Call#reject(int)}.
+     * @param rejectReason the reason the user provided for rejecting the call.
+     */
+    public void onReject(@android.telecom.Call.RejectReason int rejectReason) {
+        // to be implemented by ConnectionService.
+    }
+
+    /**
      * Notifies this Connection, which is in {@link #STATE_RINGING}, of
      * a request to reject with a message.
      */
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 440f044..00c2918 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -194,6 +194,7 @@
     private static final int MSG_CREATE_CONFERENCE = 35;
     private static final int MSG_CREATE_CONFERENCE_COMPLETE = 36;
     private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
+    private static final int MSG_REJECT_WITH_REASON = 38;
 
     private static Connection sNullConnection;
 
@@ -450,6 +451,21 @@
         }
 
         @Override
+        public void rejectWithReason(String callId,
+                @android.telecom.Call.RejectReason int rejectReason, Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_REJECT);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = callId;
+                args.argi1 = rejectReason;
+                args.arg2 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_REJECT_WITH_REASON, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void rejectWithMessage(String callId, String message, Session.Info sessionInfo) {
             Log.startSession(sessionInfo, SESSION_REJECT_MESSAGE);
             try {
@@ -1053,6 +1069,17 @@
                     }
                     break;
                 }
+                case MSG_REJECT_WITH_REASON: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
+                    try {
+                        reject((String) args.arg1, args.argi1);
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_REJECT_WITH_MESSAGE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     Log.continueSession((Session) args.arg3,
@@ -1981,6 +2008,11 @@
         findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
     }
 
+    private void reject(String callId, @android.telecom.Call.RejectReason int rejectReason) {
+        Log.d(this, "reject %s with reason %d", callId, rejectReason);
+        findConnectionForAction(callId, "reject").onReject(rejectReason);
+    }
+
     private void silence(String callId) {
         Log.d(this, "silence %s", callId);
         findConnectionForAction(callId, "silence").onSilence();
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 2612468..594c1eb 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -89,6 +89,19 @@
     }
 
     /**
+     * Instructs Telecom to reject the specified call.
+     *
+     * @param callId The identifier of the call to reject.
+     * @param rejectReason The reason the call was rejected.
+     */
+    public void rejectCall(String callId, @Call.RejectReason int rejectReason) {
+        try {
+            mAdapter.rejectCallWithReason(callId, rejectReason);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Instructs Telecom to disconnect the specified call.
      *
      * @param callId The identifier of the call to disconnect.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 96f2483..4249dff 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -77,6 +77,8 @@
 
     void reject(String callId, in Session.Info sessionInfo);
 
+    void rejectWithReason(String callId, int rejectReason, in Session.Info sessionInfo);
+
     void rejectWithMessage(String callId, String message, in Session.Info sessionInfo);
 
     void disconnect(String callId, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 60745e4..eb2d714 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -34,6 +34,8 @@
 
     void rejectCall(String callId, boolean rejectWithMessage, String textMessage);
 
+    void rejectCallWithReason(String callId, int rejectReason);
+
     void disconnectCall(String callId);
 
     void holdCall(String callId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 71aaa6e..71411d5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3758,26 +3758,26 @@
         sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
                 // Boundaries: [-140 dB, -44 dB]
                 new int[] {
-                    -125, /* SIGNAL_STRENGTH_POOR */
-                    -115, /* SIGNAL_STRENGTH_MODERATE */
-                    -105, /* SIGNAL_STRENGTH_GOOD */
-                    -95,  /* SIGNAL_STRENGTH_GREAT */
+                    -110, /* SIGNAL_STRENGTH_POOR */
+                    -90, /* SIGNAL_STRENGTH_MODERATE */
+                    -80, /* SIGNAL_STRENGTH_GOOD */
+                    -65,  /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
                 // Boundaries: [-20 dB, -3 dB]
                 new int[] {
-                    -14, /* SIGNAL_STRENGTH_POOR */
-                    -12, /* SIGNAL_STRENGTH_MODERATE */
-                    -10, /* SIGNAL_STRENGTH_GOOD */
-                    -8  /* SIGNAL_STRENGTH_GREAT */
+                    -16, /* SIGNAL_STRENGTH_POOR */
+                    -11, /* SIGNAL_STRENGTH_MODERATE */
+                    -9, /* SIGNAL_STRENGTH_GOOD */
+                    -7  /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
                 // Boundaries: [-23 dB, 40 dB]
                 new int[] {
-                    -8, /* SIGNAL_STRENGTH_POOR */
-                    0, /* SIGNAL_STRENGTH_MODERATE */
-                    8, /* SIGNAL_STRENGTH_GOOD */
-                    16  /* SIGNAL_STRENGTH_GREAT */
+                    -5, /* SIGNAL_STRENGTH_POOR */
+                    5, /* SIGNAL_STRENGTH_MODERATE */
+                    15, /* SIGNAL_STRENGTH_GOOD */
+                    30  /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
                 CellSignalStrengthNr.USE_SSRSRP);
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 4d67bcf..f4c13ff 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -45,28 +45,28 @@
     // Lifted from Default carrier configs and max range of SSRSRP
     // Boundaries: [-140 dB, -44 dB]
     private int[] mSsRsrpThresholds = new int[] {
-            -125, /* SIGNAL_STRENGTH_POOR */
-            -115, /* SIGNAL_STRENGTH_MODERATE */
-            -105, /* SIGNAL_STRENGTH_GOOD */
-            -95,  /* SIGNAL_STRENGTH_GREAT */
+            -110, /* SIGNAL_STRENGTH_POOR */
+            -90, /* SIGNAL_STRENGTH_MODERATE */
+            -80, /* SIGNAL_STRENGTH_GOOD */
+            -65,  /* SIGNAL_STRENGTH_GREAT */
     };
 
     // Lifted from Default carrier configs and max range of SSRSRQ
     // Boundaries: [-20 dB, -3 dB]
     private int[] mSsRsrqThresholds = new int[] {
-            -14, /* SIGNAL_STRENGTH_POOR */
-            -12, /* SIGNAL_STRENGTH_MODERATE */
-            -10, /* SIGNAL_STRENGTH_GOOD */
-            -8  /* SIGNAL_STRENGTH_GREAT */
+            -16, /* SIGNAL_STRENGTH_POOR */
+            -11, /* SIGNAL_STRENGTH_MODERATE */
+            -9, /* SIGNAL_STRENGTH_GOOD */
+            -7  /* SIGNAL_STRENGTH_GREAT */
     };
 
     // Lifted from Default carrier configs and max range of SSSINR
     // Boundaries: [-23 dB, 40 dB]
     private int[] mSsSinrThresholds = new int[] {
-            -8, /* SIGNAL_STRENGTH_POOR */
-            0, /* SIGNAL_STRENGTH_MODERATE */
-            8, /* SIGNAL_STRENGTH_GOOD */
-            16  /* SIGNAL_STRENGTH_GREAT */
+            -5, /* SIGNAL_STRENGTH_POOR */
+            5, /* SIGNAL_STRENGTH_MODERATE */
+            15, /* SIGNAL_STRENGTH_GOOD */
+            30  /* SIGNAL_STRENGTH_GREAT */
     };
 
     /**
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 9b4292f..704e5aa 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -27,11 +27,7 @@
 
 /**
  * Provides access to information about Telephony IMS services on the device.
- *
- * @hide
  */
-@SystemApi
-@TestApi
 @SystemService(Context.TELEPHONY_IMS_SERVICE)
 public class ImsManager {
 
@@ -45,7 +41,10 @@
      * <p class="note">
      * Carrier applications may listen to this broadcast to be notified of possible IMS provisioning
      * issues.
+     * @hide
      */
+    @SystemApi
+    @TestApi
     // Moved from TelephonyIntents, need to keep backwards compatibility with OEM apps that have
     // this value hard-coded in BroadcastReceiver.
     @SuppressLint("ActionValue")
@@ -104,7 +103,10 @@
      * @param subscriptionId The ID of the subscription that this ImsRcsManager will use.
      * @throws IllegalArgumentException if the subscription is invalid.
      * @return a ImsRcsManager instance with the specific subscription ID.
+     * @hide
      */
+    @SystemApi
+    @TestApi
     @NonNull
     public ImsRcsManager getImsRcsManager(int subscriptionId) {
         if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index aee7cca..bd2375f 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -199,10 +199,10 @@
     }
 
     /**
+     * Indicate if the ModemActivityInfo is invalid due to modem's invalid reporting.
+     *
      * @return {@code true} if this {@link ModemActivityInfo} record is valid,
      * {@code false} otherwise.
-     *
-     * @hide
      */
     public boolean isValid() {
         for (TransmitPower powerInfo : getTransmitPowerInfo()) {
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 31434c1..0cfb8c5 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -20,6 +20,9 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.net.LinkProperties;
 import android.os.Build;
@@ -31,8 +34,6 @@
 import android.telephony.Annotation.NetworkType;
 import android.telephony.data.ApnSetting;
 
-import dalvik.system.VMRuntime;
-
 import java.util.Objects;
 
 
@@ -134,6 +135,13 @@
     }
 
     /**
+     * To check the SDK version for {@link PreciseDataConnectionState#getDataConnectionState}.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    private static final long GET_DATA_CONNECTION_STATE_CODE_CHANGE = 147600208L;
+
+    /**
      * Returns the state of data connection that supported the apn types returned by
      * {@link #getDataConnectionApnTypeBitMask()}
      *
@@ -144,7 +152,7 @@
     @SystemApi
     public @DataState int getDataConnectionState() {
         if (mState == TelephonyManager.DATA_DISCONNECTING
-                && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) {
+                && !Compatibility.isChangeEnabled(GET_DATA_CONNECTION_STATE_CODE_CHANGE)) {
             return TelephonyManager.DATA_CONNECTED;
         }
 
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 0ba36b1..e7b2613 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -25,11 +25,12 @@
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.app.ActivityThread;
 import android.app.PendingIntent;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.database.CursorWindow;
 import android.net.Uri;
 import android.os.Build;
@@ -388,7 +389,7 @@
             String destinationAddress, String scAddress, String text,
             PendingIntent sentIntent, PendingIntent deliveryIntent) {
         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
-                true /* persistMessage*/, ActivityThread.currentPackageName());
+                true /* persistMessage*/, null);
     }
 
     /**
@@ -598,7 +599,7 @@
             String destinationAddress, String scAddress, String text,
             PendingIntent sentIntent, PendingIntent deliveryIntent) {
         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
-                false /* persistMessage */, ActivityThread.currentPackageName());
+                false /* persistMessage */, null);
     }
 
     private void sendTextMessageInternal(
@@ -641,7 +642,7 @@
                         ISms iSms = getISmsServiceOrThrow();
                         if (iSms != null) {
                             iSms.sendTextForSubscriberWithOptions(subId,
-                                    ActivityThread.currentPackageName(), destinationAddress,
+                                    null, destinationAddress,
                                     scAddress,
                                     text, sentIntent, deliveryIntent, persistMessage, finalPriority,
                                     expectMore, finalValidity);
@@ -663,7 +664,7 @@
                 ISms iSms = getISmsServiceOrThrow();
                 if (iSms != null) {
                     iSms.sendTextForSubscriberWithOptions(getSubscriptionId(),
-                            ActivityThread.currentPackageName(), destinationAddress,
+                            null, destinationAddress,
                             scAddress,
                             text, sentIntent, deliveryIntent, persistMessage, finalPriority,
                             expectMore, finalValidity);
@@ -881,7 +882,7 @@
             String destinationAddress, String scAddress, ArrayList<String> parts,
             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, true /* persistMessage*/, ActivityThread.currentPackageName());
+                deliveryIntents, true /* persistMessage*/, null);
     }
 
     /**
@@ -898,8 +899,9 @@
      * subscription.
      * </p>
      *
-     * @param packageName serves as the default package name if
-     * {@link ActivityThread#currentPackageName()} is null.
+     * @param packageName serves as the default package name if the package name that is
+     *        associated with the user id is null.
+     *
      * @hide
      */
     @SystemApi
@@ -909,9 +911,7 @@
             @NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents,
             @Nullable List<PendingIntent> deliveryIntents, @NonNull String packageName) {
         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, true /* persistMessage*/,
-                ActivityThread.currentPackageName() == null
-                        ? packageName : ActivityThread.currentPackageName());
+                deliveryIntents, true /* persistMessage*/, packageName);
     }
 
     private void sendMultipartTextMessageInternal(
@@ -1012,7 +1012,7 @@
             String destinationAddress, String scAddress, List<String> parts,
             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, false /* persistMessage*/, ActivityThread.currentPackageName());
+                deliveryIntents, false /* persistMessage*/, null);
     }
 
     /**
@@ -1174,7 +1174,7 @@
                             ISms iSms = getISmsServiceOrThrow();
                             if (iSms != null) {
                                 iSms.sendMultipartTextForSubscriberWithOptions(subId,
-                                        ActivityThread.currentPackageName(), destinationAddress,
+                                        null, destinationAddress,
                                         scAddress, parts, sentIntents, deliveryIntents,
                                         persistMessage, finalPriority, expectMore, finalValidity);
                             }
@@ -1196,7 +1196,7 @@
                     ISms iSms = getISmsServiceOrThrow();
                     if (iSms != null) {
                         iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
-                                ActivityThread.currentPackageName(), destinationAddress,
+                                null, destinationAddress,
                                 scAddress, parts, sentIntents, deliveryIntents,
                                 persistMessage, finalPriority, expectMore, finalValidity);
                     }
@@ -1327,7 +1327,7 @@
             public void onSuccess(int subId) {
                 try {
                     ISms iSms = getISmsServiceOrThrow();
-                    iSms.sendDataForSubscriber(subId, ActivityThread.currentPackageName(),
+                    iSms.sendDataForSubscriber(subId, null,
                             destinationAddress, scAddress, destinationPort & 0xFFFF, data,
                             sentIntent, deliveryIntent);
                 } catch (RemoteException e) {
@@ -1453,7 +1453,6 @@
     private void resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult) {
         int subId = getSubscriptionId();
         boolean isSmsSimPickActivityNeeded = false;
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
         try {
             ISms iSms = getISmsService();
             if (iSms != null) {
@@ -1475,14 +1474,14 @@
             return;
         }
         // We need to ask the user pick an appropriate subid for the operation.
-        Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for package "
-                + context.getPackageName());
+        Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for calling"
+                + " package. ");
         try {
             // Create the SMS pick activity and call back once the activity is complete. Can't do
             // it here because we do not have access to the activity context that is performing this
             // operation.
             // Requires that the calling process has the SEND_SMS permission.
-            getITelephony().enqueueSmsPickResult(context.getOpPackageName(),
+            getITelephony().enqueueSmsPickResult(null,
                     new IIntegerConsumer.Stub() {
                         @Override
                         public void accept(int subId) {
@@ -1500,6 +1499,13 @@
         }
     }
 
+    /**
+     * To check the SDK version for SmsManager.sendResolverResult method.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
+    private static final long GET_TARGET_SDK_VERSION_CODE_CHANGE = 145147528L;
+
     private void sendResolverResult(SubscriptionResolverResult resolverResult, int subId,
             boolean pickActivityShown) {
         if (SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -1507,7 +1513,8 @@
             return;
         }
 
-        if (getTargetSdkVersion() <= Build.VERSION_CODES.P && !pickActivityShown) {
+        if (!Compatibility.isChangeEnabled(GET_TARGET_SDK_VERSION_CODE_CHANGE)
+                && !pickActivityShown) {
             // Do not fail, return a success with an INVALID subid for apps targeting P or below
             // that tried to perform an operation and the SMS disambiguation dialog was never shown,
             // as these applications may not have been written to handle the failure case properly.
@@ -1520,19 +1527,6 @@
         }
     }
 
-    private static int getTargetSdkVersion() {
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
-        int targetSdk;
-        try {
-            targetSdk = context.getPackageManager().getApplicationInfo(
-                    context.getOpPackageName(), 0).targetSdkVersion;
-        } catch (PackageManager.NameNotFoundException e) {
-            // Default to old behavior if we can not find this.
-            targetSdk = -1;
-        }
-        return targetSdk;
-    }
-
     private static ITelephony getITelephony() {
         ITelephony binder = ITelephony.Stub.asInterface(
                 ServiceManager.getService(Context.TELEPHONY_SERVICE));
@@ -1616,7 +1610,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
+                        null,
                         status, pdu, smsc);
             }
         } catch (RemoteException ex) {
@@ -1657,7 +1651,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
+                        null,
                         messageIndex, STATUS_ON_ICC_FREE, null /* pdu */);
             }
         } catch (RemoteException ex) {
@@ -1700,7 +1694,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
+                        null,
                         messageIndex, newStatus, pdu);
             }
         } catch (RemoteException ex) {
@@ -1752,7 +1746,7 @@
             if (iSms != null) {
                 records = iSms.getAllMessagesFromIccEfForSubscriber(
                         getSubscriptionId(),
-                        ActivityThread.currentPackageName());
+                        null);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -2495,7 +2489,7 @@
         try {
             ISms iccSms = getISmsServiceOrThrow();
             return iccSms.createAppSpecificSmsToken(getSubscriptionId(),
-                    ActivityThread.currentPackageName(), intent);
+                    null, intent);
 
         } catch (RemoteException ex) {
             ex.rethrowFromSystemServer();
@@ -2615,7 +2609,7 @@
         try {
             ISms iccSms = getISmsServiceOrThrow();
             return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(),
-                    ActivityThread.currentPackageName(), prefixes, intent);
+                    null, prefixes, intent);
 
         } catch (RemoteException ex) {
             ex.rethrowFromSystemServer();
@@ -2706,7 +2700,7 @@
             ISms iccISms = getISmsServiceOrThrow();
             if (iccISms != null) {
                 return iccISms.checkSmsShortCodeDestination(getSubscriptionId(),
-                        ActivityThread.currentPackageName(), null, destAddress, countryIso);
+                        null, null, destAddress, countryIso);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e);
@@ -2742,7 +2736,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 smsc = iSms.getSmscAddressFromIccEfForSubscriber(
-                        getSubscriptionId(), ActivityThread.currentPackageName());
+                        getSubscriptionId(), null);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -2776,7 +2770,7 @@
             ISms iSms = getISmsService();
             if (iSms != null) {
                 return iSms.setSmscAddressOnIccEfForSubscriber(
-                        smsc, getSubscriptionId(), ActivityThread.currentPackageName());
+                        smsc, getSubscriptionId(), null);
             }
         } catch (RemoteException ex) {
             // ignore it
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d4ab04cc..ea95aac 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -266,7 +266,7 @@
      * <P>Type: TEXT (String)</P>
      */
     /** @hide */
-    public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+    public static final String UNIQUE_KEY_SUBSCRIPTION_ID = SimInfo.UNIQUE_KEY_SUBSCRIPTION_ID;
 
     /**
      * TelephonyProvider column name for a unique identifier for the subscription within the
@@ -275,18 +275,18 @@
      * <P>Type: TEXT (String)</P>
      */
     /** @hide */
-    public static final String ICC_ID = "icc_id";
+    public static final String ICC_ID = SimInfo.ICC_ID;
 
     /**
      * TelephonyProvider column name for user SIM_SlOT_INDEX
      * <P>Type: INTEGER (int)</P>
      */
     /** @hide */
-    public static final String SIM_SLOT_INDEX = "sim_id";
+    public static final String SIM_SLOT_INDEX = SimInfo.SIM_SLOT_INDEX;
 
     /** SIM is not inserted */
     /** @hide */
-    public static final int SIM_NOT_INSERTED = -1;
+    public static final int SIM_NOT_INSERTED = SimInfo.SIM_NOT_INSERTED;
 
     /**
      * The slot-index for Bluetooth Remote-SIM subscriptions
@@ -301,23 +301,7 @@
      * Default value is 0.
      */
     /** @hide */
-    public static final String SUBSCRIPTION_TYPE = "subscription_type";
-
-    /**
-     * TelephonyProvider column name white_listed_apn_data.
-     * It's a bitmask of APN types that will be allowed on this subscription even if it's metered
-     * and mobile data is turned off by the user.
-     * <P>Type: INTEGER (int)</P> For example, if TYPE_MMS is is true, Telephony will allow MMS
-     * data connection to setup even if MMS is metered and mobile_data is turned off on that
-     * subscription.
-     *
-     * Default value is 0.
-     *
-     * @deprecated Replaced by {@link #DATA_ENABLED_OVERRIDE_RULES}
-     * @hide
-     */
-    @Deprecated
-    public static final String WHITE_LISTED_APN_DATA = "white_listed_apn_data";
+    public static final String SUBSCRIPTION_TYPE = SimInfo.SUBSCRIPTION_TYPE;
 
     /**
      * TelephonyProvider column name data_enabled_override_rules.
@@ -330,7 +314,15 @@
      *
      * @hide
      */
-    public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+    public static final String DATA_ENABLED_OVERRIDE_RULES = SimInfo.DATA_ENABLED_OVERRIDE_RULES;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
+        value = {
+            SUBSCRIPTION_TYPE_LOCAL_SIM,
+            SUBSCRIPTION_TYPE_REMOTE_SIM})
+    public @interface SubscriptionType {}
 
     /**
      * This constant is to designate a subscription as a Local-SIM Subscription.
@@ -338,7 +330,7 @@
      * device.
      * </p>
      */
-    public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+    public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM;
 
     /**
      * This constant is to designate a subscription as a Remote-SIM Subscription.
@@ -364,29 +356,21 @@
      * was never seen before.
      * </p>
      */
-    public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
-        value = {
-            SUBSCRIPTION_TYPE_LOCAL_SIM,
-            SUBSCRIPTION_TYPE_REMOTE_SIM})
-    public @interface SubscriptionType {}
+    public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = SimInfo.SUBSCRIPTION_TYPE_REMOTE_SIM;
 
     /**
      * TelephonyProvider column name for user displayed name.
      * <P>Type: TEXT (String)</P>
      */
     /** @hide */
-    public static final String DISPLAY_NAME = "display_name";
+    public static final String DISPLAY_NAME = SimInfo.DISPLAY_NAME;
 
     /**
      * TelephonyProvider column name for the service provider name for the SIM.
      * <P>Type: TEXT (String)</P>
      */
     /** @hide */
-    public static final String CARRIER_NAME = "carrier_name";
+    public static final String CARRIER_NAME = SimInfo.CARRIER_NAME;
 
     /**
      * Default name resource
@@ -400,44 +384,44 @@
      *
      * @hide
      */
-    public static final String NAME_SOURCE = "name_source";
+    public static final String NAME_SOURCE = SimInfo.NAME_SOURCE;
 
     /**
      * The name_source is the default, which is from the carrier id.
      * @hide
      */
-    public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
+    public static final int NAME_SOURCE_DEFAULT = SimInfo.NAME_SOURCE_DEFAULT;
 
     /**
      * The name_source is from SIM EF_SPN.
      * @hide
      */
-    public static final int NAME_SOURCE_SIM_SPN = 1;
+    public static final int NAME_SOURCE_SIM_SPN = SimInfo.NAME_SOURCE_SIM_SPN;
 
     /**
      * The name_source is from user input
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public static final int NAME_SOURCE_USER_INPUT = 2;
+    public static final int NAME_SOURCE_USER_INPUT = SimInfo.NAME_SOURCE_USER_INPUT;
 
     /**
      * The name_source is carrier (carrier app, carrier config, etc.)
      * @hide
      */
-    public static final int NAME_SOURCE_CARRIER = 3;
+    public static final int NAME_SOURCE_CARRIER = SimInfo.NAME_SOURCE_CARRIER;
 
     /**
      * The name_source is from SIM EF_PNN.
      * @hide
      */
-    public static final int NAME_SOURCE_SIM_PNN = 4;
+    public static final int NAME_SOURCE_SIM_PNN = SimInfo.NAME_SOURCE_SIM_PNN;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"NAME_SOURCE_"},
             value = {
-                    NAME_SOURCE_DEFAULT_SOURCE,
+                    NAME_SOURCE_DEFAULT,
                     NAME_SOURCE_SIM_SPN,
                     NAME_SOURCE_USER_INPUT,
                     NAME_SOURCE_CARRIER,
@@ -450,67 +434,30 @@
      * <P>Type: INTEGER (int)</P>
      */
     /** @hide */
-    public static final String COLOR = "color";
-
-    /** @hide */
-    public static final int COLOR_1 = 0;
-
-    /** @hide */
-    public static final int COLOR_2 = 1;
-
-    /** @hide */
-    public static final int COLOR_3 = 2;
-
-    /** @hide */
-    public static final int COLOR_4 = 3;
-
-    /** @hide */
-    public static final int COLOR_DEFAULT = COLOR_1;
+    public static final String COLOR = SimInfo.COLOR;
 
     /**
      * TelephonyProvider column name for the phone number of a SIM.
      * <P>Type: TEXT (String)</P>
      */
     /** @hide */
-    public static final String NUMBER = "number";
+    public static final String NUMBER = SimInfo.NUMBER;
 
     /**
-     * TelephonyProvider column name for the number display format of a SIM.
+     * TelephonyProvider column name for whether data roaming is enabled.
      * <P>Type: INTEGER (int)</P>
      */
     /** @hide */
-    public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
-
-    /** @hide */
-    public static final int DISPLAY_NUMBER_NONE = 0;
-
-    /** @hide */
-    public static final int DISPLAY_NUMBER_FIRST = 1;
-
-    /** @hide */
-    public static final int DISPLAY_NUMBER_LAST = 2;
-
-    /** @hide */
-    public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
-
-    /**
-     * TelephonyProvider column name for permission for data roaming of a SIM.
-     * <P>Type: INTEGER (int)</P>
-     */
-    /** @hide */
-    public static final String DATA_ROAMING = "data_roaming";
+    public static final String DATA_ROAMING = SimInfo.DATA_ROAMING;
 
     /** Indicates that data roaming is enabled for a subscription */
-    public static final int DATA_ROAMING_ENABLE = 1;
+    public static final int DATA_ROAMING_ENABLE = SimInfo.DATA_ROAMING_ENABLE;
 
     /** Indicates that data roaming is disabled for a subscription */
-    public static final int DATA_ROAMING_DISABLE = 0;
+    public static final int DATA_ROAMING_DISABLE = SimInfo.DATA_ROAMING_DISABLE;
 
     /** @hide */
-    public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
-
-    /** @hide */
-    public static final int SIM_PROVISIONED = 0;
+    public static final int DATA_ROAMING_DEFAULT = SimInfo.DATA_ROAMING_DEFAULT;
 
     /**
      * TelephonyProvider column name for subscription carrier id.
@@ -518,61 +465,61 @@
      * <p>Type: INTEGER (int) </p>
      * @hide
      */
-    public static final String CARRIER_ID = "carrier_id";
+    public static final String CARRIER_ID = SimInfo.CARRIER_ID;
 
     /**
      * @hide A comma-separated list of EHPLMNs associated with the subscription
      * <P>Type: TEXT (String)</P>
      */
-    public static final String EHPLMNS = "ehplmns";
+    public static final String EHPLMNS = SimInfo.EHPLMNS;
 
     /**
      * @hide A comma-separated list of HPLMNs associated with the subscription
      * <P>Type: TEXT (String)</P>
      */
-    public static final String HPLMNS = "hplmns";
+    public static final String HPLMNS = SimInfo.HPLMNS;
 
     /**
      * TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
      * <P>Type: TEXT (String)</P>
      * @hide
      */
-    public static final String MCC_STRING = "mcc_string";
+    public static final String MCC_STRING = SimInfo.MCC_STRING;
 
     /**
      * TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
      * <P>Type: TEXT (String)</P>
      * @hide
      */
-    public static final String MNC_STRING = "mnc_string";
+    public static final String MNC_STRING = SimInfo.MNC_STRING;
 
     /**
      * TelephonyProvider column name for the MCC associated with a SIM.
      * <P>Type: INTEGER (int)</P>
      * @hide
      */
-    public static final String MCC = "mcc";
+    public static final String MCC = SimInfo.MCC;
 
     /**
      * TelephonyProvider column name for the MNC associated with a SIM.
      * <P>Type: INTEGER (int)</P>
      * @hide
      */
-    public static final String MNC = "mnc";
+    public static final String MNC = SimInfo.MNC;
 
     /**
      * TelephonyProvider column name for the iso country code associated with a SIM.
      * <P>Type: TEXT (String)</P>
      * @hide
      */
-    public static final String ISO_COUNTRY_CODE = "iso_country_code";
+    public static final String ISO_COUNTRY_CODE = SimInfo.ISO_COUNTRY_CODE;
 
     /**
      * TelephonyProvider column name for the sim provisioning status associated with a SIM.
      * <P>Type: INTEGER (int)</P>
      * @hide
      */
-    public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+    public static final String SIM_PROVISIONING_STATUS = SimInfo.SIM_PROVISIONING_STATUS;
 
     /**
      * TelephonyProvider column name for whether a subscription is embedded (that is, present on an
@@ -580,7 +527,7 @@
      * <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
      * @hide
      */
-    public static final String IS_EMBEDDED = "is_embedded";
+    public static final String IS_EMBEDDED = SimInfo.IS_EMBEDDED;
 
     /**
      * TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of the
@@ -588,7 +535,7 @@
      * <P>Type: TEXT (String)</P>
      * @hide
      */
-    public static final String CARD_ID = "card_id";
+    public static final String CARD_ID = SimInfo.CARD_ID;
 
     /**
      * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -596,7 +543,7 @@
      * <p>TYPE: BLOB
      * @hide
      */
-    public static final String ACCESS_RULES = "access_rules";
+    public static final String ACCESS_RULES = SimInfo.ACCESS_RULES;
 
     /**
      * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -606,7 +553,7 @@
      * @hide
      */
     public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
-            "access_rules_from_carrier_configs";
+            SimInfo.ACCESS_RULES_FROM_CARRIER_CONFIGS;
 
     /**
      * TelephonyProvider column name identifying whether an embedded subscription is on a removable
@@ -616,79 +563,79 @@
      * <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
      * @hide
      */
-    public static final String IS_REMOVABLE = "is_removable";
+    public static final String IS_REMOVABLE = SimInfo.IS_REMOVABLE;
 
     /**
      *  TelephonyProvider column name for extreme threat in CB settings
      * @hide
      */
-    public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+    public static final String CB_EXTREME_THREAT_ALERT = SimInfo.CB_EXTREME_THREAT_ALERT;
 
     /**
      * TelephonyProvider column name for severe threat in CB settings
      *@hide
      */
-    public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+    public static final String CB_SEVERE_THREAT_ALERT = SimInfo.CB_SEVERE_THREAT_ALERT;
 
     /**
      * TelephonyProvider column name for amber alert in CB settings
      *@hide
      */
-    public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+    public static final String CB_AMBER_ALERT = SimInfo.CB_AMBER_ALERT;
 
     /**
      * TelephonyProvider column name for emergency alert in CB settings
      *@hide
      */
-    public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+    public static final String CB_EMERGENCY_ALERT = SimInfo.CB_EMERGENCY_ALERT;
 
     /**
      * TelephonyProvider column name for alert sound duration in CB settings
      *@hide
      */
-    public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+    public static final String CB_ALERT_SOUND_DURATION = SimInfo.CB_ALERT_SOUND_DURATION;
 
     /**
      * TelephonyProvider column name for alert reminder interval in CB settings
      *@hide
      */
-    public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+    public static final String CB_ALERT_REMINDER_INTERVAL = SimInfo.CB_ALERT_REMINDER_INTERVAL;
 
     /**
      * TelephonyProvider column name for enabling vibrate in CB settings
      *@hide
      */
-    public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+    public static final String CB_ALERT_VIBRATE = SimInfo.CB_ALERT_VIBRATE;
 
     /**
      * TelephonyProvider column name for enabling alert speech in CB settings
      *@hide
      */
-    public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+    public static final String CB_ALERT_SPEECH = SimInfo.CB_ALERT_SPEECH;
 
     /**
      * TelephonyProvider column name for ETWS test alert in CB settings
      *@hide
      */
-    public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+    public static final String CB_ETWS_TEST_ALERT = SimInfo.CB_ETWS_TEST_ALERT;
 
     /**
      * TelephonyProvider column name for enable channel50 alert in CB settings
      *@hide
      */
-    public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+    public static final String CB_CHANNEL_50_ALERT = SimInfo.CB_CHANNEL_50_ALERT;
 
     /**
      * TelephonyProvider column name for CMAS test alert in CB settings
      *@hide
      */
-    public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
+    public static final String CB_CMAS_TEST_ALERT = SimInfo.CB_CMAS_TEST_ALERT;
 
     /**
      * TelephonyProvider column name for Opt out dialog in CB settings
      *@hide
      */
-    public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+    public static final String CB_OPT_OUT_DIALOG = SimInfo.CB_OPT_OUT_DIALOG;
 
     /**
      * TelephonyProvider column name for enable Volte.
@@ -697,37 +644,44 @@
      * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
      *@hide
      */
-    public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+    public static final String ENHANCED_4G_MODE_ENABLED = SimInfo.ENHANCED_4G_MODE_ENABLED;
 
     /**
      * TelephonyProvider column name for enable VT (Video Telephony over IMS)
      *@hide
      */
-    public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+    public static final String VT_IMS_ENABLED = SimInfo.VT_IMS_ENABLED;
 
     /**
      * TelephonyProvider column name for enable Wifi calling
      *@hide
      */
-    public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+    public static final String WFC_IMS_ENABLED = SimInfo.WFC_IMS_ENABLED;
 
     /**
      * TelephonyProvider column name for Wifi calling mode
      *@hide
      */
-    public static final String WFC_IMS_MODE = "wfc_ims_mode";
+    public static final String WFC_IMS_MODE = SimInfo.WFC_IMS_MODE;
 
     /**
      * TelephonyProvider column name for Wifi calling mode in roaming
      *@hide
      */
-    public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+    public static final String WFC_IMS_ROAMING_MODE = SimInfo.WFC_IMS_ROAMING_MODE;
 
     /**
      * TelephonyProvider column name for enable Wifi calling in roaming
      *@hide
      */
-    public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+    public static final String WFC_IMS_ROAMING_ENABLED = SimInfo.WFC_IMS_ROAMING_ENABLED;
+
+    /**
+     * Determines if the user has enabled IMS RCS User Capability Exchange (UCE) for this
+     * subscription.
+     * @hide
+     */
+    public static final String IMS_RCS_UCE_ENABLED = SimInfo.IMS_RCS_UCE_ENABLED;
 
     /**
      * TelephonyProvider column name for whether a subscription is opportunistic, that is,
@@ -736,7 +690,7 @@
      * <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
      * @hide
      */
-    public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+    public static final String IS_OPPORTUNISTIC = SimInfo.IS_OPPORTUNISTIC;
 
     /**
      * TelephonyProvider column name for group ID. Subscriptions with same group ID
@@ -745,7 +699,7 @@
      *
      * @hide
      */
-    public static final String GROUP_UUID = "group_uuid";
+    public static final String GROUP_UUID = SimInfo.GROUP_UUID;
 
     /**
      * TelephonyProvider column name for group owner. It's the package name who created
@@ -753,14 +707,7 @@
      *
      * @hide
      */
-    public static final String GROUP_OWNER = "group_owner";
-
-    /**
-     * TelephonyProvider column name for whether a subscription is metered or not, that is, whether
-     * the network it connects to charges for subscription or not. For example, paid CBRS or unpaid.
-     * @hide
-     */
-    public static final String IS_METERED = "is_metered";
+    public static final String GROUP_OWNER = SimInfo.GROUP_OWNER;
 
     /**
      * TelephonyProvider column name for the profile class of a subscription
@@ -768,7 +715,7 @@
      * <P>Type: INTEGER (int)</P>
      * @hide
      */
-    public static final String PROFILE_CLASS = "profile_class";
+    public static final String PROFILE_CLASS = SimInfo.PROFILE_CLASS;
 
     /**
      * Profile class of the subscription
@@ -776,11 +723,11 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "PROFILE_CLASS_" }, value = {
-            PROFILE_CLASS_TESTING,
-            PROFILE_CLASS_PROVISIONING,
-            PROFILE_CLASS_OPERATIONAL,
-            PROFILE_CLASS_UNSET,
-            PROFILE_CLASS_DEFAULT
+            SimInfo.PROFILE_CLASS_TESTING,
+            SimInfo.PROFILE_CLASS_PROVISIONING,
+            SimInfo.PROFILE_CLASS_OPERATIONAL,
+            SimInfo.PROFILE_CLASS_UNSET,
+            SimInfo.PROFILE_CLASS_DEFAULT
     })
     public @interface ProfileClass {}
 
@@ -792,7 +739,7 @@
      * @hide
      */
     @SystemApi
-    public static final int PROFILE_CLASS_TESTING = 0;
+    public static final int PROFILE_CLASS_TESTING = SimInfo.PROFILE_CLASS_TESTING;
 
     /**
      * A provisioning profile is pre-loaded onto the eUICC and
@@ -801,7 +748,7 @@
      * @hide
      */
     @SystemApi
-    public static final int PROFILE_CLASS_PROVISIONING = 1;
+    public static final int PROFILE_CLASS_PROVISIONING = SimInfo.PROFILE_CLASS_PROVISIONING;
 
     /**
      * An operational profile can be pre-loaded or downloaded
@@ -810,7 +757,7 @@
      * @hide
      */
     @SystemApi
-    public static final int PROFILE_CLASS_OPERATIONAL = 2;
+    public static final int PROFILE_CLASS_OPERATIONAL = SimInfo.PROFILE_CLASS_OPERATIONAL;
 
     /**
      * The profile class is unset. This occurs when profile class
@@ -819,14 +766,14 @@
      * @hide
      */
     @SystemApi
-    public static final int PROFILE_CLASS_UNSET = -1;
+    public static final int PROFILE_CLASS_UNSET = SimInfo.PROFILE_CLASS_UNSET;
 
     /**
      * Default profile class
      * @hide
      */
     @SystemApi
-    public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+    public static final int PROFILE_CLASS_DEFAULT = SimInfo.PROFILE_CLASS_DEFAULT;
 
     /**
      * IMSI (International Mobile Subscriber Identity).
@@ -834,13 +781,19 @@
      * @hide
      */
     //TODO: add @SystemApi
-    public static final String IMSI = "imsi";
+    public static final String IMSI = SimInfo.IMSI;
 
     /**
      * Whether uicc applications is set to be enabled or disabled. By default it's enabled.
      * @hide
      */
-    public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+    public static final String UICC_APPLICATIONS_ENABLED = SimInfo.UICC_APPLICATIONS_ENABLED;
+
+    /**
+     * Indicate which network type is allowed. By default it's enabled.
+     * @hide
+     */
+    public static final String ALLOWED_NETWORK_TYPES = SimInfo.ALLOWED_NETWORK_TYPES;
 
     /**
      * Broadcast Action: The user has changed one of the default subs related to
@@ -2353,7 +2306,28 @@
             try {
                 return Integer.parseInt(result);
             } catch (NumberFormatException err) {
-                logd("getBooleanSubscriptionProperty NumberFormat exception");
+                logd("getIntegerSubscriptionProperty NumberFormat exception");
+            }
+        }
+        return defValue;
+    }
+
+    /**
+     * Returns long value corresponding to query result.
+     * @param subId Subscription Id of Subscription
+     * @param propKey Column name in SubscriptionInfo database
+     * @param defValue Default long value to be returned
+     * @return long result value to be returned
+     * @hide
+     */
+    public static long getLongSubscriptionProperty(int subId, String propKey, long defValue,
+                                                     Context context) {
+        String result = getSubscriptionProperty(subId, propKey, context);
+        if (result != null) {
+            try {
+                return Long.parseLong(result);
+            } catch (NumberFormatException err) {
+                logd("getLongSubscriptionProperty NumberFormat exception");
             }
         }
         return defValue;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ef631b8..3dff079 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -37,7 +37,6 @@
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.annotation.WorkerThread;
-import android.app.ActivityThread;
 import android.app.PendingIntent;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
@@ -109,8 +108,6 @@
 import com.android.internal.telephony.SmsApplication;
 import com.android.telephony.Rlog;
 
-import dalvik.system.VMRuntime;
-
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -374,8 +371,17 @@
         // effort and get the context from the current activity thread.
         if (mContext != null) {
             return mContext.getOpPackageName();
+        } else {
+            ITelephony telephony = getITelephony();
+            if (telephony == null) return null;
+            try {
+                return telephony.getCurrentPackageName();
+            } catch (RemoteException ex) {
+                return null;
+            } catch (NullPointerException ex) {
+                return null;
+            }
         }
-        return ActivityThread.currentOpPackageName();
     }
 
     private String getFeatureId() {
@@ -1222,6 +1228,80 @@
     public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
 
     /**
+     * Broadcast Action: The Service Provider string(s) have been updated. Activities or
+     * services that use these strings should update their display.
+     *
+     * <p>The intent will have the following extra values:
+     * <dl>
+     *   <dt>{@link #EXTRA_SHOW_PLMN}</dt>
+     *   <dd>Boolean that indicates whether the PLMN should be shown.</dd>
+     *   <dt>{@link #EXTRA_PLMN}</dt>
+     *   <dd>The operator name of the registered network, as a string.</dd>
+     *   <dt>{@link #EXTRA_SHOW_SPN}</dt>
+     *   <dd>Boolean that indicates whether the SPN should be shown.</dd>
+     *   <dt>{@link #EXTRA_SPN}</dt>
+     *   <dd>The service provider name, as a string.</dd>
+     *   <dt>{@link #EXTRA_DATA_SPN}</dt>
+     *   <dd>The service provider name for data service, as a string.</dd>
+     * </dl>
+     *
+     * Note that {@link #EXTRA_SHOW_PLMN} may indicate that {@link #EXTRA_PLMN} should be displayed,
+     * even though the value for {@link #EXTRA_PLMN} is null. This can happen, for example, if the
+     * phone has not registered to a network yet. In this case the receiver may substitute an
+     * appropriate placeholder string (eg, "No service").
+     *
+     * It is recommended to display {@link #EXTRA_PLMN} before / above {@link #EXTRA_SPN} if
+     * both are displayed.
+     *
+     * <p>Note: this is a protected intent that can only be sent by the system.
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SERVICE_PROVIDERS_UPDATED =
+            "android.telephony.action.SERVICE_PROVIDERS_UPDATED";
+
+    /**
+     * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+     * whether the PLMN should be shown.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SHOW_PLMN = "android.telephony.extra.SHOW_PLMN";
+
+    /**
+     * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+     * the operator name of the registered network.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PLMN = "android.telephony.extra.PLMN";
+
+    /**
+     * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+     * whether the PLMN should be shown.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SHOW_SPN = "android.telephony.extra.SHOW_SPN";
+
+    /**
+     * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+     * the service provider name.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_SPN = "android.telephony.extra.SPN";
+
+    /**
+     * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+     * the service provider name for data service.
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DATA_SPN = "android.telephony.extra.DATA_SPN";
+
+    /**
      * Broadcast intent action indicating that when data stall recovery is attempted by Telephony,
      * intended for report every data stall recovery step attempted.
      *
@@ -2346,7 +2426,7 @@
     @UnsupportedAppUsage
     public boolean isNetworkRoaming(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
-        return getTelephonyProperty(subId, TelephonyProperties.operator_is_roaming(), false);
+        return getTelephonyProperty(phoneId, TelephonyProperties.operator_is_roaming(), false);
     }
 
     /**
@@ -5109,6 +5189,13 @@
     public static final int DATA_DISCONNECTING = 4;
 
     /**
+     * To check the SDK version for {@link TelephonyManager#getDataState}.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    private static final long GET_DATA_STATE_CODE_CHANGE = 147600208L;
+
+    /**
      * Returns a constant indicating the current data connection state
      * (cellular).
      *
@@ -5126,7 +5213,7 @@
             int state = telephony.getDataStateForSubId(
                     getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
             if (state == TelephonyManager.DATA_DISCONNECTING
-                    && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) {
+                    && !Compatibility.isChangeEnabled(GET_DATA_STATE_CODE_CHANGE)) {
                 return TelephonyManager.DATA_CONNECTED;
             }
 
@@ -5179,6 +5266,13 @@
     //
 
     /**
+     * To check the SDK version for {@link TelephonyManager#listen}.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
+    private static final long LISTEN_CODE_CHANGE = 147600208L;
+
+    /**
      * Registers a listener object to receive notification of changes
      * in specified telephony states.
      * <p>
@@ -5217,7 +5311,7 @@
                 // subId from PhoneStateListener is deprecated Q on forward, use the subId from
                 // TelephonyManager instance. keep using subId from PhoneStateListener for pre-Q.
                 int subId = mSubId;
-                if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.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.
                     //  TODO: remove this once we completely get rid of mSubId in PhoneStateListener
@@ -6878,6 +6972,30 @@
         }
     }
 
+
+    /**
+     * Resets the {@link android.telephony.ims.ImsService} associated with the specified sim slot.
+     * Used by diagnostic apps to force the IMS stack to be disabled and re-enabled in an effort to
+     * recover from scenarios where the {@link android.telephony.ims.ImsService} gets in to a bad
+     * state.
+     *
+     * @param slotIndex the sim slot to reset the IMS stack on.
+     * @hide */
+    @SystemApi
+    @WorkerThread
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void resetIms(int slotIndex) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.resetIms(slotIndex);
+            }
+        } catch (RemoteException e) {
+            Rlog.e(TAG, "toggleImsOnOff, RemoteException: "
+                    + e.getMessage());
+        }
+    }
+
     /**
      * Enables IMS for the framework. This will trigger IMS registration and ImsFeature capability
      * status updates, if not already enabled.
@@ -7286,7 +7404,9 @@
      *
      * @return the preferred network type.
      * @hide
+     * @deprecated Use {@link #getPreferredNetworkTypeBitmask} instead.
      */
+    @Deprecated
     @RequiresPermission((android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE))
     @UnsupportedAppUsage
     public @PrefNetworkMode int getPreferredNetworkType(int subId) {
@@ -7331,6 +7451,30 @@
     }
 
     /**
+     * Get the allowed network types.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
+     * @return the allowed network type bitmask
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    public @NetworkTypeBitMask long getAllowedNetworkTypes() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getAllowedNetworkTypes(getSubId());
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getAllowedNetworkTypes RemoteException", ex);
+        }
+        return -1;
+    }
+
+    /**
      * Sets the network selection mode to automatic.
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
@@ -7585,7 +7729,9 @@
      * @param networkType the preferred network type
      * @return true on success; false on any failure.
      * @hide
+     * @deprecated Use {@link #setPreferredNetworkTypeBitmask} instead.
      */
+    @Deprecated
     @UnsupportedAppUsage
     public boolean setPreferredNetworkType(int subId, @PrefNetworkMode int networkType) {
         try {
@@ -7600,7 +7746,8 @@
     }
 
     /**
-     * Set the preferred network type bitmask.
+     * Set the preferred network type bitmask but if {@link #setAllowedNetworkTypes} has been set,
+     * only the allowed network type will set to the modem.
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -7630,6 +7777,29 @@
     }
 
     /**
+     * Set the allowed network types of the device. This is for carrier or privileged apps to
+     * enable/disable certain network types on the device. The user preferred network types should
+     * be set through {@link #setPreferredNetworkTypeBitmask}.
+     *
+     * @param allowedNetworkTypes The bitmask of allowed network types.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    public boolean setAllowedNetworkTypes(@NetworkTypeBitMask long allowedNetworkTypes) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.setAllowedNetworkTypes(getSubId(), allowedNetworkTypes);
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setAllowedNetworkTypes RemoteException", ex);
+        }
+        return false;
+    }
+
+    /**
      * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
      *
      * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
@@ -10501,6 +10671,27 @@
     }
 
     /**
+     * Enable or disable signal strength changes from radio will always be reported in any
+     * condition (e.g. screen is off). This is only allowed for System caller.
+     *
+     * @param isEnabled {@code true} for enabling; {@code false} for disabling.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void setAlwaysReportSignalStrength(boolean isEnabled) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.setAlwaysReportSignalStrength(getSubId(), isEnabled);
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "setAlwaysReportSignalStrength RemoteException", ex);
+            ex.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
      * Get the most recently available signal strength information.
      *
      * Get the most recent SignalStrength information reported by the modem. Due
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index cb3f0f9..643f452 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -61,7 +61,6 @@
      * This is a configuration error and there should be no retry. The subscription used for this
      * operation is either invalid or has become inactive. The active subscriptions can be queried
      * with {@link SubscriptionManager#getActiveSubscriptionInfoList()}.
-     * @hide
      */
     public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3;
 
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index c66672f..ba8e90f 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -57,7 +57,8 @@
  * registration and MmTel capability status callbacks, as well as query/modify user settings for the
  * associated subscription.
  *
- * @see #createForSubscriptionId(int)
+ * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this
+ * manager.
  */
 public class ImsMmTelManager implements RegistrationManager {
 
@@ -225,8 +226,13 @@
      * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
      *
      * @throws IllegalArgumentException if the subscription is invalid.
-     *
+     * @deprecated Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an
+     * instance of this class.
+     * @hide
      */
+    @SystemApi
+    @TestApi
+    @Deprecated
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(anyOf = {
             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
@@ -242,7 +248,7 @@
     }
 
     /**
-     * Only visible for testing, use {@link #createForSubscriptionId(int)} instead.
+     * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
      * @hide
      */
     @VisibleForTesting
@@ -252,7 +258,7 @@
 
     /**
      * Registers a {@link RegistrationCallback} with the system, which will provide registration
-     * updates for the subscription specified in {@link #createForSubscriptionId(int)}. Use
+     * updates for the subscription specified in {@link ImsManager#getImsMmTelManager(int)}. Use
      * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
      * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
      *
@@ -450,7 +456,7 @@
     /**
      * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
      * availability updates for the subscription specified in
-     * {@link #createForSubscriptionId(int)}. The method {@see #isAvailable(int, int)}
+     * {@link ImsManager#getImsMmTelManager(int)}. The method {@see #isAvailable(int, int)}
      * can also be used to query this information at any time.
      *
      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 62bc2ae..2b3072e 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -60,9 +60,10 @@
  * The telephony framework will then bind to the ImsService you have defined in your manifest
  * if you are either:
  * 1) Defined as the default ImsService for the device in the device overlay using
- *    "config_ims_package".
+ *    "config_ims_mmtel_package" or "config_ims_rcs_package".
  * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
- *    {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
+ *    {@link CarrierConfigManager#KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING} or
+ *    {@link CarrierConfigManager#KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING}.
  *
  * There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService}
  * supports, dynamic or static definitions.
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 3e2903f..57b9b7a 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -16,10 +16,11 @@
 
 package android.telephony.ims;
 
-import android.annotation.IntDef;
+import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -37,6 +38,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class RcsContactUceCapability implements Parcelable {
 
     /** Supports 1-to-1 chat */
@@ -99,11 +101,16 @@
     public static final int CAPABILITY_CHAT_BOT_ROLE = (1 << 27);
     /** Supports the unidirectional plug-ins framework. */
     public static final int CAPABILITY_PLUG_IN = (1 << 28);
+    /** Supports standalone Chatbot communication. */
+    public static final int CAPABILITY_STANDALONE_CHAT_BOT = (1 << 29);
+    /** Supports MMTEL based call composer. */
+    public static final int CAPABILITY_MMTEL_CALL_COMPOSER = (1 << 30);
+
 
 
     /** @hide*/
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "CAPABILITY_", flag = true, value = {
+    @LongDef(prefix = "CAPABILITY_", flag = true, value = {
             CAPABILITY_CHAT_STANDALONE,
             CAPABILITY_CHAT_SESSION,
             CAPABILITY_CHAT_SESSION_STORE_FORWARD,
@@ -132,7 +139,9 @@
             CAPABILITY_SHARED_SKETCH,
             CAPABILITY_CHAT_BOT,
             CAPABILITY_CHAT_BOT_ROLE,
-            CAPABILITY_PLUG_IN
+            CAPABILITY_PLUG_IN,
+            CAPABILITY_STANDALONE_CHAT_BOT,
+            CAPABILITY_MMTEL_CALL_COMPOSER
     })
     public @interface CapabilityFlag {}
 
@@ -159,11 +168,11 @@
          * @param type The capability to map to a service URI that is different from the contact's
          *         URI.
          */
-        public @NonNull Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) {
+        public @NonNull Builder add(@CapabilityFlag long type, @NonNull Uri serviceUri) {
             mCapabilities.mCapabilities |= type;
             // Put each of these capabilities into the map separately.
-            for (int shift = 0; shift < Integer.SIZE; shift++) {
-                int cap = type & (1 << shift);
+            for (long shift = 0; shift < Integer.SIZE; shift++) {
+                long cap = type & (1 << shift);
                 if (cap != 0) {
                     mCapabilities.mServiceMap.put(cap, serviceUri);
                     // remove that capability from the field.
@@ -181,7 +190,7 @@
          * Add a UCE capability flag that this contact supports.
          * @param type the capability that the contact supports.
          */
-        public @NonNull Builder add(@CapabilityFlag int type) {
+        public @NonNull Builder add(@CapabilityFlag long type) {
             mCapabilities.mCapabilities |= type;
             return this;
         }
@@ -207,7 +216,7 @@
     private final Uri mContactUri;
     private long mCapabilities;
     private List<String> mExtensionTags = new ArrayList<>();
-    private Map<Integer, Uri> mServiceMap = new HashMap<>();
+    private Map<Long, Uri> mServiceMap = new HashMap<>();
 
     /**
      * Use {@link Builder} to build an instance of this interface.
@@ -225,7 +234,7 @@
         // read mServiceMap as key,value pair
         int mapSize = in.readInt();
         for (int i = 0; i < mapSize; i++) {
-            mServiceMap.put(in.readInt(), in.readParcelable(Uri.class.getClassLoader()));
+            mServiceMap.put(in.readLong(), in.readParcelable(Uri.class.getClassLoader()));
         }
     }
 
@@ -250,8 +259,8 @@
         // write mServiceMap as key,value pairs
         int mapSize = mServiceMap.keySet().size();
         out.writeInt(mapSize);
-        for (int key : mServiceMap.keySet()) {
-            out.writeInt(key);
+        for (long key : mServiceMap.keySet()) {
+            out.writeLong(key);
             out.writeParcelable(mServiceMap.get(key), 0);
         }
     }
@@ -266,7 +275,7 @@
      * @param type The capability flag to query.
      * @return true if the capability flag specified is set, false otherwise.
      */
-    public boolean isCapable(@CapabilityFlag int type) {
+    public boolean isCapable(@CapabilityFlag long type) {
         return (mCapabilities & type) > 0;
     }
 
@@ -290,13 +299,13 @@
      * <p>
      * This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless
      * a different service {@link Uri} was associated with this capability using
-     * {@link Builder#add(int, Uri)}.
+     * {@link Builder#add(long, Uri)}.
      *
      * @return a String containing the {@link Uri} associated with the service tag or
      * {@code null} if this capability is not set as capable.
-     * @see #isCapable(int)
+     * @see #isCapable(long)
      */
-    public @Nullable Uri getServiceUri(@CapabilityFlag int type) {
+    public @Nullable Uri getServiceUri(@CapabilityFlag long type) {
         Uri result = mServiceMap.getOrDefault(type, null);
         // If the capability is capable, but does not have a service URI associated, use the default
         // contact URI.
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index b47bcb9..d3f393a 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -21,6 +21,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Binder;
@@ -29,6 +31,7 @@
 import android.os.ServiceManager;
 import android.telephony.ims.aidl.IImsRcsController;
 import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.telephony.ims.feature.RcsFeature;
 import android.util.Log;
 
 import java.lang.annotation.Retention;
@@ -42,6 +45,8 @@
  * @see ImsRcsManager#getUceAdapter() for information on creating an instance of this class.
  * @hide
  */
+@SystemApi
+@TestApi
 public class RcsUceAdapter {
     private static final String TAG = "RcsUceAdapter";
 
@@ -197,6 +202,7 @@
     /**
      * Not to be instantiated directly, use
      * {@link ImsRcsManager#getUceAdapter()} to instantiate this manager class.
+     * @hide
      */
     RcsUceAdapter(int subId) {
         mSubId = subId;
@@ -222,7 +228,7 @@
      * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void requestCapabilities(@CallbackExecutor Executor executor,
+    public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
             @NonNull List<Uri> contactNumbers,
             @NonNull CapabilitiesCallback c) throws ImsException {
         if (c == null) {
@@ -299,7 +305,7 @@
      * for the associated subscription.
      *
      * @return true if the user’s setting for UCE is enabled, false otherwise. If false,
-     * {@link ImsRcsManager#isCapable(int)} will return false for
+     * {@link ImsRcsManager#isCapable(int, int)} will return false for
      * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and
      * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE}
      * @see #setUceSettingEnabled(boolean)
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 0d5a979..a3ce1b5 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -325,7 +325,6 @@
         */
         @NonNull
         @Override
-        @SystemApi @TestApi
         public String toString() {
             StringBuilder builder = new StringBuilder("MmTel Capabilities - [");
             builder.append("Voice: ");
@@ -514,7 +513,7 @@
      * @param callProfile The {@link ImsCallProfile} IMS call profile with details.
      *        This can be null if no call information is available for the rejected call.
      * @param reason The {@link ImsReasonInfo} call rejection reason.
-     * * @hide
+     * @hide
      */
     @SystemApi @TestApi
     public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile,
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 501e0e8..e4efc2043 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -349,9 +349,8 @@
      *
      * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if
      * it is supported by the device.
-     * @hide
      */
-    public RcsSipOptionsImplBase getOptionsExchangeImpl() {
+    public @NonNull RcsSipOptionsImplBase getOptionsExchangeImpl() {
         // Base Implementation, override to implement functionality
         return new RcsSipOptionsImplBase();
     }
@@ -365,9 +364,8 @@
      *
      * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence
      * exchange if it is supported by the device.
-     * @hide
      */
-    public RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
+    public @NonNull RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
         // Base Implementation, override to implement functionality.
         return new RcsPresenceExchangeImplBase();
     }
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index f4367da..e8f69ea 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -410,6 +410,13 @@
      * Rejects an incoming call or session update.
      *
      * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
+     *               The {@link android.telecom.InCallService} (dialer app) can use the
+     *               {@link android.telecom.Call#reject(int)} API to reject a call while specifying
+     *               a user-indicated reason for rejecting the call.
+     *               Normal call declines ({@link android.telecom.Call#REJECT_REASON_DECLINED}) will
+     *               map to {@link ImsReasonInfo#CODE_USER_DECLINE}.
+     *               Unwanted calls ({@link android.telecom.Call#REJECT_REASON_UNWANTED}) will map
+     *               to {@link ImsReasonInfo#CODE_SIP_USER_MARKED_UNWANTED}.
      * {@link ImsCallSession.Listener#callSessionStartFailed}
      */
     public void reject(int reason) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index 3ec4f34..f13371c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -17,6 +17,8 @@
 package android.telephony.ims.stub;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Bundle;
@@ -206,6 +208,13 @@
             return ImsUtImplBase.this.updateCallBarringForServiceClass(
                     cbType, action, barrList, serviceClass);
         }
+
+        @Override
+        public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
+                int serviceClass, String password) throws RemoteException {
+            return ImsUtImplBase.this.updateCallBarringWithPassword(
+                    cbType, action, barrList, serviceClass, password);
+        }
     };
 
     /**
@@ -328,6 +337,14 @@
     }
 
     /**
+     * Updates the configuration of the call barring for specified service class with password.
+     */
+    public int updateCallBarringWithPassword(int cbType, int action, @Nullable String[] barrList,
+            int serviceClass, @NonNull String password) {
+        return -1;
+    }
+
+    /**
      * Updates the configuration of the call forward.
      */
     public int updateCallForward(int action, int condition, String number, int serviceClass,
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
index fda295a..a24af2f 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
@@ -17,6 +17,8 @@
 package android.telephony.ims.stub;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.RemoteException;
 import android.telephony.ims.ImsException;
 import android.telephony.ims.aidl.IRcsFeatureListener;
@@ -32,6 +34,8 @@
  *
  * @hide
  */
+@SystemApi
+@TestApi
 public class RcsCapabilityExchange {
 
     /**  Service is unknown. */
diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
index bb03448..f200ea2 100644
--- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
@@ -18,6 +18,8 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.RemoteException;
 import android.telephony.ims.ImsException;
@@ -37,6 +39,8 @@
  *
  * @hide
  */
+@SystemApi
+@TestApi
 public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
 
     private static final String LOG_TAG = "RcsPresenceExchangeIB";
diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
index 1c68fc0..355c4dd 100644
--- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
@@ -19,6 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.RemoteException;
 import android.telephony.ims.ImsException;
@@ -35,6 +37,8 @@
  *
  * @hide
  */
+@SystemApi
+@TestApi
 public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
 
     private static final String LOG_TAG = "RcsSipOptionsImplBase";
@@ -69,6 +73,11 @@
      */
     public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4;
 
+    /**
+     * Indicates that the remote user responded with a 400 BAD REQUEST response.
+     */
+    public static final int RESPONSE_BAD_REQUEST = 5;
+
     /** @hide*/
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "RESPONSE_", value = {
@@ -77,7 +86,8 @@
             RESPONSE_TEMPORARILY_UNAVAILABLE,
             RESPONSE_REQUEST_TIMEOUT,
             RESPONSE_NOT_FOUND,
-            RESPONSE_DOES_NOT_EXIST_ANYWHERE
+            RESPONSE_DOES_NOT_EXIST_ANYWHERE,
+            RESPONSE_BAD_REQUEST
     })
     public @interface SipResponseCode {}
 
@@ -188,7 +198,6 @@
      * @param reason A non-null String containing the reason associated with the SIP code.
      * @param operationToken The token provided by the framework when
      *         {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
-     *
      */
     public void respondToCapabilityRequestWithError(@NonNull Uri contactUri,
             @SipResponseCode int code, @NonNull String reason, int operationToken) {
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index 15f8371..4a5380e 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -166,6 +166,12 @@
             String[] barrList, int serviceClass);
 
     /**
+     * Modifies the configuration of the call barring for specified service class with password.
+     */
+    public void updateCallBarring(int cbType, int action, Message result,
+            String[] barrList, int serviceClass, String password);
+
+    /**
      * Modifies the configuration of the call forward.
      */
     public void updateCallForward(int action, int condition, String number,
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 4f97cc5..302be65 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -122,4 +122,10 @@
      */
     int updateCallBarringForServiceClass(int cbType, int action, in String[] barrList,
             int serviceClass);
+
+    /**
+     * Updates the configuration of the call barring for specified service class with password.
+     */
+    int updateCallBarringWithPassword(int cbType, int action, in String[] barrList,
+            int serviceClass, String password);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 1f84451..f3b467b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -828,6 +828,11 @@
     void disableIms(int slotId);
 
     /**
+    * Toggle framework IMS disables and enables.
+    */
+    void resetIms(int slotIndex);
+
+    /**
      *  Get IImsMmTelFeature binder from ImsResolver that corresponds to the subId and MMTel feature
      *  as well as registering the MmTelFeature for callbacks using the IImsServiceFeatureCallback
      *  interface.
@@ -922,6 +927,23 @@
             int subId, in OperatorInfo operatorInfo, boolean persisSelection);
 
     /**
+     * Get the allowed network types that store in the telephony provider.
+     *
+     * @param subId the id of the subscription.
+     * @return allowedNetworkTypes the allowed network types.
+     */
+    long getAllowedNetworkTypes(int subId);
+
+    /**
+     * Set the allowed network types.
+     *
+     * @param subId the id of the subscription.
+     * @param allowedNetworkTypes the allowed network types.
+     * @return true on success; false on any failure.
+     */
+    boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes);
+
+    /**
      * Set the preferred network type.
      * Used for device configuration by some CDMA operators.
      *
@@ -973,6 +995,11 @@
      boolean isManualNetworkSelectionAllowed(int subId);
 
     /**
+     * Enable or disable always reporting signal strength changes from radio.
+     */
+     void setAlwaysReportSignalStrength(int subId, boolean isEnable);
+
+    /**
      * Get P-CSCF address from PCO after data connection is established or modified.
      * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
      * @param callingPackage The package making the call.
@@ -2087,6 +2114,11 @@
     int getRadioHalVersion();
 
     /**
+     * Get the current calling package name.
+     */
+    String getCurrentPackageName();
+
+    /**
      * Returns true if the specified type of application (e.g. {@link #APPTYPE_CSIM} is present
      * on the UICC card.
      * @hide
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 284544b..0e0a22ee 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -477,6 +477,7 @@
     int RIL_REQUEST_STOP_KEEPALIVE = 145;
     int RIL_REQUEST_ENABLE_MODEM = 146;
     int RIL_REQUEST_GET_MODEM_STATUS = 147;
+    int RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE = 148;
 
     /* The following requests are not defined in RIL.h */
     int RIL_REQUEST_HAL_NON_RIL_BASE = 200;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
index ae55a75..8559cb9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
@@ -30,10 +30,12 @@
 import android.view.Surface;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 
 import org.junit.Before;
 import org.junit.FixMethodOrder;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
@@ -50,6 +52,8 @@
 @LargeTest
 @RunWith(Parameterized.class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 147659548)
+@Ignore("Waiting bug feedback")
 public class SeamlessAppRotationTest extends FlickerTestBase {
     private int mBeginRotation;
     private int mEndRotation;
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index 5e9ef8e..609896e 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -18,7 +18,6 @@
     name: "PlatformCompatGating",
     // Only compile source java files in this apk.
     srcs: ["src/**/*.java"],
-    certificate: "platform",
     libs: [
         "android.test.runner",
         "android.test.base",
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index 932ec64..c00aa2a 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -16,7 +16,9 @@
 
 package android.compat.testing;
 
+import android.Manifest;
 import android.app.Instrumentation;
+import android.app.UiAutomation;
 import android.compat.Compatibility;
 import android.compat.Compatibility.ChangeConfig;
 import android.content.Context;
@@ -83,12 +85,16 @@
         @Override
         public void evaluate() throws Throwable {
             Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+            UiAutomation uiAutomation = instrumentation.getUiAutomation();
             String packageName = instrumentation.getTargetContext().getPackageName();
             IPlatformCompat platformCompat = IPlatformCompat.Stub
                     .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
             if (platformCompat == null) {
                 throw new IllegalStateException("Could not get IPlatformCompat service!");
             }
+            uiAutomation.adoptShellPermissionIdentity(
+                    Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+                    Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG);
             Compatibility.setOverrides(mConfig);
             try {
                 platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
@@ -101,6 +107,7 @@
             } catch (RemoteException e) {
                 throw new RuntimeException("Could not call IPlatformCompat binder method!", e);
             } finally {
+                uiAutomation.dropShellPermissionIdentity();
                 Compatibility.clearOverrides();
             }
         }
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index b2e573b..06c6301 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -38,6 +38,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.os.SystemClock;
+
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -316,9 +318,76 @@
 
         l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
         assertParcelingIsLossless(l);
+        l = new LinkAddress(V6_ADDRESS, 64, 123, 456,
+                1L, 3600000L);
+        assertParcelingIsLossless(l);
 
         l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
-        assertParcelSane(l, 4);
+        assertParcelSane(l, 6);
+    }
+
+    @Test
+    public void testDeprecationTime() {
+        try {
+            new LinkAddress(V6_ADDRESS, 64, 0, 456,
+                    LinkAddress.LIFETIME_UNKNOWN, 100000L);
+            fail("Only one time provided should cause exception");
+        } catch (IllegalArgumentException expected) { }
+
+        try {
+            new LinkAddress(V6_ADDRESS, 64, 0, 456,
+                    200000L, 100000L);
+            fail("deprecation time later than expiration time should cause exception");
+        } catch (IllegalArgumentException expected) { }
+
+        try {
+            new LinkAddress(V6_ADDRESS, 64, 0, 456,
+                    -2, 100000L);
+            fail("negative deprecation time should cause exception");
+        } catch (IllegalArgumentException expected) { }
+    }
+
+    @Test
+    public void testExpirationTime() {
+        try {
+            new LinkAddress(V6_ADDRESS, 64, 0, 456,
+                    200000L, LinkAddress.LIFETIME_UNKNOWN);
+            fail("Only one time provided should cause exception");
+        } catch (IllegalArgumentException expected) { }
+
+        try {
+            new LinkAddress(V6_ADDRESS, 64, 0, 456,
+                    100000L, -2);
+            fail("negative expiration time should cause exception");
+        } catch (IllegalArgumentException expected) { }
+    }
+
+    @Test
+    public void testGetFlags() {
+        LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
+        assertEquals(123, l.getFlags());
+
+        // Test if deprecated bit was added/remove automatically based on the provided deprecation
+        // time
+        l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
+                1L, LinkAddress.LIFETIME_PERMANENT);
+        // Check if the flag is added automatically.
+        assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
+
+        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
+                SystemClock.elapsedRealtime() + 100000L, LinkAddress.LIFETIME_PERMANENT);
+        // Check if the flag is removed automatically.
+        assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);
+
+        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
+                LinkAddress.LIFETIME_PERMANENT, LinkAddress.LIFETIME_PERMANENT);
+        // Check if the permanent flag is added.
+        assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);
+
+        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
+                1000L, SystemClock.elapsedRealtime() + 100000L);
+        // Check if the permanent flag is removed
+        assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
     }
 
     private void assertGlobalPreferred(LinkAddress l, String msg) {
@@ -389,5 +458,12 @@
                             (IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
                             RT_SCOPE_UNIVERSE);
         assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
+
+        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
+                RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
+                SystemClock.elapsedRealtime() + 200000);
+        // Although the deprecated bit is set, but the deprecation time is in the future, test
+        // if the flag is removed automatically.
+        assertGlobalPreferred(l, "v6,global,tempaddr+deprecated in the future");
     }
 }
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 1569112..3e4f3d8 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -269,9 +269,10 @@
             .setUids(uids)
             .addCapability(NET_CAPABILITY_EIMS)
             .addCapability(NET_CAPABILITY_NOT_METERED);
+        netCap.setOwnerUid(123);
         assertParcelingIsLossless(netCap);
         netCap.setSSID(TEST_SSID);
-        assertParcelSane(netCap, 12);
+        assertParcelSane(netCap, 13);
     }
 
     @Test
diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
new file mode 100644
index 0000000..7ab4b56
--- /dev/null
+++ b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
@@ -0,0 +1,248 @@
+/*
+ * 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.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsBinder;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
+
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.os.PersistableBundle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+
+import java.util.concurrent.Executor;
+
+@RunWith(JUnit4.class)
+public class ConnectivityDiagnosticsManagerTest {
+    private static final int NET_ID = 1;
+    private static final int DETECTION_METHOD = 2;
+    private static final long TIMESTAMP = 10L;
+    private static final String INTERFACE_NAME = "interface";
+    private static final String BUNDLE_KEY = "key";
+    private static final String BUNDLE_VALUE = "value";
+
+    private static final Executor INLINE_EXECUTOR = x -> x.run();
+
+    @Mock private ConnectivityDiagnosticsCallback mCb;
+
+    private ConnectivityDiagnosticsBinder mBinder;
+
+    @Before
+    public void setUp() {
+        mCb = mock(ConnectivityDiagnosticsCallback.class);
+
+        mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
+    }
+
+    private ConnectivityReport createSampleConnectivityReport() {
+        final LinkProperties linkProperties = new LinkProperties();
+        linkProperties.setInterfaceName(INTERFACE_NAME);
+
+        final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+        networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
+        final PersistableBundle bundle = new PersistableBundle();
+        bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+        return new ConnectivityReport(
+                new Network(NET_ID), TIMESTAMP, linkProperties, networkCapabilities, bundle);
+    }
+
+    private ConnectivityReport createDefaultConnectivityReport() {
+        return new ConnectivityReport(
+                new Network(0),
+                0L,
+                new LinkProperties(),
+                new NetworkCapabilities(),
+                PersistableBundle.EMPTY);
+    }
+
+    @Test
+    public void testPersistableBundleEquals() {
+        assertFalse(
+                ConnectivityDiagnosticsManager.persistableBundleEquals(
+                        null, PersistableBundle.EMPTY));
+        assertFalse(
+                ConnectivityDiagnosticsManager.persistableBundleEquals(
+                        PersistableBundle.EMPTY, null));
+        assertTrue(
+                ConnectivityDiagnosticsManager.persistableBundleEquals(
+                        PersistableBundle.EMPTY, PersistableBundle.EMPTY));
+
+        final PersistableBundle a = new PersistableBundle();
+        a.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+        final PersistableBundle b = new PersistableBundle();
+        b.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+        final PersistableBundle c = new PersistableBundle();
+        c.putString(BUNDLE_KEY, null);
+
+        assertFalse(
+                ConnectivityDiagnosticsManager.persistableBundleEquals(PersistableBundle.EMPTY, a));
+        assertFalse(
+                ConnectivityDiagnosticsManager.persistableBundleEquals(a, PersistableBundle.EMPTY));
+
+        assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(a, b));
+        assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(b, a));
+
+        assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(a, c));
+        assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(c, a));
+    }
+
+    @Test
+    public void testConnectivityReportEquals() {
+        assertEquals(createSampleConnectivityReport(), createSampleConnectivityReport());
+        assertEquals(createDefaultConnectivityReport(), createDefaultConnectivityReport());
+
+        final LinkProperties linkProperties = new LinkProperties();
+        linkProperties.setInterfaceName(INTERFACE_NAME);
+
+        final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+        networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
+        final PersistableBundle bundle = new PersistableBundle();
+        bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+        assertNotEquals(
+                createDefaultConnectivityReport(),
+                new ConnectivityReport(
+                        new Network(NET_ID),
+                        0L,
+                        new LinkProperties(),
+                        new NetworkCapabilities(),
+                        PersistableBundle.EMPTY));
+        assertNotEquals(
+                createDefaultConnectivityReport(),
+                new ConnectivityReport(
+                        new Network(0),
+                        TIMESTAMP,
+                        new LinkProperties(),
+                        new NetworkCapabilities(),
+                        PersistableBundle.EMPTY));
+        assertNotEquals(
+                createDefaultConnectivityReport(),
+                new ConnectivityReport(
+                        new Network(0),
+                        0L,
+                        linkProperties,
+                        new NetworkCapabilities(),
+                        PersistableBundle.EMPTY));
+        assertNotEquals(
+                createDefaultConnectivityReport(),
+                new ConnectivityReport(
+                        new Network(0),
+                        TIMESTAMP,
+                        new LinkProperties(),
+                        networkCapabilities,
+                        PersistableBundle.EMPTY));
+        assertNotEquals(
+                createDefaultConnectivityReport(),
+                new ConnectivityReport(
+                        new Network(0),
+                        TIMESTAMP,
+                        new LinkProperties(),
+                        new NetworkCapabilities(),
+                        bundle));
+    }
+
+    @Test
+    public void testConnectivityReportParcelUnparcel() {
+        assertParcelSane(createSampleConnectivityReport(), 5);
+    }
+
+    private DataStallReport createSampleDataStallReport() {
+        final PersistableBundle bundle = new PersistableBundle();
+        bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+        return new DataStallReport(new Network(NET_ID), TIMESTAMP, DETECTION_METHOD, bundle);
+    }
+
+    private DataStallReport createDefaultDataStallReport() {
+        return new DataStallReport(new Network(0), 0L, 0, PersistableBundle.EMPTY);
+    }
+
+    @Test
+    public void testDataStallReportEquals() {
+        assertEquals(createSampleDataStallReport(), createSampleDataStallReport());
+        assertEquals(createDefaultDataStallReport(), createDefaultDataStallReport());
+
+        final PersistableBundle bundle = new PersistableBundle();
+        bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+        assertNotEquals(
+                createDefaultDataStallReport(),
+                new DataStallReport(new Network(NET_ID), 0L, 0, PersistableBundle.EMPTY));
+        assertNotEquals(
+                createDefaultDataStallReport(),
+                new DataStallReport(new Network(0), TIMESTAMP, 0, PersistableBundle.EMPTY));
+        assertNotEquals(
+                createDefaultDataStallReport(),
+                new DataStallReport(new Network(0), 0L, DETECTION_METHOD, PersistableBundle.EMPTY));
+        assertNotEquals(
+                createDefaultDataStallReport(), new DataStallReport(new Network(0), 0L, 0, bundle));
+    }
+
+    @Test
+    public void testDataStallReportParcelUnparcel() {
+        assertParcelSane(createSampleDataStallReport(), 4);
+    }
+
+    @Test
+    public void testConnectivityDiagnosticsCallbackOnConnectivityReport() {
+        mBinder.onConnectivityReport(createSampleConnectivityReport());
+
+        // The callback will be invoked synchronously by inline executor. Immediately check the
+        // latch without waiting.
+        verify(mCb).onConnectivityReport(eq(createSampleConnectivityReport()));
+    }
+
+    @Test
+    public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() {
+        mBinder.onDataStallSuspected(createSampleDataStallReport());
+
+        // The callback will be invoked synchronously by inline executor. Immediately check the
+        // latch without waiting.
+        verify(mCb).onDataStallSuspected(eq(createSampleDataStallReport()));
+    }
+
+    @Test
+    public void testConnectivityDiagnosticsCallbackOnNetworkConnectivityReported() {
+        final Network n = new Network(NET_ID);
+        final boolean connectivity = true;
+
+        mBinder.onNetworkConnectivityReported(n, connectivity);
+
+        // The callback will be invoked synchronously by inline executor. Immediately check the
+        // latch without waiting.
+        verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity));
+    }
+}
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
new file mode 100644
index 0000000..d6a2176
--- /dev/null
+++ b/tests/net/java/android/net/Ikev2VpnProfileTest.java
@@ -0,0 +1,360 @@
+/*
+ * 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.net;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+import android.test.mock.MockContext;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.net.VpnProfile;
+import com.android.org.bouncycastle.x509.X509V1CertificateGenerator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import javax.security.auth.x500.X500Principal;
+
+/** Unit tests for {@link Ikev2VpnProfile.Builder}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Ikev2VpnProfileTest {
+    private static final String SERVER_ADDR_STRING = "1.2.3.4";
+    private static final String IDENTITY_STRING = "Identity";
+    private static final String USERNAME_STRING = "username";
+    private static final String PASSWORD_STRING = "pa55w0rd";
+    private static final String EXCL_LIST = "exclList";
+    private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
+    private static final int TEST_MTU = 1300;
+
+    private final MockContext mMockContext =
+            new MockContext() {
+                @Override
+                public String getOpPackageName() {
+                    return "fooPackage";
+                }
+            };
+    private final ProxyInfo mProxy = new ProxyInfo(SERVER_ADDR_STRING, -1, EXCL_LIST);
+
+    private X509Certificate mUserCert;
+    private X509Certificate mServerRootCa;
+    private PrivateKey mPrivateKey;
+
+    @Before
+    public void setUp() throws Exception {
+        mServerRootCa = generateRandomCertAndKeyPair().cert;
+
+        final CertificateAndKey userCertKey = generateRandomCertAndKeyPair();
+        mUserCert = userCertKey.cert;
+        mPrivateKey = userCertKey.key;
+    }
+
+    private Ikev2VpnProfile.Builder getBuilderWithDefaultOptions() {
+        final Ikev2VpnProfile.Builder builder =
+                new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING);
+
+        builder.setBypassable(true);
+        builder.setProxy(mProxy);
+        builder.setMaxMtu(TEST_MTU);
+        builder.setMetered(true);
+
+        return builder;
+    }
+
+    @Test
+    public void testBuildValidProfileWithOptions() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+        final Ikev2VpnProfile profile = builder.build();
+        assertNotNull(profile);
+
+        // Check non-auth parameters correctly stored
+        assertEquals(SERVER_ADDR_STRING, profile.getServerAddr());
+        assertEquals(IDENTITY_STRING, profile.getUserIdentity());
+        assertEquals(mProxy, profile.getProxyInfo());
+        assertTrue(profile.isBypassable());
+        assertTrue(profile.isMetered());
+        assertEquals(TEST_MTU, profile.getMaxMtu());
+    }
+
+    @Test
+    public void testBuildUsernamePasswordProfile() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+        final Ikev2VpnProfile profile = builder.build();
+        assertNotNull(profile);
+
+        assertEquals(USERNAME_STRING, profile.getUsername());
+        assertEquals(PASSWORD_STRING, profile.getPassword());
+        assertEquals(mServerRootCa, profile.getServerRootCaCert());
+
+        assertNull(profile.getPresharedKey());
+        assertNull(profile.getRsaPrivateKey());
+        assertNull(profile.getUserCert());
+    }
+
+    @Test
+    public void testBuildDigitalSignatureProfile() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+        final Ikev2VpnProfile profile = builder.build();
+        assertNotNull(profile);
+
+        assertEquals(profile.getUserCert(), mUserCert);
+        assertEquals(mPrivateKey, profile.getRsaPrivateKey());
+        assertEquals(profile.getServerRootCaCert(), mServerRootCa);
+
+        assertNull(profile.getPresharedKey());
+        assertNull(profile.getUsername());
+        assertNull(profile.getPassword());
+    }
+
+    @Test
+    public void testBuildPresharedKeyProfile() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthPsk(PSK_BYTES);
+        final Ikev2VpnProfile profile = builder.build();
+        assertNotNull(profile);
+
+        assertArrayEquals(PSK_BYTES, profile.getPresharedKey());
+
+        assertNull(profile.getServerRootCaCert());
+        assertNull(profile.getUsername());
+        assertNull(profile.getPassword());
+        assertNull(profile.getRsaPrivateKey());
+        assertNull(profile.getUserCert());
+    }
+
+    @Test
+    public void testBuildNoAuthMethodSet() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        try {
+            builder.build();
+            fail("Expected exception due to lack of auth method");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testBuildInvalidMtu() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        try {
+            builder.setMaxMtu(500);
+            fail("Expected exception due to too-small MTU");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    private void verifyVpnProfileCommon(VpnProfile profile) {
+        assertEquals(SERVER_ADDR_STRING, profile.server);
+        assertEquals(IDENTITY_STRING, profile.ipsecIdentifier);
+        assertEquals(mProxy, profile.proxy);
+        assertTrue(profile.isBypassable);
+        assertTrue(profile.isMetered);
+        assertEquals(TEST_MTU, profile.maxMtu);
+    }
+
+    @Test
+    public void testPskConvertToVpnProfile() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthPsk(PSK_BYTES);
+        final VpnProfile profile = builder.build().toVpnProfile();
+
+        verifyVpnProfileCommon(profile);
+        assertEquals(Ikev2VpnProfile.encodeForIpsecSecret(PSK_BYTES), profile.ipsecSecret);
+
+        // Check nothing else is set
+        assertEquals("", profile.username);
+        assertEquals("", profile.password);
+        assertEquals("", profile.ipsecUserCert);
+        assertEquals("", profile.ipsecCaCert);
+    }
+
+    @Test
+    public void testUsernamePasswordConvertToVpnProfile() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+        final VpnProfile profile = builder.build().toVpnProfile();
+
+        verifyVpnProfileCommon(profile);
+        assertEquals(USERNAME_STRING, profile.username);
+        assertEquals(PASSWORD_STRING, profile.password);
+        assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
+
+        // Check nothing else is set
+        assertEquals("", profile.ipsecUserCert);
+        assertEquals("", profile.ipsecSecret);
+    }
+
+    @Test
+    public void testRsaConvertToVpnProfile() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+        final VpnProfile profile = builder.build().toVpnProfile();
+
+        verifyVpnProfileCommon(profile);
+        assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert);
+        assertEquals(
+                Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded()),
+                profile.ipsecSecret);
+        assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
+
+        // Check nothing else is set
+        assertEquals("", profile.username);
+        assertEquals("", profile.password);
+    }
+
+    @Test
+    public void testPskFromVpnProfileDiscardsIrrelevantValues() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthPsk(PSK_BYTES);
+        final VpnProfile profile = builder.build().toVpnProfile();
+        profile.username = USERNAME_STRING;
+        profile.password = PASSWORD_STRING;
+        profile.ipsecCaCert = Ikev2VpnProfile.certificateToPemString(mServerRootCa);
+        profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
+
+        final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
+        assertNull(result.getUsername());
+        assertNull(result.getPassword());
+        assertNull(result.getUserCert());
+        assertNull(result.getRsaPrivateKey());
+        assertNull(result.getServerRootCaCert());
+    }
+
+    @Test
+    public void testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+        final VpnProfile profile = builder.build().toVpnProfile();
+        profile.ipsecSecret = new String(PSK_BYTES);
+        profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
+
+        final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
+        assertNull(result.getPresharedKey());
+        assertNull(result.getUserCert());
+        assertNull(result.getRsaPrivateKey());
+    }
+
+    @Test
+    public void testRsaFromVpnProfileDiscardsIrrelevantValues() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+        final VpnProfile profile = builder.build().toVpnProfile();
+        profile.username = USERNAME_STRING;
+        profile.password = PASSWORD_STRING;
+
+        final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
+        assertNull(result.getUsername());
+        assertNull(result.getPassword());
+        assertNull(result.getPresharedKey());
+    }
+
+    @Test
+    public void testPskConversionIsLossless() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthPsk(PSK_BYTES);
+        final Ikev2VpnProfile ikeProfile = builder.build();
+
+        assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
+    }
+
+    @Test
+    public void testUsernamePasswordConversionIsLossless() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+        final Ikev2VpnProfile ikeProfile = builder.build();
+
+        assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
+    }
+
+    @Test
+    public void testRsaConversionIsLossless() throws Exception {
+        final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+        builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+        final Ikev2VpnProfile ikeProfile = builder.build();
+
+        assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
+    }
+
+    private static class CertificateAndKey {
+        public final X509Certificate cert;
+        public final PrivateKey key;
+
+        CertificateAndKey(X509Certificate cert, PrivateKey key) {
+            this.cert = cert;
+            this.key = key;
+        }
+    }
+
+    private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception {
+        final Date validityBeginDate =
+                new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L));
+        final Date validityEndDate =
+                new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L));
+
+        // Generate a keypair
+        final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+        keyPairGenerator.initialize(512);
+        final KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+        final X500Principal dnName = new X500Principal("CN=test.android.com");
+        final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
+        certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
+        certGen.setSubjectDN(dnName);
+        certGen.setIssuerDN(dnName);
+        certGen.setNotBefore(validityBeginDate);
+        certGen.setNotAfter(validityEndDate);
+        certGen.setPublicKey(keyPair.getPublic());
+        certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
+
+        final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL");
+        return new CertificateAndKey(cert, keyPair.getPrivate());
+    }
+}
diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/net/java/android/net/VpnManagerTest.java
new file mode 100644
index 0000000..655c4d1
--- /dev/null
+++ b/tests/net/java/android/net/VpnManagerTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.net;
+
+import static org.mockito.Mockito.mock;
+
+import android.test.mock.MockContext;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link VpnManager}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VpnManagerTest {
+    private static final String VPN_PROFILE_KEY = "KEY";
+
+    private IConnectivityManager mMockCs;
+    private VpnManager mVpnManager;
+    private final MockContext mMockContext =
+            new MockContext() {
+                @Override
+                public String getOpPackageName() {
+                    return "fooPackage";
+                }
+            };
+
+    @Before
+    public void setUp() throws Exception {
+        mMockCs = mock(IConnectivityManager.class);
+        mVpnManager = new VpnManager(mMockContext, mMockCs);
+    }
+
+    @Test
+    public void testProvisionVpnProfile() throws Exception {
+        try {
+            mVpnManager.provisionVpnProfile(mock(PlatformVpnProfile.class));
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    @Test
+    public void testDeleteProvisionedVpnProfile() throws Exception {
+        try {
+            mVpnManager.deleteProvisionedVpnProfile();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    @Test
+    public void testStartProvisionedVpnProfile() throws Exception {
+        try {
+            mVpnManager.startProvisionedVpnProfile();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    @Test
+    public void testStopProvisionedVpnProfile() throws Exception {
+        try {
+            mVpnManager.stopProvisionedVpnProfile();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+}
diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java
new file mode 100644
index 0000000..8a4b533
--- /dev/null
+++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.internal.net;
+
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.net.IpSecAlgorithm;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+
+/** Unit tests for {@link VpnProfile}. */
+@SmallTest
+@RunWith(JUnit4.class)
+public class VpnProfileTest {
+    private static final String DUMMY_PROFILE_KEY = "Test";
+
+    @Test
+    public void testDefaults() throws Exception {
+        final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
+
+        assertEquals(DUMMY_PROFILE_KEY, p.key);
+        assertEquals("", p.name);
+        assertEquals(VpnProfile.TYPE_PPTP, p.type);
+        assertEquals("", p.server);
+        assertEquals("", p.username);
+        assertEquals("", p.password);
+        assertEquals("", p.dnsServers);
+        assertEquals("", p.searchDomains);
+        assertEquals("", p.routes);
+        assertTrue(p.mppe);
+        assertEquals("", p.l2tpSecret);
+        assertEquals("", p.ipsecIdentifier);
+        assertEquals("", p.ipsecSecret);
+        assertEquals("", p.ipsecUserCert);
+        assertEquals("", p.ipsecCaCert);
+        assertEquals("", p.ipsecServerCert);
+        assertEquals(null, p.proxy);
+        assertTrue(p.getAllowedAlgorithms() != null && p.getAllowedAlgorithms().isEmpty());
+        assertFalse(p.isBypassable);
+        assertFalse(p.isMetered);
+        assertEquals(1400, p.maxMtu);
+        assertFalse(p.areAuthParamsInline);
+    }
+
+    private VpnProfile getSampleIkev2Profile(String key) {
+        final VpnProfile p = new VpnProfile(key);
+
+        p.name = "foo";
+        p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+        p.server = "bar";
+        p.username = "baz";
+        p.password = "qux";
+        p.dnsServers = "8.8.8.8";
+        p.searchDomains = "";
+        p.routes = "0.0.0.0/0";
+        p.mppe = false;
+        p.l2tpSecret = "";
+        p.ipsecIdentifier = "quux";
+        p.ipsecSecret = "quuz";
+        p.ipsecUserCert = "corge";
+        p.ipsecCaCert = "grault";
+        p.ipsecServerCert = "garply";
+        p.proxy = null;
+        p.setAllowedAlgorithms(
+                Arrays.asList(
+                        IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+                        IpSecAlgorithm.AUTH_HMAC_SHA512,
+                        IpSecAlgorithm.CRYPT_AES_CBC));
+        p.isBypassable = true;
+        p.isMetered = true;
+        p.maxMtu = 1350;
+        p.areAuthParamsInline = true;
+
+        // Not saved, but also not compared.
+        p.saveLogin = true;
+
+        return p;
+    }
+
+    @Test
+    public void testEquals() {
+        assertEquals(
+                getSampleIkev2Profile(DUMMY_PROFILE_KEY), getSampleIkev2Profile(DUMMY_PROFILE_KEY));
+
+        final VpnProfile modified = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+        modified.maxMtu--;
+        assertNotEquals(getSampleIkev2Profile(DUMMY_PROFILE_KEY), modified);
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 22);
+    }
+
+    @Test
+    public void testSetInvalidAlgorithmValueDelimiter() {
+        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+
+        try {
+            profile.setAllowedAlgorithms(
+                    Arrays.asList("test" + VpnProfile.VALUE_DELIMITER + "test"));
+            fail("Expected failure due to value separator in algorithm name");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testSetInvalidAlgorithmListDelimiter() {
+        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+
+        try {
+            profile.setAllowedAlgorithms(
+                    Arrays.asList("test" + VpnProfile.LIST_DELIMITER + "test"));
+            fail("Expected failure due to value separator in algorithm name");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testEncodeDecode() {
+        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+        final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
+        assertEquals(profile, decoded);
+    }
+
+    @Test
+    public void testEncodeDecodeTooManyValues() {
+        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+        final byte[] tooManyValues =
+                (new String(profile.encode()) + VpnProfile.VALUE_DELIMITER + "invalid").getBytes();
+
+        assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
+    }
+
+    @Test
+    public void testEncodeDecodeInvalidNumberOfValues() {
+        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+        final String encoded = new String(profile.encode());
+        final byte[] tooFewValues =
+                encoded.substring(0, encoded.lastIndexOf(VpnProfile.VALUE_DELIMITER)).getBytes();
+
+        assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues));
+    }
+
+    @Test
+    public void testEncodeDecodeLoginsNotSaved() {
+        final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+        profile.saveLogin = false;
+
+        final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
+        assertNotEquals(profile, decoded);
+
+        // Add the username/password back, everything else must be equal.
+        decoded.username = profile.username;
+        decoded.password = profile.password;
+        assertEquals(profile, decoded);
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 783f8d1..e80b7c9 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -6313,12 +6313,24 @@
         assertEquals(wifiLp, mService.getActiveLinkProperties());
     }
 
+    @Test
+    public void testNetworkCapabilitiesRestrictedForCallerPermissions() {
+        int callerUid = Process.myUid();
+        final NetworkCapabilities originalNc = new NetworkCapabilities();
+        originalNc.setOwnerUid(callerUid);
 
-    private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
-            Set<UidRange> vpnRange) throws Exception {
+        final NetworkCapabilities newNc =
+                mService.networkCapabilitiesRestrictedForCallerPermissions(
+                        originalNc, Process.myPid(), callerUid);
+
+        assertEquals(Process.INVALID_UID, newNc.getOwnerUid());
+    }
+
+    private TestNetworkAgentWrapper establishVpn(
+            LinkProperties lp, int ownerUid, Set<UidRange> vpnRange) throws Exception {
         final TestNetworkAgentWrapper
                 vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp);
-        vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid);
+        vpnNetworkAgent.getNetworkCapabilities().setOwnerUid(ownerUid);
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.connect();
         mMockVpn.setUids(vpnRange);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f85bb5f..b9eb3f2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -3194,27 +3194,27 @@
      * soft AP state and number of connected devices immediately after a successful call to this API
      * via callback. Note that receiving an immediate WIFI_AP_STATE_FAILED value for soft AP state
      * indicates that the latest attempt to start soft AP has failed. Caller can unregister a
-     * previously registered callback using {@link unregisterSoftApCallback}
+     * previously registered callback using {@link #unregisterSoftApCallback}
      * <p>
      * Applications should have the
      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
      * without the permission will trigger a {@link java.lang.SecurityException}.
      * <p>
      *
-     * @param executor The executor to execute the callbacks of the {@code executor}
-     *                 object. If null, then the application's main executor will be used.
+     * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
+     *                 object.
      * @param callback Callback for soft AP events
      *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
-    public void registerSoftApCallback(@Nullable @CallbackExecutor Executor executor,
+    public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor,
                                        @NonNull SoftApCallback callback) {
+        if (executor == null) throw new IllegalArgumentException("executor cannot be null");
         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
         Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
 
-        executor = (executor == null) ? mContext.getMainExecutor() : executor;
         Binder binder = new Binder();
         try {
             mService.registerSoftApCallback(binder, new SoftApCallbackProxy(executor, callback),
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 4260c20..b130c17 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -693,6 +693,18 @@
     }
 
     /**
+     * Verify an IllegalArgumentException is thrown if executor is null.
+     */
+    @Test
+    public void registerSoftApCallbackThrowsIllegalArgumentExceptionOnNullArgumentForExecutor() {
+        try {
+            mWifiManager.registerSoftApCallback(null, mSoftApCallback);
+            fail("expected IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    /**
      * Verify an IllegalArgumentException is thrown if callback is not provided.
      */
     @Test
@@ -705,16 +717,6 @@
     }
 
     /**
-     * Verify main looper is used when handler is not provided.
-     */
-    @Test
-    public void registerSoftApCallbackUsesMainLooperOnNullArgumentForHandler() {
-        when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
-        mWifiManager.registerSoftApCallback(null, mSoftApCallback);
-        verify(mContext).getMainExecutor();
-    }
-
-    /**
      * Verify the call to registerSoftApCallback goes to WifiServiceImpl.
      */
     @Test