Merge "Make some SubscriptionManager APIs system APIs"
diff --git a/Android.bp b/Android.bp
index 151adf8..124f473 100644
--- a/Android.bp
+++ b/Android.bp
@@ -484,6 +484,8 @@
         "telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl",
         "telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl",
         "telecomm/java/com/android/internal/telecom/IInCallService.aidl",
+        "telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl",
+        "telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl",
         "telecomm/java/com/android/internal/telecom/ITelecomService.aidl",
         "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl",
         "telephony/java/android/telephony/data/IDataService.aidl",
@@ -677,6 +679,7 @@
 
     static_libs: [
         "apex_aidl_interface-java",
+        "networkstack-aidl-interfaces-java",
         "framework-protos",
         "android.hidl.base-V1.0-java",
         "android.hardware.cas-V1.0-java",
@@ -816,6 +819,16 @@
     output_extension: "srcjar",
 }
 
+// AIDL interfaces between the core system and the networking mainline module.
+aidl_interface {
+    name: "networkstack-aidl-interfaces",
+    local_include_dir: "core/java",
+    srcs: [
+        "core/java/android/net/INetworkStackConnector.aidl",
+    ],
+    api_dir: "aidl/networkstack",
+}
+
 // Build ext.jar
 // ============================================================
 java_library {
@@ -1147,6 +1160,7 @@
 metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
     "--hide-package com.android.okhttp " +
     "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
+    "--error UnhiddenSystemApi " +
     "--hide RequiresPermission " +
     "--hide MissingPermission --hide BroadcastBehavior " +
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
@@ -1563,6 +1577,7 @@
     dex_mapping_filename: "dex-mapping.txt",
     args: metalava_framework_docs_args +
         " --hide ReferencesHidden " +
+        " --hide UnhiddenSystemApi " +
         " --show-unannotated " +
         " --show-annotation android.annotation.SystemApi " +
         " --show-annotation android.annotation.TestApi "
diff --git a/api/current.txt b/api/current.txt
index 7b48a5b..89b14b8 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -27225,7 +27225,7 @@
     method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
     method public boolean bindProcessToNetwork(android.net.Network);
     method public android.net.Network getActiveNetwork();
-    method public android.net.NetworkInfo getActiveNetworkInfo();
+    method public deprecated android.net.NetworkInfo getActiveNetworkInfo();
     method public deprecated android.net.NetworkInfo[] getAllNetworkInfo();
     method public android.net.Network[] getAllNetworks();
     method public deprecated boolean getBackgroundDataSetting();
@@ -27236,7 +27236,7 @@
     method public int getMultipathPreference(android.net.Network);
     method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
     method public deprecated android.net.NetworkInfo getNetworkInfo(int);
-    method public android.net.NetworkInfo getNetworkInfo(android.net.Network);
+    method public deprecated android.net.NetworkInfo getNetworkInfo(android.net.Network);
     method public deprecated int getNetworkPreference();
     method public byte[] getNetworkWatchlistConfigHash();
     method public static deprecated android.net.Network getProcessDefaultNetwork();
@@ -27270,14 +27270,14 @@
     field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
     field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
-    field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
-    field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
+    field public static final deprecated java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
+    field public static final deprecated java.lang.String EXTRA_IS_FAILOVER = "isFailover";
     field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK";
     field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
     field public static final java.lang.String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
     field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType";
     field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
-    field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
+    field public static final deprecated java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     field public static final java.lang.String EXTRA_REASON = "reason";
     field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
     field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
@@ -27333,6 +27333,11 @@
     field public int serverAddress;
   }
 
+  public class InetAddresses {
+    method public static boolean isNumericAddress(java.lang.String);
+    method public static java.net.InetAddress parseNumericAddress(java.lang.String);
+  }
+
   public final class IpPrefix implements android.os.Parcelable {
     method public boolean contains(java.net.InetAddress);
     method public int describeContents();
@@ -27424,6 +27429,7 @@
     method public android.net.ProxyInfo getHttpProxy();
     method public java.lang.String getInterfaceName();
     method public java.util.List<android.net.LinkAddress> getLinkAddresses();
+    method public int getMtu();
     method public java.lang.String getPrivateDnsServerName();
     method public java.util.List<android.net.RouteInfo> getRoutes();
     method public boolean isPrivateDnsActive();
@@ -27572,10 +27578,10 @@
     field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
   }
 
-  public class NetworkInfo implements android.os.Parcelable {
+  public deprecated class NetworkInfo implements android.os.Parcelable {
     method public int describeContents();
     method public deprecated android.net.NetworkInfo.DetailedState getDetailedState();
-    method public java.lang.String getExtraInfo();
+    method public deprecated java.lang.String getExtraInfo();
     method public deprecated java.lang.String getReason();
     method public deprecated android.net.NetworkInfo.State getState();
     method public deprecated int getSubtype();
@@ -27591,7 +27597,7 @@
     field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
   }
 
-  public static final class NetworkInfo.DetailedState extends java.lang.Enum {
+  public static final deprecated class NetworkInfo.DetailedState extends java.lang.Enum {
     method public static android.net.NetworkInfo.DetailedState valueOf(java.lang.String);
     method public static final android.net.NetworkInfo.DetailedState[] values();
     enum_constant public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
@@ -27609,7 +27615,7 @@
     enum_constant public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
   }
 
-  public static final class NetworkInfo.State extends java.lang.Enum {
+  public static final deprecated class NetworkInfo.State extends java.lang.Enum {
     method public static android.net.NetworkInfo.State valueOf(java.lang.String);
     method public static final android.net.NetworkInfo.State[] values();
     enum_constant public static final android.net.NetworkInfo.State CONNECTED;
@@ -37330,10 +37336,13 @@
   }
 
   public static final class Telephony.CarrierId implements android.provider.BaseColumns {
+    method public static android.net.Uri getPreciseCarrierIdUriForSubscriptionId(int);
     method public static android.net.Uri getUriForSubscriptionId(int);
     field public static final java.lang.String CARRIER_ID = "carrier_id";
     field public static final java.lang.String CARRIER_NAME = "carrier_name";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String PRECISE_CARRIER_ID = "precise_carrier_id";
+    field public static final java.lang.String PRECISE_CARRIER_ID_NAME = "precise_carrier_id_name";
   }
 
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
@@ -37345,22 +37354,23 @@
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String CURRENT = "current";
     field public static final java.lang.String DEFAULT_SORT_ORDER = "name ASC";
-    field public static final java.lang.String MCC = "mcc";
+    field public static final deprecated java.lang.String MCC = "mcc";
     field public static final java.lang.String MMSC = "mmsc";
     field public static final java.lang.String MMSPORT = "mmsport";
     field public static final java.lang.String MMSPROXY = "mmsproxy";
-    field public static final java.lang.String MNC = "mnc";
-    field public static final java.lang.String MVNO_MATCH_DATA = "mvno_match_data";
-    field public static final java.lang.String MVNO_TYPE = "mvno_type";
+    field public static final deprecated java.lang.String MNC = "mnc";
+    field public static final deprecated java.lang.String MVNO_MATCH_DATA = "mvno_match_data";
+    field public static final deprecated java.lang.String MVNO_TYPE = "mvno_type";
     field public static final java.lang.String NAME = "name";
     field public static final java.lang.String NETWORK_TYPE_BITMASK = "network_type_bitmask";
-    field public static final java.lang.String NUMERIC = "numeric";
+    field public static final deprecated java.lang.String NUMERIC = "numeric";
     field public static final java.lang.String PASSWORD = "password";
     field public static final java.lang.String PORT = "port";
     field public static final java.lang.String PROTOCOL = "protocol";
     field public static final java.lang.String PROXY = "proxy";
     field public static final java.lang.String ROAMING_PROTOCOL = "roaming_protocol";
     field public static final java.lang.String SERVER = "server";
+    field public static final android.net.Uri SIM_APN_URI;
     field public static final java.lang.String SUBSCRIPTION_ID = "sub_id";
     field public static final java.lang.String TYPE = "type";
     field public static final java.lang.String USER = "user";
@@ -39458,13 +39468,16 @@
 
   public class CarrierIdentifier implements android.os.Parcelable {
     ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    ctor public CarrierIdentifier(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, int, int);
     ctor public CarrierIdentifier(byte[], java.lang.String, java.lang.String);
     method public int describeContents();
+    method public int getCarrierId();
     method public java.lang.String getGid1();
     method public java.lang.String getGid2();
     method public java.lang.String getImsi();
     method public java.lang.String getMcc();
     method public java.lang.String getMnc();
+    method public int getPreciseCarrierId();
     method public java.lang.String getSpn();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.carrier.CarrierIdentifier> CREATOR;
@@ -40495,13 +40508,13 @@
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
-    method public static void setegid(int) throws android.system.ErrnoException;
+    method public static deprecated void setegid(int) throws android.system.ErrnoException;
     method public static void setenv(java.lang.String, java.lang.String, boolean) throws android.system.ErrnoException;
-    method public static void seteuid(int) throws android.system.ErrnoException;
-    method public static void setgid(int) throws android.system.ErrnoException;
+    method public static deprecated void seteuid(int) throws android.system.ErrnoException;
+    method public static deprecated void setgid(int) throws android.system.ErrnoException;
     method public static int setsid() throws android.system.ErrnoException;
     method public static void setsockoptInt(java.io.FileDescriptor, int, int, int) throws android.system.ErrnoException;
-    method public static void setuid(int) throws android.system.ErrnoException;
+    method public static deprecated void setuid(int) throws android.system.ErrnoException;
     method public static void setxattr(java.lang.String, java.lang.String, byte[], int) throws android.system.ErrnoException;
     method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException;
@@ -40855,7 +40868,9 @@
     field public static final int SIOCGIFBRDADDR;
     field public static final int SIOCGIFDSTADDR;
     field public static final int SIOCGIFNETMASK;
+    field public static final int SOCK_CLOEXEC;
     field public static final int SOCK_DGRAM;
+    field public static final int SOCK_NONBLOCK;
     field public static final int SOCK_RAW;
     field public static final int SOCK_SEQPACKET;
     field public static final int SOCK_STREAM;
@@ -41934,9 +41949,12 @@
 
   public static final class VideoProfile.CameraCapabilities implements android.os.Parcelable {
     ctor public VideoProfile.CameraCapabilities(int, int);
+    ctor public VideoProfile.CameraCapabilities(int, int, boolean, float);
     method public int describeContents();
     method public int getHeight();
+    method public float getMaxZoom();
     method public int getWidth();
+    method public boolean isZoomSupported();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telecom.VideoProfile.CameraCapabilities> CREATOR;
   }
@@ -42846,6 +42864,7 @@
   public class SubscriptionInfo implements android.os.Parcelable {
     method public android.graphics.Bitmap createIconBitmap(android.content.Context);
     method public int describeContents();
+    method public int getCarrierId();
     method public java.lang.CharSequence getCarrierName();
     method public java.lang.String getCountryIso();
     method public int getDataRoaming();
@@ -42885,12 +42904,14 @@
     method public static int getSlotIndex(int);
     method public int[] getSubscriptionIds(int);
     method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
+    method public java.util.List<android.telephony.SubscriptionInfo> getSubscriptionsInGroup(int);
     method public boolean isActiveSubscriptionId(int);
     method public boolean isNetworkRoaming(int);
     method public static boolean isUsableSubscriptionId(int);
     method public static boolean isValidSubscriptionId(int);
     method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
+    method public boolean removeSubscriptionsFromGroup(int[]);
     method public java.lang.String setSubscriptionGroup(int[]);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
     method public void setSubscriptionOverrideUnmetered(int, boolean, long);
@@ -42955,6 +42976,7 @@
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
     method public android.os.PersistableBundle getCarrierConfig();
+    method public int getCarrierIdFromSimMccMnc();
     method public deprecated android.telephony.CellLocation getCellLocation();
     method public java.util.Map<java.lang.Integer, java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList();
     method public java.util.Map<java.lang.Integer, java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList(int);
@@ -42992,6 +43014,8 @@
     method public java.lang.String getSimCountryIso();
     method public java.lang.String getSimOperator();
     method public java.lang.String getSimOperatorName();
+    method public int getSimPreciseCarrierId();
+    method public java.lang.CharSequence getSimPreciseCarrierIdName();
     method public java.lang.String getSimSerialNumber();
     method public int getSimState();
     method public int getSimState(int);
@@ -43047,6 +43071,7 @@
     field public static final java.lang.String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE";
     field public static final java.lang.String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
     field public static final java.lang.String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
+    field public static final java.lang.String ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED";
     field public static final int APPTYPE_CSIM = 4; // 0x4
     field public static final int APPTYPE_ISIM = 5; // 0x5
     field public static final int APPTYPE_RUIM = 3; // 0x3
@@ -43079,6 +43104,8 @@
     field public static final java.lang.String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
     field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
     field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final java.lang.String EXTRA_PRECISE_CARRIER_ID = "android.telephony.extra.PRECISE_CARRIER_ID";
+    field public static final java.lang.String EXTRA_PRECISE_CARRIER_NAME = "android.telephony.extra.PRECISE_CARRIER_NAME";
     field public static final java.lang.String EXTRA_STATE = "state";
     field public static final java.lang.String EXTRA_STATE_IDLE;
     field public static final java.lang.String EXTRA_STATE_OFFHOOK;
diff --git a/api/system-current.txt b/api/system-current.txt
index a8f32a7..af902d4d3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -23,6 +23,7 @@
     field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
     field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
+    field public static final java.lang.String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
     field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
     field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
@@ -3044,7 +3045,20 @@
     ctor public LinkAddress(java.lang.String);
   }
 
+  public final class LinkProperties implements android.os.Parcelable {
+    ctor public LinkProperties();
+    method public boolean addRoute(android.net.RouteInfo);
+    method public void clear();
+    method public void setDnsServers(java.util.Collection<java.net.InetAddress>);
+    method public void setDomains(java.lang.String);
+    method public void setHttpProxy(android.net.ProxyInfo);
+    method public void setInterfaceName(java.lang.String);
+    method public void setLinkAddresses(java.util.Collection<android.net.LinkAddress>);
+    method public void setMtu(int);
+  }
+
   public final class NetworkCapabilities implements android.os.Parcelable {
+    method public int getSignalStrength();
     field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
   }
 
@@ -3064,6 +3078,10 @@
     method public abstract void onRequestScores(android.net.NetworkKey[]);
   }
 
+  public static class NetworkRequest.Builder {
+    method public android.net.NetworkRequest.Builder setSignalStrength(int);
+  }
+
   public class NetworkScoreManager {
     method public boolean clearScores() throws java.lang.SecurityException;
     method public void disableScoring() throws java.lang.SecurityException;
@@ -4942,6 +4960,14 @@
     ctor public PhoneAccountSuggestion(android.telecom.PhoneAccountHandle, int, boolean);
   }
 
+  public class PhoneAccountSuggestionService extends android.app.Service {
+    ctor public PhoneAccountSuggestionService();
+    method public void onAccountSuggestionRequest(java.lang.String);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public final void suggestPhoneAccounts(java.lang.String, java.util.List<android.telecom.PhoneAccountSuggestion>);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
+  }
+
   public final class RemoteConference {
     method public deprecated void setAudioState(android.telecom.AudioState);
   }
@@ -5035,6 +5061,83 @@
     field public static final java.lang.String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
   }
 
+  public class DisconnectCause {
+    field public static final int ALREADY_DIALING = 72; // 0x48
+    field public static final int ANSWERED_ELSEWHERE = 52; // 0x34
+    field public static final int BUSY = 4; // 0x4
+    field public static final int CALLING_DISABLED = 74; // 0x4a
+    field public static final int CALL_BARRED = 20; // 0x14
+    field public static final int CALL_PULLED = 51; // 0x33
+    field public static final int CANT_CALL_WHILE_RINGING = 73; // 0x49
+    field public static final int CDMA_ACCESS_BLOCKED = 35; // 0x23
+    field public static final int CDMA_ACCESS_FAILURE = 32; // 0x20
+    field public static final int CDMA_ALREADY_ACTIVATED = 49; // 0x31
+    field public static final int CDMA_DROP = 27; // 0x1b
+    field public static final int CDMA_INTERCEPT = 28; // 0x1c
+    field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 26; // 0x1a
+    field public static final int CDMA_NOT_EMERGENCY = 34; // 0x22
+    field public static final int CDMA_PREEMPTED = 33; // 0x21
+    field public static final int CDMA_REORDER = 29; // 0x1d
+    field public static final int CDMA_RETRY_ORDER = 31; // 0x1f
+    field public static final int CDMA_SO_REJECT = 30; // 0x1e
+    field public static final int CONGESTION = 5; // 0x5
+    field public static final int CS_RESTRICTED = 22; // 0x16
+    field public static final int CS_RESTRICTED_EMERGENCY = 24; // 0x18
+    field public static final int CS_RESTRICTED_NORMAL = 23; // 0x17
+    field public static final int DATA_DISABLED = 54; // 0x36
+    field public static final int DATA_LIMIT_REACHED = 55; // 0x37
+    field public static final int DIALED_CALL_FORWARDING_WHILE_ROAMING = 57; // 0x39
+    field public static final int DIALED_MMI = 39; // 0x27
+    field public static final int DIAL_LOW_BATTERY = 62; // 0x3e
+    field public static final int DIAL_MODIFIED_TO_DIAL = 48; // 0x30
+    field public static final int DIAL_MODIFIED_TO_DIAL_VIDEO = 66; // 0x42
+    field public static final int DIAL_MODIFIED_TO_SS = 47; // 0x2f
+    field public static final int DIAL_MODIFIED_TO_USSD = 46; // 0x2e
+    field public static final int DIAL_VIDEO_MODIFIED_TO_DIAL = 69; // 0x45
+    field public static final int DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 70; // 0x46
+    field public static final int DIAL_VIDEO_MODIFIED_TO_SS = 67; // 0x43
+    field public static final int DIAL_VIDEO_MODIFIED_TO_USSD = 68; // 0x44
+    field public static final int EMERGENCY_PERM_FAILURE = 64; // 0x40
+    field public static final int EMERGENCY_TEMP_FAILURE = 63; // 0x3f
+    field public static final int ERROR_UNSPECIFIED = 36; // 0x24
+    field public static final int FDN_BLOCKED = 21; // 0x15
+    field public static final int ICC_ERROR = 19; // 0x13
+    field public static final int IMEI_NOT_ACCEPTED = 58; // 0x3a
+    field public static final int IMS_ACCESS_BLOCKED = 60; // 0x3c
+    field public static final int IMS_MERGED_SUCCESSFULLY = 45; // 0x2d
+    field public static final int IMS_SIP_ALTERNATE_EMERGENCY_CALL = 71; // 0x47
+    field public static final int INCOMING_MISSED = 1; // 0x1
+    field public static final int INCOMING_REJECTED = 16; // 0x10
+    field public static final int INVALID_CREDENTIALS = 10; // 0xa
+    field public static final int INVALID_NUMBER = 7; // 0x7
+    field public static final int LIMIT_EXCEEDED = 15; // 0xf
+    field public static final int LOCAL = 3; // 0x3
+    field public static final int LOST_SIGNAL = 14; // 0xe
+    field public static final int LOW_BATTERY = 61; // 0x3d
+    field public static final int MAXIMUM_NUMBER_OF_CALLS_REACHED = 53; // 0x35
+    field public static final int MMI = 6; // 0x6
+    field public static final int NORMAL = 2; // 0x2
+    field public static final int NORMAL_UNSPECIFIED = 65; // 0x41
+    field public static final int NOT_DISCONNECTED = 0; // 0x0
+    field public static final int NOT_VALID = -1; // 0xffffffff
+    field public static final int NO_PHONE_NUMBER_SUPPLIED = 38; // 0x26
+    field public static final int NUMBER_UNREACHABLE = 8; // 0x8
+    field public static final int OTASP_PROVISIONING_IN_PROCESS = 76; // 0x4c
+    field public static final int OUTGOING_CANCELED = 44; // 0x2c
+    field public static final int OUTGOING_FAILURE = 43; // 0x2b
+    field public static final int OUT_OF_NETWORK = 11; // 0xb
+    field public static final int OUT_OF_SERVICE = 18; // 0x12
+    field public static final int POWER_OFF = 17; // 0x11
+    field public static final int SERVER_ERROR = 12; // 0xc
+    field public static final int SERVER_UNREACHABLE = 9; // 0x9
+    field public static final int TIMED_OUT = 13; // 0xd
+    field public static final int TOO_MANY_ONGOING_CALLS = 75; // 0x4b
+    field public static final int UNOBTAINABLE_NUMBER = 25; // 0x19
+    field public static final int VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED = 50; // 0x32
+    field public static final int VOICEMAIL_NUMBER_MISSING = 40; // 0x28
+    field public static final int WIFI_LOST = 59; // 0x3b
+  }
+
   public class MbmsDownloadSession implements java.lang.AutoCloseable {
     field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
   }
@@ -5081,16 +5184,15 @@
   public abstract class NetworkService extends android.app.Service {
     ctor public NetworkService();
     method protected abstract android.telephony.NetworkService.NetworkServiceProvider createNetworkServiceProvider(int);
-    field public static final java.lang.String NETWORK_SERVICE_EXTRA_SLOT_ID = "android.telephony.extra.SLOT_ID";
     field public static final java.lang.String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService";
   }
 
-  public class NetworkService.NetworkServiceProvider {
+  public abstract class NetworkService.NetworkServiceProvider implements java.lang.AutoCloseable {
     ctor public NetworkService.NetworkServiceProvider(int);
+    method public abstract void close();
     method public void getNetworkRegistrationState(int, android.telephony.NetworkServiceCallback);
     method public final int getSlotId();
     method public final void notifyNetworkRegistrationStateChanged();
-    method protected void onDestroy();
   }
 
   public class NetworkServiceCallback {
@@ -5124,14 +5226,134 @@
   }
 
   public class PhoneStateListener {
+    method public void onCallDisconnectCauseChanged(int, int);
+    method public void onPreciseCallStateChanged(android.telephony.PreciseCallState);
     method public void onRadioPowerStateChanged(int);
     method public void onSrvccStateChanged(int);
     method public void onVoiceActivationStateChanged(int);
+    field public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
+    field public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
     field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
     field public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
     field public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
   }
 
+  public final class PreciseCallState implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getBackgroundCallState();
+    method public int getForegroundCallState();
+    method public int getRingingCallState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.PreciseCallState> CREATOR;
+    field public static final int PRECISE_CALL_STATE_ACTIVE = 1; // 0x1
+    field public static final int PRECISE_CALL_STATE_ALERTING = 4; // 0x4
+    field public static final int PRECISE_CALL_STATE_DIALING = 3; // 0x3
+    field public static final int PRECISE_CALL_STATE_DISCONNECTED = 7; // 0x7
+    field public static final int PRECISE_CALL_STATE_DISCONNECTING = 8; // 0x8
+    field public static final int PRECISE_CALL_STATE_HOLDING = 2; // 0x2
+    field public static final int PRECISE_CALL_STATE_IDLE = 0; // 0x0
+    field public static final int PRECISE_CALL_STATE_INCOMING = 5; // 0x5
+    field public static final int PRECISE_CALL_STATE_NOT_VALID = -1; // 0xffffffff
+    field public static final int PRECISE_CALL_STATE_WAITING = 6; // 0x6
+  }
+
+  public class PreciseDisconnectCause {
+    field public static final int ACCESS_CLASS_BLOCKED = 260; // 0x104
+    field public static final int ACCESS_INFORMATION_DISCARDED = 43; // 0x2b
+    field public static final int ACM_LIMIT_EXCEEDED = 68; // 0x44
+    field public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 57; // 0x39
+    field public static final int BEARER_NOT_AVAIL = 58; // 0x3a
+    field public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 65; // 0x41
+    field public static final int BUSY = 17; // 0x11
+    field public static final int CALL_BARRED = 240; // 0xf0
+    field public static final int CALL_REJECTED = 21; // 0x15
+    field public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1
+    field public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee
+    field public static final int CDMA_DROP = 1001; // 0x3e9
+    field public static final int CDMA_INTERCEPT = 1002; // 0x3ea
+    field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8
+    field public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0
+    field public static final int CDMA_PREEMPTED = 1007; // 0x3ef
+    field public static final int CDMA_REORDER = 1003; // 0x3eb
+    field public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed
+    field public static final int CDMA_SO_REJECT = 1004; // 0x3ec
+    field public static final int CHANNEL_NOT_AVAIL = 44; // 0x2c
+    field public static final int CHANNEL_UNACCEPTABLE = 6; // 0x6
+    field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64
+    field public static final int DESTINATION_OUT_OF_ORDER = 27; // 0x1b
+    field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff
+    field public static final int FACILITY_REJECTED = 29; // 0x1d
+    field public static final int FDN_BLOCKED = 241; // 0xf1
+    field public static final int IMEI_NOT_ACCEPTED = 243; // 0xf3
+    field public static final int IMSI_UNKNOWN_IN_VLR = 242; // 0xf2
+    field public static final int INCOMING_CALLS_BARRED_WITHIN_CUG = 55; // 0x37
+    field public static final int INCOMPATIBLE_DESTINATION = 88; // 0x58
+    field public static final int INFORMATION_ELEMENT_NON_EXISTENT = 99; // 0x63
+    field public static final int INTERWORKING_UNSPECIFIED = 127; // 0x7f
+    field public static final int INVALID_MANDATORY_INFORMATION = 96; // 0x60
+    field public static final int INVALID_NUMBER_FORMAT = 28; // 0x1c
+    field public static final int INVALID_TRANSACTION_IDENTIFIER = 81; // 0x51
+    field public static final int MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101; // 0x65
+    field public static final int MESSAGE_TYPE_NON_IMPLEMENTED = 97; // 0x61
+    field public static final int MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98; // 0x62
+    field public static final int NETWORK_DETACH = 261; // 0x105
+    field public static final int NETWORK_OUT_OF_ORDER = 38; // 0x26
+    field public static final int NETWORK_REJECT = 252; // 0xfc
+    field public static final int NETWORK_RESP_TIMEOUT = 251; // 0xfb
+    field public static final int NORMAL = 16; // 0x10
+    field public static final int NORMAL_UNSPECIFIED = 31; // 0x1f
+    field public static final int NOT_VALID = -1; // 0xffffffff
+    field public static final int NO_ANSWER_FROM_USER = 19; // 0x13
+    field public static final int NO_CIRCUIT_AVAIL = 34; // 0x22
+    field public static final int NO_DISCONNECT_CAUSE_AVAILABLE = 0; // 0x0
+    field public static final int NO_ROUTE_TO_DESTINATION = 3; // 0x3
+    field public static final int NO_USER_RESPONDING = 18; // 0x12
+    field public static final int NO_VALID_SIM = 249; // 0xf9
+    field public static final int NUMBER_CHANGED = 22; // 0x16
+    field public static final int OEM_CAUSE_1 = 61441; // 0xf001
+    field public static final int OEM_CAUSE_10 = 61450; // 0xf00a
+    field public static final int OEM_CAUSE_11 = 61451; // 0xf00b
+    field public static final int OEM_CAUSE_12 = 61452; // 0xf00c
+    field public static final int OEM_CAUSE_13 = 61453; // 0xf00d
+    field public static final int OEM_CAUSE_14 = 61454; // 0xf00e
+    field public static final int OEM_CAUSE_15 = 61455; // 0xf00f
+    field public static final int OEM_CAUSE_2 = 61442; // 0xf002
+    field public static final int OEM_CAUSE_3 = 61443; // 0xf003
+    field public static final int OEM_CAUSE_4 = 61444; // 0xf004
+    field public static final int OEM_CAUSE_5 = 61445; // 0xf005
+    field public static final int OEM_CAUSE_6 = 61446; // 0xf006
+    field public static final int OEM_CAUSE_7 = 61447; // 0xf007
+    field public static final int OEM_CAUSE_8 = 61448; // 0xf008
+    field public static final int OEM_CAUSE_9 = 61449; // 0xf009
+    field public static final int ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70; // 0x46
+    field public static final int OPERATOR_DETERMINED_BARRING = 8; // 0x8
+    field public static final int OUT_OF_SRV = 248; // 0xf8
+    field public static final int PREEMPTION = 25; // 0x19
+    field public static final int PROTOCOL_ERROR_UNSPECIFIED = 111; // 0x6f
+    field public static final int QOS_NOT_AVAIL = 49; // 0x31
+    field public static final int RADIO_ACCESS_FAILURE = 253; // 0xfd
+    field public static final int RADIO_INTERNAL_ERROR = 250; // 0xfa
+    field public static final int RADIO_LINK_FAILURE = 254; // 0xfe
+    field public static final int RADIO_LINK_LOST = 255; // 0xff
+    field public static final int RADIO_OFF = 247; // 0xf7
+    field public static final int RADIO_RELEASE_ABNORMAL = 259; // 0x103
+    field public static final int RADIO_RELEASE_NORMAL = 258; // 0x102
+    field public static final int RADIO_SETUP_FAILURE = 257; // 0x101
+    field public static final int RADIO_UPLINK_FAILURE = 256; // 0x100
+    field public static final int RECOVERY_ON_TIMER_EXPIRED = 102; // 0x66
+    field public static final int REQUESTED_FACILITY_NOT_IMPLEMENTED = 69; // 0x45
+    field public static final int REQUESTED_FACILITY_NOT_SUBSCRIBED = 50; // 0x32
+    field public static final int RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47; // 0x2f
+    field public static final int SEMANTICALLY_INCORRECT_MESSAGE = 95; // 0x5f
+    field public static final int SERVICE_OPTION_NOT_AVAILABLE = 63; // 0x3f
+    field public static final int SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79; // 0x4f
+    field public static final int STATUS_ENQUIRY = 30; // 0x1e
+    field public static final int SWITCHING_CONGESTION = 42; // 0x2a
+    field public static final int TEMPORARY_FAILURE = 41; // 0x29
+    field public static final int UNOBTAINABLE_NUMBER = 1; // 0x1
+    field public static final int USER_NOT_MEMBER_OF_CUG = 87; // 0x57
+  }
+
   public class ServiceState implements android.os.Parcelable {
     method public android.telephony.NetworkRegistrationState getNetworkRegistrationState(int, int);
     method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates();
@@ -5169,6 +5391,7 @@
 
   public class SubscriptionInfo implements android.os.Parcelable {
     method public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
+    method public int getCardId();
   }
 
   public class SubscriptionManager {
@@ -5241,6 +5464,7 @@
     method public int getSimCardState();
     method public int getSupportedRadioAccessFamily();
     method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
+    method public android.telephony.UiccCardInfo[] getUiccCardsInfo();
     method public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
     method public android.os.Bundle getVisualVoicemailSettings();
     method public int getVoiceActivationState();
@@ -5358,6 +5582,18 @@
     field public static final android.os.Parcelable.Creator<android.telephony.UiccAccessRule> CREATOR;
   }
 
+  public class UiccCardInfo implements android.os.Parcelable {
+    ctor public UiccCardInfo(boolean, int, java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public int getCardId();
+    method public java.lang.String getEid();
+    method public java.lang.String getIccId();
+    method public int getSlotIndex();
+    method public boolean isEuicc();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.UiccCardInfo> CREATOR;
+  }
+
   public class UiccSlotInfo implements android.os.Parcelable {
     ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int, boolean);
     method public int describeContents();
@@ -5429,20 +5665,19 @@
   public abstract class DataService extends android.app.Service {
     ctor public DataService();
     method public abstract android.telephony.data.DataService.DataServiceProvider createDataServiceProvider(int);
-    field public static final java.lang.String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID";
     field public static final java.lang.String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
     field public static final int REQUEST_REASON_HANDOVER = 3; // 0x3
     field public static final int REQUEST_REASON_NORMAL = 1; // 0x1
     field public static final int REQUEST_REASON_SHUTDOWN = 2; // 0x2
   }
 
-  public class DataService.DataServiceProvider {
+  public abstract class DataService.DataServiceProvider implements java.lang.AutoCloseable {
     ctor public DataService.DataServiceProvider(int);
+    method public abstract void close();
     method public void deactivateDataCall(int, int, android.telephony.data.DataServiceCallback);
     method public void getDataCallList(android.telephony.data.DataServiceCallback);
     method public final int getSlotId();
     method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
-    method protected void onDestroy();
     method public void setDataProfile(java.util.List<android.telephony.data.DataProfile>, boolean, android.telephony.data.DataServiceCallback);
     method public void setInitialAttachApn(android.telephony.data.DataProfile, boolean, android.telephony.data.DataServiceCallback);
     method public void setupDataCall(int, android.telephony.data.DataProfile, boolean, boolean, int, android.net.LinkProperties, android.telephony.data.DataServiceCallback);
@@ -5907,6 +6142,7 @@
     field public static final int CODE_RADIO_SETUP_FAILURE = 1509; // 0x5e5
     field public static final int CODE_RADIO_UPLINK_FAILURE = 1508; // 0x5e4
     field public static final int CODE_REGISTRATION_ERROR = 1000; // 0x3e8
+    field public static final int CODE_REJECTED_ELSEWHERE = 1017; // 0x3f9
     field public static final int CODE_REJECT_1X_COLLISION = 1603; // 0x643
     field public static final int CODE_REJECT_CALL_ON_OTHER_SUB = 1602; // 0x642
     field public static final int CODE_REJECT_CALL_TYPE_NOT_ALLOWED = 1605; // 0x645
@@ -5930,26 +6166,39 @@
     field public static final int CODE_REJECT_VT_AVPF_NOT_ALLOWED = 1619; // 0x653
     field public static final int CODE_REJECT_VT_TTY_NOT_ALLOWED = 1615; // 0x64f
     field public static final int CODE_REMOTE_CALL_DECLINE = 1404; // 0x57c
+    field public static final int CODE_SESSION_MODIFICATION_FAILED = 1517; // 0x5ed
     field public static final int CODE_SIP_ALTERNATE_EMERGENCY_CALL = 1514; // 0x5ea
+    field public static final int CODE_SIP_AMBIGUOUS = 376; // 0x178
     field public static final int CODE_SIP_BAD_ADDRESS = 337; // 0x151
     field public static final int CODE_SIP_BAD_REQUEST = 331; // 0x14b
     field public static final int CODE_SIP_BUSY = 338; // 0x152
+    field public static final int CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST = 372; // 0x174
     field public static final int CODE_SIP_CLIENT_ERROR = 342; // 0x156
+    field public static final int CODE_SIP_EXTENSION_REQUIRED = 370; // 0x172
     field public static final int CODE_SIP_FORBIDDEN = 332; // 0x14c
     field public static final int CODE_SIP_GLOBAL_ERROR = 362; // 0x16a
+    field public static final int CODE_SIP_INTERVAL_TOO_BRIEF = 371; // 0x173
+    field public static final int CODE_SIP_LOOP_DETECTED = 373; // 0x175
+    field public static final int CODE_SIP_METHOD_NOT_ALLOWED = 366; // 0x16e
     field public static final int CODE_SIP_NOT_ACCEPTABLE = 340; // 0x154
     field public static final int CODE_SIP_NOT_FOUND = 333; // 0x14d
     field public static final int CODE_SIP_NOT_REACHABLE = 341; // 0x155
     field public static final int CODE_SIP_NOT_SUPPORTED = 334; // 0x14e
+    field public static final int CODE_SIP_PROXY_AUTHENTICATION_REQUIRED = 367; // 0x16f
     field public static final int CODE_SIP_REDIRECTED = 321; // 0x141
     field public static final int CODE_SIP_REQUEST_CANCELLED = 339; // 0x153
+    field public static final int CODE_SIP_REQUEST_ENTITY_TOO_LARGE = 368; // 0x170
+    field public static final int CODE_SIP_REQUEST_PENDING = 377; // 0x179
     field public static final int CODE_SIP_REQUEST_TIMEOUT = 335; // 0x14f
+    field public static final int CODE_SIP_REQUEST_URI_TOO_LARGE = 369; // 0x171
     field public static final int CODE_SIP_SERVER_ERROR = 354; // 0x162
     field public static final int CODE_SIP_SERVER_INTERNAL_ERROR = 351; // 0x15f
     field public static final int CODE_SIP_SERVER_TIMEOUT = 353; // 0x161
     field public static final int CODE_SIP_SERVICE_UNAVAILABLE = 352; // 0x160
     field public static final int CODE_SIP_TEMPRARILY_UNAVAILABLE = 336; // 0x150
+    field public static final int CODE_SIP_TOO_MANY_HOPS = 374; // 0x176
     field public static final int CODE_SIP_TRANSACTION_DOES_NOT_EXIST = 343; // 0x157
+    field public static final int CODE_SIP_UNDECIPHERABLE = 378; // 0x17a
     field public static final int CODE_SIP_USER_MARKED_UNWANTED = 365; // 0x16d
     field public static final int CODE_SIP_USER_REJECTED = 361; // 0x169
     field public static final int CODE_SUPP_SVC_CANCELLED = 1202; // 0x4b2
@@ -5959,9 +6208,11 @@
     field public static final int CODE_TIMEOUT_NO_ANSWER = 202; // 0xca
     field public static final int CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE = 203; // 0xcb
     field public static final int CODE_UNSPECIFIED = 0; // 0x0
+    field public static final int CODE_USER_CANCELLED_SESSION_MODIFICATION = 512; // 0x200
     field public static final int CODE_USER_DECLINE = 504; // 0x1f8
     field public static final int CODE_USER_IGNORE = 503; // 0x1f7
     field public static final int CODE_USER_NOANSWER = 502; // 0x1f6
+    field public static final int CODE_USER_REJECTED_SESSION_MODIFICATION = 511; // 0x1ff
     field public static final int CODE_USER_TERMINATED = 501; // 0x1f5
     field public static final int CODE_USER_TERMINATED_BY_REMOTE = 510; // 0x1fe
     field public static final int CODE_UT_CB_PASSWORD_MISMATCH = 821; // 0x335
diff --git a/api/test-current.txt b/api/test-current.txt
index b5b128a..dfa1c16 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -967,6 +967,14 @@
     ctor public PhoneAccountSuggestion(android.telecom.PhoneAccountHandle, int, boolean);
   }
 
+  public class PhoneAccountSuggestionService extends android.app.Service {
+    ctor public PhoneAccountSuggestionService();
+    method public void onAccountSuggestionRequest(java.lang.String);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public final void suggestPhoneAccounts(java.lang.String, java.util.List<android.telecom.PhoneAccountSuggestion>);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
+  }
+
 }
 
 package android.telephony {
diff --git a/cmds/incident_helper/src/TextParserBase.h b/cmds/incident_helper/src/TextParserBase.h
index 784c181..a6074e7 100644
--- a/cmds/incident_helper/src/TextParserBase.h
+++ b/cmds/incident_helper/src/TextParserBase.h
@@ -30,7 +30,7 @@
 public:
     String8 name;
 
-    TextParserBase(String8 name) : name(name) {};
+    explicit TextParserBase(String8 name) : name(name) {};
     virtual ~TextParserBase() {};
 
     virtual status_t Parse(const int in, const int out) const = 0;
diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h
index c02a349..09dc8e6 100644
--- a/cmds/incident_helper/src/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -109,7 +109,7 @@
 class Reader
 {
 public:
-    Reader(const int fd);
+    explicit Reader(const int fd);
     ~Reader();
 
     bool readLine(std::string* line);
@@ -162,7 +162,7 @@
 class Message
 {
 public:
-    Message(Table* table);
+    explicit Message(Table* table);
     ~Message();
 
     // Reconstructs the typical proto message by adding its message fields.
diff --git a/cmds/incidentd/src/IncidentService.h b/cmds/incidentd/src/IncidentService.h
index e176bfd..140484b 100644
--- a/cmds/incidentd/src/IncidentService.h
+++ b/cmds/incidentd/src/IncidentService.h
@@ -97,7 +97,7 @@
 // ================================================================================
 class IncidentService : public BnIncidentManager {
 public:
-    IncidentService(const sp<Looper>& handlerLooper);
+    explicit IncidentService(const sp<Looper>& handlerLooper);
     virtual ~IncidentService();
 
     virtual Status reportIncident(const IncidentReportArgs& args);
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index a3df490..a0159d9 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -83,7 +83,7 @@
     static PrivacySpec new_spec(int dest);
 
 private:
-    PrivacySpec(uint8_t dest) : dest(dest) {}
+    explicit PrivacySpec(uint8_t dest) : dest(dest) {}
 };
 
 }  // namespace incidentd
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index 45fd944..2a3abd7 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -89,7 +89,7 @@
     ReportRequestSet batch;
 
     Reporter();                       // PROD must use this constructor.
-    Reporter(const char* directory);  // For testing purpose only.
+    explicit Reporter(const char* directory);  // For testing purpose only.
     virtual ~Reporter();
 
     // Run the report as described in the batch and args parameters.
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 72a4103..bb5221c 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -410,7 +410,7 @@
     bool workerDone;
     status_t workerError;
 
-    WorkerThreadData(const WorkerThreadSection* section);
+    explicit WorkerThreadData(const WorkerThreadSection* section);
     virtual ~WorkerThreadData();
 };
 
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.h b/cmds/statsd/src/anomaly/AlarmMonitor.h
index 3badb1f..bca858e 100644
--- a/cmds/statsd/src/anomaly/AlarmMonitor.h
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.h
@@ -42,7 +42,7 @@
  * Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
  */
 struct InternalAlarm : public RefBase {
-    InternalAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
+    explicit InternalAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
     }
 
     const uint32_t timestampSec;
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index a2a03b1..7dfe7d6 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -64,10 +64,22 @@
     optional StateField option = 1 [default = STATE_FIELD_UNSET];
 }
 
+// Used to generate StatsLog.write APIs.
+enum LogMode {
+    MODE_UNSET = 0;
+    // Log fields as their actual types e.g., all primary data types.
+    // Or fields that are hardcoded in stats_log_api_gen tool e.g., AttributionNode
+    MODE_AUTOMATIC = 1;
+    // Log fields in their proto binary format. These fields will not be parsed in statsd
+    MODE_BYTES = 2;
+}
+
 extend google.protobuf.FieldOptions {
     // Flags to decorate an atom that presents a state change.
     optional StateAtomFieldOption stateFieldOption = 50000;
 
     // Flags to decorate the uid fields in an atom.
     optional bool is_uid = 50001 [default = false];
+
+    optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC];
 }
\ No newline at end of file
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 281f900..d9fa0f1 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -26,6 +26,7 @@
 import "frameworks/base/core/proto/android/bluetooth/enums.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
 import "frameworks/base/core/proto/android/telecomm/enums.proto";
 import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/core/proto/android/view/enums.proto";
@@ -59,7 +60,8 @@
         LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 11;
         MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12;
         WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13;
-        // 14 - 19 are available
+        // 14 - 18 are available
+        LauncherUIChanged launcher_event = 19;
         BatterySaverModeStateChanged battery_saver_mode_state_changed = 20;
         DeviceIdleModeStateChanged device_idle_mode_state_changed = 21;
         DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22;
@@ -1166,6 +1168,14 @@
     optional State state = 1;
 }
 
+message LauncherUIChanged {
+    optional android.stats.launcher.LauncherAction action = 1;
+    optional android.stats.launcher.LauncherState src_state = 2;
+    optional android.stats.launcher.LauncherState dst_state = 3;
+    optional android.stats.launcher.LauncherExtension extension = 4 [(log_mode) = MODE_BYTES];
+    optional bool is_swipe_up_enabled = 5;
+}
+
 /**
  * Logs that a setting was updated.
  * Logged from:
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index a6f88af..2c88147 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -29,7 +29,7 @@
 class ConditionWizard : public virtual android::RefBase {
 public:
     ConditionWizard(){};  // for testing
-    ConditionWizard(std::vector<sp<ConditionTracker>>& conditionTrackers)
+    explicit ConditionWizard(std::vector<sp<ConditionTracker>>& conditionTrackers)
         : mAllConditions(conditionTrackers){};
 
     virtual ~ConditionWizard(){};
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
index dc79519..4cc9393 100644
--- a/cmds/statsd/src/config/ConfigKey.h
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -33,7 +33,7 @@
 class ConfigKey {
 public:
     ConfigKey();
-    explicit ConfigKey(const ConfigKey& that);
+    ConfigKey(const ConfigKey& that);
     ConfigKey(int uid, const int64_t& id);
     ~ConfigKey();
 
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 16b7e79..5fea90b 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -106,14 +106,14 @@
         // Add to set.
         mConfigs[key.GetUid()].insert(key);
 
-        for (sp<ConfigListener> listener : mListeners) {
+        for (const sp<ConfigListener>& listener : mListeners) {
             broadcastList.push_back(listener);
         }
     }
 
     const int64_t timestampNs = getElapsedRealtimeNs();
     // Tell everyone
-    for (sp<ConfigListener> listener : broadcastList) {
+    for (const sp<ConfigListener>& listener : broadcastList) {
         listener->OnConfigUpdated(timestampNs, key, config);
     }
 }
@@ -137,7 +137,7 @@
         if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end()) {
             // Remove from map
             uidIt->second.erase(key);
-            for (sp<ConfigListener> listener : mListeners) {
+            for (const sp<ConfigListener>& listener : mListeners) {
                 broadcastList.push_back(listener);
             }
         }
@@ -153,7 +153,7 @@
         remove_saved_configs(key);
     }
 
-    for (sp<ConfigListener> listener:broadcastList) {
+    for (const sp<ConfigListener>& listener:broadcastList) {
         listener->OnConfigRemoved(key);
     }
 }
@@ -183,7 +183,7 @@
 
         mConfigs.erase(uidIt);
 
-        for (sp<ConfigListener> listener : mListeners) {
+        for (const sp<ConfigListener>& listener : mListeners) {
             broadcastList.push_back(listener);
         }
     }
@@ -191,7 +191,7 @@
     // Remove separately so if they do anything in the callback they can't mess up our iteration.
     for (auto& key : removed) {
         // Tell everyone
-        for (sp<ConfigListener> listener:broadcastList) {
+        for (const sp<ConfigListener>& listener:broadcastList) {
             listener->OnConfigRemoved(key);
         }
     }
@@ -213,7 +213,7 @@
         }
 
         mConfigReceivers.clear();
-        for (sp<ConfigListener> listener : mListeners) {
+        for (const sp<ConfigListener>& listener : mListeners) {
             broadcastList.push_back(listener);
         }
     }
@@ -221,7 +221,7 @@
     // Remove separately so if they do anything in the callback they can't mess up our iteration.
     for (auto& key : removed) {
         // Tell everyone
-        for (sp<ConfigListener> listener:broadcastList) {
+        for (const sp<ConfigListener>& listener:broadcastList) {
             listener->OnConfigRemoved(key);
         }
     }
diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.h b/cmds/statsd/src/external/ResourceHealthManagerPuller.h
index 9b238eaf5..ba6e6c3 100644
--- a/cmds/statsd/src/external/ResourceHealthManagerPuller.h
+++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.h
@@ -28,7 +28,7 @@
  */
 class ResourceHealthManagerPuller : public StatsPuller {
 public:
-    ResourceHealthManagerPuller(int tagId);
+    explicit ResourceHealthManagerPuller(int tagId);
     bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
 };
 
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.h b/cmds/statsd/src/external/StatsCompanionServicePuller.h
index 0a49732..a16baf0 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.h
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.h
@@ -25,7 +25,7 @@
 
 class StatsCompanionServicePuller : public StatsPuller {
 public:
-    StatsCompanionServicePuller(int tagId);
+    explicit StatsCompanionServicePuller(int tagId);
     bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override;
 
     void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) override;
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index caac677..35be12b 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -33,7 +33,7 @@
 
 class StatsPuller : public virtual RefBase {
 public:
-    StatsPuller(const int tagId);
+    explicit StatsPuller(const int tagId);
 
     virtual ~StatsPuller() {}
 
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index 4501b64..2713d327 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -111,7 +111,7 @@
                              (long long)state.residencyInMsecSinceBoot,
                              (long long)state.totalTransitions,
                              state.supportedOnlyInSuspend ? 1 : 0);
-                        for (auto voter : state.voters) {
+                        for (const auto& voter : state.voters) {
                             auto voterPtr = make_shared<LogEvent>(
                                 android::util::SUBSYSTEM_SLEEP_STATE,
                                 wallClockTimestampNs, elapsedTimestampNs);
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 4e4f146..5d6d02b 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -379,7 +379,7 @@
 
 string LogEvent::ToString() const {
     string result;
-    result += StringPrintf("{ %lld %lld (%d)", (long long)mLogdTimestampNs,
+    result += StringPrintf("{ uid(%d) %lld %lld (%d)", mLogUid, (long long)mLogdTimestampNs,
                            (long long)mElapsedTimestampNs, mTagId);
     for (const auto& value : mValues) {
         result +=
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 24d624d..8a03ac4 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -158,7 +158,7 @@
      * Don't copy, it's slower. If we really need this we can add it but let's try to
      * avoid it.
      */
-    explicit LogEvent(const LogEvent&);
+    LogEvent(const LogEvent&);
 
     /**
      * Parses a log_msg into a LogEvent object.
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 4fac0e1..a6c7f3a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -395,7 +395,7 @@
 // Returns the total byte size of all metrics managed by a single config source.
 size_t MetricsManager::byteSize() {
     size_t totalSize = 0;
-    for (auto metricProducer : mAllMetricProducers) {
+    for (const auto& metricProducer : mAllMetricProducers) {
         totalSize += metricProducer->byteSize();
     }
     return totalSize;
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 811a00e..a1c80b8 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -537,7 +537,7 @@
         }
         noReportMetricIds.insert(no_report_metric);
     }
-    for (auto it : allMetricProducers) {
+    for (const auto& it : allMetricProducers) {
         uidMap.addListener(it);
     }
     return true;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 73ac968..88957df 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -141,7 +141,7 @@
     // listener removes itself before we call it. It's then the listener's job to handle it (expect
     // the callback to be called after listener is removed, and the listener should properly
     // ignore it).
-    for (auto weakPtr : broadcastList) {
+    for (const auto& weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
             strongPtr->onUidMapReceived(timestamp);
@@ -181,7 +181,7 @@
         StatsdStats::getInstance().setUidMapChanges(mChanges.size());
     }
 
-    for (auto weakPtr : broadcastList) {
+    for (const auto& weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
             strongPtr->notifyAppUpgrade(timestamp, appName, uid, versionCode);
@@ -248,7 +248,7 @@
         getListenerListCopyLocked(&broadcastList);
     }
 
-    for (auto weakPtr : broadcastList) {
+    for (const auto& weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
             strongPtr->notifyAppRemoved(timestamp, app, uid);
diff --git a/cmds/statsd/src/socket/StatsSocketListener.h b/cmds/statsd/src/socket/StatsSocketListener.h
index 73e4d33..b8185d2 100644
--- a/cmds/statsd/src/socket/StatsSocketListener.h
+++ b/cmds/statsd/src/socket/StatsSocketListener.h
@@ -35,7 +35,7 @@
 
 class StatsSocketListener : public SocketListener, public virtual android::RefBase {
 public:
-    StatsSocketListener(const sp<LogListener>& listener);
+    explicit StatsSocketListener(const sp<LogListener>& listener);
 
     virtual ~StatsSocketListener();
 
@@ -51,4 +51,4 @@
 };
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index a0ab3e4..11ce717 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -25,15 +25,16 @@
 #include <utils/Log.h>
 #include <utils/SystemClock.h>
 
+using android::util::AtomsInfo;
 using android::util::FIELD_COUNT_REPEATED;
 using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FIXED64;
 using android::util::FIELD_TYPE_FLOAT;
 using android::util::FIELD_TYPE_INT32;
 using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_UINT64;
-using android::util::FIELD_TYPE_FIXED64;
 using android::util::FIELD_TYPE_MESSAGE;
 using android::util::FIELD_TYPE_STRING;
+using android::util::FIELD_TYPE_UINT64;
 using android::util::ProtoOutputStream;
 
 namespace android {
@@ -294,8 +295,9 @@
 // }
 //
 //
-void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& dims, size_t* index,
-                                       int depth, int prefix, ProtoOutputStream* protoOutput) {
+void writeFieldValueTreeToStreamHelper(int tagId, const std::vector<FieldValue>& dims,
+                                       size_t* index, int depth, int prefix,
+                                       ProtoOutputStream* protoOutput) {
     size_t count = dims.size();
     while (*index < count) {
         const auto& dim = dims[*index];
@@ -319,9 +321,33 @@
                 case FLOAT:
                     protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
                     break;
-                case STRING:
-                    protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
+                case STRING: {
+                    bool isBytesField = false;
+                    // Bytes field is logged via string format in log_msg format. So here we check
+                    // if this string field is a byte field.
+                    std::map<int, std::vector<int>>::const_iterator itr;
+                    if (depth == 0 && (itr = AtomsInfo::kBytesFieldAtoms.find(tagId)) !=
+                                              AtomsInfo::kBytesFieldAtoms.end()) {
+                        const std::vector<int>& bytesFields = itr->second;
+                        for (int bytesField : bytesFields) {
+                            if (bytesField == fieldNum) {
+                                // This is a bytes field
+                                isBytesField = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (isBytesField) {
+                        if (dim.mValue.str_value.length() > 0) {
+                            protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
+                                               (const char*)dim.mValue.str_value.c_str(),
+                                               dim.mValue.str_value.length());
+                        }
+                    } else {
+                        protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
+                    }
                     break;
+                }
                 default:
                     break;
             }
@@ -337,7 +363,7 @@
             }
             // Directly jump to the leaf value because the repeated position field is implied
             // by the position of the sub msg in the parent field.
-            writeFieldValueTreeToStreamHelper(dims, index, valueDepth,
+            writeFieldValueTreeToStreamHelper(tagId, dims, index, valueDepth,
                                               dim.mField.getPrefix(valueDepth), protoOutput);
             if (msg_token != 0) {
                 protoOutput->end(msg_token);
@@ -354,7 +380,7 @@
     uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
 
     size_t index = 0;
-    writeFieldValueTreeToStreamHelper(values, &index, 0, 0, protoOutput);
+    writeFieldValueTreeToStreamHelper(tagId, values, &index, 0, 0, protoOutput);
     protoOutput->end(atomToken);
 }
 
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 2fcde29..b29de53 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/logd/LogEvent.h"
 #include <gtest/gtest.h>
 #include <log/log_event_list.h>
-#include "src/logd/LogEvent.h"
+#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
+#include "frameworks/base/core/proto/android/stats/launcher/launcher.pb.h"
 
 #ifdef __ANDROID__
 
@@ -22,6 +24,9 @@
 namespace os {
 namespace statsd {
 
+using std::string;
+using util::ProtoOutputStream;
+
 TEST(LogEventTest, TestLogParsing) {
     LogEvent event1(1, 2000);
 
@@ -159,6 +164,94 @@
 }
 
 
+TEST(LogEventTest, TestBinaryFieldAtom) {
+    Atom launcherAtom;
+    auto launcher_event = launcherAtom.mutable_launcher_event();
+    launcher_event->set_action(stats::launcher::LauncherAction::LONGPRESS);
+    launcher_event->set_src_state(stats::launcher::LauncherState::OVERVIEW);
+    launcher_event->set_dst_state(stats::launcher::LauncherState::ALLAPPS);
+
+    auto extension = launcher_event->mutable_extension();
+
+    auto src_target = extension->add_src_target();
+    src_target->set_type(stats::launcher::LauncherTarget_Type_ITEM_TYPE);
+    src_target->set_item(stats::launcher::LauncherTarget_Item_FOLDER_ICON);
+
+    auto dst_target = extension->add_dst_target();
+    dst_target->set_type(stats::launcher::LauncherTarget_Type_ITEM_TYPE);
+    dst_target->set_item(stats::launcher::LauncherTarget_Item_WIDGET);
+
+    string extension_str;
+    extension->SerializeToString(&extension_str);
+
+    LogEvent event1(Atom::kLauncherEventFieldNumber, 1000);
+
+    event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS);
+    event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW);
+    event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS);
+    event1.write(extension_str);
+    event1.init();
+
+    ProtoOutputStream proto;
+    event1.ToProto(proto);
+
+    std::vector<uint8_t> outData;
+    outData.resize(proto.size());
+    size_t pos = 0;
+    auto iter = proto.data();
+    while (iter.readBuffer() != NULL) {
+        size_t toRead = iter.currentToRead();
+        std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
+        pos += toRead;
+        iter.rp()->move(toRead);
+    }
+
+    std::string result_str(outData.begin(), outData.end());
+    std::string orig_str;
+    launcherAtom.SerializeToString(&orig_str);
+
+    EXPECT_EQ(orig_str, result_str);
+}
+
+TEST(LogEventTest, TestBinaryFieldAtom_empty) {
+    Atom launcherAtom;
+    auto launcher_event = launcherAtom.mutable_launcher_event();
+    launcher_event->set_action(stats::launcher::LauncherAction::LONGPRESS);
+    launcher_event->set_src_state(stats::launcher::LauncherState::OVERVIEW);
+    launcher_event->set_dst_state(stats::launcher::LauncherState::ALLAPPS);
+
+    // empty string.
+    string extension_str;
+
+    LogEvent event1(Atom::kLauncherEventFieldNumber, 1000);
+
+    event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS);
+    event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW);
+    event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS);
+    event1.write(extension_str);
+    event1.init();
+
+    ProtoOutputStream proto;
+    event1.ToProto(proto);
+
+    std::vector<uint8_t> outData;
+    outData.resize(proto.size());
+    size_t pos = 0;
+    auto iter = proto.data();
+    while (iter.readBuffer() != NULL) {
+        size_t toRead = iter.currentToRead();
+        std::memcpy(&(outData[pos]), iter.readBuffer(), toRead);
+        pos += toRead;
+        iter.rp()->move(toRead);
+    }
+
+    std::string result_str(outData.begin(), outData.end());
+    std::string orig_str;
+    launcherAtom.SerializeToString(&orig_str);
+
+    EXPECT_EQ(orig_str, result_str);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index 218d52a..e125887 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -71,12 +71,12 @@
                          const std::shared_ptr<DimToValMap>& currentBucket,
                          const std::set<const MetricDimensionKey>& trueList,
                          const std::set<const MetricDimensionKey>& falseList) {
-    for (MetricDimensionKey key : trueList) {
+    for (const MetricDimensionKey& key : trueList) {
         if (!tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
             return false;
         }
     }
-    for (MetricDimensionKey key : falseList) {
+    for (const MetricDimensionKey& key : falseList) {
         if (tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
             return false;
         }
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index a39f5e3..4174ad7 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -51,6 +51,8 @@
     private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP =
             "add-or-remove-call-companion-app";
     private static final String COMMAND_SET_TEST_AUTO_MODE_APP = "set-test-auto-mode-app";
+    private static final String COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT =
+            "set-phone-acct-suggestion-component";
     private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
     private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
@@ -64,36 +66,37 @@
 
     @Override
     public void onShowUsage(PrintStream out) {
-        out.println(
-                "usage: telecom [subcommand] [options]\n" +
-                "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n" +
-                "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n" +
-                "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n" +
-                "usage: telecom set-test-call-redirection-app <PACKAGE>\n" +
-                "usage: telecom set-test-call-screening-app <PACKAGE>\n" +
-                "usage: telecom set-test-auto-mode-app <PACKAGE>\n" +
-                "usage: telecom add-or-remove-call-companion-app <PACKAGE> <1/0>\n" +
-                "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN> <LABEL> <ADDRESS>\n" +
-                "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n" +
-                "usage: telecom set-default-dialer <PACKAGE>\n" +
-                "usage: telecom get-default-dialer\n" +
-                "usage: telecom get-system-dialer\n" +
-                "usage: telecom wait-on-handlers\n" +
-                "\n" +
-                "telecom set-phone-account-enabled: Enables the given phone account, if it has \n" +
-                " already been registered with Telecom.\n" +
-                "\n" +
-                "telecom set-phone-account-disabled: Disables the given phone account, if it \n" +
-                " has already been registered with telecom.\n" +
-                "\n" +
-                "telecom set-default-dialer: Sets the default dialer to the given component. \n" +
-                "\n" +
-                "telecom get-default-dialer: Displays the current default dialer. \n" +
-                "\n" +
-                "telecom get-system-dialer: Displays the current system dialer. \n" +
-                "\n" +
-                "telecom wait-on-handlers: Wait until all handlers finish their work. \n"
-                );
+        out.println("usage: telecom [subcommand] [options]\n"
+                + "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n"
+                + "usage: telecom set-test-call-redirection-app <PACKAGE>\n"
+                + "usage: telecom set-test-call-screening-app <PACKAGE>\n"
+                + "usage: telecom set-test-auto-mode-app <PACKAGE>\n"
+                + "usage: telecom set-phone-acct-suggestion-component <COMPONENT>\n"
+                + "usage: telecom add-or-remove-call-companion-app <PACKAGE> <1/0>\n"
+                + "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN>"
+                + " <LABEL> <ADDRESS>\n"
+                + "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom set-default-dialer <PACKAGE>\n"
+                + "usage: telecom get-default-dialer\n"
+                + "usage: telecom get-system-dialer\n"
+                + "usage: telecom wait-on-handlers\n"
+                + "\n"
+                + "telecom set-phone-account-enabled: Enables the given phone account, if it has \n"
+                + " already been registered with Telecom.\n"
+                + "\n"
+                + "telecom set-phone-account-disabled: Disables the given phone account, if it \n"
+                + " has already been registered with telecom.\n"
+                + "\n"
+                + "telecom set-default-dialer: Sets the default dialer to the given component. \n"
+                + "\n"
+                + "telecom get-default-dialer: Displays the current default dialer. \n"
+                + "\n"
+                + "telecom get-system-dialer: Displays the current system dialer. \n"
+                + "\n"
+                + "telecom wait-on-handlers: Wait until all handlers finish their work. \n"
+        );
     }
 
     @Override
@@ -134,6 +137,9 @@
             case COMMAND_SET_TEST_AUTO_MODE_APP:
                 runSetTestAutoModeApp();
                 break;
+            case COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT:
+                runSetTestPhoneAcctSuggestionComponent();
+                break;
             case COMMAND_REGISTER_SIM_PHONE_ACCOUNT:
                 runRegisterSimPhoneAccount();
                 break;
@@ -216,6 +222,11 @@
         mTelecomService.setTestAutoModeApp(packageName);
     }
 
+    private void runSetTestPhoneAcctSuggestionComponent() throws RemoteException {
+        final String componentName = nextArg();
+        mTelecomService.setTestPhoneAcctSuggestionComponent(componentName);
+    }
+
     private void runUnregisterPhoneAccount() throws RemoteException {
         final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
         mTelecomService.unregisterPhoneAccount(handle);
diff --git a/config/dirty-image-objects b/config/dirty-image-objects
index 9b4d199..9e2230b 100644
--- a/config/dirty-image-objects
+++ b/config/dirty-image-objects
@@ -44,7 +44,6 @@
 sun.misc.FormattedFloatingDecimal
 java.util.stream.IntStream
 android.icu.util.TimeZone
-libcore.io.DropBox
 org.apache.harmony.luni.internal.util.TimezoneGetter
 dalvik.system.SocketTagger
 dalvik.system.CloseGuard
@@ -137,7 +136,6 @@
 android.icu.util.ULocale
 dalvik.system.BaseDexClassLoader
 android.icu.text.BreakIterator
-libcore.io.EventLogger
 libcore.net.NetworkSecurityPolicy
 android.icu.text.UnicodeSet
 com.android.org.conscrypt.TrustedCertificateStore$PreloadHolder
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 2aeb431..648ff27 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2938,7 +2938,6 @@
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mActiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDcFailCause:Lcom/android/internal/telephony/dataconnection/DcFailCause;
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingErrorCreatingConnection:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectionErrorCreatingConnection;
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectingState;
@@ -2949,10 +2948,8 @@
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mNetworkInfo:Landroid/net/NetworkInfo;
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone;
 Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DcFailCause;)V
 Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V
 Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfDisconnectDcRetrying(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyConnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;Lcom/android/internal/telephony/dataconnection/DcFailCause;Z)V
 Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V
 Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V
 Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V
@@ -2961,22 +2958,6 @@
 Lcom/android/internal/telephony/dataconnection/DcController;->mDcListActiveByCid:Ljava/util/HashMap;
 Lcom/android/internal/telephony/dataconnection/DcController;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
 Lcom/android/internal/telephony/dataconnection/DcController;->mDcTesterDeactivateAll:Lcom/android/internal/telephony/dataconnection/DcTesterDeactivateAll;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_GGSN:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_UNSPECIFIED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->APN_TYPE_CONFLICT:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->INSUFFICIENT_RESOURCES:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->MISSING_UNKNOWN_APN:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->NSAPI_IN_USE:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV4_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV6_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_SINGLE_BEARER_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->OPERATOR_BARRED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->PROTOCOL_ERRORS:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUBSCRIBED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUPPORTED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_OUT_OF_ORDER:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->UNKNOWN_PDP_ADDRESS_TYPE:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->USER_AUTHENTICATION:Lcom/android/internal/telephony/dataconnection/DcFailCause;
 Lcom/android/internal/telephony/dataconnection/DcTracker$RecoveryAction;->isAggressiveRecovery(I)Z
 Lcom/android/internal/telephony/dataconnection/DcTracker;->cancelReconnectAlarm(Lcom/android/internal/telephony/dataconnection/ApnContext;)V
 Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(Ljava/lang/String;)V
@@ -3011,7 +2992,6 @@
 Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentDataStallAlarm(Landroid/content/Intent;)V
 Lcom/android/internal/telephony/dataconnection/DcTracker;->onActionIntentProvisioningApnAlarm(Landroid/content/Intent;)V
 Lcom/android/internal/telephony/dataconnection/DcTracker;->onRecordsLoadedOrSubIdChanged()V
-Lcom/android/internal/telephony/dataconnection/DcTracker;->onSetUserDataEnabled(Z)V
 Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Lcom/android/internal/telephony/dataconnection/ApnContext;)Z
 Lcom/android/internal/telephony/dataconnection/DcTracker;->onTrySetupData(Ljava/lang/String;)Z
 Lcom/android/internal/telephony/dataconnection/DcTracker;->registerSettingsObserver()V
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 495615b..fafcc6b 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -6124,12 +6124,6 @@
 libcore.io.ClassPathURLStreamHandler
 libcore.io.ClassPathURLStreamHandler$ClassPathURLConnection
 libcore.io.ClassPathURLStreamHandler$ClassPathURLConnection$1
-libcore.io.DropBox
-libcore.io.DropBox$DefaultReporter
-libcore.io.DropBox$Reporter
-libcore.io.EventLogger
-libcore.io.EventLogger$DefaultReporter
-libcore.io.EventLogger$Reporter
 libcore.io.ForwardingOs
 libcore.io.IoBridge
 libcore.io.IoTracker
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 47fddfe..15af8a9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -81,7 +81,6 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
-import android.os.DropBoxManager;
 import android.os.Environment;
 import android.os.GraphicsEnvironment;
 import android.os.Handler;
@@ -157,8 +156,6 @@
 import dalvik.system.VMDebug;
 import dalvik.system.VMRuntime;
 
-import libcore.io.DropBox;
-import libcore.io.EventLogger;
 import libcore.io.IoUtils;
 import libcore.net.event.NetworkEventDispatcher;
 
@@ -6680,9 +6677,6 @@
             }
         }
 
-        // add dropbox logging to libcore
-        DropBox.setReporter(new DropBoxReporter());
-
         ViewRootImpl.ConfigChangedCallback configChangedCallback
                 = (Configuration globalConfig) -> {
             synchronized (mResourcesManager) {
@@ -6736,38 +6730,6 @@
         }
     }
 
-    private static class EventLoggingReporter implements EventLogger.Reporter {
-        @Override
-        public void report (int code, Object... list) {
-            EventLog.writeEvent(code, list);
-        }
-    }
-
-    private class DropBoxReporter implements DropBox.Reporter {
-
-        private DropBoxManager dropBox;
-
-        public DropBoxReporter() {}
-
-        @Override
-        public void addData(String tag, byte[] data, int flags) {
-            ensureInitialized();
-            dropBox.addData(tag, data, flags);
-        }
-
-        @Override
-        public void addText(String tag, String data) {
-            ensureInitialized();
-            dropBox.addText(tag, data);
-        }
-
-        private synchronized void ensureInitialized() {
-            if (dropBox == null) {
-                dropBox = (DropBoxManager) getSystemContext().getSystemService(Context.DROPBOX_SERVICE);
-            }
-        }
-    }
-
     public static void main(String[] args) {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
 
@@ -6778,9 +6740,6 @@
 
         Environment.initForCurrentUser();
 
-        // Set the reporter for event logging in libcore
-        EventLogger.setReporter(new EventLoggingReporter());
-
         // Make sure TrustedCertificateStore looks in the right place for CA certificates
         final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
         TrustedCertificateStore.setDefaultUserDirectory(configDir);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index b976d3f..15005d0 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -87,6 +87,7 @@
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
+import android.net.NetworkStack;
 import android.net.NetworkWatchlistManager;
 import android.net.lowpan.ILowpanManager;
 import android.net.lowpan.LowpanManager;
@@ -283,6 +284,13 @@
                 return new ConnectivityManager(context, service);
             }});
 
+        registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class,
+                new StaticServiceFetcher<NetworkStack>() {
+                @Override
+                public NetworkStack createService() {
+                    return new NetworkStack();
+                }});
+
         registerService(Context.IPSEC_SERVICE, IpSecManager.class,
                 new CachedServiceFetcher<IpSecManager>() {
             @Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 72795cf..81e72cc 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -49,6 +49,7 @@
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.net.NetworkStack;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -3504,6 +3505,15 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link NetworkStack} for communicating with the network stack
+     * @hide
+     * @see #getSystemService(String)
+     * @see NetworkStack
+     */
+    public static final String NETWORK_STACK_SERVICE = "network_stack";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
      * IPSec.
      *
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4714587..49c3dc6 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -187,13 +187,19 @@
      * is for a network to which the connectivity manager was failing over
      * following a disconnect on another network.
      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
+     *
+     * @deprecated See {@link NetworkInfo}.
      */
+    @Deprecated
     public static final String EXTRA_IS_FAILOVER = "isFailover";
     /**
      * The lookup key for a {@link NetworkInfo} object. This is supplied when
      * there is another network that it may be possible to connect to. Retrieve with
      * {@link android.content.Intent#getParcelableExtra(String)}.
+     *
+     * @deprecated See {@link NetworkInfo}.
      */
+    @Deprecated
     public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
     /**
      * The lookup key for a boolean that indicates whether there is a
@@ -214,7 +220,10 @@
      * may be passed up from the lower networking layers, and its
      * meaning may be specific to a particular network type. Retrieve
      * it with {@link android.content.Intent#getStringExtra(String)}.
+     *
+     * @deprecated See {@link NetworkInfo#getExtraInfo()}.
      */
+    @Deprecated
     public static final String EXTRA_EXTRA_INFO = "extraInfo";
     /**
      * The lookup key for an int that provides information about
@@ -895,7 +904,9 @@
      *
      * @return a {@link NetworkInfo} object for the current default network
      *        or {@code null} if no default network is currently active
+     * @deprecated See {@link NetworkInfo}.
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public NetworkInfo getActiveNetworkInfo() {
         try {
@@ -1079,7 +1090,9 @@
      * @return a {@link NetworkInfo} object for the requested
      *        network or {@code null} if the {@code Network}
      *        is not valid.
+     * @deprecated See {@link NetworkInfo}.
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public NetworkInfo getNetworkInfo(Network network) {
         return getNetworkInfoForUid(network, Process.myUid(), false);
diff --git a/core/java/android/net/INetdEventCallback.aidl b/core/java/android/net/INetdEventCallback.aidl
index 4b1a08d..0877a1a4 100644
--- a/core/java/android/net/INetdEventCallback.aidl
+++ b/core/java/android/net/INetdEventCallback.aidl
@@ -45,6 +45,20 @@
             in String[] ipAddresses, int ipAddressesCount, long timestamp, int uid);
 
     /**
+     * Represents adding or removing a NAT64 prefix.
+     * This method must not block or perform long-running operations.
+     *
+     * @param netId the ID of the network the prefix was performed on.
+     * @param added true if the NAT64 prefix was added, or false if the NAT64 prefix was removed.
+     *        There is only one prefix at a time for each netId. If a prefix is added, it replaces
+     *        the previous-added prefix.
+     * @param prefixString the detected NAT64 prefix as a string literal.
+     * @param prefixLength the prefix length associated with this NAT64 prefix.
+     */
+    void onNat64PrefixEvent(int netId, boolean added, @utf8InCpp String prefixString,
+            int prefixLength);
+
+    /**
      * Represents a private DNS validation success or failure.
      * This method must not block or perform long-running operations.
      *
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
new file mode 100644
index 0000000..29f8828
--- /dev/null
+++ b/core/java/android/net/INetworkStackConnector.aidl
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing perNmissions and
+ * limitations under the License.
+ */
+package android.net;
+
+/** @hide */
+oneway interface INetworkStackConnector {
+    // TODO: requestDhcpServer(), etc. will go here
+}
\ No newline at end of file
diff --git a/core/java/android/net/InetAddresses.java b/core/java/android/net/InetAddresses.java
new file mode 100644
index 0000000..8e6c69a
--- /dev/null
+++ b/core/java/android/net/InetAddresses.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import libcore.net.InetAddressUtils;
+
+import java.net.InetAddress;
+
+/**
+ * Utility methods for {@link InetAddress} implementations.
+ */
+public class InetAddresses {
+
+    private InetAddresses() {}
+
+    /**
+     * Checks to see if the {@code address} is a numeric address (such as {@code "192.0.2.1"} or
+     * {@code "2001:db8::1:2"}).
+     *
+     * <p>A numeric address is either an IPv4 address containing exactly 4 decimal numbers or an
+     * IPv6 numeric address. IPv4 addresses that consist of either hexadecimal or octal digits or
+     * do not have exactly 4 numbers are not treated as numeric.
+     *
+     * <p>This method will never do a DNS lookup.
+     *
+     * @param address the address to parse.
+     * @return true if the supplied address is numeric, false otherwise.
+     */
+    public static boolean isNumericAddress(String address) {
+        return InetAddressUtils.isNumericAddress(address);
+    }
+
+    /**
+     * Returns an InetAddress corresponding to the given numeric address (such
+     * as {@code "192.168.0.1"} or {@code "2001:4860:800d::68"}).
+     *
+     * <p>See {@link #isNumericAddress(String)} (String)} for a definition as to what constitutes a
+     * numeric address.
+     *
+     * <p>This method will never do a DNS lookup.
+     *
+     * @param address the address to parse, must be numeric.
+     * @return an {@link InetAddress} instance corresponding to the address.
+     * @throws IllegalArgumentException if {@code address} is not a numeric address.
+     */
+    public static InetAddress parseNumericAddress(String address) {
+        return InetAddressUtils.parseNumericAddress(address);
+    }
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 1b9a66c..80517ce 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -161,7 +162,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public LinkProperties() {
     }
 
@@ -195,7 +196,7 @@
      * @param iface The name of the network interface used for this link.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public void setInterfaceName(String iface) {
         mIfaceName = iface;
         ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
@@ -346,7 +347,7 @@
      *                  object.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public void setLinkAddresses(Collection<LinkAddress> addresses) {
         mLinkAddresses.clear();
         for (LinkAddress address: addresses) {
@@ -392,7 +393,7 @@
      * @param dnsServers The {@link Collection} of DNS servers to set in this object.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public void setDnsServers(Collection<InetAddress> dnsServers) {
         mDnses.clear();
         for (InetAddress dnsServer: dnsServers) {
@@ -529,7 +530,7 @@
      *                domains to search when resolving host names on this link.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public void setDomains(String domains) {
         mDomains = domains;
     }
@@ -552,7 +553,7 @@
      * @param mtu The MTU to use for this link.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public void setMtu(int mtu) {
         mMtu = mtu;
     }
@@ -562,9 +563,7 @@
      * this will return 0.
      *
      * @return The mtu value set for this link.
-     * @hide
      */
-    @UnsupportedAppUsage
     public int getMtu() {
         return mMtu;
     }
@@ -613,7 +612,7 @@
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public boolean addRoute(RouteInfo route) {
         if (route != null) {
             String routeIface = route.getInterface();
@@ -688,7 +687,7 @@
      * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public void setHttpProxy(ProxyInfo proxy) {
         mHttpProxy = proxy;
     }
@@ -760,7 +759,7 @@
      * Clears this object to its initial state.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public void clear() {
         mIfaceName = null;
         mLinkAddresses.clear();
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8a5f43d..1b44c92 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -1017,7 +1017,7 @@
      * @return The bearer-specific signal strength.
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public int getSignalStrength() {
         return mSignalStrength;
     }
@@ -1467,7 +1467,7 @@
             appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities,
                     NetworkCapabilities::capabilityNameOf, "&");
         }
-        if (0 != mNetworkCapabilities) {
+        if (0 != mUnwantedNetworkCapabilities) {
             sb.append(" Unwanted: ");
             appendStringRepresentationOfBitMaskToStringBuilder(sb, mUnwantedNetworkCapabilities,
                     NetworkCapabilities::capabilityNameOf, "&");
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 1a1d2d334..89d9961 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -28,7 +28,20 @@
  * Describes the status of a network interface.
  * <p>Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents
  * the current network connection.
+ *
+ * @deprecated Callers should instead use the {@link ConnectivityManager.NetworkCallback} API to
+ *             learn about connectivity changes, or switch to use
+ *             {@link ConnectivityManager#getNetworkCapabilities} or
+ *             {@link ConnectivityManager#getLinkProperties} to get information synchronously. Keep
+ *             in mind that while callbacks are guaranteed to be called for every event in order,
+ *             synchronous calls have no such constraints, and as such it is unadvisable to use the
+ *             synchronous methods inside the callbacks as they will often not offer a view of
+ *             networking that is consistent (that is: they may return a past or a future state with
+ *             respect to the event being processed by the callback). Instead, callers are advised
+ *             to only use the arguments of the callbacks, possibly memorizing the specific bits of
+ *             information they need to keep from one callback to another.
  */
+@Deprecated
 public class NetworkInfo implements Parcelable {
 
     /**
@@ -52,7 +65,10 @@
      * <tr><td><code>FAILED</code></td><td><code>DISCONNECTED</code></td></tr>
      * <tr><td><code>BLOCKED</code></td><td><code>DISCONNECTED</code></td></tr>
      * </table>
+     *
+     * @deprecated See {@link NetworkInfo}.
      */
+    @Deprecated
     public enum State {
         CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN
     }
@@ -61,7 +77,10 @@
      * The fine-grained state of a network connection. This level of detail
      * is probably of interest to few applications. Most should use
      * {@link android.net.NetworkInfo.State State} instead.
+     *
+     * @deprecated See {@link NetworkInfo}.
      */
+    @Deprecated
     public enum DetailedState {
         /** Ready to start data connection setup. */
         IDLE,
@@ -463,8 +482,10 @@
      * Set the extraInfo field.
      * @param extraInfo an optional {@code String} providing addditional network state
      * information passed up from the lower networking layers.
+     * @deprecated See {@link NetworkInfo#getExtraInfo}.
      * @hide
      */
+    @Deprecated
     public void setExtraInfo(String extraInfo) {
         synchronized (this) {
             this.mExtraInfo = extraInfo;
@@ -488,7 +509,10 @@
      * Report the extra information about the network state, if any was
      * provided by the lower networking layers.
      * @return the extra information, or null if not available
+     * @deprecated Use other services e.g. WifiManager to get additional information passed up from
+     *             the lower networking layers.
      */
+    @Deprecated
     public String getExtraInfo() {
         synchronized (this) {
             return mExtraInfo;
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 04b6b44..3b01b03 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.NetworkCapabilities.NetCapability;
 import android.net.NetworkCapabilities.Transport;
@@ -344,7 +345,7 @@
          * @param signalStrength the bearer-specific signal strength.
          * @hide
          */
-        @UnsupportedAppUsage
+        @SystemApi
         public Builder setSignalStrength(int signalStrength) {
             mNetworkCapabilities.setSignalStrength(signalStrength);
             return this;
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
new file mode 100644
index 0000000..82a4e31
--- /dev/null
+++ b/core/java/android/net/NetworkStack.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+/**
+ * Service used to communicate with the network stack, which is running in a separate module.
+ * @hide
+ */
+@SystemService(Context.NETWORK_STACK_SERVICE)
+public class NetworkStack {
+    private static final String TAG = NetworkStack.class.getSimpleName();
+
+    @NonNull
+    @GuardedBy("mPendingNetStackRequests")
+    private final ArrayList<NetworkStackRequest> mPendingNetStackRequests = new ArrayList<>();
+    @Nullable
+    @GuardedBy("mPendingNetStackRequests")
+    private INetworkStackConnector mConnector;
+
+    private interface NetworkStackRequest {
+        void onNetworkStackConnected(INetworkStackConnector connector);
+    }
+
+    public NetworkStack() { }
+
+    private class NetworkStackConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            registerNetworkStackService(service);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            // TODO: crash/reboot the system ?
+            Slog.wtf(TAG, "Lost network stack connector");
+        }
+    };
+
+    private void registerNetworkStackService(@NonNull IBinder service) {
+        final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service);
+
+        ServiceManager.addService(Context.NETWORK_STACK_SERVICE, service, false /* allowIsolated */,
+                DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+
+        final ArrayList<NetworkStackRequest> requests;
+        synchronized (mPendingNetStackRequests) {
+            requests = new ArrayList<>(mPendingNetStackRequests);
+            mPendingNetStackRequests.clear();
+            mConnector = connector;
+        }
+
+        for (NetworkStackRequest r : requests) {
+            r.onNetworkStackConnected(connector);
+        }
+    }
+
+    /**
+     * Start the network stack. Should be called only once on device startup.
+     *
+     * <p>This method will start the network stack either in the network stack process, or inside
+     * the system server on devices that do not support the network stack module. The network stack
+     * connector will then be delivered asynchronously to clients that requested it before it was
+     * started.
+     */
+    public void start(Context context) {
+        // Try to bind in-process if the library is available
+        IBinder connector = null;
+        try {
+            final Class service = Class.forName(
+                    "com.android.server.NetworkStackService",
+                    true /* initialize */,
+                    context.getClassLoader());
+            connector = (IBinder) service.getMethod("makeConnector").invoke(null);
+        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+            Slog.wtf(TAG, "Could not create network stack connector from NetworkStackService");
+            // TODO: crash/reboot system here ?
+            return;
+        } catch (ClassNotFoundException e) {
+            // Normal behavior if stack is provided by the app: fall through
+        }
+
+        // In-process network stack. Add the service to the service manager here.
+        if (connector != null) {
+            registerNetworkStackService(connector);
+            return;
+        }
+        // Start the network stack process. The service will be added to the service manager in
+        // NetworkStackConnection.onServiceConnected().
+        final Intent intent = new Intent(INetworkStackConnector.class.getName());
+        final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
+        intent.setComponent(comp);
+
+        if (comp == null || !context.bindServiceAsUser(intent, new NetworkStackConnection(),
+                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
+            Slog.wtf(TAG,
+                    "Could not bind to network stack in-process, or in app with " + intent);
+            // TODO: crash/reboot system server if no network stack after a timeout ?
+        }
+    }
+
+    // TODO: use this method to obtain the connector when implementing network stack operations
+    private void requestConnector(@NonNull NetworkStackRequest request) {
+        // TODO: PID check.
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            // Don't even attempt to obtain the connector and give a nice error message
+            throw new SecurityException(
+                    "Only the system server should try to bind to the network stack.");
+        }
+
+        final INetworkStackConnector connector;
+        synchronized (mPendingNetStackRequests) {
+            connector = mConnector;
+            if (connector == null) {
+                mPendingNetStackRequests.add(request);
+                return;
+            }
+        }
+
+        request.onNetworkStackConnected(connector);
+    }
+}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 34e9476..c0aa4a6 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.util.Log;
 import android.util.Pair;
@@ -294,8 +295,10 @@
      * @param addrString
      * @return the InetAddress
      * @hide
+     * @deprecated Use {@link InetAddresses#parseNumericAddress(String)}, if possible.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @Deprecated
     public static InetAddress numericToInetAddress(String addrString)
             throws IllegalArgumentException {
         return InetAddress.parseNumericAddress(addrString);
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index be8cf0e..fdd7488 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -390,7 +390,7 @@
     /**
      * Setup a new VPN.
      */
-    void createVirtualNetwork(int netId, boolean hasDNS, boolean secure);
+    void createVirtualNetwork(int netId, boolean secure);
 
     /**
      * Remove a network.
diff --git a/core/java/android/os/NativeHandle.java b/core/java/android/os/NativeHandle.java
index fbecc8e..f7ffc37 100644
--- a/core/java/android/os/NativeHandle.java
+++ b/core/java/android/os/NativeHandle.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import static android.system.OsConstants.F_DUPFD_CLOEXEC;
+
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.system.ErrnoException;
@@ -108,7 +110,10 @@
         FileDescriptor[] fds = new FileDescriptor[mFds.length];
         try {
             for (int i = 0; i < mFds.length; i++) {
-                fds[i] = Os.dup(mFds[i]);
+                FileDescriptor newFd = new FileDescriptor();
+                int fdint = Os.fcntlInt(mFds[i], F_DUPFD_CLOEXEC, 0);
+                newFd.setInt$(fdint);
+                fds[i] = newFd;
             }
         } catch (ErrnoException e) {
             e.rethrowAsIOException();
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index d0cdf6e..f2837ecb 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -174,6 +174,12 @@
      */
     public static final int SE_UID = 1068;
 
+    /**
+     * Defines the UID/GID for the NetworkStack app.
+     * @hide
+     */
+    public static final int NETWORK_STACK_UID = 1073;
+
     /** {@hide} */
     public static final int NOBODY_UID = 9999;
 
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index e930f40..568ca0f 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -71,10 +71,8 @@
      * @param gid2 group id level 2
      * @param carrierid carrier unique identifier {@link TelephonyManager#getSimCarrierId()}, used
      *                  to uniquely identify the carrier and look up the carrier configurations.
-     * @param preciseCarrierId precise carrier identifier {@link TelephonyManager#getSimPreciseCarrierId()}
-     * @hide
-     *
-     * TODO: expose this to public API
+     * @param preciseCarrierId precise carrier identifier
+     * {@link TelephonyManager#getSimPreciseCarrierId()}
      */
     public CarrierIdentifier(String mcc, String mnc, @Nullable String spn,
                              @Nullable String imsi, @Nullable String gid1, @Nullable String gid2,
@@ -155,16 +153,16 @@
     }
 
     /**
-     * Get the carrier id {@link TelephonyManager#getSimCarrierId() }
-     * @hide
+     * Returns the carrier id.
+     * @see TelephonyManager#getSimCarrierId()
      */
     public int getCarrierId() {
         return mCarrierId;
     }
 
     /**
-     * Get the precise carrier id {@link TelephonyManager#getSimPreciseCarrierId()}
-     * @hide
+     * Returns the precise carrier id.
+     * @see TelephonyManager#getSimPreciseCarrierId()
      */
     public int getPreciseCarrierId() {
         return mPreciseCarrierId;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 2e98d03..1dbe166 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -268,6 +268,13 @@
     public static final int FX_SURFACE_DIM = 0x00020000;
 
     /**
+     * Surface creation flag: Creates a container surface.
+     * This surface will have no buffers and will only be used
+     * as a container for other surfaces, or for its InputInfo.
+     */
+    public static final int FX_SURFACE_CONTAINER = 0x00080000;
+
+    /**
      * Mask used for FX values above.
      *
      */
@@ -523,14 +530,39 @@
          */
         public Builder setColorLayer(boolean isColorLayer) {
             if (isColorLayer) {
-                mFlags |= FX_SURFACE_DIM;
+                setFlags(FX_SURFACE_DIM, FX_SURFACE_MASK);
             } else {
-                mFlags &= ~FX_SURFACE_DIM;
+                setBufferLayer();
             }
             return this;
         }
 
         /**
+         * Indicates whether a 'ContainerLayer' is to be constructed.
+         *
+         * Container layers will not be rendered in any fashion and instead are used
+         * as a parent of renderable layers.
+         *
+         * @param isContainerLayer Whether to create a container layer.
+         */
+        public Builder setContainerLayer(boolean isContainerLayer) {
+            if (isContainerLayer) {
+                setFlags(FX_SURFACE_CONTAINER, FX_SURFACE_MASK);
+            } else {
+                setBufferLayer();
+            }
+            return this;
+        }
+
+        /**
+         * Indicates whether a buffer layer is to be constructed.
+         *
+         */
+        public Builder setBufferLayer() {
+            return setFlags(FX_SURFACE_NORMAL, FX_SURFACE_MASK);
+        }
+
+        /**
          * Set 'Surface creation flags' such as {@link HIDDEN}, {@link SECURE}.
          *
          * TODO: Finish conversion to individual builder methods?
@@ -540,6 +572,11 @@
             mFlags = flags;
             return this;
         }
+
+        private Builder setFlags(int flags, int mask) {
+            mFlags = (mFlags & ~mask) | flags;
+            return this;
+        }
     }
 
     /**
diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
index 3fa1b01..e44d6eb 100644
--- a/core/java/android/webkit/WebSyncManager.java
+++ b/core/java/android/webkit/WebSyncManager.java
@@ -26,6 +26,7 @@
 abstract class WebSyncManager implements Runnable {
     protected static final java.lang.String LOGTAG = "websync";
     protected android.webkit.WebViewDatabase mDataBase;
+    @UnsupportedAppUsage
     protected android.os.Handler mHandler;
 
     protected WebSyncManager(Context context, String name) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 8bdb000..c2c6ae6 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -536,9 +536,11 @@
     static ClassLoader createPathClassLoader(String classPath, int targetSdkVersion) {
         String libraryPath = System.getProperty("java.library.path");
 
+        // We use the boot class loader, that's what the runtime expects at AOT.
+        ClassLoader parent = ClassLoader.getSystemClassLoader().getParent();
+
         return ClassLoaderFactory.createClassLoader(classPath, libraryPath, libraryPath,
-                ClassLoader.getSystemClassLoader(), targetSdkVersion, true /* isNamespaceShared */,
-                null /* classLoaderName */);
+                parent, targetSdkVersion, true /* isNamespaceShared */, null /* classLoaderName */);
     }
 
     /**
diff --git a/core/java/com/android/internal/widget/NumericTextView.java b/core/java/com/android/internal/widget/NumericTextView.java
index 27c5834..d215670 100644
--- a/core/java/com/android/internal/widget/NumericTextView.java
+++ b/core/java/com/android/internal/widget/NumericTextView.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
@@ -53,6 +54,7 @@
 
     private OnValueChangedListener mListener;
 
+    @UnsupportedAppUsage
     public NumericTextView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
diff --git a/core/java/com/android/server/net/BaseNetdEventCallback.java b/core/java/com/android/server/net/BaseNetdEventCallback.java
index 97247aa..a65214a 100644
--- a/core/java/com/android/server/net/BaseNetdEventCallback.java
+++ b/core/java/com/android/server/net/BaseNetdEventCallback.java
@@ -32,6 +32,12 @@
     }
 
     @Override
+    public void onNat64PrefixEvent(int netId, boolean added, String prefixString,
+            int prefixLength) {
+        // default no-op
+    }
+
+    @Override
     public void onPrivateDnsValidationEvent(int netId, String ipAddress,
             String hostname, boolean validated) {
         // default no-op
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index b5860d8..c81a77d 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -264,7 +264,7 @@
         "libhardware",
         "libhardware_legacy",
         "libselinux",
-        "libicuuc",
+        "libandroidicu",
         "libmedia",
         "libmediametrics",
         "libaudioclient",
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 5a74a24..b085bc9 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -48,7 +48,7 @@
 
 class BitmapWrapper {
 public:
-    BitmapWrapper(Bitmap* bitmap)
+    explicit BitmapWrapper(Bitmap* bitmap)
         : mBitmap(bitmap) { }
 
     void freePixels() {
diff --git a/core/jni/android/graphics/FontUtils.h b/core/jni/android/graphics/FontUtils.h
index 9eaaa49..30fdf24 100644
--- a/core/jni/android/graphics/FontUtils.h
+++ b/core/jni/android/graphics/FontUtils.h
@@ -27,7 +27,7 @@
 namespace android {
 
 struct FontFamilyWrapper {
-  FontFamilyWrapper(std::shared_ptr<minikin::FontFamily>&& family) : family(family) {}
+  explicit FontFamilyWrapper(std::shared_ptr<minikin::FontFamily>&& family) : family(family) {}
   std::shared_ptr<minikin::FontFamily> family;
 };
 
diff --git a/core/jni/android/graphics/GIFMovie.cpp b/core/jni/android/graphics/GIFMovie.cpp
index dd99b37..f84a4bd 100644
--- a/core/jni/android/graphics/GIFMovie.cpp
+++ b/core/jni/android/graphics/GIFMovie.cpp
@@ -21,7 +21,7 @@
 
 class GIFMovie : public Movie {
 public:
-    GIFMovie(SkStream* stream);
+    explicit GIFMovie(SkStream* stream);
     virtual ~GIFMovie();
 
 protected:
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 6c9f463..9963a45 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -20,7 +20,6 @@
 #include "android_media_AudioTrack.h"
 
 #include <nativehelper/JNIHelp.h>
-#include <nativehelper/JniConstants.h>
 #include "core_jni_helpers.h"
 
 #include <utils/Log.h>
diff --git a/core/jni/android_media_DeviceCallback.cpp b/core/jni/android_media_DeviceCallback.cpp
index 108fa00..a1a0351 100644
--- a/core/jni/android_media_DeviceCallback.cpp
+++ b/core/jni/android_media_DeviceCallback.cpp
@@ -20,7 +20,6 @@
 
 #include <utils/Log.h>
 #include <nativehelper/JNIHelp.h>
-#include <nativehelper/JniConstants.h>
 #include "core_jni_helpers.h"
 #include <media/AudioSystem.h>
 
diff --git a/core/jni/android_os_SharedMemory.cpp b/core/jni/android_os_SharedMemory.cpp
index f6e5c7a..c33405d 100644
--- a/core/jni/android_os_SharedMemory.cpp
+++ b/core/jni/android_os_SharedMemory.cpp
@@ -20,8 +20,9 @@
 
 #include <cutils/ashmem.h>
 #include <utils/Log.h>
+
+#include <nativehelper/jni_macros.h>
 #include <nativehelper/JNIHelp.h>
-#include <nativehelper/JniConstants.h>
 #include <nativehelper/ScopedLocalRef.h>
 
 #include <algorithm>
@@ -31,10 +32,10 @@
 
 namespace {
 
-static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
-    static jmethodID ctor = env->GetMethodID(JniConstants::errnoExceptionClass,
-            "<init>", "(Ljava/lang/String;I)V");
+jclass errnoExceptionClass;
+jmethodID errnoExceptionCtor;  // MethodID for ErrnoException.<init>(String,I)
 
+void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
     ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
     if (detailMessage.get() == NULL) {
         // Not really much we can do here. We're probably dead in the water,
@@ -42,12 +43,14 @@
         env->ExceptionClear();
     }
 
-    jobject exception = env->NewObject(JniConstants::errnoExceptionClass, ctor,
-            detailMessage.get(), error);
+    jobject exception = env->NewObject(errnoExceptionClass,
+                                       errnoExceptionCtor,
+                                       detailMessage.get(),
+                                       error);
     env->Throw(reinterpret_cast<jthrowable>(exception));
 }
 
-static jobject SharedMemory_create(JNIEnv* env, jobject, jstring jname, jint size) {
+jobject SharedMemory_nCreate(JNIEnv* env, jobject, jstring jname, jint size) {
 
     // Name is optional so we can't use ScopedUtfChars for this as it throws NPE on null
     const char* name = jname ? env->GetStringUTFChars(jname, nullptr) : nullptr;
@@ -69,7 +72,7 @@
     return jniCreateFileDescriptor(env, fd);
 }
 
-static jint SharedMemory_getSize(JNIEnv* env, jobject, jobject fileDescriptor) {
+jint SharedMemory_nGetSize(JNIEnv* env, jobject, jobject fileDescriptor) {
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     if (!ashmem_valid(fd)) {
         return -1;
@@ -78,7 +81,7 @@
     return static_cast<jint>(std::min(size, static_cast<size_t>(std::numeric_limits<jint>::max())));
 }
 
-static jint SharedMemory_setProt(JNIEnv* env, jobject, jobject fileDescriptor, jint prot) {
+jint SharedMemory_nSetProt(JNIEnv* env, jobject, jobject fileDescriptor, jint prot) {
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     int err = 0;
     if (ashmem_set_prot_region(fd, prot)) {
@@ -87,18 +90,21 @@
     return err;
 }
 
-static const JNINativeMethod methods[] = {
-    {"nCreate", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)SharedMemory_create},
-    {"nGetSize", "(Ljava/io/FileDescriptor;)I", (void*)SharedMemory_getSize},
-    {"nSetProt", "(Ljava/io/FileDescriptor;I)I", (void*)SharedMemory_setProt},
+const JNINativeMethod methods[] = {
+  NATIVE_METHOD(SharedMemory, nCreate, "(Ljava/lang/String;I)Ljava/io/FileDescriptor;"),
+  NATIVE_METHOD(SharedMemory, nGetSize, "(Ljava/io/FileDescriptor;)I"),
+  NATIVE_METHOD(SharedMemory, nSetProt, "(Ljava/io/FileDescriptor;I)I")
 };
 
 } // anonymous namespace
 
 namespace android {
 
-int register_android_os_SharedMemory(JNIEnv* env)
-{
+int register_android_os_SharedMemory(JNIEnv* env) {
+    errnoExceptionClass =
+        MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
+    errnoExceptionCtor =
+        GetMethodIDOrDie(env, errnoExceptionClass, "<init>", "(Ljava/lang/String;I)V");
     return RegisterMethodsOrDie(env, "android/os/SharedMemory", methods, NELEM(methods));
 }
 
diff --git a/core/jni/android_util_jar_StrictJarFile.cpp b/core/jni/android_util_jar_StrictJarFile.cpp
index 4ab8db4..182a621 100644
--- a/core/jni/android_util_jar_StrictJarFile.cpp
+++ b/core/jni/android_util_jar_StrictJarFile.cpp
@@ -22,24 +22,26 @@
 
 #include <log/log.h>
 
+#include <nativehelper/jni_macros.h>
 #include <nativehelper/JNIHelp.h>
-#include <nativehelper/JniConstants.h>
 #include <nativehelper/ScopedLocalRef.h>
 #include <nativehelper/ScopedUtfChars.h>
-#include "jni.h"
+
+#include "core_jni_helpers.h"
 #include "ziparchive/zip_archive.h"
 
-namespace android {
+namespace {
 
+jclass zipEntryClass;
 // The method ID for ZipEntry.<init>(String,String,JJJIII[BJJ)
-static jmethodID zipEntryCtor;
+jmethodID zipEntryCtor;
 
-static void throwIoException(JNIEnv* env, const int32_t errorCode) {
+void throwIoException(JNIEnv* env, const int32_t errorCode) {
   jniThrowException(env, "java/io/IOException", ErrorCodeString(errorCode));
 }
 
-static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, jstring entryName) {
-  return env->NewObject(JniConstants::zipEntryClass,
+jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, jstring entryName) {
+  return env->NewObject(zipEntryClass,
                         zipEntryCtor,
                         entryName,
                         NULL,  // comment
@@ -52,7 +54,7 @@
                         static_cast<jlong>(entry.offset));
 }
 
-static jlong StrictJarFile_nativeOpenJarFile(JNIEnv* env, jobject, jstring name, jint fd) {
+jlong StrictJarFile_nativeOpenJarFile(JNIEnv* env, jobject, jstring name, jint fd) {
   // Name argument is used for logging, and can be any string.
   ScopedUtfChars nameChars(env, name);
   if (nameChars.c_str() == NULL) {
@@ -90,7 +92,7 @@
 };
 
 
-static jlong StrictJarFile_nativeStartIteration(JNIEnv* env, jobject, jlong nativeHandle,
+jlong StrictJarFile_nativeStartIteration(JNIEnv* env, jobject, jlong nativeHandle,
                                                 jstring prefix) {
   ScopedUtfChars prefixChars(env, prefix);
   if (prefixChars.c_str() == NULL) {
@@ -116,7 +118,7 @@
   return reinterpret_cast<jlong>(handle);
 }
 
-static jobject StrictJarFile_nativeNextEntry(JNIEnv* env, jobject, jlong iterationHandle) {
+jobject StrictJarFile_nativeNextEntry(JNIEnv* env, jobject, jlong iterationHandle) {
   ZipEntry data;
   ZipString entryName;
 
@@ -135,7 +137,7 @@
   return newZipEntry(env, data, entryNameString.get());
 }
 
-static jobject StrictJarFile_nativeFindEntry(JNIEnv* env, jobject, jlong nativeHandle,
+jobject StrictJarFile_nativeFindEntry(JNIEnv* env, jobject, jlong nativeHandle,
                                              jstring entryName) {
   ScopedUtfChars entryNameChars(env, entryName);
   if (entryNameChars.c_str() == NULL) {
@@ -152,11 +154,11 @@
   return newZipEntry(env, data, entryName);
 }
 
-static void StrictJarFile_nativeClose(JNIEnv*, jobject, jlong nativeHandle) {
+void StrictJarFile_nativeClose(JNIEnv*, jobject, jlong nativeHandle) {
   CloseArchive(reinterpret_cast<ZipArchiveHandle>(nativeHandle));
 }
 
-static JNINativeMethod gMethods[] = {
+JNINativeMethod gMethods[] = {
   NATIVE_METHOD(StrictJarFile, nativeOpenJarFile, "(Ljava/lang/String;I)J"),
   NATIVE_METHOD(StrictJarFile, nativeStartIteration, "(JLjava/lang/String;)J"),
   NATIVE_METHOD(StrictJarFile, nativeNextEntry, "(J)Ljava/util/zip/ZipEntry;"),
@@ -164,14 +166,15 @@
   NATIVE_METHOD(StrictJarFile, nativeClose, "(J)V"),
 };
 
+}  // namespace
+
+namespace android {
+
 int register_android_util_jar_StrictJarFile(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "android/util/jar/StrictJarFile", gMethods, NELEM(gMethods));
-
-  zipEntryCtor = env->GetMethodID(JniConstants::zipEntryClass, "<init>",
-      "(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V");
-  LOG_ALWAYS_FATAL_IF(zipEntryCtor == NULL, "Unable to find ZipEntry.<init>");
-
-  return 0;
+  zipEntryClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/zip/ZipEntry"));
+  zipEntryCtor = GetMethodIDOrDie(env, zipEntryClass, "<init>",
+                                  "(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V");
+  return jniRegisterNativeMethods(env, "android/util/jar/StrictJarFile", gMethods, NELEM(gMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 01105ba..d4fe1ed 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -414,7 +414,7 @@
     }
     endmntent(fp);
 
-    for (auto path : toUnmount) {
+    for (const auto& path : toUnmount) {
         if (umount2(path.c_str(), MNT_DETACH)) {
             ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
         }
@@ -917,6 +917,13 @@
     capabilities |= (1LL << CAP_SYS_NICE);
   }
 
+  if (multiuser_get_app_id(uid) == AID_NETWORK_STACK) {
+    capabilities |= (1LL << CAP_NET_ADMIN);
+    capabilities |= (1LL << CAP_NET_BROADCAST);
+    capabilities |= (1LL << CAP_NET_BIND_SERVICE);
+    capabilities |= (1LL << CAP_NET_RAW);
+  }
+
   /*
    * Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
    */
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index d457a1b..d8d919d 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -148,7 +148,7 @@
   const bool is_sock;
 
  private:
-  FileDescriptorInfo(int fd);
+  explicit FileDescriptorInfo(int fd);
 
   FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
                      int fd_flags, int fs_flags, off_t offset);
@@ -327,11 +327,13 @@
     return false;
   }
 
-  if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
+  int dupFlags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
+  if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dupFlags)) == -1) {
     close(new_fd);
-    *error_msg = android::base::StringPrintf("Failed dup2(%d, %d) (%s): %s",
+    *error_msg = android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
                                              fd,
                                              new_fd,
+                                             dupFlags,
                                              file_path.c_str(),
                                              strerror(errno));
     return false;
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index a3570d7..09022a2 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -86,7 +86,7 @@
   bool ReopenOrDetach(std::string* error_msg);
 
  private:
-  FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
+  explicit FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
 
   bool RestatInternal(std::set<int>& open_fds, std::string* error_msg);
 
diff --git a/core/proto/android/stats/launcher/launcher.proto b/core/proto/android/stats/launcher/launcher.proto
new file mode 100644
index 0000000..dbd0e03
--- /dev/null
+++ b/core/proto/android/stats/launcher/launcher.proto
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package android.stats.launcher;
+option java_multiple_files = true;
+
+enum LauncherAction {
+    DEFAULT_ACTION = 0;
+    LAUNCH_APP = 1;
+    LAUNCH_TASK = 2;
+    DISMISS_TASK = 3;
+    LONGPRESS = 4;
+    DRAGDROP = 5;
+    SWIPE_UP = 6;
+    SWIPE_DOWN = 7;
+    SWIPE_LEFT = 8;
+    SWIPE_RIGHT = 9;
+}
+
+enum LauncherState {
+    BACKGROUND = 0;
+    HOME = 1;
+    OVERVIEW = 2;
+    ALLAPPS = 3;
+}
+
+message LauncherTarget {
+    enum Type {
+        NONE = 0;
+        ITEM_TYPE = 1;
+        CONTROL_TYPE = 2;
+        CONTAINER_TYPE = 3;
+    }
+    enum Item {
+        DEFAULT_ITEM = 0;
+        APP_ICON = 1;
+        SHORTCUT = 2;
+        WIDGET = 3;
+        FOLDER_ICON = 4;
+        DEEPSHORTCUT = 5;
+        SEARCHBOX = 6;
+        EDITTEXT = 7;
+        NOTIFICATION = 8;
+        TASK = 9;
+    }
+    enum Container {
+        DEFAULT_CONTAINER = 0;
+        HOTSEAT = 1;
+        FOLDER = 2;
+        PREDICTION = 3;
+        SEARCHRESULT = 4;
+    }
+    enum Control {
+        DEFAULT_CONTROL = 0;
+        MENU = 1;
+        UNINSTALL = 2;
+        REMOVE = 3;
+    }
+    optional Type type = 1;
+    optional Item item = 2;
+    optional Container container = 3;
+    optional Control control = 4;
+    optional string launch_component = 5;
+    optional int32 page_id = 6;
+    optional int32 grid_x = 7;
+    optional int32 grid_y = 8;
+}
+
+message LauncherExtension {
+    repeated LauncherTarget src_target = 1;
+    repeated LauncherTarget dst_target = 2;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5154de0..344b74c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1832,6 +1832,15 @@
     <permission android:name="android.permission.BIND_SCREENING_SERVICE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Must be required by a {@link android.telecom.PhoneAccountSuggestionService},
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature|privileged
+         @SystemApi
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Must be required by a {@link android.telecom.CallRedirectionService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0082f4b..c8bd847 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -33,6 +33,10 @@
         <permission name="android.permission.CRYPT_KEEPER"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.carrierconfig">
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.cellbroadcastreceiver">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
@@ -315,6 +319,8 @@
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
         <permission name="android.permission.READ_FRAME_BUFFER"/>
         <permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
+        <!-- Needed for test only -->
+        <permission name="android.permission.READ_PRECISE_PHONE_STATE" />
         <permission name="android.permission.REAL_GET_TASKS"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.REGISTER_CALL_PROVIDER"/>
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 6ac52d1..36b7e37 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -54,6 +54,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.security.InvalidKeyException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
@@ -303,13 +304,14 @@
     }
 
     /**
-     * List uids of all keys that are auth bound to the current user. 
+     * List uids of all keys that are auth bound to the current user.
      * Only system is allowed to call this method.
      */
     @UnsupportedAppUsage
     public int[] listUidsOfAuthBoundKeys() {
-        final int MAX_RESULT_SIZE = 100;
-        int[] uidsOut = new int[MAX_RESULT_SIZE];
+        // uids are returned as a list of strings because list of integers
+        // as an output parameter is not supported by aidl-cpp.
+        List<String> uidsOut = new ArrayList<>();
         try {
             int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
             if (rc != NO_ERROR) {
@@ -323,8 +325,8 @@
             Log.w(TAG, "KeyStore exception", e);
             return null;
         }
-        // Remove any 0 entries
-        return Arrays.stream(uidsOut).filter(x -> x > 0).toArray();
+        // Turn list of strings into an array of uid integers.
+        return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
    }
 
     public String[] list(String prefix) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 953cef7d..aa29174 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -210,6 +210,10 @@
                         throw new InvalidAlgorithmParameterException(
                             "HMAC key size must be at least 64 bits.");
                     }
+                    if (mKeySizeBits > 512 && spec.isStrongBoxBacked()) {
+                        throw new InvalidAlgorithmParameterException(
+                            "StrongBox HMAC key size must be smaller than 512 bits.");
+                    }
 
                     // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
                     // implies SHA-256 digest). Because keymaster HMAC key is authorized only for
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 5fc742a..d44c894 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -303,7 +303,7 @@
             if (mKeySizeBits == -1) {
                 mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
             }
-            checkValidKeySize(keymasterAlgorithm, mKeySizeBits);
+            checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
 
             if (spec.getKeystoreAlias() == null) {
                 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
@@ -724,10 +724,18 @@
         }
     }
 
-    private static void checkValidKeySize(int keymasterAlgorithm, int keySize)
+    private static void checkValidKeySize(
+            int keymasterAlgorithm,
+            int keySize,
+            boolean isStrongBoxBacked)
             throws InvalidAlgorithmParameterException {
         switch (keymasterAlgorithm) {
             case KeymasterDefs.KM_ALGORITHM_EC:
+                if (isStrongBoxBacked && keySize != 256) {
+                    throw new InvalidAlgorithmParameterException(
+                            "Unsupported StrongBox EC key size: "
+                            + keySize + " bits. Supported: 256");
+                }
                 if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
                     throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
                             + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 38ad9c0..e9fba3a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -30,7 +30,7 @@
 
 class SkiaPipeline : public renderthread::IRenderPipeline {
 public:
-    SkiaPipeline(renderthread::RenderThread& thread);
+    explicit SkiaPipeline(renderthread::RenderThread& thread);
     virtual ~SkiaPipeline();
 
     TaskManager* getTaskManager() override;
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
index 5ae7d6b..3233c8d 100644
--- a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
@@ -23,7 +23,7 @@
 
 class SkiaProfileRenderer : public IProfileRenderer {
 public:
-    SkiaProfileRenderer(SkCanvas* canvas) : mCanvas(canvas) {}
+    explicit SkiaProfileRenderer(SkCanvas* canvas) : mCanvas(canvas) {}
 
     void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
     void drawRects(const float* rects, int count, const SkPaint& paint) override;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 03b4c79..3d00386 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -25,7 +25,7 @@
 
 class SkiaVulkanPipeline : public SkiaPipeline {
 public:
-    SkiaVulkanPipeline(renderthread::RenderThread& thread);
+    explicit SkiaVulkanPipeline(renderthread::RenderThread& thread);
     virtual ~SkiaVulkanPipeline() {}
 
     renderthread::MakeCurrentResult makeCurrent() override;
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
index 74e48ce..5e892aa 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
@@ -62,8 +62,8 @@
 public:
     enum class StorageMode { allowSharedSurface, disallowSharedSurface };
 
-    VectorDrawableAtlas(size_t surfaceArea,
-                        StorageMode storageMode = StorageMode::allowSharedSurface);
+    explicit VectorDrawableAtlas(size_t surfaceArea,
+                                 StorageMode storageMode = StorageMode::allowSharedSurface);
 
     /**
      * "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 7d73352..78d2539 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -59,7 +59,7 @@
 private:
     friend class RenderThread;
 
-    CacheManager(const DisplayInfo& display);
+    explicit CacheManager(const DisplayInfo& display);
 
     void reset(sk_sp<GrContext> grContext);
     void destroy();
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index c319c9e..ea69704 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -127,6 +127,7 @@
             fPtr = ptr;
             return *this;
         }
+        // NOLINTNEXTLINE(google-explicit-constructor)
         operator FNPTR_TYPE() const { return fPtr; }
 
     private:
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index 0d87776..d189a93 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -76,7 +76,7 @@
                             paint.setStrokeWidth(strokeWidth);
                             // fill column with each op
                             int middleCount = canvas.save(SaveFlags::MatrixClip);
-                            for (auto op : ops) {
+                            for (const auto& op : ops) {
                                 int innerCount = canvas.save(SaveFlags::MatrixClip);
                                 canvas.clipRect(0, 0, cellSize, cellSize, SkClipOp::kIntersect);
                                 canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 02f740c..4f299e3 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -251,7 +251,7 @@
 }
 
 TEST(PathParser, parseStringForData) {
-    for (TestData testData : sTestDataSet) {
+    for (const TestData& testData : sTestDataSet) {
         PathParser::ParseResult result;
         // Test generated path data against the given data.
         PathData pathData;
@@ -271,7 +271,7 @@
 }
 
 TEST(VectorDrawableUtils, createSkPathFromPathData) {
-    for (TestData testData : sTestDataSet) {
+    for (const TestData& testData : sTestDataSet) {
         SkPath expectedPath;
         testData.skPathLamda(&expectedPath);
         SkPath actualPath;
@@ -281,7 +281,7 @@
 }
 
 TEST(PathParser, parseAsciiStringForSkPath) {
-    for (TestData testData : sTestDataSet) {
+    for (const TestData& testData : sTestDataSet) {
         PathParser::ParseResult result;
         size_t length = strlen(testData.pathString);
         // Check the return value as well as the SkPath generated.
@@ -304,8 +304,8 @@
 }
 
 TEST(VectorDrawableUtils, morphPathData) {
-    for (TestData fromData : sTestDataSet) {
-        for (TestData toData : sTestDataSet) {
+    for (const TestData& fromData : sTestDataSet) {
+        for (const TestData& toData : sTestDataSet) {
             bool canMorph = VectorDrawableUtils::canMorph(fromData.pathData, toData.pathData);
             if (fromData.pathData == toData.pathData) {
                 EXPECT_TRUE(canMorph);
@@ -319,8 +319,8 @@
 
 TEST(VectorDrawableUtils, interpolatePathData) {
     // Interpolate path data with itself and every other path data
-    for (TestData fromData : sTestDataSet) {
-        for (TestData toData : sTestDataSet) {
+    for (const TestData& fromData : sTestDataSet) {
+        for (const TestData& toData : sTestDataSet) {
             PathData outData;
             bool success = VectorDrawableUtils::interpolatePathData(&outData, fromData.pathData,
                                                                     toData.pathData, 0.5);
@@ -331,7 +331,7 @@
 
     float fractions[] = {0, 0.00001, 0.28, 0.5, 0.7777, 0.9999999, 1};
     // Now try to interpolate with a slightly modified version of self and expect success
-    for (TestData fromData : sTestDataSet) {
+    for (const TestData& fromData : sTestDataSet) {
         PathData toPathData = fromData.pathData;
         for (size_t i = 0; i < toPathData.points.size(); i++) {
             toPathData.points[i]++;
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h
index c56f689..ee1e33c 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include/android/os/IncidentReportArgs.h
@@ -40,7 +40,7 @@
 class IncidentReportArgs : public Parcelable {
 public:
     IncidentReportArgs();
-    explicit IncidentReportArgs(const IncidentReportArgs& that);
+    IncidentReportArgs(const IncidentReportArgs& that);
     virtual ~IncidentReportArgs();
 
     virtual status_t writeToParcel(Parcel* out) const;
diff --git a/native/android/net.c b/native/android/net.c
index e32b787..4cac371 100644
--- a/native/android/net.c
+++ b/native/android/net.c
@@ -84,8 +84,7 @@
     return android_getaddrinfofornet(node, service, hints, netid, 0, res);
 }
 
-int android_res_nquery(net_handle_t network,
-        const char *dname, int ns_class, int ns_type) {
+int android_res_nquery(net_handle_t network, const char *dname, int ns_class, int ns_type) {
     unsigned netid;
     if (!getnetidfromhandle(network, &netid)) {
         return -ENONET;
@@ -94,12 +93,11 @@
     return resNetworkQuery(netid, dname, ns_class, ns_type);
 }
 
-int android_res_nresult(int fd, int *rcode, unsigned char *answer, int anslen) {
+int android_res_nresult(int fd, int *rcode, uint8_t *answer, size_t anslen) {
     return resNetworkResult(fd, rcode, answer, anslen);
 }
 
-int android_res_nsend(net_handle_t network,
-        const unsigned char *msg, int msglen) {
+int android_res_nsend(net_handle_t network, const uint8_t *msg, size_t msglen) {
     unsigned netid;
     if (!getnetidfromhandle(network, &netid)) {
         return -ENONET;
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
new file mode 100644
index 0000000..55bb517
--- /dev/null
+++ b/packages/NetworkStack/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Library including the network stack, used to compile the network stack app, or linked into the
+// system server on devices that run the stack there
+java_library {
+    name: "NetworkStackLib",
+    installable: true,
+    srcs: [
+        "src/**/*.java",
+    ],
+}
+
+// Updatable network stack packaged as an application
+android_app {
+    name: "NetworkStack",
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+    static_libs: [
+        "NetworkStackLib"
+    ],
+    manifest: "AndroidManifest.xml",
+}
\ No newline at end of file
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
new file mode 100644
index 0000000..d1c5cb6
--- /dev/null
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.google.android.networkstack"
+          android:sharedUserId="android.uid.networkstack">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <!-- Launch captive portal app as specific user -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <application
+        android:label="NetworkStack"
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true"
+        android:usesCleartextTraffic="true">
+        <service android:name="com.android.server.NetworkStackService">
+            <intent-filter>
+                <action android:name="android.net.INetworkStackConnector"/>
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
new file mode 100644
index 0000000..5afaf58
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.os.Binder.getCallingUid;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.net.INetworkStackConnector;
+import android.os.IBinder;
+import android.os.Process;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Android service used to start the network stack when bound to via an intent.
+ *
+ * <p>The service returns a binder for the system server to communicate with the network stack.
+ */
+public class NetworkStackService extends Service {
+    private static final String TAG = NetworkStackService.class.getSimpleName();
+
+    /**
+     * Create a binder connector for the system server to communicate with the network stack.
+     *
+     * <p>On platforms where the network stack runs in the system server process, this method may
+     * be called directly instead of obtaining the connector by binding to the service.
+     */
+    public static IBinder makeConnector() {
+        return new NetworkStackConnector();
+    }
+
+    @NonNull
+    @Override
+    public IBinder onBind(Intent intent) {
+        return makeConnector();
+    }
+
+    private static class NetworkStackConnector extends INetworkStackConnector.Stub {
+        // TODO: makeDhcpServer(), etc. will go here.
+
+        @Override
+        protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
+                @Nullable String[] args) {
+            checkCaller();
+            fout.println("NetworkStack logs:");
+            // TODO: dump logs here
+        }
+    }
+
+    private static void checkCaller() {
+        // TODO: check that the calling PID is the system server.
+        if (getCallingUid() != Process.SYSTEM_UID && getCallingUid() != Process.ROOT_UID) {
+            throw new SecurityException("Invalid caller: " + getCallingUid());
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
index 4c45a75..cb2a088 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
@@ -25,9 +25,9 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.sysprop.CarProperties;
 import android.util.Log;
 
 import com.android.internal.util.UserIcons;
@@ -43,7 +43,6 @@
 @Deprecated
 public final class UserManagerHelper {
     private static final String TAG = "UserManagerHelper";
-    private static final String HEADLESS_SYSTEM_USER = "android.car.systemuser.headless";
     private final Context mContext;
     private final UserManager mUserManager;
     private final ActivityManager mActivityManager;
@@ -84,7 +83,7 @@
      * @return {@boolean true} if headless system user.
      */
     public boolean isHeadlessSystemUser() {
-        return SystemProperties.getBoolean(HEADLESS_SYSTEM_USER, false);
+        return CarProperties.headless_system_user().orElse(false);
     }
 
     /**
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index adeff5d..9306219 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -26,6 +26,7 @@
     <uses-permission android:name="android.permission.SEND_SMS" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 83021ca..be46d2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -19,7 +19,7 @@
 import android.app.ActivityManager;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
-import android.os.SystemProperties;
+import android.sysprop.CarProperties;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
@@ -56,7 +56,7 @@
         CarBatteryController.BatteryViewHandler {
     private static final String TAG = "CarStatusBar";
     public static final boolean ENABLE_HVAC_CONNECTION
-            = !SystemProperties.getBoolean("android.car.hvac.demo", true);
+            = !CarProperties.hvac_demo().orElse(true);
 
     private TaskStackListenerImpl mTaskStackListener;
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 49de4b1..555e899 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -76,6 +76,7 @@
 import java.util.LinkedList;
 import java.util.Locale;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -1279,7 +1280,11 @@
             if (mService == null) {
                 return;
             }
-            mService.unlinkToDeath(this, 0);
+            try {
+                mService.unlinkToDeath(this, 0);
+            } catch (NoSuchElementException e) {
+                Log.e(TAG, "error unlinking to death", e);
+            }
             mService = null;
             mClassName = null;
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 89194e4..66ceae4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5714,7 +5714,6 @@
                 // This should never fail.  Specifying an already in use NetID will cause failure.
                 if (networkAgent.isVPN()) {
                     mNMS.createVirtualNetwork(networkAgent.network.netId,
-                            !networkAgent.linkProperties.getDnsServers().isEmpty(),
                             (networkAgent.networkMisc == null ||
                                 !networkAgent.networkMisc.allowBypass));
                 } else {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index d0e8b47..00b1320 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -163,8 +163,6 @@
 
     private static final int MAX_UID_RANGES_PER_COMMAND = 10;
 
-    private static final  String[] EMPTY_STRING_ARRAY = new String[0];
-
     /**
      * Name representing {@link #setGlobalAlert(long)} limit when delivered to
      * {@link INetworkManagementEventObserver#limitReached(String, String)}.
@@ -954,8 +952,7 @@
     public String[] listInterfaces() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            final List<String> result = mNetdService.interfaceGetList();
-            return result.toArray(EMPTY_STRING_ARRAY);
+            return mNetdService.interfaceGetList();
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
@@ -1247,8 +1244,7 @@
     public String[] listTetheredInterfaces() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            final List<String> result = mNetdService.tetherInterfaceList();
-            return result.toArray(EMPTY_STRING_ARRAY);
+            return mNetdService.tetherInterfaceList();
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
@@ -1271,8 +1267,7 @@
     public String[] getDnsForwarders() {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            final List<String> result = mNetdService.tetherDnsList();
-            return result.toArray(EMPTY_STRING_ARRAY);
+            return mNetdService.tetherDnsList();
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
@@ -2313,11 +2308,11 @@
     }
 
     @Override
-    public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
+    public void createVirtualNetwork(int netId, boolean secure) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mNetdService.networkCreateVpn(netId, hasDNS, secure);
+            mNetdService.networkCreateVpn(netId, secure);
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 66ae47c..7b29fe5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -210,6 +210,10 @@
 
     private PreciseCallState mPreciseCallState = new PreciseCallState();
 
+    private int mCallDisconnectCause = DisconnectCause.NOT_VALID;
+
+    private int mCallPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
+
     private boolean mCarrierNetworkChangeState = false;
 
     private PhoneCapability mPhoneCapability = null;
@@ -708,6 +712,14 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
+                        try {
+                            r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause,
+                                    mCallPreciseDisconnectCause);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                     if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
                         try {
                             r.callback.onPreciseDataConnectionStateChanged(
@@ -1478,9 +1490,8 @@
             }
             handleRemoveListLocked();
         }
-        broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState,
-                DisconnectCause.NOT_VALID,
-                PreciseDisconnectCause.NOT_VALID);
+        broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState,
+                backgroundCallState);
     }
 
     public void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause) {
@@ -1488,12 +1499,14 @@
             return;
         }
         synchronized (mRecords) {
-            mPreciseCallState = new PreciseCallState(mRingingCallState, mForegroundCallState,
-                    mBackgroundCallState, disconnectCause, preciseDisconnectCause);
+            mCallDisconnectCause = disconnectCause;
+            mCallPreciseDisconnectCause = preciseDisconnectCause;
             for (Record r : mRecords) {
-                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)) {
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener
+                        .LISTEN_CALL_DISCONNECT_CAUSES)) {
                     try {
-                        r.callback.onPreciseCallStateChanged(mPreciseCallState);
+                        r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause,
+                                mCallPreciseDisconnectCause);
                     } catch (RemoteException ex) {
                         mRemoveList.add(r.binder);
                     }
@@ -1501,8 +1514,6 @@
             }
             handleRemoveListLocked();
         }
-        broadcastPreciseCallStateChanged(mRingingCallState, mForegroundCallState,
-                mBackgroundCallState, disconnectCause, preciseDisconnectCause);
     }
 
     public void notifyPreciseDataConnectionFailed(String reason, String apnType,
@@ -1703,6 +1714,8 @@
             }
             pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
             pw.println("mPreciseCallState=" + mPreciseCallState);
+            pw.println("mCallDisconnectCause=" + mCallDisconnectCause);
+            pw.println("mCallPreciseDisconnectCause=" + mCallPreciseDisconnectCause);
             pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
             pw.println("mRingingCallState=" + mRingingCallState);
             pw.println("mForegroundCallState=" + mForegroundCallState);
@@ -1877,13 +1890,11 @@
     }
 
     private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
-            int backgroundCallState, int disconnectCause, int preciseDisconnectCause) {
+            int backgroundCallState) {
         Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
         intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
         intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
         intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
-        intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause);
-        intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                 android.Manifest.permission.READ_PRECISE_PHONE_STATE);
     }
@@ -1964,6 +1975,11 @@
         }
 
 
+        if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
+        }
+
         return true;
     }
 
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 79c98e5..2649807 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -15,7 +15,7 @@
 jjaggi@google.com
 racarr@google.com
 chaviw@google.com
-brycelee@google.com
+vishnun@google.com
 akulian@google.com
 roosa@google.com
 
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 422f556..e40949b 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -217,6 +217,19 @@
     @Override
     // Called concurrently by multiple binder threads.
     // This method must not block or perform long-running operations.
+    public synchronized void onNat64PrefixEvent(int netId,
+            boolean added, String prefixString, int prefixLength)
+            throws RemoteException {
+        for (INetdEventCallback callback : mNetdEventCallbackList) {
+            if (callback != null) {
+                callback.onNat64PrefixEvent(netId, added, prefixString, prefixLength);
+            }
+        }
+    }
+
+    @Override
+    // Called concurrently by multiple binder threads.
+    // This method must not block or perform long-running operations.
     public synchronized void onPrivateDnsValidationEvent(int netId,
             String ipAddress, String hostname, boolean validated)
             throws RemoteException {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index bf95210..9684f4c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -944,6 +944,10 @@
     private class WaitingForNextProbeState extends State {
         @Override
         public void enter() {
+            scheduleNextProbe();
+        }
+
+        private void scheduleNextProbe() {
             final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
             sendMessageDelayed(msg, mReevaluateDelayMs);
             mReevaluateDelayMs *= 2;
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index c370959..3ea9810 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -43,8 +43,6 @@
 import com.android.net.IProxyPortListener;
 import com.android.net.IProxyService;
 
-import libcore.io.Streams;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.net.URL;
@@ -71,6 +69,11 @@
     private static final int DELAY_LONG = 4;
     private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
 
+    // Return values for #setCurrentProxyScriptUrl
+    enum ToSendOrNotToSendBroadcast {
+        DONT_SEND_BROADCAST, DO_SEND_BROADCAST
+    }
+
     private String mCurrentPac;
     @GuardedBy("mProxyLock")
     private volatile Uri mPacUrl = Uri.EMPTY;
@@ -171,13 +174,13 @@
      * PacManager will trigger a new broadcast when it is ready.
      *
      * @param proxy Proxy information that is about to be broadcast.
-     * @return Returns true when the broadcast should not be sent
+     * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
      */
-    synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+    synchronized ToSendOrNotToSendBroadcast setCurrentProxyScriptUrl(ProxyInfo proxy) {
         if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
             if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
                 // Allow to send broadcast, nothing to do.
-                return false;
+                return ToSendOrNotToSendBroadcast.DO_SEND_BROADCAST;
             }
             mPacUrl = proxy.getPacFileUrl();
             mCurrentDelay = DELAY_1;
@@ -185,7 +188,7 @@
             mHasDownloaded = false;
             getAlarmManager().cancel(mPacRefreshIntent);
             bind();
-            return true;
+            return ToSendOrNotToSendBroadcast.DONT_SEND_BROADCAST;
         } else {
             getAlarmManager().cancel(mPacRefreshIntent);
             synchronized (mProxyLock) {
@@ -201,7 +204,7 @@
                     }
                 }
             }
-            return false;
+            return ToSendOrNotToSendBroadcast.DO_SEND_BROADCAST;
         }
     }
 
@@ -296,7 +299,7 @@
         Intent intent = new Intent();
         intent.setClassName(PAC_PACKAGE, PAC_SERVICE);
         if ((mProxyConnection != null) && (mConnection != null)) {
-            // Already bound no need to bind again, just download the new file.
+            // Already bound: no need to bind again, just download the new file.
             mNetThreadHandler.post(mPacDownloader);
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index 15468ff..fdddccd 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -208,7 +208,10 @@
     public void sendProxyBroadcast() {
         final ProxyInfo defaultProxy = getDefaultProxy();
         final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : new ProxyInfo("", 0, "");
-        if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)) return;
+        if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)
+                == PacManager.ToSendOrNotToSendBroadcast.DONT_SEND_BROADCAST) {
+            return;
+        }
         if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 268e844..0120dc3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -80,8 +80,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import libcore.util.EmptyArray;
 
 /**
@@ -93,6 +95,31 @@
     private final Locale HONG_KONG = new Locale("zh", "HK");
     private final Locale MACAU = new Locale("zh", "MO");
 
+    private static final Map<String, String> mTerminologyToBibliographicMap;
+    static {
+        mTerminologyToBibliographicMap = new HashMap<>();
+        // NOTE: (TERMINOLOGY_CODE, BIBLIOGRAPHIC_CODE)
+        mTerminologyToBibliographicMap.put("sqi", "alb"); // Albanian
+        mTerminologyToBibliographicMap.put("hye", "arm"); // Armenian
+        mTerminologyToBibliographicMap.put("eus", "baq"); // Basque
+        mTerminologyToBibliographicMap.put("mya", "bur"); // Burmese
+        mTerminologyToBibliographicMap.put("ces", "cze"); // Czech
+        mTerminologyToBibliographicMap.put("nld", "dut"); // Dutch
+        mTerminologyToBibliographicMap.put("kat", "geo"); // Georgian
+        mTerminologyToBibliographicMap.put("deu", "ger"); // German
+        mTerminologyToBibliographicMap.put("ell", "gre"); // Greek
+        mTerminologyToBibliographicMap.put("fra", "fre"); // French
+        mTerminologyToBibliographicMap.put("isl", "ice"); // Icelandic
+        mTerminologyToBibliographicMap.put("mkd", "mac"); // Macedonian
+        mTerminologyToBibliographicMap.put("mri", "mao"); // Maori
+        mTerminologyToBibliographicMap.put("msa", "may"); // Malay
+        mTerminologyToBibliographicMap.put("fas", "per"); // Persian
+        mTerminologyToBibliographicMap.put("ron", "rum"); // Romanian
+        mTerminologyToBibliographicMap.put("slk", "slo"); // Slovak
+        mTerminologyToBibliographicMap.put("bod", "tib"); // Tibetan
+        mTerminologyToBibliographicMap.put("cym", "wel"); // Welsh
+    }
+
     static final String PERMISSION = "android.permission.HDMI_CEC";
 
     // The reason code to initiate intializeCec().
@@ -176,7 +203,18 @@
                 // Chinese used in Taiwan/Hong Kong/Macau.
                 return "chi";
             } else {
-                return locale.getISO3Language();
+                String language = locale.getISO3Language();
+
+                // locale.getISO3Language() returns terminology code and need to
+                // send it as bibliographic code instead since the Bibliographic
+                // codes of ISO/FDIS 639-2 shall be used.
+                // NOTE: Chinese also has terminology/bibliographic code "zho" and "chi"
+                // But, as it depends on the locale, is not handled here.
+                if (mTerminologyToBibliographicMap.containsKey(language)) {
+                    language = mTerminologyToBibliographicMap.get(language);
+                }
+
+                return language;
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index cc640f0..5e1ed03 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -404,12 +404,17 @@
                 + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
                 + " target-filter=" + compilerFilter);
 
-        // TODO(calin): b/64530081 b/66984396. Use SKIP_SHARED_LIBRARY_CHECK for the context
-        // (instead of dexUseInfo.getClassLoaderContext()) in order to compile secondary dex files
-        // in isolation (and avoid to extract/verify the main apk if it's in the class path).
-        // Note this trades correctness for performance since the resulting slow down is
-        // unacceptable in some cases until b/64530081 is fixed.
-        String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
+        String classLoaderContext;
+        if (dexUseInfo.isUnknownClassLoaderContext() || dexUseInfo.isVariableClassLoaderContext()) {
+            // If we have an unknown (not yet set), or a variable class loader chain, compile
+            // without a context and mark the oat file with SKIP_SHARED_LIBRARY_CHECK. Note that
+            // this might lead to a incorrect compilation.
+            // TODO(calin): We should just extract in this case.
+            classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
+        } else {
+            classLoaderContext = dexUseInfo.getClassLoaderContext();
+        }
+
         int reason = options.getCompilationReason();
         try {
             for (String isa : dexUseInfo.getLoaderIsas()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9345ad1..f4673a8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -456,6 +456,7 @@
     private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
     private static final int SHELL_UID = Process.SHELL_UID;
     private static final int SE_UID = Process.SE_UID;
+    private static final int NETWORKSTACK_UID = Process.NETWORK_STACK_UID;
 
     // Suffix used during package installation when copying/moving
     // package apks to install directory.
@@ -2469,6 +2470,8 @@
                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.se", SE_UID,
                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
 
         String separateProcesses = SystemProperties.get("debug.separate_processes");
         if (separateProcesses != null && separateProcesses.length() > 0) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 7856bcf..e5b9030 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -627,9 +627,13 @@
                     pw.print("=");
                 }
                 pw.print(info.packageName);
-                if (showVersionCode && !isApex) {
+                if (showVersionCode) {
                     pw.print(" versionCode:");
-                    pw.print(info.applicationInfo.versionCode);
+                    if (info.applicationInfo != null) {
+                        pw.print(info.applicationInfo.versionCode);
+                    } else {
+                        pw.print(info.versionCode);
+                    }
                 }
                 if (listInstaller && !isApex) {
                     pw.print("  installer=");
@@ -2701,7 +2705,7 @@
         pw.println("    Prints all system libraries.");
         pw.println("");
         pw.println("  list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] ");
-        pw.println("      [--apex-only] [--uid UID] [--user USER_ID] [FILTER]");
+        pw.println("      [--show-versioncode] [--apex-only] [--uid UID] [--user USER_ID] [FILTER]");
         pw.println("    Prints all packages; optionally only those whose name contains");
         pw.println("    the text in FILTER.  Options are:");
         pw.println("      -f: see their associated file");
@@ -2714,6 +2718,7 @@
         pw.println("      -l: ignored (used for compatibility with older releases)");
         pw.println("      -U: also show the package UID");
         pw.println("      -u: also include uninstalled packages");
+        pw.println("      --show-versioncode: also show the version code");
         pw.println("      --apex-only: only show APEX packages");
         pw.println("      --uid UID: filter to only show packages with the given UID");
         pw.println("      --user USER_ID: only list packages belonging to the given user");
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 519a20d..a194f57 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -863,15 +863,13 @@
 
         public String getClassLoaderContext() { return mClassLoaderContext; }
 
-        @VisibleForTesting
-        /* package */ boolean isUnknownClassLoaderContext() {
+        public boolean isUnknownClassLoaderContext() {
             // The class loader context may be unknown if we loaded the data from a previous version
             // which didn't save the context.
             return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
         }
 
-        @VisibleForTesting
-        /* package */ boolean isVariableClassLoaderContext() {
+        public boolean isVariableClassLoaderContext() {
             return VARIABLE_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
         }
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index ad92f81..bef974a 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -69,6 +69,7 @@
                 .setFormat(PixelFormat.TRANSLUCENT)
                 .setMetadata(appToken.windowType,
                         window != null ? window.mOwnerUid : Binder.getCallingUid())
+                .setBufferLayer()
                 .build();
 
         if (SHOW_TRANSACTIONS) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2941e93..6700a12 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -773,7 +773,8 @@
 
         final SurfaceControl.Builder b = mService.makeSurfaceBuilder(mSession)
                 .setSize(mSurfaceSize, mSurfaceSize)
-                .setOpaque(true);
+                .setOpaque(true)
+                .setContainerLayer(true);
         mWindowingLayer = b.setName("Display Root").build();
         mOverlayLayer = b.setName("Display Overlays").build();
 
@@ -3890,7 +3891,7 @@
         SurfaceSession s = child != null ? child.getSession() : getSession();
         final SurfaceControl.Builder b = mService.makeSurfaceBuilder(s);
         b.setSize(mSurfaceSize, mSurfaceSize);
-
+        b.setContainerLayer(true);
         if (child == null) {
             return b;
         }
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index fff42c5..8dda485 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -2,6 +2,6 @@
 jjaggi@google.com
 racarr@google.com
 chaviw@google.com
-brycelee@google.com
+vishnun@google.com
 akulian@google.com
 roosa@google.com
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 66c8cca..4548cec 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -104,6 +104,7 @@
 
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
         final SurfaceControl.Builder b = win.makeSurface()
+                .setBufferLayer()
                 .setParent(win.getSurfaceControl())
                 .setName(name)
                 .setSize(w, h)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4decd4f..2d07fd6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1204,6 +1204,16 @@
             }
             traceEnd();
 
+            traceBeginAndSlog("StartNetworkStack");
+            try {
+                final android.net.NetworkStack networkStack =
+                        context.getSystemService(android.net.NetworkStack.class);
+                networkStack.start(context);
+            } catch (Throwable e) {
+                reportWtf("starting Network Stack", e);
+            }
+            traceEnd();
+
             traceBeginAndSlog("StartNsdService");
             try {
                 serviceDiscovery = NsdService.create(context);
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index b9cc372..f037905 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -139,7 +139,8 @@
         DROPPED_IPV6_MULTICAST_PING,
         DROPPED_IPV6_NON_ICMP_MULTICAST,
         DROPPED_802_3_FRAME,
-        DROPPED_ETHERTYPE_BLACKLISTED;
+        DROPPED_ETHERTYPE_BLACKLISTED,
+        DROPPED_ARP_REPLY_SPA_NO_HOST;
 
         // Returns the negative byte offset from the end of the APF data segment for
         // a given counter.
@@ -156,7 +157,7 @@
     /**
      * When APFv4 is supported, loads R1 with the offset of the specified counter.
      */
-    private void maybeSetCounter(ApfGenerator gen, Counter c) {
+    private void maybeSetupCounter(ApfGenerator gen, Counter c) {
         if (mApfCapabilities.hasDataAccess()) {
             gen.addLoadImmediate(Register.R1, c.offset());
         }
@@ -288,16 +289,18 @@
     private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
 
     private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
-    private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
-    private static final short ARP_OPCODE_REQUEST = 1;
-    private static final short ARP_OPCODE_REPLY = 2;
     private static final byte[] ARP_IPV4_HEADER = {
             0, 1, // Hardware type: Ethernet (1)
             8, 0, // Protocol type: IP (0x0800)
             6,    // Hardware size: 6
             4,    // Protocol size: 4
     };
-    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
+    private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
+    // Opcode: ARP request (0x0001), ARP reply (0x0002)
+    private static final short ARP_OPCODE_REQUEST = 1;
+    private static final short ARP_OPCODE_REPLY = 2;
+    private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
+    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
     // Do not log ApfProgramEvents whose actual lifetimes was less than this.
     private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
     // Limit on the Black List size to cap on program usage for this
@@ -816,7 +819,7 @@
                     gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
                 }
             }
-            maybeSetCounter(gen, Counter.DROPPED_RA);
+            maybeSetupCounter(gen, Counter.DROPPED_RA);
             gen.addJump(mCountAndDropLabel);
             gen.defineLabel(nextFilterLabel);
             return filterLifetime;
@@ -883,6 +886,8 @@
         //   pass
         // if not ARP IPv4 reply or request
         //   pass
+        // if ARP reply source ip is 0.0.0.0
+        //   drop
         // if unicast ARP reply
         //   pass
         // if interface has no IPv4 address
@@ -897,18 +902,23 @@
 
         // Pass if not ARP IPv4.
         gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
-        maybeSetCounter(gen, Counter.PASSED_ARP_NON_IPV4);
+        maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4);
         gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
 
         // Pass if unknown ARP opcode.
         gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
         gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
-        maybeSetCounter(gen, Counter.PASSED_ARP_UNKNOWN);
+        maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN);
         gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
 
+        // Drop if ARP reply source IP is 0.0.0.0
+        gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET);
+        maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST);
+        gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
+
         // Pass if unicast reply.
         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
-        maybeSetCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
+        maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
         gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
 
         // Either a unicast request, a unicast reply, or a broadcast reply.
@@ -916,17 +926,17 @@
         if (mIPv4Address == null) {
             // When there is no IPv4 address, drop GARP replies (b/29404209).
             gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
-            maybeSetCounter(gen, Counter.DROPPED_GARP_REPLY);
+            maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY);
             gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
         } else {
             // When there is an IPv4 address, drop unicast/broadcast requests
             // and broadcast replies with a different target IPv4 address.
             gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
-            maybeSetCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
+            maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
             gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
         }
 
-        maybeSetCounter(gen, Counter.PASSED_ARP);
+        maybeSetupCounter(gen, Counter.PASSED_ARP);
         gen.addJump(mCountAndPassLabel);
     }
 
@@ -970,7 +980,7 @@
             // NOTE: Relies on R1 containing IPv4 header offset.
             gen.addAddR1();
             gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
-            maybeSetCounter(gen, Counter.PASSED_DHCP);
+            maybeSetupCounter(gen, Counter.PASSED_DHCP);
             gen.addJump(mCountAndPassLabel);
 
             // Drop all multicasts/broadcasts.
@@ -979,30 +989,30 @@
             // If IPv4 destination address is in multicast range, drop.
             gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
             gen.addAnd(0xf0);
-            maybeSetCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
+            maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
             gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
 
             // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
-            maybeSetCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
+            maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
             gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
             gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
             if (mIPv4Address != null && mIPv4PrefixLength < 31) {
-                maybeSetCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
+                maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
                 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
                 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
             }
 
             // If L2 broadcast packet, drop.
             // TODO: can we invert this condition to fall through to the common pass case below?
-            maybeSetCounter(gen, Counter.PASSED_IPV4_UNICAST);
+            maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
             gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
             gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
-            maybeSetCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
+            maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
             gen.addJump(mCountAndDropLabel);
         }
 
         // Otherwise, pass
-        maybeSetCounter(gen, Counter.PASSED_IPV4);
+        maybeSetupCounter(gen, Counter.PASSED_IPV4);
         gen.addJump(mCountAndPassLabel);
     }
 
@@ -1050,16 +1060,16 @@
 
             // Drop all other packets sent to ff00::/8 (multicast prefix).
             gen.defineLabel(dropAllIPv6MulticastsLabel);
-            maybeSetCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
+            maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
             gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
             gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
             // Not multicast. Pass.
-            maybeSetCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
+            maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
             gen.addJump(mCountAndPassLabel);
             gen.defineLabel(skipIPv6MulticastFilterLabel);
         } else {
             // If not ICMPv6, pass.
-            maybeSetCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
+            maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
             gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
         }
 
@@ -1069,7 +1079,7 @@
         String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
         gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
         // Drop all router solicitations (b/32833400)
-        maybeSetCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
+        maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
         gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
         // If not neighbor announcements, skip filter.
         gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
@@ -1078,7 +1088,7 @@
         gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
         gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
                 skipUnsolicitedMulticastNALabel);
-        maybeSetCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
+        maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
         gen.addJump(mCountAndDropLabel);
         gen.defineLabel(skipUnsolicitedMulticastNALabel);
     }
@@ -1108,7 +1118,7 @@
 
         if (mApfCapabilities.hasDataAccess()) {
             // Increment TOTAL_PACKETS
-            maybeSetCounter(gen, Counter.TOTAL_PACKETS);
+            maybeSetupCounter(gen, Counter.TOTAL_PACKETS);
             gen.addLoadData(Register.R0, 0);  // load counter
             gen.addAdd(1);
             gen.addStoreData(Register.R0, 0);  // write-back counter
@@ -1134,12 +1144,12 @@
 
         if (mDrop802_3Frames) {
             // drop 802.3 frames (ethtype < 0x0600)
-            maybeSetCounter(gen, Counter.DROPPED_802_3_FRAME);
+            maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME);
             gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
         }
 
         // Handle ether-type black list
-        maybeSetCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
+        maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
         for (int p : mEthTypeBlackList) {
             gen.addJumpIfR0Equals(p, mCountAndDropLabel);
         }
@@ -1168,9 +1178,9 @@
 
         // Drop non-IP non-ARP broadcasts, pass the rest
         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
-        maybeSetCounter(gen, Counter.PASSED_NON_IP_UNICAST);
+        maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST);
         gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
-        maybeSetCounter(gen, Counter.DROPPED_ETH_BROADCAST);
+        maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST);
         gen.addJump(mCountAndDropLabel);
 
         // Add IPv6 filters:
@@ -1193,7 +1203,7 @@
 
         // Execution will reach the bottom of the program if none of the filters match,
         // which will pass the packet to the application processor.
-        maybeSetCounter(gen, Counter.PASSED_IPV6_ICMP);
+        maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP);
 
         // Append the count & pass trampoline, which increments the counter at the data address
         // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java
index cee6fa9..35d29e7 100644
--- a/services/net/java/android/net/dhcp/DhcpServer.java
+++ b/services/net/java/android/net/dhcp/DhcpServer.java
@@ -39,7 +39,6 @@
 import android.net.MacAddress;
 import android.net.NetworkUtils;
 import android.net.TrafficStats;
-import android.net.util.InterfaceParams;
 import android.net.util.SharedLog;
 import android.os.Handler;
 import android.os.Looper;
@@ -85,7 +84,7 @@
     @NonNull
     private final ServerHandler mHandler;
     @NonNull
-    private final InterfaceParams mIface;
+    private final String mIfName;
     @NonNull
     private final DhcpLeaseRepository mLeaseRepo;
     @NonNull
@@ -161,20 +160,20 @@
         }
     }
 
-    public DhcpServer(@NonNull Looper looper, @NonNull InterfaceParams iface,
+    public DhcpServer(@NonNull Looper looper, @NonNull String ifName,
             @NonNull DhcpServingParams params, @NonNull SharedLog log) {
-        this(looper, iface, params, log, null);
+        this(looper, ifName, params, log, null);
     }
 
     @VisibleForTesting
-    DhcpServer(@NonNull Looper looper, @NonNull InterfaceParams iface,
+    DhcpServer(@NonNull Looper looper, @NonNull String ifName,
             @NonNull DhcpServingParams params, @NonNull SharedLog log,
             @Nullable Dependencies deps) {
         if (deps == null) {
             deps = new DependenciesImpl();
         }
         mHandler = new ServerHandler(looper);
-        mIface = iface;
+        mIfName = ifName;
         mServingParams = params;
         mLog = log;
         mDeps = deps;
@@ -444,7 +443,7 @@
 
     private boolean addArpEntry(@NonNull MacAddress macAddr, @NonNull Inet4Address inetAddr) {
         try {
-            mDeps.addArpEntry(inetAddr, macAddr, mIface.name, mSocket);
+            mDeps.addArpEntry(inetAddr, macAddr, mIfName, mSocket);
             return true;
         } catch (IOException e) {
             mLog.e("Error adding client to ARP table", e);
@@ -526,7 +525,7 @@
                 // SO_BINDTODEVICE actually takes a string. This works because the first member
                 // of struct ifreq is a NULL-terminated interface name.
                 // TODO: add a setsockoptString()
-                Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIface.name);
+                Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIfName);
                 Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1);
                 Os.bind(mSocket, Inet4Address.ANY, DHCP_SERVER);
                 NetworkUtils.protectFromVpn(mSocket);
diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java
index 823c0a1..493350d 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -138,9 +138,9 @@
             return NetdService.getInstance();
         }
 
-        public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
+        public DhcpServer makeDhcpServer(Looper looper, String ifName,
                 DhcpServingParams params, SharedLog log) {
-            return new DhcpServer(looper, iface, params, log);
+            return new DhcpServer(looper, ifName, params, log);
         }
     }
 
@@ -256,12 +256,6 @@
         if (mUsingLegacyDhcp) {
             return true;
         }
-
-        final InterfaceParams ifaceParams = mDeps.getInterfaceParams(mIfaceName);
-        if (ifaceParams == null) {
-            Log.e(TAG, "Failed to find interface params for DHCPv4");
-            return false;
-        }
         final DhcpServingParams params;
         try {
             params = new DhcpServingParams.Builder()
@@ -277,7 +271,7 @@
             return false;
         }
 
-        mDhcpServer = mDeps.makeDhcpServer(getHandler().getLooper(), ifaceParams, params,
+        mDhcpServer = mDeps.makeDhcpServer(getHandler().getLooper(), mIfaceName, params,
                 mLog.forSubComponent("DHCP"));
         mDhcpServer.start();
         return true;
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index de40e0d..91cec554 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -24,6 +24,9 @@
         "libdexfile",
         "slicer",
     ],
+    static_libs: [
+        "libtinyxml2",
+    ],
 }
 
 cc_library_host_static {
@@ -32,7 +35,9 @@
     srcs: [
         "dex_builder.cc",
         "java_lang_builder.cc",
+        "tinyxml_layout_parser.cc",
         "util.cc",
+        "layout_validation.cc",
     ],
 }
 
@@ -43,7 +48,6 @@
         "main.cc",
     ],
     static_libs: [
-        "libtinyxml2",
         "libgflags",
         "libviewcompiler",
     ],
@@ -54,6 +58,7 @@
     defaults: ["viewcompiler_defaults"],
     srcs: [
         "dex_builder_test.cc",
+        "layout_validation_test.cc",
         "util_test.cc",
     ],
     static_libs: [
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 906d64c..a78f7d5 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -61,18 +61,49 @@
     case Instruction::Op::kInvokeDirect:
       out << "kInvokeDirect";
       return out;
+    case Instruction::Op::kInvokeStatic:
+      out << "kInvokeStatic";
+      return out;
+    case Instruction::Op::kInvokeInterface:
+      out << "kInvokeInterface";
+      return out;
     case Instruction::Op::kBindLabel:
       out << "kBindLabel";
       return out;
     case Instruction::Op::kBranchEqz:
       out << "kBranchEqz";
       return out;
+    case Instruction::Op::kBranchNEqz:
+      out << "kBranchNEqz";
+      return out;
     case Instruction::Op::kNew:
       out << "kNew";
       return out;
+    case Instruction::Op::kCheckCast:
+      out << "kCheckCast";
+      return out;
   }
 }
 
+std::ostream& operator<<(std::ostream& out, const Value& value) {
+  if (value.is_register()) {
+    out << "Register(" << value.value() << ")";
+  } else if (value.is_parameter()) {
+    out << "Parameter(" << value.value() << ")";
+  } else if (value.is_immediate()) {
+    out << "Immediate(" << value.value() << ")";
+  } else if (value.is_string()) {
+    out << "String(" << value.value() << ")";
+  } else if (value.is_label()) {
+    out << "Label(" << value.value() << ")";
+  } else if (value.is_type()) {
+    out << "Type(" << value.value() << ")";
+  } else {
+    out << "UnknownValue";
+  }
+  return out;
+}
+
 void* TrackingAllocator::Allocate(size_t size) {
   std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
   void* raw_buffer = buffer.get();
@@ -289,12 +320,20 @@
       return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL);
     case Instruction::Op::kInvokeDirect:
       return EncodeInvoke(instruction, art::Instruction::INVOKE_DIRECT);
+    case Instruction::Op::kInvokeStatic:
+      return EncodeInvoke(instruction, art::Instruction::INVOKE_STATIC);
+    case Instruction::Op::kInvokeInterface:
+      return EncodeInvoke(instruction, art::Instruction::INVOKE_INTERFACE);
     case Instruction::Op::kBindLabel:
       return BindLabel(instruction.args()[0]);
     case Instruction::Op::kBranchEqz:
       return EncodeBranch(art::Instruction::IF_EQZ, instruction);
+    case Instruction::Op::kBranchNEqz:
+      return EncodeBranch(art::Instruction::IF_NEZ, instruction);
     case Instruction::Op::kNew:
       return EncodeNew(instruction);
+    case Instruction::Op::kCheckCast:
+      return EncodeCast(instruction);
   }
 }
 
@@ -353,7 +392,9 @@
 
   // If there is a return value, add a move-result instruction
   if (instruction.dest().has_value()) {
-    Encode11x(art::Instruction::MOVE_RESULT, RegisterValue(*instruction.dest()));
+    Encode11x(instruction.result_is_object() ? art::Instruction::MOVE_RESULT_OBJECT
+                                             : art::Instruction::MOVE_RESULT,
+              RegisterValue(*instruction.dest()));
   }
 
   max_args_ = std::max(max_args_, instruction.args().size());
@@ -386,6 +427,18 @@
   Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
 }
 
+void MethodBuilder::EncodeCast(const Instruction& instruction) {
+  DCHECK_EQ(Instruction::Op::kCheckCast, instruction.opcode());
+  DCHECK(instruction.dest().has_value());
+  DCHECK(instruction.dest()->is_variable());
+  DCHECK_EQ(1, instruction.args().size());
+
+  const Value& type = instruction.args()[0];
+  DCHECK_LT(RegisterValue(*instruction.dest()), 256);
+  DCHECK(type.is_type());
+  Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
+}
+
 size_t MethodBuilder::RegisterValue(const Value& value) const {
   if (value.is_register()) {
     return value.value();
@@ -447,7 +500,7 @@
     auto& ir_node = dex_file_->methods_map[new_index];
     SLICER_CHECK(ir_node == nullptr);
     ir_node = decl;
-    decl->orig_index = new_index;
+    decl->orig_index = decl->index = new_index;
 
     entry = {id, decl};
   }
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index adf82bf..757d863 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -73,7 +73,7 @@
   bool operator<(const TypeDescriptor& rhs) const { return descriptor_ < rhs.descriptor_; }
 
  private:
-  TypeDescriptor(std::string descriptor) : descriptor_{descriptor} {}
+  explicit TypeDescriptor(std::string descriptor) : descriptor_{descriptor} {}
 
   const std::string descriptor_;
 };
@@ -83,7 +83,7 @@
 class Prototype {
  public:
   template <typename... TypeDescriptors>
-  Prototype(TypeDescriptor return_type, TypeDescriptors... param_types)
+  explicit Prototype(TypeDescriptor return_type, TypeDescriptors... param_types)
       : return_type_{return_type}, param_types_{param_types...} {}
 
   // Encode this prototype into the dex file.
@@ -142,14 +142,18 @@
   // The operation performed by this instruction. These are virtual instructions that do not
   // correspond exactly to DEX instructions.
   enum class Op {
-    kReturn,
-    kReturnObject,
-    kMove,
-    kInvokeVirtual,
-    kInvokeDirect,
     kBindLabel,
     kBranchEqz,
-    kNew
+    kBranchNEqz,
+    kCheckCast,
+    kInvokeDirect,
+    kInvokeInterface,
+    kInvokeStatic,
+    kInvokeVirtual,
+    kMove,
+    kNew,
+    kReturn,
+    kReturnObject,
   };
 
   ////////////////////////
@@ -163,19 +167,60 @@
   // For most instructions, which take some number of arguments and have an optional return value.
   template <typename... T>
   static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest, T... args) {
-    return Instruction{opcode, /*method_id*/ 0, dest, args...};
+    return Instruction{opcode, /*method_id=*/0, /*result_is_object=*/false, dest, args...};
   }
+
+  // A cast instruction. Basically, `(type)val`
+  static inline Instruction Cast(Value val, Value type) {
+    DCHECK(type.is_type());
+    return OpWithArgs(Op::kCheckCast, val, type);
+  }
+
   // For method calls.
   template <typename... T>
   static inline Instruction InvokeVirtual(size_t method_id, std::optional<const Value> dest,
                                           Value this_arg, T... args) {
-    return Instruction{Op::kInvokeVirtual, method_id, dest, this_arg, args...};
+    return Instruction{
+        Op::kInvokeVirtual, method_id, /*result_is_object=*/false, dest, this_arg, args...};
+  }
+  // Returns an object
+  template <typename... T>
+  static inline Instruction InvokeVirtualObject(size_t method_id, std::optional<const Value> dest,
+                                                Value this_arg, T... args) {
+    return Instruction{
+        Op::kInvokeVirtual, method_id, /*result_is_object=*/true, dest, this_arg, args...};
   }
   // For direct calls (basically, constructors).
   template <typename... T>
   static inline Instruction InvokeDirect(size_t method_id, std::optional<const Value> dest,
                                          Value this_arg, T... args) {
-    return Instruction{Op::kInvokeDirect, method_id, dest, this_arg, args...};
+    return Instruction{
+        Op::kInvokeDirect, method_id, /*result_is_object=*/false, dest, this_arg, args...};
+  }
+  // Returns an object
+  template <typename... T>
+  static inline Instruction InvokeDirectObject(size_t method_id, std::optional<const Value> dest,
+                                               Value this_arg, T... args) {
+    return Instruction{
+        Op::kInvokeDirect, method_id, /*result_is_object=*/true, dest, this_arg, args...};
+  }
+  // For static calls.
+  template <typename... T>
+  static inline Instruction InvokeStatic(size_t method_id, std::optional<const Value> dest,
+                                         T... args) {
+    return Instruction{Op::kInvokeStatic, method_id, /*result_is_object=*/false, dest, args...};
+  }
+  // Returns an object
+  template <typename... T>
+  static inline Instruction InvokeStaticObject(size_t method_id, std::optional<const Value> dest,
+                                               T... args) {
+    return Instruction{Op::kInvokeStatic, method_id, /*result_is_object=*/true, dest, args...};
+  }
+  // For static calls.
+  template <typename... T>
+  static inline Instruction InvokeInterface(size_t method_id, std::optional<const Value> dest,
+                                            T... args) {
+    return Instruction{Op::kInvokeInterface, method_id, /*result_is_object=*/false, dest, args...};
   }
 
   ///////////////
@@ -184,21 +229,27 @@
 
   Op opcode() const { return opcode_; }
   size_t method_id() const { return method_id_; }
+  bool result_is_object() const { return result_is_object_; }
   const std::optional<const Value>& dest() const { return dest_; }
   const std::vector<const Value>& args() const { return args_; }
 
  private:
   inline Instruction(Op opcode, size_t method_id, std::optional<const Value> dest)
-      : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{} {}
+      : opcode_{opcode}, method_id_{method_id}, result_is_object_{false}, dest_{dest}, args_{} {}
 
   template <typename... T>
-  inline constexpr Instruction(Op opcode, size_t method_id, std::optional<const Value> dest,
-                               T... args)
-      : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{args...} {}
+  inline constexpr Instruction(Op opcode, size_t method_id, bool result_is_object,
+                               std::optional<const Value> dest, T... args)
+      : opcode_{opcode},
+        method_id_{method_id},
+        result_is_object_{result_is_object},
+        dest_{dest},
+        args_{args...} {}
 
   const Op opcode_;
   // The index of the method to invoke, for kInvokeVirtual and similar opcodes.
   const size_t method_id_{0};
+  const bool result_is_object_;
   const std::optional<const Value> dest_;
   const std::vector<const Value> args_;
 };
@@ -244,6 +295,8 @@
 
   // TODO: add builders for more instructions
 
+  DexBuilder* dex_file() const { return dex_; }
+
  private:
   void EncodeInstructions();
   void EncodeInstruction(const Instruction& instruction);
@@ -257,6 +310,7 @@
   void EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode);
   void EncodeBranch(art::Instruction::Code op, const Instruction& instruction);
   void EncodeNew(const Instruction& instruction);
+  void EncodeCast(const Instruction& instruction);
 
   // Low-level instruction format encoding. See
   // https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
index e20f3a9..42d4161 100644
--- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
@@ -20,6 +20,7 @@
 import dalvik.system.InMemoryDexClassLoader;
 import dalvik.system.PathClassLoader;
 import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
 import org.junit.Assert;
@@ -84,6 +85,15 @@
   }
 
   @Test
+  public void returnIfNotZero() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("returnIfNotZero", int.class);
+    Assert.assertEquals(3, method.invoke(null, 0));
+    Assert.assertEquals(5, method.invoke(null, 17));
+  }
+
+  @Test
   public void backwardsBranch() throws Exception {
     ClassLoader loader = loadDexFile("simple.dex");
     Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
@@ -124,4 +134,41 @@
     Assert.assertEquals("b", method.invoke(null, 0));
     Assert.assertEquals("a", method.invoke(null, 1));
   }
+
+  @Test
+  public void invokeStaticReturnObject() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("invokeStaticReturnObject", int.class, int.class);
+    Assert.assertEquals("10", method.invoke(null, 10, 10));
+    Assert.assertEquals("a", method.invoke(null, 10, 16));
+    Assert.assertEquals("5", method.invoke(null, 5, 16));
+  }
+
+  @Test
+  public void invokeVirtualReturnObject() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("invokeVirtualReturnObject", String.class, int.class);
+    Assert.assertEquals("bc", method.invoke(null, "abc", 1));
+  }
+
+  @Test
+  public void castObjectToString() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("castObjectToString", Object.class);
+    Assert.assertEquals("abc", method.invoke(null, "abc"));
+    boolean castFailed = false;
+    try {
+      method.invoke(null, 5);
+    } catch (InvocationTargetException e) {
+      if (e.getCause() instanceof ClassCastException) {
+        castFailed = true;
+      } else {
+        throw e;
+      }
+    }
+    Assert.assertTrue(castFailed);
+  }
 }
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc
index e2bf43bc..f62ec5dd 100644
--- a/startop/view_compiler/dex_testcase_generator.cc
+++ b/startop/view_compiler/dex_testcase_generator.cc
@@ -108,6 +108,27 @@
   }
   returnIfZero.Encode();
 
+  // int returnIfNotZero(int x) { if (x != 0) { return 5; } else { return 3; } }
+  MethodBuilder returnIfNotZero{cbuilder.CreateMethod(
+      "returnIfNotZero", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
+  {
+    Value resultIfNotZero{returnIfNotZero.MakeRegister()};
+    Value else_target{returnIfNotZero.MakeLabel()};
+    returnIfNotZero.AddInstruction(Instruction::OpWithArgs(
+        Instruction::Op::kBranchNEqz, /*dest=*/{}, Value::Parameter(0), else_target));
+    // else branch
+    returnIfNotZero.BuildConst4(resultIfNotZero, 3);
+    returnIfNotZero.AddInstruction(
+        Instruction::OpWithArgs(Instruction::Op::kReturn, /*dest=*/{}, resultIfNotZero));
+    // then branch
+    returnIfNotZero.AddInstruction(
+        Instruction::OpWithArgs(Instruction::Op::kBindLabel, /*dest=*/{}, else_target));
+    returnIfNotZero.BuildConst4(resultIfNotZero, 5);
+    returnIfNotZero.AddInstruction(
+        Instruction::OpWithArgs(Instruction::Op::kReturn, /*dest=*/{}, resultIfNotZero));
+  }
+  returnIfNotZero.Encode();
+
   // Make sure backwards branches work too.
   //
   // Pseudo code for test:
@@ -216,6 +237,51 @@
     method.Encode();
   }(returnStringIfZeroBA);
 
+  // Make sure we can invoke static methods that return an object
+  // String invokeStaticReturnObject(int n, int radix) { return java.lang.Integer.toString(n,
+  // radix); }
+  MethodBuilder invokeStaticReturnObject{
+      cbuilder.CreateMethod("invokeStaticReturnObject",
+                            Prototype{string_type, TypeDescriptor::Int(), TypeDescriptor::Int()})};
+  [&](MethodBuilder& method) {
+    Value result{method.MakeRegister()};
+    MethodDeclData to_string{dex_file.GetOrDeclareMethod(
+        TypeDescriptor::FromClassname("java.lang.Integer"),
+        "toString",
+        Prototype{string_type, TypeDescriptor::Int(), TypeDescriptor::Int()})};
+    method.AddInstruction(Instruction::InvokeStaticObject(
+        to_string.id, result, Value::Parameter(0), Value::Parameter(1)));
+    method.BuildReturn(result, /*is_object=*/true);
+    method.Encode();
+  }(invokeStaticReturnObject);
+
+  // Make sure we can invoke virtual methods that return an object
+  // String invokeVirtualReturnObject(String s, int n) { return s.substring(n); }
+  MethodBuilder invokeVirtualReturnObject{cbuilder.CreateMethod(
+      "invokeVirtualReturnObject", Prototype{string_type, string_type, TypeDescriptor::Int()})};
+  [&](MethodBuilder& method) {
+    Value result{method.MakeRegister()};
+    MethodDeclData substring{dex_file.GetOrDeclareMethod(
+        string_type, "substring", Prototype{string_type, TypeDescriptor::Int()})};
+    method.AddInstruction(Instruction::InvokeVirtualObject(
+        substring.id, result, Value::Parameter(0), Value::Parameter(1)));
+    method.BuildReturn(result, /*is_object=*/true);
+    method.Encode();
+  }(invokeVirtualReturnObject);
+
+  // Make sure we can cast objects
+  // String castObjectToString(Object o) { return (String)o; }
+  MethodBuilder castObjectToString{cbuilder.CreateMethod(
+      "castObjectToString",
+      Prototype{string_type, TypeDescriptor::FromClassname("java.lang.Object")})};
+  [&](MethodBuilder& method) {
+    const ir::Type* type_def = dex_file.GetOrAddType(string_type.descriptor());
+    method.AddInstruction(
+        Instruction::Cast(Value::Parameter(0), Value::Type(type_def->orig_index)));
+    method.BuildReturn(Value::Parameter(0), /*is_object=*/true);
+    method.Encode();
+  }(castObjectToString);
+
   slicer::MemView image{dex_file.CreateImage()};
   std::ofstream out_file(outdir + "/simple.dex");
   out_file.write(image.ptr<const char>(), image.size());
diff --git a/startop/view_compiler/layout_validation.cc b/startop/view_compiler/layout_validation.cc
new file mode 100644
index 0000000..8c77377
--- /dev/null
+++ b/startop/view_compiler/layout_validation.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "layout_validation.h"
+
+#include "android-base/stringprintf.h"
+
+namespace startop {
+
+void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) {
+  if (0 == name.compare(u"merge")) {
+    message_ = "Merge tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"include")) {
+    message_ = "Include tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"view")) {
+    message_ = "View tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"fragment")) {
+    message_ = "Fragment tags are not supported";
+    can_compile_ = false;
+  }
+}
+
+}  // namespace startop
\ No newline at end of file
diff --git a/startop/view_compiler/layout_validation.h b/startop/view_compiler/layout_validation.h
new file mode 100644
index 0000000..bed34bb
--- /dev/null
+++ b/startop/view_compiler/layout_validation.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LAYOUT_VALIDATION_H_
+#define LAYOUT_VALIDATION_H_
+
+#include "dex_builder.h"
+
+#include <string>
+
+namespace startop {
+
+// This visitor determines whether a layout can be compiled. Since we do not currently support all
+// features, such as includes and merges, we need to pre-validate the layout before we start
+// compiling.
+class LayoutValidationVisitor {
+ public:
+  void VisitStartDocument() const {}
+  void VisitEndDocument() const {}
+  void VisitStartTag(const std::u16string& name);
+  void VisitEndTag() const {}
+
+  const std::string& message() const { return message_; }
+  bool can_compile() const { return can_compile_; }
+
+ private:
+  std::string message_{"Okay"};
+  bool can_compile_{true};
+};
+
+}  // namespace startop
+
+#endif  // LAYOUT_VALIDATION_H_
diff --git a/startop/view_compiler/layout_validation_test.cc b/startop/view_compiler/layout_validation_test.cc
new file mode 100644
index 0000000..b74cdae
--- /dev/null
+++ b/startop/view_compiler/layout_validation_test.cc
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "tinyxml_layout_parser.h"
+
+#include "gtest/gtest.h"
+
+using startop::CanCompileLayout;
+using std::string;
+
+namespace {
+void ValidateXmlText(const string& xml, bool expected) {
+  tinyxml2::XMLDocument doc;
+  doc.Parse(xml.c_str());
+  EXPECT_EQ(CanCompileLayout(doc), expected);
+}
+}  // namespace
+
+TEST(LayoutValidationTest, SingleButtonLayout) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:text="Hello, World!">
+
+</Button>)";
+  ValidateXmlText(xml, /*expected=*/true);
+}
+
+TEST(LayoutValidationTest, SmallConstraintLayout) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/button6"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="16dp"
+        android:layout_marginBottom="16dp"
+        android:text="Button"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent" />
+
+    <Button
+        android:id="@+id/button7"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="16dp"
+        android:text="Button2"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/button6" />
+
+    <Button
+        android:id="@+id/button8"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="16dp"
+        android:text="Button1"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/button7" />
+</android.support.constraint.ConstraintLayout>)";
+  ValidateXmlText(xml, /*expected=*/true);
+}
+
+TEST(LayoutValidationTest, MergeNode) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <TextView
+        android:id="@+id/textView3"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="TextView" />
+
+    <Button
+        android:id="@+id/button9"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Button" />
+</merge>)";
+  ValidateXmlText(xml, /*expected=*/false);
+}
+
+TEST(LayoutValidationTest, IncludeLayout) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <include
+        layout="@layout/single_button_layout"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+</android.support.constraint.ConstraintLayout>)";
+  ValidateXmlText(xml, /*expected=*/false);
+}
+
+TEST(LayoutValidationTest, ViewNode) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <view
+        class="android.support.design.button.MaterialButton"
+        id="@+id/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+</android.support.constraint.ConstraintLayout>)";
+  ValidateXmlText(xml, /*expected=*/false);
+}
+
+TEST(LayoutValidationTest, FragmentNode) {
+  // This test case is from https://developer.android.com/guide/components/fragments
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <fragment android:name="com.example.news.ArticleListFragment"
+            android:id="@+id/list"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" />
+    <fragment android:name="com.example.news.ArticleReaderFragment"
+            android:id="@+id/viewer"
+            android:layout_weight="2"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" />
+</LinearLayout>)";
+  ValidateXmlText(xml, /*expected=*/false);
+}
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index 7d791c2..55bfdc7 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -18,6 +18,7 @@
 
 #include "dex_builder.h"
 #include "java_lang_builder.h"
+#include "tinyxml_layout_parser.h"
 #include "util.h"
 
 #include "tinyxml2.h"
@@ -41,7 +42,7 @@
 
 class ViewCompilerXmlVisitor : public XMLVisitor {
  public:
-  ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {}
+  explicit ViewCompilerXmlVisitor(JavaLangViewBuilder* builder) : builder_(builder) {}
 
   bool VisitEnter(const XMLDocument& /*doc*/) override {
     builder_->Start();
@@ -100,6 +101,12 @@
   XMLDocument xml;
   xml.LoadFile(filename);
 
+  string message{};
+  if (!startop::CanCompileLayout(xml, &message)) {
+    LOG(ERROR) << "Layout not supported: " << message;
+    return 1;
+  }
+
   std::ofstream outfile;
   if (FLAGS_out != kStdoutFilename) {
     outfile.open(FLAGS_out);
diff --git a/startop/view_compiler/tinyxml_layout_parser.cc b/startop/view_compiler/tinyxml_layout_parser.cc
new file mode 100644
index 0000000..1b3a81f
--- /dev/null
+++ b/startop/view_compiler/tinyxml_layout_parser.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "tinyxml_layout_parser.h"
+
+#include "layout_validation.h"
+
+namespace startop {
+
+bool CanCompileLayout(const tinyxml2::XMLDocument& xml, std::string* message) {
+  LayoutValidationVisitor validator;
+  TinyXmlVisitorAdapter adapter{&validator};
+  xml.Accept(&adapter);
+
+  if (message != nullptr) {
+    *message = validator.message();
+  }
+
+  return validator.can_compile();
+}
+
+}  // namespace startop
diff --git a/startop/view_compiler/tinyxml_layout_parser.h b/startop/view_compiler/tinyxml_layout_parser.h
new file mode 100644
index 0000000..8f714a2
--- /dev/null
+++ b/startop/view_compiler/tinyxml_layout_parser.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef TINYXML_LAYOUT_PARSER_H_
+#define TINYXML_LAYOUT_PARSER_H_
+
+#include "tinyxml2.h"
+
+#include <codecvt>
+#include <locale>
+#include <string>
+
+namespace startop {
+
+template <typename Visitor>
+class TinyXmlVisitorAdapter : public tinyxml2::XMLVisitor {
+ public:
+  explicit TinyXmlVisitorAdapter(Visitor* visitor) : visitor_{visitor} {}
+
+  bool VisitEnter(const tinyxml2::XMLDocument& /*doc*/) override {
+    visitor_->VisitStartDocument();
+    return true;
+  }
+
+  bool VisitExit(const tinyxml2::XMLDocument& /*doc*/) override {
+    visitor_->VisitEndDocument();
+    return true;
+  }
+
+  bool VisitEnter(const tinyxml2::XMLElement& element,
+                  const tinyxml2::XMLAttribute* /*firstAttribute*/) override {
+    visitor_->VisitStartTag(
+        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
+            element.Name()));
+    return true;
+  }
+
+  bool VisitExit(const tinyxml2::XMLElement& /*element*/) override {
+    visitor_->VisitEndTag();
+    return true;
+  }
+
+ private:
+  Visitor* visitor_;
+};
+
+// Returns whether a layout resource represented by a TinyXML document is supported by the layout
+// compiler.
+bool CanCompileLayout(const tinyxml2::XMLDocument& xml, std::string* message = nullptr);
+
+}  // namespace startop
+
+#endif  // TINYXML_LAYOUT_PARSER_H_
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index bf0ffb9..36d0188 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -29,7 +29,6 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
-import java.lang.String;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
@@ -919,10 +918,16 @@
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
-            sb.append("[pa: ");
+            sb.append("[id: ");
+            sb.append(mTelecomCallId);
+            sb.append(", pa: ");
             sb.append(mAccountHandle);
             sb.append(", hdl: ");
-            sb.append(Log.pii(mHandle));
+            sb.append(Log.piiHandle(mHandle));
+            sb.append(", hdlPres: ");
+            sb.append(mHandlePresentation);
+            sb.append(", videoState: ");
+            sb.append(VideoProfile.videoStateToString(mVideoState));
             sb.append(", caps: ");
             sb.append(capabilitiesToString(mCallCapabilities));
             sb.append(", props: ");
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 7db6940..6628743 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -27,8 +27,8 @@
 import android.os.RemoteException;
 
 import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.ICallScreeningService;
 import com.android.internal.telecom.ICallScreeningAdapter;
+import com.android.internal.telecom.ICallScreeningService;
 
 /**
  * This service can be implemented by the default dialer (see
@@ -147,7 +147,7 @@
             private boolean mShouldSkipCallLog;
             private boolean mShouldSkipNotification;
 
-            /*
+            /**
              * Sets whether the incoming call should be blocked.
              */
             public Builder setDisallowCall(boolean shouldDisallowCall) {
@@ -155,7 +155,7 @@
                 return this;
             }
 
-            /*
+            /**
              * Sets whether the incoming call should be disconnected as if the user had manually
              * rejected it. This property should only be set to true if the call is disallowed.
              */
@@ -164,16 +164,20 @@
                 return this;
             }
 
-            /*
+            /**
              * Sets whether the incoming call should not be displayed in the call log. This property
              * should only be set to true if the call is disallowed.
+             * <p>
+             * Note: Calls will still be logged with type
+             * {@link android.provider.CallLog.Calls#BLOCKED_TYPE}, regardless of how this property
+             * is set.
              */
             public Builder setSkipCallLog(boolean shouldSkipCallLog) {
                 mShouldSkipCallLog = shouldSkipCallLog;
                 return this;
             }
 
-            /*
+            /**
              * Sets whether a missed call notification should not be shown for the incoming call.
              * This property should only be set to true if the call is disallowed.
              */
@@ -211,6 +215,17 @@
      * Called when a new incoming call is added.
      * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}
      * should be called to allow or disallow the call.
+     * <p>
+     * Note: The {@link Call.Details} instance provided to a call screening service will only have
+     * the following properties set.  The rest of the {@link Call.Details} properties will be set to
+     * their default value or {@code null}.
+     * <ul>
+     *     <li>{@link Call.Details#getState()}</li>
+     *     <li>{@link Call.Details#getConnectTimeMillis()}</li>
+     *     <li>{@link Call.Details#getCreationTimeMillis()}</li>
+     *     <li>{@link Call.Details#getHandle()}</li>
+     *     <li>{@link Call.Details#getHandlePresentation()}</li>
+     * </ul>
      *
      * @param callDetails Information about a new incoming call, see {@link Call.Details}.
      */
diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestion.aidl b/telecomm/java/android/telecom/PhoneAccountSuggestion.aidl
new file mode 100644
index 0000000..e2fa7e4
--- /dev/null
+++ b/telecomm/java/android/telecom/PhoneAccountSuggestion.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom;
+
+/**
+ * {@hide}
+  */
+parcelable PhoneAccountSuggestion;
\ No newline at end of file
diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestion.java b/telecomm/java/android/telecom/PhoneAccountSuggestion.java
index 4e6a178..b401bcf 100644
--- a/telecomm/java/android/telecom/PhoneAccountSuggestion.java
+++ b/telecomm/java/android/telecom/PhoneAccountSuggestion.java
@@ -24,6 +24,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 public final class PhoneAccountSuggestion implements Parcelable {
 
@@ -132,4 +133,19 @@
         dest.writeInt(mReason);
         dest.writeByte((byte) (mShouldAutoSelect ? 1 : 0));
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PhoneAccountSuggestion that = (PhoneAccountSuggestion) o;
+        return mReason == that.mReason
+                && mShouldAutoSelect == that.mShouldAutoSelect
+                && Objects.equals(mHandle, that.mHandle);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mHandle, mReason, mShouldAutoSelect);
+    }
 }
diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestionService.java b/telecomm/java/android/telecom/PhoneAccountSuggestionService.java
new file mode 100644
index 0000000..ba3822c
--- /dev/null
+++ b/telecomm/java/android/telecom/PhoneAccountSuggestionService.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom;
+
+import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.telecom.IPhoneAccountSuggestionCallback;
+import com.android.internal.telecom.IPhoneAccountSuggestionService;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base class for service that allows system apps to suggest phone accounts for outgoing calls.
+ *
+ * Phone account suggestions allow OEMs to intelligently select phone accounts based on knowledge
+ * about the user's past behavior, carrier billing patterns, or other factors unknown to the AOSP
+ * Telecom system.
+ * OEMs who wish to provide a phone account suggestion service on their device should implement this
+ * service in an app that resides in the /system/priv-app/ directory on their device. For security
+ * reasons, the service's entry {@code AndroidManifest.xml} file must declare the
+ * {@link android.Manifest.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE} permission:
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourServiceName"
+ *          android:permission="android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE">
+ *      <intent-filter>
+ *          <action android:name="android.telecom.PhoneAccountSuggestionService"/>
+ *      </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ * Only one system app on each device may implement this service. If multiple system apps implement
+ * this service, none of them will be queried for suggestions.
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class PhoneAccountSuggestionService extends Service {
+    /**
+     * The {@link Intent} that must be declared in the {@code intent-filter} element of the
+     * service's manifest entry.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
+
+    private IPhoneAccountSuggestionService mInterface = new IPhoneAccountSuggestionService.Stub() {
+        @Override
+        public void onAccountSuggestionRequest(IPhoneAccountSuggestionCallback callback,
+                String number) {
+            mCallbackMap.put(number, callback);
+            PhoneAccountSuggestionService.this.onAccountSuggestionRequest(number);
+        }
+    };
+
+    private final Map<String, IPhoneAccountSuggestionCallback> mCallbackMap =
+            new HashMap<>();
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mInterface.asBinder();
+    }
+
+    /**
+     * The system calls this method during the outgoing call flow if it needs account suggestions.
+     *
+     * The implementer of this service must override this method to implement its account suggestion
+     * logic. After preparing the suggestions, the implementation of the service must call
+     * {@link #suggestPhoneAccounts(String, List)} to deliver the suggestions back to the system.
+     *
+     * Note that the system will suspend the outgoing call process after it calls this method until
+     * this service calls {@link #suggestPhoneAccounts}.
+     *
+     * @param number The phone number to provide suggestions for.
+     */
+    public void onAccountSuggestionRequest(@NonNull String number) {}
+
+    /**
+     * The implementation of this service calls this method to deliver suggestions to the system.
+     *
+     * The implementation of this service must call this method after receiving a call to
+     * {@link #onAccountSuggestionRequest(String)}. If no suggestions are available, pass an empty
+     * list as the {@code suggestions} argument.
+     *
+     * @param number The phone number to provide suggestions for.
+     * @param suggestions The list of suggestions.
+     */
+    public final void suggestPhoneAccounts(@NonNull String number,
+            @NonNull List<PhoneAccountSuggestion> suggestions) {
+        IPhoneAccountSuggestionCallback callback = mCallbackMap.remove(number);
+        if (callback == null) {
+            Log.w(this, "No suggestions requested for the number %s", Log.pii(number));
+            return;
+        }
+        try {
+            callback.suggestPhoneAccounts(number, suggestions);
+        } catch (RemoteException e) {
+            Log.w(this, "Remote exception calling suggestPhoneAccounts");
+        }
+    }
+}
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index bbac8eb..7b23061 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -369,16 +369,13 @@
         }
 
         /**
-         * Create a call camera capabilities instance that optionally
-         * supports zoom.
+         * Create a call camera capabilities instance that optionally supports zoom.
          *
          * @param width The width of the camera video (in pixels).
          * @param height The height of the camera video (in pixels).
          * @param zoomSupported True when camera supports zoom.
          * @param maxZoom Maximum zoom supported by camera.
-         * @hide
          */
-        @UnsupportedAppUsage
         public CameraCapabilities(int width, int height, boolean zoomSupported, float maxZoom) {
             mWidth = width;
             mHeight = height;
@@ -455,16 +452,14 @@
         }
 
         /**
-         * Whether the camera supports zoom.
-         * @hide
+         * Returns {@code true} is zoom is supported, {@code false} otherwise.
          */
         public boolean isZoomSupported() {
             return mZoomSupported;
         }
 
         /**
-         * The maximum zoom supported by the camera.
-         * @hide
+         * Returns the maximum zoom supported by the camera.
          */
         public float getMaxZoom() {
             return mMaxZoom;
diff --git a/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl b/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl
new file mode 100644
index 0000000..cb14241
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecom;
+
+import android.telecom.PhoneAccountSuggestion;
+/**
+ * Internal remote callback interface for a phone acct suggestion service.
+ * @hide
+ */
+oneway interface IPhoneAccountSuggestionCallback{
+    void suggestPhoneAccounts(in String number, in List<PhoneAccountSuggestion> suggestions);
+}
diff --git a/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl b/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl
new file mode 100644
index 0000000..0ffab93
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecom;
+
+import com.android.internal.telecom.IPhoneAccountSuggestionCallback;
+
+/**
+ * Internal remote interface for a phone acct suggestion service.
+ * @hide
+ */
+oneway interface IPhoneAccountSuggestionService {
+    void onAccountSuggestionRequest(in IPhoneAccountSuggestionCallback callback,
+            in String number);
+}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index d64efea..6f1b66a 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -307,6 +307,8 @@
 
     void setTestDefaultCallRedirectionApp(String packageName);
 
+    void setTestPhoneAcctSuggestionComponent(String flattenedComponentName);
+
     void setTestDefaultCallScreeningApp(String packageName);
 
     void addOrRemoveTestCallCompanionApp(String packageName, boolean isAdded);
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 0b5aa14..3e4482e 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2668,10 +2668,26 @@
 
         /**
          * The {@code content://} style URL for this table.
+         * For MSIM, this will return APNs for the default subscription
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
+         * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
          */
         public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers");
 
         /**
+         * The {@code content://} style URL for this table. Used for APN query based on current
+         * subscription. Instead of specifying carrier matching information in the selection,
+         * this API will return all matching APNs from current subscription carrier and queries
+         * will be applied on top of that. If there is no match for MVNO (Mobile Virtual Network
+         * Operator) APNs, return APNs from its MNO (based on mccmnc) instead. For MSIM, this will
+         * return APNs for the default subscription
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
+         * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
+         */
+        public static final Uri SIM_APN_URI = Uri.parse(
+                "content://telephony/carriers/sim_apn_list");
+
+        /**
          * The {@code content://} style URL to be called from DevicePolicyManagerService,
          * can manage DPC-owned APNs.
          * @hide
@@ -2681,7 +2697,9 @@
         /**
          * The {@code content://} style URL to be called from Telephony to query APNs.
          * When DPC-owned APNs are enforced, only DPC-owned APNs are returned, otherwise only
-         * non-DPC-owned APNs are returned.
+         * non-DPC-owned APNs are returned. For MSIM, this will return APNs for the default
+         * subscription {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId
+         * for MSIM, use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
          * @hide
          */
         public static final Uri FILTERED_URI = Uri.parse("content://telephony/carriers/filtered");
@@ -2695,13 +2713,6 @@
                 "content://telephony/carriers/enforce_managed");
 
         /**
-         * The {@code content://} style URL to be called from Telephony to query current APNs.
-         * @hide
-         */
-        public static final Uri SIM_APN_LIST = Uri.parse(
-                "content://telephony/carriers/sim_apn_list");
-
-        /**
          * The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced.
          * @hide
          */
@@ -2775,18 +2786,30 @@
         /**
          * Mobile Country Code (MCC).
          * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify MCC and
+         * other carrier matching information. In the future, Android will not support MCC for
+         * APN query.
          */
         public static final String MCC = "mcc";
 
         /**
          * Mobile Network Code (MNC).
          * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify MNC and
+         * other carrier matching information. In the future, Android will not support MNC for
+         * APN query.
          */
         public static final String MNC = "mnc";
 
         /**
          * Numeric operator ID (as String). Usually {@code MCC + MNC}.
          * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify Numeric
+         * and other carrier matching information. In the future, Android will not support Numeric
+         * for APN query.
          */
         public static final String NUMERIC = "numeric";
 
@@ -2867,6 +2890,10 @@
          * MVNO type:
          * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
          * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify MVNO_TYPE
+         * and other carrier matching information. In the future, Android will not support MVNO_TYPE
+         * for APN query.
          */
         public static final String MVNO_TYPE = "mvno_type";
 
@@ -2879,6 +2906,10 @@
          *     <li>GID: 4E, 33, ...</li>
          * </ul>
          * <P>Type: TEXT</P>
+         * @deprecated Use {@link #SIM_APN_URI} to query APN instead, this API will return
+         * matching APNs based on current subscription carrier, thus no need to specify
+         * MVNO_MATCH_DATA and other carrier matching information. In the future, Android will not
+         * support MVNO_MATCH_DATA for APN query.
          */
         public static final String MVNO_MATCH_DATA = "mvno_match_data";
 
@@ -3087,7 +3118,6 @@
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface EditStatus {}
-
     }
 
     /**
@@ -3577,8 +3607,9 @@
 
         /**
          * Generates a content {@link Uri} used to receive updates on precise carrier identity
-         * change on the given subscriptionId
-         * {@link TelephonyManager#ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED}.
+         * change on the given subscriptionId returned by
+         * {@link TelephonyManager#getSimPreciseCarrierId()}.
+         * @see TelephonyManager#ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED
          * <p>
          * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
          * precise carrier identity {@link TelephonyManager#getSimPreciseCarrierId()}
@@ -3589,7 +3620,6 @@
          *
          * @param subscriptionId the subscriptionId to receive updates on
          * @return the Uri used to observe precise carrier identity changes
-         * @hide
          */
         public static Uri getPreciseCarrierIdUriForSubscriptionId(int subscriptionId) {
             return Uri.withAppendedPath(Uri.withAppendedPath(CONTENT_URI, "precise"),
@@ -3611,24 +3641,22 @@
         public static final String CARRIER_ID = "carrier_id";
 
         /**
-         * A user facing carrier name for precise carrier id.
-         * @see TelephonyManager#getSimPreciseCarrierIdName()
-         * This is not a database column, only used to notify content observers for
-         * {@link #getPreciseCarrierIdUriForSubscriptionId(int)}
-         * @hide
-         */
-        public static final String PRECISE_CARRIER_ID_NAME = "precise_carrier_id_name";
-
-        /**
          * A fine-grained carrier id.
          * @see TelephonyManager#getSimPreciseCarrierId()
          * This is not a database column, only used to notify content observers for
          * {@link #getPreciseCarrierIdUriForSubscriptionId(int)}
-         * @hide
          */
         public static final String PRECISE_CARRIER_ID = "precise_carrier_id";
 
         /**
+         * A user facing carrier name for precise carrier id {@link #PRECISE_CARRIER_ID}.
+         * @see TelephonyManager#getSimPreciseCarrierIdName()
+         * This is not a database column, only used to notify content observers for
+         * {@link #getPreciseCarrierIdUriForSubscriptionId(int)}
+         */
+        public static final String PRECISE_CARRIER_ID_NAME = "precise_carrier_id_name";
+
+        /**
          * A unique parent carrier id. The parent-child
          * relationship can be used to further differentiate a single carrier by different networks,
          * by prepaid v.s. postpaid or even by 4G v.s. 3G plan. It's an optional field.
@@ -3640,18 +3668,6 @@
         public static final String PARENT_CARRIER_ID = "parent_carrier_id";
 
         /**
-         * A unique mno carrier id. mno carrier shares the same {@link All#MCCMNC} as carrier id
-         * and can be solely identified by {@link All#MCCMNC} only. If there is no such mno
-         * carrier, then mno carrier id equals to {@link #CARRIER_ID carrier id}.
-         *
-         * <p>mno carrier id can be used as fallback id. When the exact carrier id configurations
-         * are not found, usually fall back to its mno carrier id.
-         * <P>Type: INTEGER </P>
-         * @hide
-         */
-        public static final String MNO_CARRIER_ID = "mno_carrier_id";
-
-        /**
          * Contains mappings between matching rules with carrier id for all carriers.
          * @hide
          */
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 14e0909..4561ea3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -68,7 +68,13 @@
      * This intent is broadcast by the system when carrier config changes. An int is specified in
      * {@link #EXTRA_SLOT_INDEX} to indicate the slot index that this is for. An optional int extra
      * {@link #EXTRA_SUBSCRIPTION_INDEX} is included to indicate the subscription index if a valid
-     * one is available for the slot index.
+     * one is available for the slot index. An optional int extra
+     * {@link TelephonyManager#EXTRA_CARRIER_ID} is included to indicate the carrier id for the
+     * changed carrier configuration. An optional int extra
+     * {@link TelephonyManager#EXTRA_PRECISE_CARRIER_ID} is included to indicate the precise
+     * carrier id for the changed carrier configuration.
+     * @see TelephonyManager#getSimCarrierId()
+     * @see TelephonyManager#getSimPreciseCarrierId()
      */
     public static final String
             ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
@@ -1392,9 +1398,9 @@
      * Example: "default"
      *
      * {@code ERROR_CODE_1} is an integer defined in
-     * {@link com.android.internal.telephony.dataconnection.DcFailCause DcFailure}
+     * {@link DataFailCause DcFailure}
      * Example:
-     * {@link com.android.internal.telephony.dataconnection.DcFailCause#MISSING_UNKNOWN_APN}
+     * {@link DataFailCause#MISSING_UNKNOWN_APN}
      *
      * {@code CARRIER_ACTION_IDX_1} is an integer defined in
      * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
@@ -1994,6 +2000,8 @@
      * Determine whether to use only RSRP for the number of LTE signal bars.
      * @hide
      */
+    // FIXME: this key and related keys must not be exposed without a consistent philosophy for
+    // all RATs.
     public static final String KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL =
             "use_only_rsrp_for_lte_signal_bar_bool";
 
@@ -2237,6 +2245,8 @@
      * Currently this only supports the value "rscp"
      * @hide
      */
+    // FIXME: this key and related keys must not be exposed without a consistent philosophy for
+    // all RATs.
     public static final String KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING =
             "wcdma_default_signal_strength_measurement_string";
 
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 598f567..fa19867 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -16,7 +16,6 @@
 
 package android.telephony;
 
-import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.cdma.CdmaCellLocation;
 
@@ -71,30 +70,13 @@
      *        to 2592000
      * @param lat Latitude is a decimal number ranges from -1296000
      *        to 1296000
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat) {
-        this(nid, sid, bid, lon, lat, null, null);
-    }
-
-    /**
-     * public constructor
-     * @param nid Network Id 0..65535
-     * @param sid CDMA System Id 0..32767
-     * @param bid Base Station Id 0..65535
-     * @param lon Longitude is a decimal number ranges from -2592000
-     *        to 2592000
-     * @param lat Latitude is a decimal number ranges from -1296000
-     *        to 1296000
      * @param alphal long alpha Operator Name String or Enhanced Operator Name String
      * @param alphas short alpha Operator Name String or Enhanced Operator Name String
      *
      * @hide
      */
-    public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat, String alphal,
-                             String alphas) {
+    public CellIdentityCdma(
+            int nid, int sid, int bid, int lon, int lat, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_CDMA, null, null, alphal, alphas);
         mNetworkId = nid;
         mSystemId = sid;
@@ -107,6 +89,17 @@
         }
     }
 
+    /** @hide */
+    public CellIdentityCdma(android.hardware.radio.V1_0.CellIdentityCdma cid) {
+        this(cid.networkId, cid.systemId, cid.baseStationId, cid.longitude, cid.latitude, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityCdma(android.hardware.radio.V1_2.CellIdentityCdma cid) {
+        this(cid.base.networkId, cid.base.systemId, cid.base.baseStationId, cid.base.longitude,
+                cid.base.latitude, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
+    }
+
     private CellIdentityCdma(CellIdentityCdma cid) {
         this(cid.mNetworkId, cid.mSystemId, cid.mBasestationId, cid.mLongitude, cid.mLatitude,
                 cid.mAlphaLong, cid.mAlphaShort);
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 04c28e5..9a24e47 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
@@ -35,10 +36,8 @@
     // 16-bit GSM Cell Identity described in TS 27.007, 0..65535
     private final int mCid;
     // 16-bit GSM Absolute RF Channel Number
-    @UnsupportedAppUsage
     private final int mArfcn;
     // 6-bit Base Station Identity Code
-    @UnsupportedAppUsage
     private final int mBsic;
 
     /**
@@ -52,34 +51,6 @@
         mArfcn = CellInfo.UNAVAILABLE;
         mBsic = CellInfo.UNAVAILABLE;
     }
-    /**
-     * public constructor
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535
-     * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
-     *
-     * @hide
-     */
-    public CellIdentityGsm(int mcc, int mnc, int lac, int cid) {
-        this(lac, cid, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
-                String.valueOf(mcc), String.valueOf(mnc), null, null);
-    }
-
-    /**
-     * public constructor
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535
-     * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
-     * @param arfcn 16-bit GSM Absolute RF Channel Number
-     * @param bsic 6-bit Base Station Identity Code
-     *
-     * @hide
-     */
-    public CellIdentityGsm(int mcc, int mnc, int lac, int cid, int arfcn, int bsic) {
-        this(lac, cid, arfcn, bsic, String.valueOf(mcc), String.valueOf(mnc), null, null);
-    }
 
     /**
      * public constructor
@@ -100,9 +71,21 @@
         mLac = lac;
         mCid = cid;
         mArfcn = arfcn;
-        // In RIL BSIC is a UINT8, so 0xFF is the 'INVALID' designator
-        // for inbound parcels
-        mBsic = (bsic == 0xFF) ? CellInfo.UNAVAILABLE : bsic;
+        mBsic = bsic;
+    }
+
+    /** @hide */
+    public CellIdentityGsm(android.hardware.radio.V1_0.CellIdentityGsm cid) {
+        this(cid.lac, cid.cid, cid.arfcn,
+                cid.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.bsic,
+                cid.mcc, cid.mnc, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityGsm(android.hardware.radio.V1_2.CellIdentityGsm cid) {
+        this(cid.base.lac, cid.base.cid, cid.base.arfcn,
+                cid.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.base.bsic, cid.base.mcc,
+                cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
     }
 
     private CellIdentityGsm(CellIdentityGsm cid) {
@@ -169,6 +152,7 @@
     /**
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown.
      */
+    @Nullable
     public String getMobileNetworkOperator() {
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 04b6a6c..d957d07 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
@@ -37,7 +38,6 @@
     // 16-bit tracking area code
     private final int mTac;
     // 18-bit Absolute RF Channel Number
-    @UnsupportedAppUsage
     private final int mEarfcn;
     // cell bandwidth, in kHz
     private final int mBandwidth;
@@ -73,22 +73,6 @@
 
     /**
      *
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param ci 28-bit Cell Identity
-     * @param pci Physical Cell Id 0..503
-     * @param tac 16-bit Tracking Area Code
-     * @param earfcn 18-bit LTE Absolute RF Channel Number
-     *
-     * @hide
-     */
-    public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac, int earfcn) {
-        this(ci, pci, tac, earfcn, CellInfo.UNAVAILABLE, String.valueOf(mcc), String.valueOf(mnc),
-                null, null);
-    }
-
-    /**
-     *
      * @param ci 28-bit Cell Identity
      * @param pci Physical Cell Id 0..503
      * @param tac 16-bit Tracking Area Code
@@ -111,6 +95,18 @@
         mBandwidth = bandwidth;
     }
 
+    /** @hide */
+    public CellIdentityLte(android.hardware.radio.V1_0.CellIdentityLte cid) {
+        this(cid.ci, cid.pci, cid.tac, cid.earfcn, CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityLte(android.hardware.radio.V1_2.CellIdentityLte cid) {
+        this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, cid.bandwidth,
+                cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
+                cid.operatorNames.alphaShort);
+    }
+
     private CellIdentityLte(CellIdentityLte cid) {
         this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBandwidth, cid.mMccStr,
                 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
@@ -197,6 +193,7 @@
     /**
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown.
      */
+    @Nullable
     public String getMobileNetworkOperator() {
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 8b1c1b9..3814333 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
 
@@ -50,22 +51,6 @@
     }
 
     /**
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown
-     * @param cid 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, CellInfo.
-     *        UNAVAILABLE if unknown
-     * @param cpid 8-bit Cell Parameters ID described in TS 25.331, 0..127, CellInfo.UNAVAILABLE
-     *        if unknown
-     * @param uarfcn 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3
-     *
-     * @hide
-     */
-    public CellIdentityTdscdma(int mcc, int mnc, int lac, int cid, int cpid, int uarfcn) {
-        this(String.valueOf(mcc), String.valueOf(mnc), lac, cid, cpid, uarfcn, null, null);
-    }
-
-    /**
      * @param mcc 3-digit Mobile Country Code in string format
      * @param mnc 2 or 3-digit Mobile Network Code in string format
      * @param lac 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown
@@ -93,6 +78,17 @@
                 cid.mCpid, cid.mUarfcn, cid.mAlphaLong, cid.mAlphaShort);
     }
 
+    /** @hide */
+    public CellIdentityTdscdma(android.hardware.radio.V1_0.CellIdentityTdscdma cid) {
+        this(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, CellInfo.UNAVAILABLE, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityTdscdma(android.hardware.radio.V1_2.CellIdentityTdscdma cid) {
+        this(cid.base.mcc, cid.base.mnc, cid.base.lac, cid.base.cid, cid.base.cpid,
+                cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
+    }
+
     CellIdentityTdscdma copy() {
         return new CellIdentityTdscdma(this);
     }
@@ -116,6 +112,7 @@
     /**
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
      */
+    @Nullable
     public String getMobileNetworkOperator() {
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 3416ffe..6e09784 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
@@ -50,35 +51,6 @@
         mPsc = CellInfo.UNAVAILABLE;
         mUarfcn = CellInfo.UNAVAILABLE;
     }
-    /**
-     * public constructor
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535
-     * @param cid 28-bit UMTS Cell Identity
-     * @param psc 9-bit UMTS Primary Scrambling Code
-     *
-     * @hide
-     */
-    public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc) {
-        this(lac, cid, psc, CellInfo.UNAVAILABLE, String.valueOf(mcc), String.valueOf(mnc),
-                null, null);
-    }
-
-    /**
-     * public constructor
-     * @param mcc 3-digit Mobile Country Code, 0..999
-     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
-     * @param lac 16-bit Location Area Code, 0..65535
-     * @param cid 28-bit UMTS Cell Identity
-     * @param psc 9-bit UMTS Primary Scrambling Code
-     * @param uarfcn 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3
-     *
-     * @hide
-     */
-    public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc, int uarfcn) {
-        this(lac, cid, psc, uarfcn, String.valueOf(mcc), String.valueOf(mnc), null, null);
-    }
 
     /**
      * public constructor
@@ -102,6 +74,18 @@
         mUarfcn = uarfcn;
     }
 
+    /** @hide */
+    public CellIdentityWcdma(android.hardware.radio.V1_0.CellIdentityWcdma cid) {
+        this(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc, "", "");
+    }
+
+    /** @hide */
+    public CellIdentityWcdma(android.hardware.radio.V1_2.CellIdentityWcdma cid) {
+        this(cid.base.lac, cid.base.cid, cid.base.psc, cid.base.uarfcn,
+                cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
+                cid.operatorNames.alphaShort);
+    }
+
     private CellIdentityWcdma(CellIdentityWcdma cid) {
         this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr,
                 cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
@@ -173,6 +157,7 @@
     /**
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
      */
+    @Nullable
     public String getMobileNetworkOperator() {
         return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index d0b2687..b761bd7 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -132,7 +132,8 @@
     /** Connection status is unknown. */
     public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE;
 
-    private int mCellConnectionStatus = CONNECTION_NONE;
+    /** A cell connection status */
+    private int mCellConnectionStatus;
 
     // True if device is mRegistered to the mobile network
     private boolean mRegistered;
@@ -144,6 +145,7 @@
     protected CellInfo() {
         this.mRegistered = false;
         this.mTimeStamp = Long.MAX_VALUE;
+        mCellConnectionStatus = CONNECTION_NONE;
     }
 
     /** @hide */
@@ -300,4 +302,44 @@
             return new CellInfo[size];
         }
     };
+
+    /** @hide */
+    protected CellInfo(android.hardware.radio.V1_0.CellInfo ci) {
+        this.mRegistered = ci.registered;
+        this.mTimeStamp = ci.timeStamp;
+        this.mCellConnectionStatus = CONNECTION_UNKNOWN;
+    }
+
+    /** @hide */
+    protected CellInfo(android.hardware.radio.V1_2.CellInfo ci) {
+        this.mRegistered = ci.registered;
+        this.mTimeStamp = ci.timeStamp;
+        this.mCellConnectionStatus = ci.connectionStatus;
+    }
+
+    /** @hide */
+    public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
+        if (ci == null) return null;
+        switch(ci.cellInfoType) {
+            case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
+            case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
+            case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
+            case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
+            case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
+            default: return null;
+        }
+    }
+
+    /** @hide */
+    public static CellInfo create(android.hardware.radio.V1_2.CellInfo ci) {
+        if (ci == null) return null;
+        switch(ci.cellInfoType) {
+            case android.hardware.radio.V1_0.CellInfoType.GSM: return new CellInfoGsm(ci);
+            case android.hardware.radio.V1_0.CellInfoType.CDMA: return new CellInfoCdma(ci);
+            case android.hardware.radio.V1_0.CellInfoType.LTE: return new CellInfoLte(ci);
+            case android.hardware.radio.V1_0.CellInfoType.WCDMA: return new CellInfoWcdma(ci);
+            case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: return new CellInfoTdscdma(ci);
+            default: return null;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index f67733d..8c76eae 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -48,6 +48,24 @@
         this.mCellSignalStrengthCdma = ci.mCellSignalStrengthCdma.copy();
     }
 
+    /** @hide */
+    public CellInfoCdma(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoCdma cic = ci.cdma.get(0);
+        mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+        mCellSignalStrengthCdma =
+            new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+    }
+
+    /** @hide */
+    public CellInfoCdma(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoCdma cic = ci.cdma.get(0);
+        mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+        mCellSignalStrengthCdma =
+            new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+    }
+
     @Override
     public CellIdentityCdma getCellIdentity() {
         return mCellIdentityCdma;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index 7211de1..ad16dfa 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -43,8 +43,24 @@
     /** @hide */
     public CellInfoGsm(CellInfoGsm ci) {
         super(ci);
-        this.mCellIdentityGsm = ci.mCellIdentityGsm.copy();
-        this.mCellSignalStrengthGsm = ci.mCellSignalStrengthGsm.copy();
+        mCellIdentityGsm = ci.mCellIdentityGsm.copy();
+        mCellSignalStrengthGsm = ci.mCellSignalStrengthGsm.copy();
+    }
+
+    /** @hide */
+    public CellInfoGsm(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoGsm cig = ci.gsm.get(0);
+        mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+        mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+    }
+
+    /** @hide */
+    public CellInfoGsm(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoGsm cig = ci.gsm.get(0);
+        mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+        mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 7d5388b..8ca6a1a 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -51,6 +51,24 @@
         this.mCellConfig = new CellConfigLte(ci.mCellConfig);
     }
 
+    /** @hide */
+    public CellInfoLte(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoLte cil = ci.lte.get(0);
+        mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
+        mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
+        mCellConfig = new CellConfigLte();
+    }
+
+    /** @hide */
+    public CellInfoLte(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoLte cil = ci.lte.get(0);
+        mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
+        mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
+        mCellConfig = new CellConfigLte();
+    }
+
     @Override
     public CellIdentityLte getCellIdentity() {
         if (DBG) log("getCellIdentity: " + mCellIdentityLte);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 40cadde..a8c49b7 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -48,8 +48,23 @@
         this.mCellSignalStrengthTdscdma = ci.mCellSignalStrengthTdscdma.copy();
     }
 
-    @Override
-    public CellIdentityTdscdma getCellIdentity() {
+    /** @hide */
+    public CellInfoTdscdma(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoTdscdma cit = ci.tdscdma.get(0);
+        mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+        mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+    }
+
+    /** @hide */
+    public CellInfoTdscdma(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.tdscdma.get(0);
+        mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+        mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+    }
+
+    @Override public CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
     }
     /** @hide */
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index 4f9dcb1..a427e80 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -47,6 +47,22 @@
         this.mCellSignalStrengthWcdma = ci.mCellSignalStrengthWcdma.copy();
     }
 
+    /** @hide */
+    public CellInfoWcdma(android.hardware.radio.V1_0.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_0.CellInfoWcdma ciw = ci.wcdma.get(0);
+        mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+    }
+
+    /** @hide */
+    public CellInfoWcdma(android.hardware.radio.V1_2.CellInfo ci) {
+        super(ci);
+        final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.wcdma.get(0);
+        mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+    }
+
     @Override
     public CellIdentityWcdma getCellIdentity() {
         return mCellIdentityWcdma;
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index afa4922..a18275f 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -16,6 +16,8 @@
 
 package android.telephony;
 
+import android.os.PersistableBundle;
+
 /**
  * Abstract base class for cell phone signal strength related information.
  */
@@ -80,9 +82,74 @@
      */
     public abstract CellSignalStrength copy();
 
+    /**
+     * Checks and returns whether there are any non-default values in this CellSignalStrength.
+     *
+     * Checks all the values in the subclass of CellSignalStrength and returns true if any of them
+     * have been set to a value other than their default.
+     *
+     * @hide
+     */
+    public abstract boolean isValid();
+
     @Override
     public abstract int hashCode();
 
     @Override
     public abstract boolean equals (Object o);
+
+    /**
+     * Calculate and set the carrier-influenced values such as the signal "Level".
+     *
+     * @hide
+     */
+    public abstract void updateLevel(PersistableBundle cc, ServiceState ss);
+
+    // Range for RSSI in ASU (0-31, 99) as defined in TS 27.007 8.69
+    /** @hide */
+    protected static final int getRssiDbmFromAsu(int asu) {
+        if (asu > 31 || asu < 0) return CellInfo.UNAVAILABLE;
+        return -113 + (2 * asu);
+    }
+
+    // Range for RSSI in ASU (0-31, 99) as defined in TS 27.007 8.69
+    /** @hide */
+    protected static final int getAsuFromRssiDbm(int dbm) {
+        if (dbm == CellInfo.UNAVAILABLE) return 99;
+        return (dbm / 2) + 113;
+    }
+
+    // Range for RSCP in ASU (0-96, 255) as defined in TS 27.007 8.69
+    /** @hide */
+    protected static final int getRscpDbmFromAsu(int asu) {
+        if (asu > 96 || asu < 0) return CellInfo.UNAVAILABLE;
+        return asu - 120;
+    }
+
+    // Range for RSCP in ASU (0-96, 255) as defined in TS 27.007 8.69
+    /** @hide */
+    protected static final int getAsuFromRscpDbm(int dbm) {
+        if (dbm == CellInfo.UNAVAILABLE) return 255;
+        return dbm + 120;
+    }
+
+    // Range for SNR in ASU (0-49, 255) as defined in TS 27.007 8.69
+    /** @hide */
+    protected static final int getEcNoDbFromAsu(int asu) {
+        if (asu > 49 || asu < 0) return CellInfo.UNAVAILABLE;
+        return -24 + (asu / 2);
+    }
+
+    /** @hide */
+    protected static final int inRangeOrUnavailable(int value, int rangeMin, int rangeMax) {
+        if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE;
+        return value;
+    }
+
+    /** @hide */
+    protected static final int inRangeOrUnavailable(
+            int value, int rangeMin, int rangeMax, int special) {
+        if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
+        return value;
+    }
 }
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 5123052..47faf1e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.telephony.Rlog;
 
 import java.util.Objects;
@@ -35,6 +36,7 @@
     private int mEvdoDbm;   // This value is the EVDO RSSI value
     private int mEvdoEcio;  // This value is the EVDO Ec/Io
     private int mEvdoSnr;   // Valid values are 0-8.  8 is the highest signal to noise ratio
+    private int mLevel;
 
     /** @hide */
     public CellSignalStrengthCdma() {
@@ -55,23 +57,29 @@
      * rather than left as -1, which is a departure from SignalStrength, which is stuck with the
      * values it currently reports.
      *
-     * @param cdmaDbm negative of the CDMA signal strength value or -1 if invalid.
-     * @param cdmaEcio negative of the CDMA pilot/noise ratio or -1 if invalid.
-     * @param evdoDbm negative of the EvDO signal strength value or -1 if invalid.
-     * @param evdoEcio negative of the EvDO pilot/noise ratio or -1 if invalid.
-     * @param evdoSnr an SNR value 0..8 or -1 if invalid.
+     * @param cdmaDbm CDMA signal strength value or CellInfo.UNAVAILABLE if invalid.
+     * @param cdmaEcio CDMA pilot/noise ratio or CellInfo.UNAVAILABLE  if invalid.
+     * @param evdoDbm negative of the EvDO signal strength value or CellInfo.UNAVAILABLE if invalid.
+     * @param evdoEcio negative of the EvDO pilot/noise ratio or CellInfo.UNAVAILABLE if invalid.
+     * @param evdoSnr an SNR value 0..8 or CellInfo.UNVAILABLE if invalid.
      * @hide
      */
     public CellSignalStrengthCdma(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio,
             int evdoSnr) {
-        // The values here were lifted from SignalStrength.validateInput()
-        // FIXME: Combine all checking and setting logic between this and SignalStrength.
-        mCdmaDbm = ((cdmaDbm > 0) && (cdmaDbm < 120))  ? -cdmaDbm : CellInfo.UNAVAILABLE;
-        mCdmaEcio = ((cdmaEcio > 0) && (cdmaEcio < 160)) ? -cdmaEcio : CellInfo.UNAVAILABLE;
+        mCdmaDbm = inRangeOrUnavailable(cdmaDbm, -120, 0);
+        mCdmaEcio = inRangeOrUnavailable(cdmaEcio, -160, 0);
+        mEvdoDbm = inRangeOrUnavailable(evdoDbm, -120, 0);
+        mEvdoEcio = inRangeOrUnavailable(evdoEcio, -160, 0);
+        mEvdoSnr = inRangeOrUnavailable(evdoSnr, 0, 8);
 
-        mEvdoDbm = ((evdoDbm > 0) && (evdoDbm < 120)) ? -evdoDbm : CellInfo.UNAVAILABLE;
-        mEvdoEcio = ((evdoEcio > 0) && (evdoEcio < 160)) ? -evdoEcio : CellInfo.UNAVAILABLE;
-        mEvdoSnr = ((evdoSnr > 0) && (evdoSnr <= 8)) ? evdoSnr : CellInfo.UNAVAILABLE;
+        updateLevel(null, null);
+    }
+
+    /** @hide */
+    public CellSignalStrengthCdma(android.hardware.radio.V1_0.CdmaSignalStrength cdma,
+            android.hardware.radio.V1_0.EvdoSignalStrength evdo) {
+        // Convert from HAL values as part of construction.
+        this(-cdma.dbm, -cdma.ecio, -evdo.dbm, -evdo.ecio, evdo.signalNoiseRatio);
     }
 
     /** @hide */
@@ -86,6 +94,7 @@
         mEvdoDbm = s.mEvdoDbm;
         mEvdoEcio = s.mEvdoEcio;
         mEvdoSnr = s.mEvdoSnr;
+        mLevel = s.mLevel;
     }
 
     /** @hide */
@@ -102,6 +111,7 @@
         mEvdoDbm = CellInfo.UNAVAILABLE;
         mEvdoEcio = CellInfo.UNAVAILABLE;
         mEvdoSnr = CellInfo.UNAVAILABLE;
+        mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
     /**
@@ -112,26 +122,54 @@
      */
     @Override
     public int getLevel() {
-        int level;
+        return mLevel;
+    }
 
+    /** @hide */
+    @Override
+    public void updateLevel(PersistableBundle cc, ServiceState ss) {
         int cdmaLevel = getCdmaLevel();
         int evdoLevel = getEvdoLevel();
         if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
             /* We don't know evdo, use cdma */
-            level = getCdmaLevel();
+            mLevel = getCdmaLevel();
         } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
             /* We don't know cdma, use evdo */
-            level = getEvdoLevel();
+            mLevel = getEvdoLevel();
         } else {
             /* We know both, use the lowest level */
-            level = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
+            mLevel = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
         }
-        if (DBG) log("getLevel=" + level);
-        return level;
     }
 
     /**
-     * Get the signal level as an asu value between 0..97, 99 is unknown
+     * Get the 1xRTT Level in (Android) ASU.
+     *
+     * There is no standard definition of ASU for CDMA; however, Android defines it as the
+     * the lesser of the following two results (for 1xRTT):
+     * <table>
+     *     <thead><tr><th>RSSI Range (dBm)</th><th>ASU Value</th></tr><thead>
+     *     <tbody>
+     *         <tr><td>-75..</td><td>16</td></tr>
+     *         <tr><td>-82..-76</td><td>8</td></tr>
+     *         <tr><td>-90..-83</td><td>4</td></tr>
+     *         <tr><td>-95..-91</td><td>2</td></tr>
+     *         <tr><td>-100..-96</td><td>1</td></tr>
+     *         <tr><td>..-101</td><td>99</td></tr>
+     *     </tbody>
+     * </table>
+     * <table>
+     *     <thead><tr><th>Ec/Io Range (dB)</th><th>ASU Value</th></tr><thead>
+     *     <tbody>
+     *         <tr><td>-90..</td><td>16</td></tr>
+     *         <tr><td>-100..-91</td><td>8</td></tr>
+     *         <tr><td>-115..-101</td><td>4</td></tr>
+     *         <tr><td>-130..-116</td><td>2</td></tr>
+     *         <tr><td>--150..-131</td><td>1</td></tr>
+     *         <tr><td>..-151</td><td>99</td></tr>
+     *     </tbody>
+     * </table>
+     * @return 1xRTT Level in Android ASU {1,2,4,8,16,99}
      */
     @Override
     public int getAsuLevel() {
@@ -220,6 +258,63 @@
     }
 
     /**
+     * Get the EVDO Level in (Android) ASU.
+     *
+     * There is no standard definition of ASU for CDMA; however, Android defines it as the
+     * the lesser of the following two results (for EVDO):
+     * <table>
+     *     <thead><tr><th>RSSI Range (dBm)</th><th>ASU Value</th></tr><thead>
+     *     <tbody>
+     *         <tr><td>-65..</td><td>16</td></tr>
+     *         <tr><td>-75..-66</td><td>8</td></tr>
+     *         <tr><td>-85..-76</td><td>4</td></tr>
+     *         <tr><td>-95..-86</td><td>2</td></tr>
+     *         <tr><td>-105..-96</td><td>1</td></tr>
+     *         <tr><td>..-106</td><td>99</td></tr>
+     *     </tbody>
+     * </table>
+     * <table>
+     *     <thead><tr><th>SNR Range (unitless)</th><th>ASU Value</th></tr><thead>
+     *     <tbody>
+     *         <tr><td>7..</td><td>16</td></tr>
+     *         <tr><td>6</td><td>8</td></tr>
+     *         <tr><td>5</td><td>4</td></tr>
+     *         <tr><td>3..4</td><td>2</td></tr>
+     *         <tr><td>1..2</td><td>1</td></tr>
+     *         <tr><td>0</td><td>99</td></tr>
+     *     </tbody>
+     * </table>
+     *
+     * @return EVDO Level in Android ASU {1,2,4,8,16,99}
+     *
+     * @hide
+     */
+    public int getEvdoAsuLevel() {
+        int evdoDbm = getEvdoDbm();
+        int evdoSnr = getEvdoSnr();
+        int levelEvdoDbm;
+        int levelEvdoSnr;
+
+        if (evdoDbm >= -65) levelEvdoDbm = 16;
+        else if (evdoDbm >= -75) levelEvdoDbm = 8;
+        else if (evdoDbm >= -85) levelEvdoDbm = 4;
+        else if (evdoDbm >= -95) levelEvdoDbm = 2;
+        else if (evdoDbm >= -105) levelEvdoDbm = 1;
+        else levelEvdoDbm = 99;
+
+        if (evdoSnr >= 7) levelEvdoSnr = 16;
+        else if (evdoSnr >= 6) levelEvdoSnr = 8;
+        else if (evdoSnr >= 5) levelEvdoSnr = 4;
+        else if (evdoSnr >= 3) levelEvdoSnr = 2;
+        else if (evdoSnr >= 1) levelEvdoSnr = 1;
+        else levelEvdoSnr = 99;
+
+        int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
+        if (DBG) log("getEvdoAsuLevel=" + level);
+        return level;
+    }
+
+    /**
      * Get the signal strength as dBm
      */
     @Override
@@ -237,6 +332,7 @@
     public int getCdmaDbm() {
         return mCdmaDbm;
     }
+
     /** @hide */
     public void setCdmaDbm(int cdmaDbm) {
         mCdmaDbm = cdmaDbm;
@@ -248,6 +344,7 @@
     public int getCdmaEcio() {
         return mCdmaEcio;
     }
+
     /** @hide */
     public void setCdmaEcio(int cdmaEcio) {
         mCdmaEcio = cdmaEcio;
@@ -259,6 +356,7 @@
     public int getEvdoDbm() {
         return mEvdoDbm;
     }
+
     /** @hide */
     public void setEvdoDbm(int evdoDbm) {
         mEvdoDbm = evdoDbm;
@@ -270,6 +368,7 @@
     public int getEvdoEcio() {
         return mEvdoEcio;
     }
+
     /** @hide */
     public void setEvdoEcio(int evdoEcio) {
         mEvdoEcio = evdoEcio;
@@ -281,6 +380,7 @@
     public int getEvdoSnr() {
         return mEvdoSnr;
     }
+
     /** @hide */
     public void setEvdoSnr(int evdoSnr) {
         mEvdoSnr = evdoSnr;
@@ -288,28 +388,29 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mCdmaDbm, mCdmaEcio, mEvdoDbm, mEvdoEcio, mEvdoSnr);
+        return Objects.hash(mCdmaDbm, mCdmaEcio, mEvdoDbm, mEvdoEcio, mEvdoSnr, mLevel);
+    }
+
+    private static final CellSignalStrengthCdma sInvalid = new CellSignalStrengthCdma();
+
+    /** @hide */
+    @Override
+    public boolean isValid() {
+        return !this.equals(sInvalid);
     }
 
     @Override
     public boolean equals (Object o) {
         CellSignalStrengthCdma s;
-
-        try {
-            s = (CellSignalStrengthCdma) o;
-        } catch (ClassCastException ex) {
-            return false;
-        }
-
-        if (o == null) {
-            return false;
-        }
+        if (!(o instanceof CellSignalStrengthCdma)) return false;
+        s = (CellSignalStrengthCdma) o;
 
         return mCdmaDbm == s.mCdmaDbm
                 && mCdmaEcio == s.mCdmaEcio
                 && mEvdoDbm == s.mEvdoDbm
                 && mEvdoEcio == s.mEvdoEcio
-                && mEvdoSnr == s.mEvdoSnr;
+                && mEvdoSnr == s.mEvdoSnr
+                && mLevel == s.mLevel;
     }
 
     /**
@@ -322,7 +423,8 @@
                 + " cdmaEcio=" + mCdmaEcio
                 + " evdoDbm=" + mEvdoDbm
                 + " evdoEcio=" + mEvdoEcio
-                + " evdoSnr=" + mEvdoSnr;
+                + " evdoSnr=" + mEvdoSnr
+                + " level=" + mLevel;
     }
 
     /** Implement the Parcelable interface */
@@ -334,6 +436,7 @@
         dest.writeInt(mEvdoDbm);
         dest.writeInt(mEvdoEcio);
         dest.writeInt(mEvdoSnr);
+        dest.writeInt(mLevel);
     }
 
     /**
@@ -349,6 +452,7 @@
         mEvdoDbm = in.readInt();
         mEvdoEcio = in.readInt();
         mEvdoSnr = in.readInt();
+        mLevel = in.readInt();
         if (DBG) log("CellSignalStrengthCdma(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index e906f46..7b29f69 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -19,6 +19,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.telephony.Rlog;
 
 import java.util.Objects;
@@ -31,16 +32,18 @@
     private static final String LOG_TAG = "CellSignalStrengthGsm";
     private static final boolean DBG = false;
 
-    private static final int GSM_SIGNAL_STRENGTH_GREAT = 12;
-    private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
-    private static final int GSM_SIGNAL_STRENGTH_MODERATE = 5;
+    private static final int GSM_RSSI_MAX = -51;
+    private static final int GSM_RSSI_GREAT = -89;
+    private static final int GSM_RSSI_GOOD = -97;
+    private static final int GSM_RSSI_MODERATE = -103;
+    private static final int GSM_RSSI_POOR = -107;
 
+    private int mRssi; // in dBm [-113, -51] or UNAVAILABLE
     @UnsupportedAppUsage
-    private int mSignalStrength; // in ASU; Valid values are (0-31, 99) as defined in TS 27.007 8.5
-    @UnsupportedAppUsage
-    private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
-    @UnsupportedAppUsage
+    private int mBitErrorRate; // bit error rate (0-7, 99) TS 27.007 8.5 or UNAVAILABLE
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
     private int mTimingAdvance; // range from 0-219 or CellInfo.UNAVAILABLE if unknown
+    private int mLevel;
 
     /** @hide */
     @UnsupportedAppUsage
@@ -49,15 +52,17 @@
     }
 
     /** @hide */
-    public CellSignalStrengthGsm(int ss, int ber) {
-        this(ss, ber, CellInfo.UNAVAILABLE);
+    public CellSignalStrengthGsm(int rssi, int ber, int ta) {
+        mRssi = inRangeOrUnavailable(rssi, -113, -51);
+        mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99);
+        mTimingAdvance = inRangeOrUnavailable(ta, 0, 219);
+        updateLevel(null, null);
     }
 
     /** @hide */
-    public CellSignalStrengthGsm(int ss, int ber, int ta) {
-        mSignalStrength = ss;
-        mBitErrorRate = ber;
-        mTimingAdvance = ta;
+    public CellSignalStrengthGsm(android.hardware.radio.V1_0.GsmSignalStrength gsm) {
+        // Convert from HAL values as part of construction.
+        this(getRssiDbmFromAsu(gsm.signalStrength), gsm.bitErrorRate, gsm.timingAdvance);
     }
 
     /** @hide */
@@ -67,9 +72,10 @@
 
     /** @hide */
     protected void copyFrom(CellSignalStrengthGsm s) {
-        mSignalStrength = s.mSignalStrength;
+        mRssi = s.mRssi;
         mBitErrorRate = s.mBitErrorRate;
         mTimingAdvance = s.mTimingAdvance;
+        mLevel = s.mLevel;
     }
 
     /** @hide */
@@ -81,9 +87,10 @@
     /** @hide */
     @Override
     public void setDefaultValues() {
-        mSignalStrength = CellInfo.UNAVAILABLE;
+        mRssi = CellInfo.UNAVAILABLE;
         mBitErrorRate = CellInfo.UNAVAILABLE;
         mTimingAdvance = CellInfo.UNAVAILABLE;
+        mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
     /**
@@ -94,20 +101,18 @@
      */
     @Override
     public int getLevel() {
-        int level;
+        return mLevel;
+    }
 
-        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-        // asu = 0 (-113dB or less) is very weak
-        // signal, its better to show 0 bars to the user in such cases.
-        // asu = 99 is a special case, where the signal strength is unknown.
-        int asu = mSignalStrength;
-        if (asu <= 2 || asu == 99) level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (asu >= GSM_SIGNAL_STRENGTH_GREAT) level = SIGNAL_STRENGTH_GREAT;
-        else if (asu >= GSM_SIGNAL_STRENGTH_GOOD)  level = SIGNAL_STRENGTH_GOOD;
-        else if (asu >= GSM_SIGNAL_STRENGTH_MODERATE)  level = SIGNAL_STRENGTH_MODERATE;
-        else level = SIGNAL_STRENGTH_POOR;
-        if (DBG) log("getLevel=" + level);
-        return level;
+    /** @hide */
+    @Override
+    public void updateLevel(PersistableBundle cc, ServiceState ss) {
+        if (mRssi > GSM_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (mRssi >= GSM_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mRssi >= GSM_RSSI_GOOD)  mLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mRssi >= GSM_RSSI_MODERATE)  mLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mRssi >= GSM_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR;
+        else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
     /**
@@ -126,55 +131,52 @@
      */
     @Override
     public int getDbm() {
-        int dBm;
-
-        int level = mSignalStrength;
-        int asu = (level == 99 ? CellInfo.UNAVAILABLE : level);
-        if (asu != CellInfo.UNAVAILABLE) {
-            dBm = -113 + (2 * asu);
-        } else {
-            dBm = CellInfo.UNAVAILABLE;
-        }
-        if (DBG) log("getDbm=" + dBm);
-        return dBm;
+        return mRssi;
     }
 
     /**
-     * Get the signal level as an asu value between 0..31, 99 is unknown
+     * Get the RSSI in ASU.
+     *
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     *
+     * @return RSSI in ASU 0..31, 99, or UNAVAILABLE
      */
     @Override
     public int getAsuLevel() {
-        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-        // asu = 0 (-113dB or less) is very weak
-        // signal, its better to show 0 bars to the user in such cases.
-        // asu = 99 is a special case, where the signal strength is unknown.
-        int level = mSignalStrength;
-        if (DBG) log("getAsuLevel=" + level);
-        return level;
+        return getAsuFromRssiDbm(mRssi);
+    }
+
+    /**
+     * Return the Bit Error Rate
+     * @returns the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or UNAVAILABLE.
+     * @hide
+     */
+    public int getBitErrorRate() {
+        return mBitErrorRate;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSignalStrength, mBitErrorRate, mTimingAdvance);
+        return Objects.hash(mRssi, mBitErrorRate, mTimingAdvance);
+    }
+
+    private static final CellSignalStrengthGsm sInvalid = new CellSignalStrengthGsm();
+
+    /** @hide */
+    @Override
+    public boolean isValid() {
+        return !this.equals(sInvalid);
     }
 
     @Override
-    public boolean equals (Object o) {
-        CellSignalStrengthGsm s;
+    public boolean equals(Object o) {
+        if (!(o instanceof CellSignalStrengthGsm)) return false;
+        CellSignalStrengthGsm s = (CellSignalStrengthGsm) o;
 
-        try {
-            s = (CellSignalStrengthGsm) o;
-        } catch (ClassCastException ex) {
-            return false;
-        }
-
-        if (o == null) {
-            return false;
-        }
-
-        return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate &&
-                        s.mTimingAdvance == mTimingAdvance;
+        return mRssi == s.mRssi
+                && mBitErrorRate == s.mBitErrorRate
+                && mTimingAdvance == s.mTimingAdvance
+                && mLevel == s.mLevel;
     }
 
     /**
@@ -183,18 +185,20 @@
     @Override
     public String toString() {
         return "CellSignalStrengthGsm:"
-                + " ss=" + mSignalStrength
+                + " rssi=" + mRssi
                 + " ber=" + mBitErrorRate
-                + " mTa=" + mTimingAdvance;
+                + " mTa=" + mTimingAdvance
+                + " mLevel=" + mLevel;
     }
 
     /** Implement the Parcelable interface */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
-        dest.writeInt(mSignalStrength);
+        dest.writeInt(mRssi);
         dest.writeInt(mBitErrorRate);
         dest.writeInt(mTimingAdvance);
+        dest.writeInt(mLevel);
     }
 
     /**
@@ -202,9 +206,10 @@
      * where the token is already been processed.
      */
     private CellSignalStrengthGsm(Parcel in) {
-        mSignalStrength = in.readInt();
+        mRssi = in.readInt();
         mBitErrorRate = in.readInt();
         mTimingAdvance = in.readInt();
+        mLevel = in.readInt();
         if (DBG) log("CellSignalStrengthGsm(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index d075394..893dbe3 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -19,7 +19,9 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -28,7 +30,7 @@
 public final class CellSignalStrengthLte extends CellSignalStrength implements Parcelable {
 
     private static final String LOG_TAG = "CellSignalStrengthLte";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
 
     /**
      * Indicates the unknown or undetectable RSSI value in ASU.
@@ -49,18 +51,23 @@
      */
     private static final int SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MIN_VALUE = 0;
 
-    @UnsupportedAppUsage
-    private int mSignalStrength;
-    @UnsupportedAppUsage
+    private static final int MAX_LTE_RSRP = -44;
+    private static final int MIN_LTE_RSRP = -140;
+
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
+    private int mSignalStrength; // To be removed
+    private int mRssi;
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
     private int mRsrp;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
     private int mRsrq;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
     private int mRssnr;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
     private int mCqi;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
     private int mTimingAdvance;
+    private int mLevel;
 
     /** @hide */
     @UnsupportedAppUsage
@@ -68,15 +75,38 @@
         setDefaultValues();
     }
 
+    /**
+     * Construct a cell signal strength
+     *
+     * @param rssi in dBm [-113,-51], UNKNOWN
+     * @param rsrp in dBm [-140,-43], UNKNOWN
+     * @param rsrq in dB [-20,-3], UNKNOWN
+     * @param rssnr in 10*dB [-200, +300], UNKNOWN
+     * @param cqi [0, 15], UNKNOWN
+     * @param timingAdvance [0, 1282], UNKNOWN
+     *
+     */
     /** @hide */
-    public CellSignalStrengthLte(int signalStrength, int rsrp, int rsrq, int rssnr, int cqi,
+    public CellSignalStrengthLte(int rssi, int rsrp, int rsrq, int rssnr, int cqi,
             int timingAdvance) {
-        mSignalStrength = signalStrength;
-        mRsrp = rsrp;
-        mRsrq = rsrq;
-        mRssnr = rssnr;
-        mCqi = cqi;
-        mTimingAdvance = timingAdvance;
+
+        mRssi = inRangeOrUnavailable(rssi, -113, -51);
+        mSignalStrength = mRssi;
+        mRsrp = inRangeOrUnavailable(rsrp, -140, -43);
+        mRsrq = inRangeOrUnavailable(rsrq, -20, -3);
+        mRssnr = inRangeOrUnavailable(rssnr, -200, 300);
+        mCqi = inRangeOrUnavailable(cqi, 0, 15);
+        mTimingAdvance = inRangeOrUnavailable(timingAdvance, 0, 1282);
+        updateLevel(null, null);
+    }
+
+    /** @hide */
+    public CellSignalStrengthLte(android.hardware.radio.V1_0.LteSignalStrength lte) {
+        // Convert from HAL values as part of construction.
+        this(convertRssiAsuToDBm(lte.signalStrength),
+                lte.rsrp != CellInfo.UNAVAILABLE ? -lte.rsrp : lte.rsrp,
+                lte.rsrq != CellInfo.UNAVAILABLE ? -lte.rsrq : lte.rsrq,
+                lte.rssnr, lte.cqi, lte.timingAdvance);
     }
 
     /** @hide */
@@ -87,11 +117,13 @@
     /** @hide */
     protected void copyFrom(CellSignalStrengthLte s) {
         mSignalStrength = s.mSignalStrength;
+        mRssi = s.mRssi;
         mRsrp = s.mRsrp;
         mRsrq = s.mRsrq;
         mRssnr = s.mRssnr;
         mCqi = s.mCqi;
         mTimingAdvance = s.mTimingAdvance;
+        mLevel = s.mLevel;
     }
 
     /** @hide */
@@ -104,11 +136,13 @@
     @Override
     public void setDefaultValues() {
         mSignalStrength = CellInfo.UNAVAILABLE;
+        mRssi = CellInfo.UNAVAILABLE;
         mRsrp = CellInfo.UNAVAILABLE;
         mRsrq = CellInfo.UNAVAILABLE;
         mRssnr = CellInfo.UNAVAILABLE;
         mCqi = CellInfo.UNAVAILABLE;
         mTimingAdvance = CellInfo.UNAVAILABLE;
+        mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
     /**
@@ -119,34 +153,106 @@
      */
     @Override
     public int getLevel() {
-        int levelRsrp = 0;
-        int levelRssnr = 0;
+        return mLevel;
+    }
 
-        if (mRsrp == CellInfo.UNAVAILABLE) levelRsrp = 0;
-        else if (mRsrp >= -95) levelRsrp = SIGNAL_STRENGTH_GREAT;
-        else if (mRsrp >= -105) levelRsrp = SIGNAL_STRENGTH_GOOD;
-        else if (mRsrp >= -115) levelRsrp = SIGNAL_STRENGTH_MODERATE;
-        else levelRsrp = SIGNAL_STRENGTH_POOR;
+    // Lifted from Default carrier configs and max range of RSRP
+    private static final int[] sThresholds = new int[]{-115, -105, -95, -85};
+    private static final int sRsrpBoost = 0;
 
-        // See RIL_LTE_SignalStrength in ril.h
-        if (mRssnr == CellInfo.UNAVAILABLE) levelRssnr = 0;
-        else if (mRssnr >= 45) levelRssnr = SIGNAL_STRENGTH_GREAT;
-        else if (mRssnr >= 10) levelRssnr = SIGNAL_STRENGTH_GOOD;
-        else if (mRssnr >= -30) levelRssnr = SIGNAL_STRENGTH_MODERATE;
-        else levelRssnr = SIGNAL_STRENGTH_POOR;
-
-        int level;
-        if (mRsrp == CellInfo.UNAVAILABLE) {
-            level = levelRssnr;
-        } else if (mRssnr == CellInfo.UNAVAILABLE) {
-            level = levelRsrp;
+    /** @hide */
+    @Override
+    public void updateLevel(PersistableBundle cc, ServiceState ss) {
+        int[] thresholds;
+        boolean rsrpOnly;
+        if (cc == null) {
+            thresholds = sThresholds;
+            rsrpOnly = false;
         } else {
-            level = (levelRssnr < levelRsrp) ? levelRssnr : levelRsrp;
+            rsrpOnly = cc.getBoolean(
+                    CarrierConfigManager.KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL, false);
+            thresholds = cc.getIntArray(
+                    CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY);
+            if (thresholds == null) thresholds = sThresholds;
+            if (DBG) log("updateLevel() carrierconfig - rsrpOnly="
+                    + rsrpOnly + ", thresholds=" + Arrays.toString(thresholds));
         }
 
-        if (DBG) log("Lte rsrp level: " + levelRsrp
-                + " snr level: " + levelRssnr + " level: " + level);
-        return level;
+
+        int rsrpBoost = 0;
+        if (ss != null) {
+            rsrpBoost = ss.getLteEarfcnRsrpBoost();
+        }
+
+        int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        int rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        int snrIconLevel = -1;
+
+        int rsrp = mRsrp + rsrpBoost;
+
+        if (rsrp < MIN_LTE_RSRP || rsrp > MAX_LTE_RSRP) {
+            rsrpIconLevel = -1;
+        } else {
+            rsrpIconLevel = thresholds.length;
+            while (rsrpIconLevel > 0 && rsrp < thresholds[rsrpIconLevel - 1]) rsrpIconLevel--;
+        }
+
+        if (rsrpOnly) {
+            if (DBG) log("updateLevel() - rsrp = " + rsrpIconLevel);
+            if (rsrpIconLevel != -1) {
+                mLevel = rsrpIconLevel;
+                return;
+            }
+        }
+
+        /*
+         * Values are -200 dB to +300 (SNR*10dB) RS_SNR >= 13.0 dB =>4 bars 4.5
+         * dB <= RS_SNR < 13.0 dB => 3 bars 1.0 dB <= RS_SNR < 4.5 dB => 2 bars
+         * -3.0 dB <= RS_SNR < 1.0 dB 1 bar RS_SNR < -3.0 dB/No Service Antenna
+         * Icon Only
+         */
+        if (mRssnr > 300) snrIconLevel = -1;
+        else if (mRssnr >= 130) snrIconLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mRssnr >= 45) snrIconLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mRssnr >= 10) snrIconLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mRssnr >= -30) snrIconLevel = SIGNAL_STRENGTH_POOR;
+        else if (mRssnr >= -200)
+            snrIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+
+        if (DBG) log("updateLevel() - rsrp:" + mRsrp + " snr:" + mRssnr + " rsrpIconLevel:"
+                + rsrpIconLevel + " snrIconLevel:" + snrIconLevel
+                + " lteRsrpBoost:" + sRsrpBoost);
+
+        /* Choose a measurement type to use for notification */
+        if (snrIconLevel != -1 && rsrpIconLevel != -1) {
+            /*
+             * The number of bars displayed shall be the smaller of the bars
+             * associated with LTE RSRP and the bars associated with the LTE
+             * RS_SNR
+             */
+            mLevel = (rsrpIconLevel < snrIconLevel ? rsrpIconLevel : snrIconLevel);
+            return;
+        }
+
+        if (snrIconLevel != -1) {
+            mLevel = snrIconLevel;
+            return;
+        }
+
+        if (rsrpIconLevel != -1) {
+            mLevel = rsrpIconLevel;
+            return;
+        }
+
+        if (mRssi > -51) rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (mRssi >= -89) rssiIconLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mRssi >= -97) rssiIconLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mRssi >= -103) rssiIconLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mRssi >= -113) rssiIconLevel = SIGNAL_STRENGTH_POOR;
+        else rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        if (DBG) log("getLteLevel - rssi:" + mRssi + " rssiIconLevel:"
+                + rssiIconLevel);
+        mLevel = rssiIconLevel;
     }
 
     /**
@@ -169,7 +275,7 @@
      * @return the RSSI if available or {@link CellInfo#UNAVAILABLE} if unavailable.
      */
     public int getRssi() {
-        return convertRssiAsuToDBm(mSignalStrength);
+        return mRssi;
     }
 
     /**
@@ -212,13 +318,16 @@
     }
 
     /**
-     * Get the LTE signal level as an asu value between 0..97, 99 is unknown
+     * Get the RSRP in ASU.
+     *
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     *
+     * @return RSCP in ASU 0..97, 255, or UNAVAILABLE
      */
     @Override
     public int getAsuLevel() {
         int lteAsuLevel = 99;
-        int lteDbm = getDbm();
+        int lteDbm = mRsrp;
         if (lteDbm == CellInfo.UNAVAILABLE) lteAsuLevel = 99;
         else if (lteDbm <= -140) lteAsuLevel = 0;
         else if (lteDbm >= -43) lteAsuLevel = 97;
@@ -241,29 +350,31 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSignalStrength, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance);
+        return Objects.hash(mRssi, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance, mLevel);
+    }
+
+    private static final CellSignalStrengthLte sInvalid = new CellSignalStrengthLte();
+
+    /** @hide */
+    @Override
+    public boolean isValid() {
+        return !this.equals(sInvalid);
     }
 
     @Override
     public boolean equals (Object o) {
         CellSignalStrengthLte s;
 
-        try {
-            s = (CellSignalStrengthLte) o;
-        } catch (ClassCastException ex) {
-            return false;
-        }
+        if (!(o instanceof CellSignalStrengthLte)) return false;
+        s = (CellSignalStrengthLte) o;
 
-        if (o == null) {
-            return false;
-        }
-
-        return mSignalStrength == s.mSignalStrength
+        return mRssi == s.mRssi
                 && mRsrp == s.mRsrp
                 && mRsrq == s.mRsrq
                 && mRssnr == s.mRssnr
                 && mCqi == s.mCqi
-                && mTimingAdvance == s.mTimingAdvance;
+                && mTimingAdvance == s.mTimingAdvance
+                && mLevel == s.mLevel;
     }
 
     /**
@@ -272,27 +383,29 @@
     @Override
     public String toString() {
         return "CellSignalStrengthLte:"
-                + " ss=" + mSignalStrength
+                + " rssi=" + mRssi
                 + " rsrp=" + mRsrp
                 + " rsrq=" + mRsrq
                 + " rssnr=" + mRssnr
                 + " cqi=" + mCqi
-                + " ta=" + mTimingAdvance;
+                + " ta=" + mTimingAdvance
+                + " level=" + mLevel;
     }
 
     /** Implement the Parcelable interface */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
-        dest.writeInt(mSignalStrength);
+        dest.writeInt(mRssi);
         // Need to multiply rsrp and rsrq by -1
         // to ensure consistency when reading values written here
         // unless the values are invalid
-        dest.writeInt(mRsrp * (mRsrp != CellInfo.UNAVAILABLE ? -1 : 1));
-        dest.writeInt(mRsrq * (mRsrq != CellInfo.UNAVAILABLE ? -1 : 1));
+        dest.writeInt(mRsrp);
+        dest.writeInt(mRsrq);
         dest.writeInt(mRssnr);
         dest.writeInt(mCqi);
         dest.writeInt(mTimingAdvance);
+        dest.writeInt(mLevel);
     }
 
     /**
@@ -300,16 +413,14 @@
      * where the token is already been processed.
      */
     private CellSignalStrengthLte(Parcel in) {
-        mSignalStrength = in.readInt();
-        // rsrp and rsrq are written into the parcel as positive values.
-        // Need to convert into negative values unless the values are invalid
+        mRssi = in.readInt();
+        mSignalStrength = mRssi;
         mRsrp = in.readInt();
-        if (mRsrp != CellInfo.UNAVAILABLE) mRsrp *= -1;
         mRsrq = in.readInt();
-        if (mRsrq != CellInfo.UNAVAILABLE) mRsrq *= -1;
         mRssnr = in.readInt();
         mCqi = in.readInt();
         mTimingAdvance = in.readInt();
+        mLevel = in.readInt();
         if (DBG) log("CellSignalStrengthLte(Parcel): " + toString());
     }
 
@@ -342,13 +453,12 @@
     }
 
     private static int convertRssiAsuToDBm(int rssiAsu) {
-        if (rssiAsu != SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN
-                && (rssiAsu < SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MIN_VALUE
-                || rssiAsu > SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MAX_VALUE)) {
-            Rlog.e(LOG_TAG, "convertRssiAsuToDBm: invalid RSSI in ASU=" + rssiAsu);
+        if (rssiAsu == SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN) {
             return CellInfo.UNAVAILABLE;
         }
-        if (rssiAsu == SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN) {
+        if ((rssiAsu < SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MIN_VALUE
+                || rssiAsu > SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MAX_VALUE)) {
+            Rlog.e(LOG_TAG, "convertRssiAsuToDBm: invalid RSSI in ASU=" + rssiAsu);
             return CellInfo.UNAVAILABLE;
         }
         return -113 + (2 * rssiAsu);
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 8079242..061cd4b 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 
 import java.util.Objects;
 
@@ -48,6 +49,12 @@
     private int mSsRsrp;
     private int mSsRsrq;
     private int mSsSinr;
+    private int mLevel;
+
+    /** @hide */
+    public CellSignalStrengthNr() {
+        setDefaultValues();
+    }
 
     /**
      * @param csiRsrp CSI reference signal received power.
@@ -60,12 +67,13 @@
      */
     public CellSignalStrengthNr(
             int csiRsrp, int csiRsrq, int csiSinr, int ssRsrp, int ssRsrq, int ssSinr) {
-        mCsiRsrp = csiRsrp;
-        mCsiRsrq = csiRsrq;
-        mCsiSinr = csiSinr;
-        mSsRsrp = ssRsrp;
-        mSsRsrq = ssRsrq;
-        mSsSinr = ssSinr;
+        mCsiRsrp = inRangeOrUnavailable(csiRsrp, -140, -44);
+        mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3);
+        mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
+        mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
+        mSsRsrq = inRangeOrUnavailable(ssRsrq, -20, -3);
+        mSsSinr = inRangeOrUnavailable(ssSinr, -23, 40);
+        updateLevel(null, null);
     }
 
     /**
@@ -142,6 +150,7 @@
         dest.writeInt(mSsRsrp);
         dest.writeInt(mSsRsrq);
         dest.writeInt(mSsSinr);
+        dest.writeInt(mLevel);
     }
 
     private CellSignalStrengthNr(Parcel in) {
@@ -151,6 +160,7 @@
         mSsRsrp = in.readInt();
         mSsRsrq = in.readInt();
         mSsSinr = in.readInt();
+        mLevel = in.readInt();
     }
 
     /** @hide */
@@ -162,27 +172,36 @@
         mSsRsrp = CellInfo.UNAVAILABLE;
         mSsRsrq = CellInfo.UNAVAILABLE;
         mSsSinr = CellInfo.UNAVAILABLE;
+        mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
     @Override
     public int getLevel() {
+        return mLevel;
+    }
+
+    /** @hide */
+    @Override
+    public void updateLevel(PersistableBundle cc, ServiceState ss) {
         if (mCsiRsrp == CellInfo.UNAVAILABLE) {
-            return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+            mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
         } else if (mCsiRsrp >= SIGNAL_GREAT_THRESHOLD) {
-            return SIGNAL_STRENGTH_GREAT;
+            mLevel = SIGNAL_STRENGTH_GREAT;
         } else if (mCsiRsrp >= SIGNAL_GOOD_THRESHOLD) {
-            return SIGNAL_STRENGTH_GOOD;
+            mLevel = SIGNAL_STRENGTH_GOOD;
         } else if (mCsiRsrp >= SIGNAL_MODERATE_THRESHOLD) {
-            return SIGNAL_STRENGTH_MODERATE;
+            mLevel = SIGNAL_STRENGTH_MODERATE;
         } else {
-            return SIGNAL_STRENGTH_POOR;
+            mLevel = SIGNAL_STRENGTH_POOR;
         }
     }
 
     /**
-     * Calculates the NR signal as an asu value between 0..97, 99 is unknown.
-     * Asu is calculated based on 3GPP RSRP, refer to 3GPP TS 27.007 section 8.69.
-     * @return an integer represent the asu level of the signal strength.
+     * Get the RSRP in ASU.
+     *
+     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     *
+     * @return RSCP in ASU 0..97, 255, or UNAVAILABLE
      */
     @Override
     public int getAsuLevel() {
@@ -206,15 +225,33 @@
     }
 
     /** @hide */
+    public CellSignalStrengthNr(CellSignalStrengthNr s) {
+        mCsiRsrp = s.mCsiRsrp;
+        mCsiRsrq = s.mCsiRsrq;
+        mCsiSinr = s.mCsiSinr;
+        mSsRsrp = s.mSsRsrp;
+        mSsRsrq = s.mSsRsrq;
+        mSsSinr = s.mSsSinr;
+        mLevel = s.mLevel;
+    }
+
+    /** @hide */
     @Override
-    public CellSignalStrength copy() {
-        return new CellSignalStrengthNr(
-                mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr);
+    public CellSignalStrengthNr copy() {
+        return new CellSignalStrengthNr(this);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr);
+        return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr, mLevel);
+    }
+
+    private static final CellSignalStrengthNr sInvalid = new CellSignalStrengthNr();
+
+    /** @hide */
+    @Override
+    public boolean isValid() {
+        return !this.equals(sInvalid);
     }
 
     @Override
@@ -222,7 +259,8 @@
         if (obj instanceof CellSignalStrengthNr) {
             CellSignalStrengthNr o = (CellSignalStrengthNr) obj;
             return mCsiRsrp == o.mCsiRsrp && mCsiRsrq == o.mCsiRsrq && mCsiSinr == o.mCsiSinr
-                    && mSsRsrp == o.mSsRsrp && mSsRsrq == o.mSsRsrq && mSsSinr == o.mSsSinr;
+                    && mSsRsrp == o.mSsRsrp && mSsRsrq == o.mSsRsrq && mSsSinr == o.mSsSinr
+                    && mLevel == o.mLevel;
         }
         return false;
     }
@@ -237,6 +275,7 @@
                 .append(" ssRsrp = " + mSsRsrp)
                 .append(" ssRsrq = " + mSsRsrq)
                 .append(" ssSinr = " + mSsSinr)
+                .append(" level = " + mLevel)
                 .append(" }")
                 .toString();
     }
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index 4d040cc..6f52b85 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 
 import java.util.Objects;
 
@@ -31,27 +32,53 @@
     private static final String LOG_TAG = "CellSignalStrengthTdscdma";
     private static final boolean DBG = false;
 
-    private static final int TDSCDMA_SIGNAL_STRENGTH_GREAT = 12;
-    private static final int TDSCDMA_SIGNAL_STRENGTH_GOOD = 8;
-    private static final int TDSCDMA_SIGNAL_STRENGTH_MODERATE = 5;
+    private static final int TDSCDMA_RSSI_MAX = -51;
+    private static final int TDSCDMA_RSSI_GREAT = -77;
+    private static final int TDSCDMA_RSSI_GOOD = -87;
+    private static final int TDSCDMA_RSSI_MODERATE = -97;
+    private static final int TDSCDMA_RSSI_POOR = -107;
 
-    private int mSignalStrength; // in ASU; Valid values are (0-31, 99) as defined in TS 27.007 8.5
-                                 // or CellInfo.UNAVAILABLE if unknown
+    private static final int TDSCDMA_RSCP_MIN = -120;
+    private static final int TDSCDMA_RSCP_MAX = -24;
+
+    private int mRssi; // in dBm [-113, -51], CellInfo.UNAVAILABLE
+
     private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
                                // CellInfo.UNAVAILABLE if unknown
-    private int mRscp; // Pilot power (0-96, 255) as defined in TS 27.007 8.69 or
+    private int mRscp; // Pilot Power in dBm [-120, -24] or CellInfo.UNAVAILABLE
                        // CellInfo.UNAVAILABLE if unknown
 
+    private int mLevel;
+
     /** @hide */
     public CellSignalStrengthTdscdma() {
         setDefaultValues();
     }
 
+    /**
+     * @param rssi in dBm [-113, -51] or UNAVAILABLE
+     * @param ber [0-7], 99 or UNAVAILABLE
+     * @param rscp in dBm [-120, -24] or UNAVAILABLE
+     * @hide */
+    public CellSignalStrengthTdscdma(int rssi, int ber, int rscp) {
+        mRssi = inRangeOrUnavailable(rssi, -113, -51);
+        mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99);
+        mRscp = inRangeOrUnavailable(rscp, -120, -24);
+        updateLevel(null, null);
+    }
+
     /** @hide */
-    public CellSignalStrengthTdscdma(int ss, int ber, int rscp) {
-        mSignalStrength = ss;
-        mBitErrorRate = ber;
-        mRscp = rscp;
+    public CellSignalStrengthTdscdma(android.hardware.radio.V1_0.TdScdmaSignalStrength tdscdma) {
+        // Convert from HAL values as part of construction.
+        this(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+                tdscdma.rscp != CellInfo.UNAVAILABLE ? -tdscdma.rscp : tdscdma.rscp);
+    }
+
+    /** @hide */
+    public CellSignalStrengthTdscdma(android.hardware.radio.V1_2.TdscdmaSignalStrength tdscdma) {
+        // Convert from HAL values as part of construction.
+        this(getRssiDbmFromAsu(tdscdma.signalStrength),
+                tdscdma.bitErrorRate, getRscpDbmFromAsu(tdscdma.rscp));
     }
 
     /** @hide */
@@ -61,9 +88,10 @@
 
     /** @hide */
     protected void copyFrom(CellSignalStrengthTdscdma s) {
-        mSignalStrength = s.mSignalStrength;
+        mRssi = s.mRssi;
         mBitErrorRate = s.mBitErrorRate;
         mRscp = s.mRscp;
+        mLevel = s.mLevel;
     }
 
     /** @hide */
@@ -75,9 +103,10 @@
     /** @hide */
     @Override
     public void setDefaultValues() {
-        mSignalStrength = CellInfo.UNAVAILABLE;
+        mRssi = CellInfo.UNAVAILABLE;
         mBitErrorRate = CellInfo.UNAVAILABLE;
         mRscp = CellInfo.UNAVAILABLE;
+        mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
     /**
@@ -88,26 +117,18 @@
      */
     @Override
     public int getLevel() {
-        int level;
+        return mLevel;
+    }
 
-        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-        // asu = 0 (-113dB or less) is very weak
-        // signal, its better to show 0 bars to the user in such cases.
-        // asu = 99 is a special case, where the signal strength is unknown.
-        int asu = mSignalStrength;
-        if (asu <= 2 || asu == 99) {
-            level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        } else if (asu >= TDSCDMA_SIGNAL_STRENGTH_GREAT) {
-            level = SIGNAL_STRENGTH_GREAT;
-        } else if (asu >= TDSCDMA_SIGNAL_STRENGTH_GOOD) {
-            level = SIGNAL_STRENGTH_GOOD;
-        } else if (asu >= TDSCDMA_SIGNAL_STRENGTH_MODERATE) {
-            level = SIGNAL_STRENGTH_MODERATE;
-        } else {
-            level = SIGNAL_STRENGTH_POOR;
-        }
-        if (DBG) log("getLevel=" + level);
-        return level;
+    /** @hide */
+    @Override
+    public void updateLevel(PersistableBundle cc, ServiceState ss) {
+        if (mRssi > TDSCDMA_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (mRssi >= TDSCDMA_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mRssi >= TDSCDMA_RSSI_GOOD)  mLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mRssi >= TDSCDMA_RSSI_MODERATE)  mLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mRssi >= TDSCDMA_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR;
+        else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
     /**
@@ -115,56 +136,55 @@
      */
     @Override
     public int getDbm() {
-        int dBm;
-
-        int level = mSignalStrength;
-        int asu = (level == 99 ? CellInfo.UNAVAILABLE : level);
-        if (asu != CellInfo.UNAVAILABLE) {
-            dBm = -113 + (2 * asu);
-        } else {
-            dBm = CellInfo.UNAVAILABLE;
-        }
-        if (DBG) log("getDbm=" + dBm);
-        return dBm;
+        return mRscp;
     }
 
     /**
-     * Get the signal level as an asu value between 0..31, 99 is unknown
+     * Get the RSCP as dBm
+     * @hide
+     */
+    public int getRscp() {
+        return mRscp;
+    }
+
+    /**
+     * Get the RSCP in ASU.
+     *
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     *
+     * @return RSCP in ASU 0..96, 255, or UNAVAILABLE
      */
     @Override
     public int getAsuLevel() {
-        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-        // asu = 0 (-113dB or less) is very weak
-        // signal, its better to show 0 bars to the user in such cases.
-        // asu = 99 is a special case, where the signal strength is unknown.
-        int level = mSignalStrength;
-        if (DBG) log("getAsuLevel=" + level);
-        return level;
+        if (mRscp != CellInfo.UNAVAILABLE) return getAsuFromRscpDbm(mRscp);
+        // For historical reasons, if RSCP is unavailable, this API will very incorrectly return
+        // RSSI. This hackery will be removed when most devices are using Radio HAL 1.2+
+        if (mRssi != CellInfo.UNAVAILABLE) return getAsuFromRssiDbm(mRssi);
+        return getAsuFromRscpDbm(CellInfo.UNAVAILABLE);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSignalStrength, mBitErrorRate);
+        return Objects.hash(mRssi, mBitErrorRate, mRscp, mLevel);
+    }
+
+    private static final CellSignalStrengthTdscdma sInvalid = new CellSignalStrengthTdscdma();
+
+    /** @hide */
+    @Override
+    public boolean isValid() {
+        return !this.equals(sInvalid);
     }
 
     @Override
     public boolean equals(Object o) {
-        CellSignalStrengthTdscdma s;
+        if (!(o instanceof CellSignalStrengthTdscdma)) return false;
+        CellSignalStrengthTdscdma s = (CellSignalStrengthTdscdma) o;
 
-        try {
-            s = (CellSignalStrengthTdscdma) o;
-        } catch (ClassCastException ex) {
-            return false;
-        }
-
-        if (o == null) {
-            return false;
-        }
-
-        return mSignalStrength == s.mSignalStrength
+        return mRssi == s.mRssi
                 && mBitErrorRate == s.mBitErrorRate
-                && mRscp == s.mRscp;
+                && mRscp == s.mRscp
+                && mLevel == s.mLevel;
     }
 
     /**
@@ -173,18 +193,20 @@
     @Override
     public String toString() {
         return "CellSignalStrengthTdscdma:"
-                + " ss=" + mSignalStrength
+                + " rssi=" + mRssi
                 + " ber=" + mBitErrorRate
-                + " rscp=" + mRscp;
+                + " rscp=" + mRscp
+                + " level=" + mLevel;
     }
 
     /** Implement the Parcelable interface */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
-        dest.writeInt(mSignalStrength);
+        dest.writeInt(mRssi);
         dest.writeInt(mBitErrorRate);
         dest.writeInt(mRscp);
+        dest.writeInt(mLevel);
     }
 
     /**
@@ -192,9 +214,10 @@
      * where the token is already been processed.
      */
     private CellSignalStrengthTdscdma(Parcel in) {
-        mSignalStrength = in.readInt();
+        mRssi = in.readInt();
         mBitErrorRate = in.readInt();
         mRscp = in.readInt();
+        mLevel = in.readInt();
         if (DBG) log("CellSignalStrengthTdscdma(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 0048cbd..88f6fbc 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -16,11 +16,14 @@
 
 package android.telephony;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.StringDef;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.telephony.Rlog;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
@@ -31,20 +34,32 @@
     private static final String LOG_TAG = "CellSignalStrengthWcdma";
     private static final boolean DBG = false;
 
-    private static final int WCDMA_SIGNAL_STRENGTH_GREAT = 12;
-    private static final int WCDMA_SIGNAL_STRENGTH_GOOD = 8;
-    private static final int WCDMA_SIGNAL_STRENGTH_MODERATE = 5;
+    private static final int WCDMA_RSSI_MAX = -51;
+    private static final int WCDMA_RSSI_GREAT = -77;
+    private static final int WCDMA_RSSI_GOOD = -87;
+    private static final int WCDMA_RSSI_MODERATE = -97;
+    private static final int WCDMA_RSSI_POOR = -107;
+    private static final int WCDMA_RSSI_MIN = -113;
 
-    @UnsupportedAppUsage
-    private int mSignalStrength; // in ASU; Valid values are (0-31, 99) as defined in TS 27.007 8.5
-                                 // or CellInfo.UNAVAILABLE if unknown
-    @UnsupportedAppUsage
+    private static final int WCDMA_RSCP_MIN = -120;
+    private static final int WCDMA_RSCP_MAX = -24;
+
+    // TODO: Because these are used as values in CarrierConfig, they should be exposed somehow.
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef({LEVEL_CALCULATION_METHOD_RSSI, LEVEL_CALCULATION_METHOD_RSCP})
+    public @interface LevelCalculationMethod {}
+    /** @hide */
+    public static final String LEVEL_CALCULATION_METHOD_RSSI = "rssi";
+    /** @hide */
+    public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp";
+
+    private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown
     private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
                                // CellInfo.UNAVAILABLE if unknown
-    private int mRscp; // bit error rate (0-96, 255) as defined in TS 27.007 8.69 or
-                       // CellInfo.UNAVAILABLE if unknown
-    private int mEcNo; // signal to noise radio (0-49, 255) as defined in TS 27.007 8.69 or
-                       // CellInfo.UNAVAILABLE if unknown
+    private int mRscp; // in dBm [-120, -24]
+    private int mEcNo; // range -24, 1, CellInfo.UNAVAILABLE if unknown
+    private int mLevel;
 
     /** @hide */
     public CellSignalStrengthWcdma() {
@@ -52,11 +67,28 @@
     }
 
     /** @hide */
-    public CellSignalStrengthWcdma(int ss, int ber, int rscp, int ecno) {
-        mSignalStrength = ss;
-        mBitErrorRate = ber;
-        mRscp = rscp;
-        mEcNo = ecno;
+    public CellSignalStrengthWcdma(int rssi, int ber, int rscp, int ecno) {
+        mRssi = inRangeOrUnavailable(rssi, WCDMA_RSSI_MIN, WCDMA_RSSI_MAX);
+        mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99);
+        mRscp = inRangeOrUnavailable(rscp, -120, -24);
+        mEcNo = inRangeOrUnavailable(ecno, -24, 1);
+        updateLevel(null, null);
+    }
+
+    /** @hide */
+    public CellSignalStrengthWcdma(android.hardware.radio.V1_0.WcdmaSignalStrength wcdma) {
+        // Convert from HAL values as part of construction.
+        this(getRssiDbmFromAsu(wcdma.signalStrength),
+                wcdma.bitErrorRate, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE);
+    }
+
+    /** @hide */
+    public CellSignalStrengthWcdma(android.hardware.radio.V1_2.WcdmaSignalStrength wcdma) {
+        // Convert from HAL values as part of construction.
+        this(getRssiDbmFromAsu(wcdma.base.signalStrength),
+                    wcdma.base.bitErrorRate,
+                    getRscpDbmFromAsu(wcdma.rscp),
+                    getEcNoDbFromAsu(wcdma.ecno));
     }
 
     /** @hide */
@@ -66,10 +98,11 @@
 
     /** @hide */
     protected void copyFrom(CellSignalStrengthWcdma s) {
-        mSignalStrength = s.mSignalStrength;
+        mRssi = s.mRssi;
         mBitErrorRate = s.mBitErrorRate;
         mRscp = s.mRscp;
         mEcNo = s.mEcNo;
+        mLevel = s.mLevel;
     }
 
     /** @hide */
@@ -81,12 +114,17 @@
     /** @hide */
     @Override
     public void setDefaultValues() {
-        mSignalStrength = CellInfo.UNAVAILABLE;
+        mRssi = CellInfo.UNAVAILABLE;
         mBitErrorRate = CellInfo.UNAVAILABLE;
         mRscp = CellInfo.UNAVAILABLE;
         mEcNo = CellInfo.UNAVAILABLE;
+        mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
+    private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI;
+    private static final int[] sThresholds = new int[]{
+            WCDMA_RSSI_POOR, WCDMA_RSSI_GOOD, WCDMA_RSSI_GOOD, WCDMA_RSSI_GREAT};
+
     /**
      * Retrieve an abstract level value for the overall signal strength.
      *
@@ -95,20 +133,49 @@
      */
     @Override
     public int getLevel() {
-        int level;
+        return mLevel;
+    }
 
-        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-        // asu = 0 (-113dB or less) is very weak
-        // signal, its better to show 0 bars to the user in such cases.
-        // asu = 99 is a special case, where the signal strength is unknown.
-        int asu = mSignalStrength;
-        if (asu <= 2 || asu == 99) level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (asu >= WCDMA_SIGNAL_STRENGTH_GREAT) level = SIGNAL_STRENGTH_GREAT;
-        else if (asu >= WCDMA_SIGNAL_STRENGTH_GOOD)  level = SIGNAL_STRENGTH_GOOD;
-        else if (asu >= WCDMA_SIGNAL_STRENGTH_MODERATE)  level = SIGNAL_STRENGTH_MODERATE;
-        else level = SIGNAL_STRENGTH_POOR;
-        if (DBG) log("getLevel=" + level);
-        return level;
+    /** @hide */
+    @Override
+    public void updateLevel(PersistableBundle cc, ServiceState ss) {
+        String calcMethod;
+        int[] thresholds;
+
+        if (cc == null) {
+            calcMethod = sLevelCalculationMethod;
+            thresholds = sThresholds;
+        } else {
+            // TODO: abstract this entire thing into a series of functions
+            calcMethod = cc.getString(
+                    CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
+                    sLevelCalculationMethod);
+            thresholds = cc.getIntArray(
+                    CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
+            if (thresholds == null) thresholds = sThresholds;
+        }
+
+        int level = thresholds.length;
+        switch (calcMethod) {
+            case LEVEL_CALCULATION_METHOD_RSCP:
+                if (mRscp < WCDMA_RSCP_MIN || mRscp > WCDMA_RSCP_MAX) {
+                    mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+                    return;
+                }
+                while (level > 0 && mRscp < thresholds[level - 1]) level--;
+                mLevel = level;
+                return;
+            case LEVEL_CALCULATION_METHOD_RSSI:
+                if (mRssi < WCDMA_RSSI_MIN || mRssi > WCDMA_RSSI_MAX) {
+                    mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+                    return;
+                }
+                while (level > 0 && mRssi < thresholds[level - 1]) level--;
+                mLevel = level;
+                return;
+            default:
+                mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        }
     }
 
     /**
@@ -116,57 +183,66 @@
      */
     @Override
     public int getDbm() {
-        int dBm;
-
-        int level = mSignalStrength;
-        int asu = (level == 99 ? CellInfo.UNAVAILABLE : level);
-        if (asu != CellInfo.UNAVAILABLE) {
-            dBm = -113 + (2 * asu);
-        } else {
-            dBm = CellInfo.UNAVAILABLE;
-        }
-        if (DBG) log("getDbm=" + dBm);
-        return dBm;
+        if (mRscp != CellInfo.UNAVAILABLE) return mRscp;
+        return mRssi;
     }
 
     /**
-     * Get the signal level as an asu value between 0..31, 99 is unknown
-     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     * Get the RSCP in ASU.
+     *
+     * Asu is calculated based on 3GPP RSCP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     *
+     * @return RSCP in ASU 0..96, 255, or UNAVAILABLE
      */
     @Override
     public int getAsuLevel() {
-        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-        // asu = 0 (-113dB or less) is very weak
-        // signal, its better to show 0 bars to the user in such cases.
-        // asu = 99 is a special case, where the signal strength is unknown.
-        int level = mSignalStrength;
-        if (DBG) log("getAsuLevel=" + level);
-        return level;
+        if (mRscp != CellInfo.UNAVAILABLE) return getAsuFromRscpDbm(mRscp);
+        // For historical reasons, if RSCP is unavailable, this API will very incorrectly return
+        // RSSI. This hackery will be removed when most devices are using Radio HAL 1.2+
+        if (mRssi != CellInfo.UNAVAILABLE) return getAsuFromRssiDbm(mRssi);
+        return getAsuFromRscpDbm(CellInfo.UNAVAILABLE);
+    }
+
+    /**
+     * Get the signal strength as dBm
+     *
+     * @hide
+     */
+    public int getRssi() {
+        return mRssi;
+    }
+
+    /**
+     * Get the RSCP as dBm
+     * @hide
+     */
+    public int getRscp() {
+        return mRscp;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mSignalStrength, mBitErrorRate);
+        return Objects.hash(mRssi, mBitErrorRate, mRscp, mEcNo, mLevel);
+    }
+
+    private static final CellSignalStrengthWcdma sInvalid = new CellSignalStrengthWcdma();
+
+    /** @hide */
+    @Override
+    public boolean isValid() {
+        return !this.equals(sInvalid);
     }
 
     @Override
-    public boolean equals (Object o) {
-        CellSignalStrengthWcdma s;
+    public boolean equals(Object o) {
+        if (!(o instanceof CellSignalStrengthWcdma)) return false;
+        CellSignalStrengthWcdma s = (CellSignalStrengthWcdma) o;
 
-        try {
-            s = (CellSignalStrengthWcdma) o;
-        } catch (ClassCastException ex) {
-            return false;
-        }
-
-        if (o == null) {
-            return false;
-        }
-
-        return mSignalStrength == s.mSignalStrength
+        return mRssi == s.mRssi
                 && mBitErrorRate == s.mBitErrorRate
                 && mRscp == s.mRscp
-                && mEcNo == s.mEcNo;
+                && mEcNo == s.mEcNo
+                && mLevel == s.mLevel;
     }
 
     /**
@@ -175,20 +251,22 @@
     @Override
     public String toString() {
         return "CellSignalStrengthWcdma:"
-                + " ss=" + mSignalStrength
+                + " ss=" + mRssi
                 + " ber=" + mBitErrorRate
                 + " rscp=" + mRscp
-                + " ecno=" + mEcNo;
+                + " ecno=" + mEcNo
+                + " level=" + mLevel;
     }
 
     /** Implement the Parcelable interface */
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
-        dest.writeInt(mSignalStrength);
+        dest.writeInt(mRssi);
         dest.writeInt(mBitErrorRate);
         dest.writeInt(mRscp);
         dest.writeInt(mEcNo);
+        dest.writeInt(mLevel);
     }
 
     /**
@@ -196,10 +274,11 @@
      * where the token is already been processed.
      */
     private CellSignalStrengthWcdma(Parcel in) {
-        mSignalStrength = in.readInt();
+        mRssi = in.readInt();
         mBitErrorRate = in.readInt();
         mRscp = in.readInt();
         mEcNo = in.readInt();
+        mLevel = in.readInt();
         if (DBG) log("CellSignalStrengthWcdma(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
new file mode 100644
index 0000000..c53b37d
--- /dev/null
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.PersistableBundle;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Returned as the reason for a data connection failure as defined by modem and some local errors.
+ * @hide
+ */
+public final class DataFailCause {
+    /** There is no failure */
+    public static final int NONE = 0;
+
+    // This series of errors as specified by the standards
+    // specified in ril.h
+    /** Operator determined barring. */
+    public static final int OPERATOR_BARRED = 0x08;
+    /** NAS signalling. */
+    public static final int NAS_SIGNALLING = 0x0E;
+    /** Logical Link Control (LLC) Sub Network Dependent Convergence Protocol (SNDCP). */
+    public static final int LLC_SNDCP = 0x19;
+    /** Insufficient resources. */
+    public static final int INSUFFICIENT_RESOURCES = 0x1A;
+    /** Missing or unknown APN. */
+    public static final int MISSING_UNKNOWN_APN = 0x1B;              /* no retry */
+    /** Unknown Packet Data Protocol (PDP) address type. */
+    public static final int UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;         /* no retry */
+    /** User authentication. */
+    public static final int USER_AUTHENTICATION = 0x1D;              /* no retry */
+    /** Activation rejected by Gateway GPRS Support Node (GGSN), Serving Gateway or PDN Gateway. */
+    public static final int ACTIVATION_REJECT_GGSN = 0x1E;           /* no retry */
+    /** Activation rejected, unspecified. */
+    public static final int ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
+    /** Service option not supported. */
+    public static final int SERVICE_OPTION_NOT_SUPPORTED = 0x20;     /* no retry */
+    /** Requested service option not subscribed. */
+    public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;    /* no retry */
+    /** Service option temporarily out of order. */
+    public static final int SERVICE_OPTION_OUT_OF_ORDER = 0x22;
+    /** The Network Service Access Point Identifier (NSAPI) is in use. */
+    public static final int NSAPI_IN_USE = 0x23;                     /* no retry */
+    /* possibly restart radio, based on config */
+    /** Regular deactivation. */
+    public static final int REGULAR_DEACTIVATION = 0x24;
+    /** Quality of service (QoS) is not accepted. */
+    public static final int QOS_NOT_ACCEPTED = 0x25;
+    /** Network Failure. */
+    public static final int NETWORK_FAILURE = 0x26;
+    /** Universal Mobile Telecommunications System (UMTS) reactivation request. */
+    public static final int UMTS_REACTIVATION_REQ = 0x27;
+    /** Feature not supported. */
+    public static final int FEATURE_NOT_SUPP = 0x28;
+    /** Semantic error in the Traffic flow templates (TFT) operation. */
+    public static final int TFT_SEMANTIC_ERROR = 0x29;
+    /** Syntactical error in the Traffic flow templates (TFT) operation. */
+    public static final int TFT_SYTAX_ERROR = 0x2A;
+    /** Unknown Packet Data Protocol (PDP) context. */
+    public static final int UNKNOWN_PDP_CONTEXT = 0x2B;
+    /** Semantic errors in packet filter. */
+    public static final int FILTER_SEMANTIC_ERROR = 0x2C;
+    /** Syntactical errors in packet filter(s). */
+    public static final int FILTER_SYTAX_ERROR = 0x2D;
+    /** Packet Data Protocol (PDP) without active traffic flow template (TFT). */
+    public static final int PDP_WITHOUT_ACTIVE_TFT = 0x2E;
+    /** Packet Data Protocol (PDP) type IPv4 only allowed. */
+    public static final int ONLY_IPV4_ALLOWED = 0x32;                /* no retry */
+    /** Packet Data Protocol (PDP) type IPv6 only allowed. */
+    public static final int ONLY_IPV6_ALLOWED = 0x33;                /* no retry */
+    /** Single address bearers only allowed. */
+    public static final int ONLY_SINGLE_BEARER_ALLOWED = 0x34;
+    /** EPS Session Management (ESM) information is not received. */
+    public static final int ESM_INFO_NOT_RECEIVED = 0x35;
+    /** PDN connection does not exist. */
+    public static final int PDN_CONN_DOES_NOT_EXIST = 0x36;
+    /** Multiple connections to a same PDN is not allowed. */
+    public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37;
+    /** Packet Data Protocol (PDP) */
+    public static final int MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41;
+    /** Unsupported APN in current public land mobile network (PLMN). */
+    public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42;
+    /** Invalid transaction id. */
+    public static final int INVALID_TRANSACTION_ID = 0x51;
+    /** Incorrect message semantic. */
+    public static final int MESSAGE_INCORRECT_SEMANTIC = 0x5F;
+    /** Invalid mandatory information. */
+    public static final int INVALID_MANDATORY_INFO = 0x60;
+    /** Unsupported message type. */
+    public static final int MESSAGE_TYPE_UNSUPPORTED = 0x61;
+    /** Message type uncompatible. */
+    public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 0x62;
+    /** Unknown info element. */
+    public static final int UNKNOWN_INFO_ELEMENT = 0x63;
+    /** Conditional Information Element (IE) error. */
+    public static final int CONDITIONAL_IE_ERROR = 0x64;
+    /** Message and protocol state uncompatible. */
+    public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65;
+    /** Protocol errors. */
+    public static final int PROTOCOL_ERRORS = 0x6F;                  /* no retry */
+    /** APN type conflict. */
+    public static final int APN_TYPE_CONFLICT = 0x70;
+    /** Invalid Proxy-Call Session Control Function (P-CSCF) address. */
+    public static final int INVALID_PCSCF_ADDR = 0x71;
+    /** Internal data call preempt by high priority APN. */
+    public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72;
+    /** EPS (Evolved Packet System) Mobility Management (EMM) access barred. */
+    public static final int EMM_ACCESS_BARRED = 0x73;
+    /** Emergency interface only. */
+    public static final int EMERGENCY_IFACE_ONLY = 0x74;
+    /** Interface mismatch. */
+    public static final int IFACE_MISMATCH = 0x75;
+    /** Companion interface in use. */
+    public static final int COMPANION_IFACE_IN_USE = 0x76;
+    /** IP address mismatch. */
+    public static final int IP_ADDRESS_MISMATCH = 0x77;
+    public static final int IFACE_AND_POL_FAMILY_MISMATCH = 0x78;
+    /** EPS (Evolved Packet System) Mobility Management (EMM) access barred infinity retry. **/
+    public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79;
+    /** Authentication failure on emergency call. */
+    public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A;
+
+    // OEM sepecific error codes. To be used by OEMs when they don't
+    // want to reveal error code which would be replaced by ERROR_UNSPECIFIED
+    public static final int OEM_DCFAILCAUSE_1 = 0x1001;
+    public static final int OEM_DCFAILCAUSE_2 = 0x1002;
+    public static final int OEM_DCFAILCAUSE_3 = 0x1003;
+    public static final int OEM_DCFAILCAUSE_4 = 0x1004;
+    public static final int OEM_DCFAILCAUSE_5 = 0x1005;
+    public static final int OEM_DCFAILCAUSE_6 = 0x1006;
+    public static final int OEM_DCFAILCAUSE_7 = 0x1007;
+    public static final int OEM_DCFAILCAUSE_8 = 0x1008;
+    public static final int OEM_DCFAILCAUSE_9 = 0x1009;
+    public static final int OEM_DCFAILCAUSE_10 = 0x100A;
+    public static final int OEM_DCFAILCAUSE_11 = 0x100B;
+    public static final int OEM_DCFAILCAUSE_12 = 0x100C;
+    public static final int OEM_DCFAILCAUSE_13 = 0x100D;
+    public static final int OEM_DCFAILCAUSE_14 = 0x100E;
+    public static final int OEM_DCFAILCAUSE_15 = 0x100F;
+
+    // Local errors generated by Vendor RIL
+    // specified in ril.h
+    public static final int REGISTRATION_FAIL = -1;
+    public static final int GPRS_REGISTRATION_FAIL = -2;
+    public static final int SIGNAL_LOST = -3;                        /* no retry */
+    public static final int PREF_RADIO_TECH_CHANGED = -4;
+    public static final int RADIO_POWER_OFF = -5;                    /* no retry */
+    public static final int TETHERED_CALL_ACTIVE = -6;               /* no retry */
+    public static final int ERROR_UNSPECIFIED = 0xFFFF;
+
+    // Errors generated by the Framework
+    // specified here
+    public static final int UNKNOWN = 0x10000;
+    public static final int RADIO_NOT_AVAILABLE = 0x10001;                   /* no retry */
+    public static final int UNACCEPTABLE_NETWORK_PARAMETER = 0x10002;        /* no retry */
+    public static final int CONNECTION_TO_DATACONNECTIONAC_BROKEN = 0x10003;
+    public static final int LOST_CONNECTION = 0x10004;
+    /** Data was reset by framework. */
+    public static final int RESET_BY_FRAMEWORK = 0x10005;
+
+    /** @hide */
+    @IntDef(value = {
+            NONE,
+            OPERATOR_BARRED,
+            NAS_SIGNALLING,
+            LLC_SNDCP,
+            INSUFFICIENT_RESOURCES,
+            MISSING_UNKNOWN_APN,
+            UNKNOWN_PDP_ADDRESS_TYPE,
+            USER_AUTHENTICATION,
+            ACTIVATION_REJECT_GGSN,
+            ACTIVATION_REJECT_UNSPECIFIED,
+            SERVICE_OPTION_NOT_SUPPORTED,
+            SERVICE_OPTION_NOT_SUBSCRIBED,
+            SERVICE_OPTION_OUT_OF_ORDER,
+            NSAPI_IN_USE,
+            REGULAR_DEACTIVATION,
+            QOS_NOT_ACCEPTED,
+            NETWORK_FAILURE,
+            UMTS_REACTIVATION_REQ,
+            FEATURE_NOT_SUPP,
+            TFT_SEMANTIC_ERROR,
+            TFT_SYTAX_ERROR,
+            UNKNOWN_PDP_CONTEXT,
+            FILTER_SEMANTIC_ERROR,
+            FILTER_SYTAX_ERROR,
+            PDP_WITHOUT_ACTIVE_TFT,
+            ONLY_IPV4_ALLOWED,
+            ONLY_IPV6_ALLOWED,
+            ONLY_SINGLE_BEARER_ALLOWED,
+            ESM_INFO_NOT_RECEIVED,
+            PDN_CONN_DOES_NOT_EXIST,
+            MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
+            MAX_ACTIVE_PDP_CONTEXT_REACHED,
+            UNSUPPORTED_APN_IN_CURRENT_PLMN,
+            INVALID_TRANSACTION_ID,
+            MESSAGE_INCORRECT_SEMANTIC,
+            INVALID_MANDATORY_INFO,
+            MESSAGE_TYPE_UNSUPPORTED,
+            MSG_TYPE_NONCOMPATIBLE_STATE,
+            UNKNOWN_INFO_ELEMENT,
+            CONDITIONAL_IE_ERROR,
+            MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
+            PROTOCOL_ERRORS,                 /* no retry */
+            APN_TYPE_CONFLICT,
+            INVALID_PCSCF_ADDR,
+            INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
+            EMM_ACCESS_BARRED,
+            EMERGENCY_IFACE_ONLY,
+            IFACE_MISMATCH,
+            COMPANION_IFACE_IN_USE,
+            IP_ADDRESS_MISMATCH,
+            IFACE_AND_POL_FAMILY_MISMATCH,
+            EMM_ACCESS_BARRED_INFINITE_RETRY,
+            AUTH_FAILURE_ON_EMERGENCY_CALL,
+            OEM_DCFAILCAUSE_1,
+            OEM_DCFAILCAUSE_2,
+            OEM_DCFAILCAUSE_3,
+            OEM_DCFAILCAUSE_4,
+            OEM_DCFAILCAUSE_5,
+            OEM_DCFAILCAUSE_6,
+            OEM_DCFAILCAUSE_7,
+            OEM_DCFAILCAUSE_8,
+            OEM_DCFAILCAUSE_9,
+            OEM_DCFAILCAUSE_10,
+            OEM_DCFAILCAUSE_11,
+            OEM_DCFAILCAUSE_12,
+            OEM_DCFAILCAUSE_13,
+            OEM_DCFAILCAUSE_14,
+            OEM_DCFAILCAUSE_15,
+            REGISTRATION_FAIL,
+            GPRS_REGISTRATION_FAIL,
+            SIGNAL_LOST,
+            PREF_RADIO_TECH_CHANGED,
+            RADIO_POWER_OFF,
+            TETHERED_CALL_ACTIVE,
+            ERROR_UNSPECIFIED,
+            UNKNOWN,
+            RADIO_NOT_AVAILABLE,
+            UNACCEPTABLE_NETWORK_PARAMETER,
+            CONNECTION_TO_DATACONNECTIONAC_BROKEN,
+            LOST_CONNECTION,
+            RESET_BY_FRAMEWORK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FailCause{}
+
+    private static final Map<Integer, String> sFailCauseMap;
+    static {
+        sFailCauseMap = new HashMap<>();
+        sFailCauseMap.put(NONE, "NONE");
+        sFailCauseMap.put(OPERATOR_BARRED, "OPERATOR_BARRED");
+        sFailCauseMap.put(NAS_SIGNALLING, "NAS_SIGNALLING");
+        sFailCauseMap.put(LLC_SNDCP, "LLC_SNDCP");
+        sFailCauseMap.put(INSUFFICIENT_RESOURCES, "INSUFFICIENT_RESOURCES");
+        sFailCauseMap.put(MISSING_UNKNOWN_APN, "MISSING_UNKNOWN_APN");
+        sFailCauseMap.put(UNKNOWN_PDP_ADDRESS_TYPE, "UNKNOWN_PDP_ADDRESS_TYPE");
+        sFailCauseMap.put(USER_AUTHENTICATION, "USER_AUTHENTICATION");
+        sFailCauseMap.put(ACTIVATION_REJECT_GGSN, "ACTIVATION_REJECT_GGSN");
+        sFailCauseMap.put(ACTIVATION_REJECT_UNSPECIFIED,
+                "ACTIVATION_REJECT_UNSPECIFIED");
+        sFailCauseMap.put(SERVICE_OPTION_NOT_SUPPORTED,
+                "SERVICE_OPTION_NOT_SUPPORTED");
+        sFailCauseMap.put(SERVICE_OPTION_NOT_SUBSCRIBED,
+                "SERVICE_OPTION_NOT_SUBSCRIBED");
+        sFailCauseMap.put(SERVICE_OPTION_OUT_OF_ORDER, "SERVICE_OPTION_OUT_OF_ORDER");
+        sFailCauseMap.put(NSAPI_IN_USE, "NSAPI_IN_USE");
+        sFailCauseMap.put(REGULAR_DEACTIVATION, "REGULAR_DEACTIVATION");
+        sFailCauseMap.put(QOS_NOT_ACCEPTED, "QOS_NOT_ACCEPTED");
+        sFailCauseMap.put(NETWORK_FAILURE, "NETWORK_FAILURE");
+        sFailCauseMap.put(UMTS_REACTIVATION_REQ, "UMTS_REACTIVATION_REQ");
+        sFailCauseMap.put(FEATURE_NOT_SUPP, "FEATURE_NOT_SUPP");
+        sFailCauseMap.put(TFT_SEMANTIC_ERROR, "TFT_SEMANTIC_ERROR");
+        sFailCauseMap.put(TFT_SYTAX_ERROR, "TFT_SYTAX_ERROR");
+        sFailCauseMap.put(UNKNOWN_PDP_CONTEXT, "UNKNOWN_PDP_CONTEXT");
+        sFailCauseMap.put(FILTER_SEMANTIC_ERROR, "FILTER_SEMANTIC_ERROR");
+        sFailCauseMap.put(FILTER_SYTAX_ERROR, "FILTER_SYTAX_ERROR");
+        sFailCauseMap.put(PDP_WITHOUT_ACTIVE_TFT, "PDP_WITHOUT_ACTIVE_TFT");
+        sFailCauseMap.put(ONLY_IPV4_ALLOWED, "ONLY_IPV4_ALLOWED");
+        sFailCauseMap.put(ONLY_IPV6_ALLOWED, "ONLY_IPV6_ALLOWED");
+        sFailCauseMap.put(ONLY_SINGLE_BEARER_ALLOWED, "ONLY_SINGLE_BEARER_ALLOWED");
+        sFailCauseMap.put(ESM_INFO_NOT_RECEIVED, "ESM_INFO_NOT_RECEIVED");
+        sFailCauseMap.put(PDN_CONN_DOES_NOT_EXIST, "PDN_CONN_DOES_NOT_EXIST");
+        sFailCauseMap.put(MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
+                "MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED");
+        sFailCauseMap.put(MAX_ACTIVE_PDP_CONTEXT_REACHED,
+                "MAX_ACTIVE_PDP_CONTEXT_REACHED");
+        sFailCauseMap.put(UNSUPPORTED_APN_IN_CURRENT_PLMN,
+                "UNSUPPORTED_APN_IN_CURRENT_PLMN");
+        sFailCauseMap.put(INVALID_TRANSACTION_ID, "INVALID_TRANSACTION_ID");
+        sFailCauseMap.put(MESSAGE_INCORRECT_SEMANTIC, "MESSAGE_INCORRECT_SEMANTIC");
+        sFailCauseMap.put(INVALID_MANDATORY_INFO, "INVALID_MANDATORY_INFO");
+        sFailCauseMap.put(MESSAGE_TYPE_UNSUPPORTED, "MESSAGE_TYPE_UNSUPPORTED");
+        sFailCauseMap.put(MSG_TYPE_NONCOMPATIBLE_STATE, "MSG_TYPE_NONCOMPATIBLE_STATE");
+        sFailCauseMap.put(UNKNOWN_INFO_ELEMENT, "UNKNOWN_INFO_ELEMENT");
+        sFailCauseMap.put(CONDITIONAL_IE_ERROR, "CONDITIONAL_IE_ERROR");
+        sFailCauseMap.put(MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
+                "MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE");
+        sFailCauseMap.put(PROTOCOL_ERRORS, "PROTOCOL_ERRORS");
+        sFailCauseMap.put(APN_TYPE_CONFLICT, "APN_TYPE_CONFLICT");
+        sFailCauseMap.put(INVALID_PCSCF_ADDR, "INVALID_PCSCF_ADDR");
+        sFailCauseMap.put(INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
+                "INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN");
+        sFailCauseMap.put(EMM_ACCESS_BARRED, "EMM_ACCESS_BARRED");
+        sFailCauseMap.put(EMERGENCY_IFACE_ONLY, "EMERGENCY_IFACE_ONLY");
+        sFailCauseMap.put(IFACE_MISMATCH, "IFACE_MISMATCH");
+        sFailCauseMap.put(COMPANION_IFACE_IN_USE, "COMPANION_IFACE_IN_USE");
+        sFailCauseMap.put(IP_ADDRESS_MISMATCH, "IP_ADDRESS_MISMATCH");
+        sFailCauseMap.put(IFACE_AND_POL_FAMILY_MISMATCH,
+                "IFACE_AND_POL_FAMILY_MISMATCH");
+        sFailCauseMap.put(EMM_ACCESS_BARRED_INFINITE_RETRY,
+                "EMM_ACCESS_BARRED_INFINITE_RETRY");
+        sFailCauseMap.put(AUTH_FAILURE_ON_EMERGENCY_CALL,
+                "AUTH_FAILURE_ON_EMERGENCY_CALL");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_1, "OEM_DCFAILCAUSE_1");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_2, "OEM_DCFAILCAUSE_2");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_3, "OEM_DCFAILCAUSE_3");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_4, "OEM_DCFAILCAUSE_4");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_5, "OEM_DCFAILCAUSE_5");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_6, "OEM_DCFAILCAUSE_6");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_7, "OEM_DCFAILCAUSE_7");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_8, "OEM_DCFAILCAUSE_8");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_9, "OEM_DCFAILCAUSE_9");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_10, "OEM_DCFAILCAUSE_10");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_11, "OEM_DCFAILCAUSE_11");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_12, "OEM_DCFAILCAUSE_12");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_13, "OEM_DCFAILCAUSE_13");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_14, "OEM_DCFAILCAUSE_14");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_15, "OEM_DCFAILCAUSE_15");
+        sFailCauseMap.put(REGISTRATION_FAIL, "REGISTRATION_FAIL");
+        sFailCauseMap.put(GPRS_REGISTRATION_FAIL, "GPRS_REGISTRATION_FAIL");
+        sFailCauseMap.put(SIGNAL_LOST, "SIGNAL_LOST");
+        sFailCauseMap.put(PREF_RADIO_TECH_CHANGED, "PREF_RADIO_TECH_CHANGED");
+        sFailCauseMap.put(RADIO_POWER_OFF, "RADIO_POWER_OFF");
+        sFailCauseMap.put(TETHERED_CALL_ACTIVE, "TETHERED_CALL_ACTIVE");
+        sFailCauseMap.put(ERROR_UNSPECIFIED, "ERROR_UNSPECIFIED");
+        sFailCauseMap.put(UNKNOWN, "UNKNOWN");
+        sFailCauseMap.put(RADIO_NOT_AVAILABLE, "RADIO_NOT_AVAILABLE");
+        sFailCauseMap.put(UNACCEPTABLE_NETWORK_PARAMETER,
+                "UNACCEPTABLE_NETWORK_PARAMETER");
+        sFailCauseMap.put(CONNECTION_TO_DATACONNECTIONAC_BROKEN,
+                "CONNECTION_TO_DATACONNECTIONAC_BROKEN");
+        sFailCauseMap.put(LOST_CONNECTION, "LOST_CONNECTION");
+        sFailCauseMap.put(RESET_BY_FRAMEWORK, "RESET_BY_FRAMEWORK");
+    }
+
+    /**
+     * Map of subId -> set of data call setup permanent failure for the carrier.
+     */
+    private static final HashMap<Integer, Set<Integer>> sPermanentFailureCache =
+            new HashMap<>();
+
+    /**
+     * Returns whether or not the fail cause is a failure that requires a modem restart
+     *
+     * @param context device context
+     * @param cause data disconnect cause
+     * @param subId subscription index
+     * @return true if the fail cause code needs platform to trigger a modem restart.
+     */
+    public static boolean isRadioRestartFailure(@NonNull Context context, @FailCause int cause,
+                                                int subId) {
+        CarrierConfigManager configManager = (CarrierConfigManager)
+                context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (configManager != null) {
+            PersistableBundle b = configManager.getConfigForSubId(subId);
+
+            if (b != null) {
+                if (cause == REGULAR_DEACTIVATION
+                        && b.getBoolean(CarrierConfigManager
+                        .KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL)) {
+                    // This is for backward compatibility support. We need to continue support this
+                    // old configuration until it gets removed in the future.
+                    return true;
+                }
+                // Check the current configurations.
+                int[] causeCodes = b.getIntArray(CarrierConfigManager
+                        .KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY);
+                if (causeCodes != null) {
+                    return Arrays.stream(causeCodes).anyMatch(i -> i == cause);
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public static boolean isPermanentFailure(@NonNull Context context, @FailCause int failCause,
+                                             int subId) {
+        synchronized (sPermanentFailureCache) {
+
+            Set<Integer> permanentFailureSet = sPermanentFailureCache.get(subId);
+
+            // In case of cache miss, we need to look up the settings from carrier config.
+            if (permanentFailureSet == null) {
+                // Retrieve the permanent failure from carrier config
+                CarrierConfigManager configManager = (CarrierConfigManager)
+                        context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+                if (configManager != null) {
+                    PersistableBundle b = configManager.getConfigForSubId(subId);
+                    if (b != null) {
+                        String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager.
+                                KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
+                        if (permanentFailureStrings != null) {
+                            permanentFailureSet = new HashSet<>();
+                            for (Map.Entry<Integer, String> e : sFailCauseMap.entrySet()) {
+                                if (ArrayUtils.contains(permanentFailureStrings, e.getValue())) {
+                                    permanentFailureSet.add(e.getKey());
+                                }
+                            }
+                        }
+                    }
+                }
+
+                // If we are not able to find the configuration from carrier config, use the default
+                // ones.
+                if (permanentFailureSet == null) {
+                    permanentFailureSet = new HashSet<Integer>() {
+                        {
+                            add(OPERATOR_BARRED);
+                            add(MISSING_UNKNOWN_APN);
+                            add(UNKNOWN_PDP_ADDRESS_TYPE);
+                            add(USER_AUTHENTICATION);
+                            add(ACTIVATION_REJECT_GGSN);
+                            add(SERVICE_OPTION_NOT_SUPPORTED);
+                            add(SERVICE_OPTION_NOT_SUBSCRIBED);
+                            add(NSAPI_IN_USE);
+                            add(ONLY_IPV4_ALLOWED);
+                            add(ONLY_IPV6_ALLOWED);
+                            add(PROTOCOL_ERRORS);
+                            add(RADIO_POWER_OFF);
+                            add(TETHERED_CALL_ACTIVE);
+                            add(RADIO_NOT_AVAILABLE);
+                            add(UNACCEPTABLE_NETWORK_PARAMETER);
+                            add(SIGNAL_LOST);
+                        }
+                    };
+                }
+
+                sPermanentFailureCache.put(subId, permanentFailureSet);
+            }
+
+            return permanentFailureSet.contains(failCause);
+        }
+    }
+
+    public static boolean isEventLoggable(@FailCause int dataFailCause) {
+        return (dataFailCause == OPERATOR_BARRED) || (dataFailCause == INSUFFICIENT_RESOURCES)
+                || (dataFailCause == UNKNOWN_PDP_ADDRESS_TYPE)
+                || (dataFailCause == USER_AUTHENTICATION)
+                || (dataFailCause == ACTIVATION_REJECT_GGSN)
+                || (dataFailCause == ACTIVATION_REJECT_UNSPECIFIED)
+                || (dataFailCause == SERVICE_OPTION_NOT_SUBSCRIBED)
+                || (dataFailCause == SERVICE_OPTION_NOT_SUPPORTED)
+                || (dataFailCause == SERVICE_OPTION_OUT_OF_ORDER)
+                || (dataFailCause == NSAPI_IN_USE)
+                || (dataFailCause == ONLY_IPV4_ALLOWED)
+                || (dataFailCause == ONLY_IPV6_ALLOWED)
+                || (dataFailCause == PROTOCOL_ERRORS)
+                || (dataFailCause == SIGNAL_LOST)
+                || (dataFailCause == RADIO_POWER_OFF)
+                || (dataFailCause == TETHERED_CALL_ACTIVE)
+                || (dataFailCause == UNACCEPTABLE_NETWORK_PARAMETER);
+    }
+
+    public static String toString(@FailCause int dataFailCause) {
+        int cause = getFailCause(dataFailCause);
+        return (cause == UNKNOWN) ? "UNKNOWN(" + dataFailCause + ")" : sFailCauseMap.get(cause);
+    }
+
+    public static int getFailCause(@FailCause int failCause) {
+        if (sFailCauseMap.containsKey(failCause)) {
+            return failCause;
+        } else {
+            return UNKNOWN;
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index c6887ab..f53cb82 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -16,12 +16,16 @@
 
 package android.telephony;
 
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 
 /**
- * Contains disconnect call causes generated by the framework and the RIL.
+ * Describes the cause of a disconnected call. Those disconnect causes can be converted into a more
+ * generic {@link android.telecom.DisconnectCause} object.
+ *
  * @hide
  */
+@SystemApi
 public class DisconnectCause {
 
     /** The disconnect cause is not valid (Not received a disconnect cause) */
@@ -101,8 +105,8 @@
     /** Unknown error or not specified */
     public static final int ERROR_UNSPECIFIED              = 36;
     /**
-     * Only emergency numbers are allowed, but we tried to dial
-     * a non-emergency number.
+     * Only emergency numbers are allowed, but we tried to dial a non-emergency number.
+     * @hide
      */
     // TODO: This should be the same as NOT_EMERGENCY
     public static final int EMERGENCY_ONLY                 = 37;
@@ -115,8 +119,7 @@
      */
     public static final int DIALED_MMI                     = 39;
     /**
-     * We tried to call a voicemail: URI but the device has no
-     * voicemail number configured.
+     * We tried to call a voicemail: URI but the device has no voicemail number configured.
      */
     public static final int VOICEMAIL_NUMBER_MISSING       = 40;
     /**
@@ -129,6 +132,8 @@
      * needs to be triggered by a *disconnect* event, rather than when
      * the InCallScreen first comes to the foreground.  For now we use
      * the needToShowCallLostDialog field for this (see below.)
+     *
+     * @hide
      */
     public static final int CDMA_CALL_LOST                 = 41;
     /**
@@ -169,62 +174,52 @@
 
     /**
      * Stk Call Control modified DIAL request to USSD request.
-     * {@hide}
      */
     public static final int DIAL_MODIFIED_TO_USSD          = 46;
     /**
      * Stk Call Control modified DIAL request to SS request.
-     * {@hide}
      */
     public static final int DIAL_MODIFIED_TO_SS            = 47;
     /**
      * Stk Call Control modified DIAL request to DIAL with modified data.
-     * {@hide}
      */
     public static final int DIAL_MODIFIED_TO_DIAL          = 48;
 
     /**
      * The call was terminated because CDMA phone service and roaming have already been activated.
-     * {@hide}
      */
     public static final int CDMA_ALREADY_ACTIVATED         = 49;
 
     /**
      * The call was terminated because it is not possible to place a video call while TTY is
      * enabled.
-     * {@hide}
      */
     public static final int VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED = 50;
 
     /**
      * The call was terminated because it was pulled to another device.
-     * {@hide}
      */
     public static final int CALL_PULLED = 51;
 
     /**
      * The call was terminated because it was answered on another device.
-     * {@hide}
      */
     public static final int ANSWERED_ELSEWHERE = 52;
 
     /**
      * The call was terminated because the maximum allowable number of calls has been reached.
-     * {@hide}
      */
     public static final int MAXIMUM_NUMBER_OF_CALLS_REACHED = 53;
 
     /**
      * The call was terminated because cellular data has been disabled.
      * Used when in a video call and the user disables cellular data via the settings.
-     * {@hide}
      */
     public static final int DATA_DISABLED = 54;
 
     /**
      * The call was terminated because the data policy has disabled cellular data.
      * Used when in a video call and the user has exceeded the device data limit.
-     * {@hide}
      */
     public static final int DATA_LIMIT_REACHED = 55;
 
@@ -237,7 +232,6 @@
     /**
      * The network does not accept the emergency call request because IMEI was used as
      * identification and this cability is not supported by the network.
-     * {@hide}
      */
     public static final int IMEI_NOT_ACCEPTED = 58;
 
@@ -249,7 +243,6 @@
 
     /**
      * The call has failed because of access class barring.
-     * {@hide}
      */
     public static final int IMS_ACCESS_BLOCKED = 60;
 
@@ -265,51 +258,43 @@
 
     /**
      * Emergency call failed with a temporary fail cause and can be redialed on this slot.
-     * {@hide}
      */
     public static final int EMERGENCY_TEMP_FAILURE = 63;
 
     /**
      * Emergency call failed with a permanent fail cause and should not be redialed on this
-     * slot. 
-     * {@hide}
+     * slot.
      */
     public static final int EMERGENCY_PERM_FAILURE = 64;
 
     /**
      * This cause is used to report a normal event only when no other cause in the normal class
      * applies.
-     * {@hide}
      */
     public static final int NORMAL_UNSPECIFIED = 65;
 
     /**
      * Stk Call Control modified DIAL request to video DIAL request.
-     * {@hide}
      */
     public static final int DIAL_MODIFIED_TO_DIAL_VIDEO = 66;
 
     /**
      * Stk Call Control modified Video DIAL request to SS request.
-     * {@hide}
      */
     public static final int DIAL_VIDEO_MODIFIED_TO_SS = 67;
 
     /**
      * Stk Call Control modified Video DIAL request to USSD request.
-     * {@hide}
      */
     public static final int DIAL_VIDEO_MODIFIED_TO_USSD = 68;
 
     /**
      * Stk Call Control modified Video DIAL request to DIAL request.
-     * {@hide}
      */
     public static final int DIAL_VIDEO_MODIFIED_TO_DIAL = 69;
 
     /**
      * Stk Call Control modified Video DIAL request to Video DIAL request.
-     * {@hide}
      */
     public static final int DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 70;
 
@@ -359,7 +344,10 @@
         // Do nothing.
     }
 
-    /** Returns descriptive string for the specified disconnect cause. */
+    /**
+     * Returns descriptive string for the specified disconnect cause.
+     * @hide
+     */
     @UnsupportedAppUsage
     public static String toString(int cause) {
         switch (cause) {
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index 4354314..4bca404 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -16,7 +16,6 @@
 
 package android.telephony;
 
-import android.annotation.CallSuper;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
@@ -53,7 +52,6 @@
     private final String TAG = NetworkService.class.getSimpleName();
 
     public static final String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService";
-    public static final String NETWORK_SERVICE_EXTRA_SLOT_ID = "android.telephony.extra.SLOT_ID";
 
     private static final int NETWORK_SERVICE_CREATE_NETWORK_SERVICE_PROVIDER                 = 1;
     private static final int NETWORK_SERVICE_REMOVE_NETWORK_SERVICE_PROVIDER                 = 2;
@@ -81,7 +79,7 @@
      * must extend this class to support network connection. Note that each instance of network
      * service is associated with one physical SIM slot.
      */
-    public class NetworkServiceProvider {
+    public abstract class NetworkServiceProvider implements AutoCloseable {
         private final int mSlotId;
 
         private final List<INetworkServiceCallback>
@@ -137,12 +135,12 @@
         }
 
         /**
-         * Called when the instance of network service is destroyed (e.g. got unbind or binder died).
+         * Called when the instance of network service is destroyed (e.g. got unbind or binder died)
+         * or when the network service provider is removed. The extended class should implement this
+         * method to perform cleanup works.
          */
-        @CallSuper
-        protected void onDestroy() {
-            mNetworkRegistrationStateChangedCallbacks.clear();
-        }
+        @Override
+        public abstract void close();
     }
 
     private class NetworkServiceHandler extends Handler {
@@ -168,7 +166,7 @@
                 case NETWORK_SERVICE_REMOVE_NETWORK_SERVICE_PROVIDER:
                     // If the service provider doesn't exist yet, we try to create it.
                     if (serviceProvider != null) {
-                        serviceProvider.onDestroy();
+                        serviceProvider.close();
                         mServiceMap.remove(slotId);
                     }
                     break;
@@ -176,7 +174,7 @@
                     for (int i = 0; i < mServiceMap.size(); i++) {
                         serviceProvider = mServiceMap.get(i);
                         if (serviceProvider != null) {
-                            serviceProvider.onDestroy();
+                            serviceProvider.close();
                         }
                     }
                     mServiceMap.clear();
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index e8a28ca..2b1628c 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -171,14 +171,14 @@
     public static final int LISTEN_CELL_INFO = 0x00000400;
 
     /**
-     * Listen for precise changes and fails to the device calls (cellular).
+     * Listen for {@link PreciseCallState.State} of ringing, background and foreground calls.
      * {@more}
      * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
      * READ_PRECISE_PHONE_STATE}
      *
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
     public static final int LISTEN_PRECISE_CALL_STATE                       = 0x00000800;
 
     /**
@@ -316,6 +316,18 @@
      */
     public static final int LISTEN_EMERGENCY_NUMBER_LIST                   = 0x01000000;
 
+    /**
+     * Listen for call disconnect causes which contains {@link DisconnectCause} and
+     * {@link PreciseDisconnectCause}.
+     * {@more}
+     * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+     * READ_PRECISE_PHONE_STATE}
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int LISTEN_CALL_DISCONNECT_CAUSES                  = 0x02000000;
+
     /*
      * Subscription used to listen to the phone state changes
      * @hide
@@ -526,11 +538,23 @@
 
     /**
      * Callback invoked when precise device call state changes.
+     * @param callState {@link PreciseCallState}
+     * @hide
+     */
+    @SystemApi
+    public void onPreciseCallStateChanged(PreciseCallState callState) {
+        // default implementation empty
+    }
+
+    /**
+     * Callback invoked when call disconnect cause changes.
+     * @param disconnectCause {@link DisconnectCause}.
+     * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
      *
      * @hide
      */
-    @UnsupportedAppUsage
-    public void onPreciseCallStateChanged(PreciseCallState callState) {
+    @SystemApi
+    public void onCallDisconnectCauseChanged(int disconnectCause, int preciseDisconnectCause) {
         // default implementation empty
     }
 
@@ -780,6 +804,15 @@
                     () -> mExecutor.execute(() -> psl.onPreciseCallStateChanged(callState)));
         }
 
+        public void onCallDisconnectCauseChanged(int disconnectCause, int preciseDisconnectCause) {
+            PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
+            if (psl == null) return;
+
+            Binder.withCleanCallingIdentity(
+                    () -> mExecutor.execute(() -> psl.onCallDisconnectCauseChanged(
+                            disconnectCause, preciseDisconnectCause)));
+        }
+
         public void onPreciseDataConnectionStateChanged(
                 PreciseDataConnectionState dataConnectionState) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index ed5c26a..59f3e1f 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -16,29 +16,51 @@
 
 package android.telephony;
 
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseDisconnectCause;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
 /**
- * Contains precise call state and call fail causes generated by the
- * framework and the RIL.
+ * Contains precise call states.
  *
  * The following call information is included in returned PreciseCallState:
  *
  * <ul>
- *   <li>Ringing call state.
- *   <li>Foreground call state.
- *   <li>Background call state.
- *   <li>Disconnect cause; generated by the framework.
- *   <li>Precise disconnect cause; generated by the RIL.
+ *   <li>Precise ringing call state.
+ *   <li>Precise foreground call state.
+ *   <li>Precise background call state.
  * </ul>
  *
+ * @see android.telephony.TelephonyManager.CallState which contains generic call states.
+ *
  * @hide
  */
-public class PreciseCallState implements Parcelable {
+@SystemApi
+public final class PreciseCallState implements Parcelable {
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"PRECISE_CALL_STATE_"},
+            value = {
+                    PRECISE_CALL_STATE_NOT_VALID,
+                    PRECISE_CALL_STATE_IDLE,
+                    PRECISE_CALL_STATE_ACTIVE,
+                    PRECISE_CALL_STATE_HOLDING,
+                    PRECISE_CALL_STATE_DIALING,
+                    PRECISE_CALL_STATE_ALERTING,
+                    PRECISE_CALL_STATE_INCOMING,
+                    PRECISE_CALL_STATE_WAITING,
+                    PRECISE_CALL_STATE_DISCONNECTED,
+                    PRECISE_CALL_STATE_DISCONNECTING})
+    public @interface State {}
 
     /** Call state is not valid (Not received a call state). */
     public static final int PRECISE_CALL_STATE_NOT_VALID =      -1;
@@ -61,9 +83,9 @@
     /** Call state: Disconnecting. */
     public static final int PRECISE_CALL_STATE_DISCONNECTING =  8;
 
-    private int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
-    private int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
-    private int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @State int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @State int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @State int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
     private int mDisconnectCause = DisconnectCause.NOT_VALID;
     private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
 
@@ -73,8 +95,9 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public PreciseCallState(int ringingCall, int foregroundCall, int backgroundCall,
-            int disconnectCause, int preciseDisconnectCause) {
+    public PreciseCallState(@State int ringingCall, @State int foregroundCall,
+                            @State int backgroundCall, int disconnectCause,
+                            int preciseDisconnectCause) {
         mRingingCallState = ringingCall;
         mForegroundCallState = foregroundCall;
         mBackgroundCallState = backgroundCall;
@@ -92,6 +115,8 @@
 
     /**
      * Construct a PreciseCallState object from the given parcel.
+     *
+     * @hide
      */
     private PreciseCallState(Parcel in) {
         mRingingCallState = in.readInt();
@@ -102,59 +127,23 @@
     }
 
     /**
-     * Get precise ringing call state
-     *
-     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
-     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
-     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
-     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
-     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
-     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
-     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
-     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
-     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
-     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     * Returns the precise ringing call state.
      */
-    @UnsupportedAppUsage
-    public int getRingingCallState() {
+    public @State int getRingingCallState() {
         return mRingingCallState;
     }
 
     /**
-     * Get precise foreground call state
-     *
-     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
-     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
-     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
-     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
-     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
-     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
-     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
-     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
-     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
-     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     * Returns the precise foreground call state.
      */
-    @UnsupportedAppUsage
-    public int getForegroundCallState() {
+    public @State int getForegroundCallState() {
         return mForegroundCallState;
     }
 
     /**
-     * Get precise background call state
-     *
-     * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
-     * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
-     * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
-     * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
-     * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
-     * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
-     * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
-     * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
-     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
-     * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+     * Returns the precise background call state.
      */
-    @UnsupportedAppUsage
-    public int getBackgroundCallState() {
+    public @State int getBackgroundCallState() {
         return mBackgroundCallState;
     }
 
@@ -199,6 +188,11 @@
      * @see DisconnectCause#CDMA_NOT_EMERGENCY
      * @see DisconnectCause#CDMA_ACCESS_BLOCKED
      * @see DisconnectCause#ERROR_UNSPECIFIED
+     *
+     * TODO: remove disconnect cause from preciseCallState as there is no link between random
+     * connection disconnect cause with foreground, background or ringing call.
+     *
+     * @hide
      */
     @UnsupportedAppUsage
     public int getDisconnectCause() {
@@ -238,6 +232,11 @@
      * @see PreciseDisconnectCause#CDMA_NOT_EMERGENCY
      * @see PreciseDisconnectCause#CDMA_ACCESS_BLOCKED
      * @see PreciseDisconnectCause#ERROR_UNSPECIFIED
+     *
+     * TODO: remove precise disconnect cause from preciseCallState as there is no link between
+     * random connection disconnect cause with foreground, background or ringing call.
+     *
+     * @hide
      */
     @UnsupportedAppUsage
     public int getPreciseDisconnectCause() {
@@ -272,14 +271,8 @@
 
     @Override
     public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + mRingingCallState;
-        result = prime * result + mForegroundCallState;
-        result = prime * result + mBackgroundCallState;
-        result = prime * result + mDisconnectCause;
-        result = prime * result + mPreciseDisconnectCause;
-        return result;
+        return Objects.hash(mRingingCallState, mForegroundCallState, mForegroundCallState,
+                mDisconnectCause, mPreciseDisconnectCause);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
index 2acaf34..af88748 100644
--- a/telephony/java/android/telephony/PreciseDisconnectCause.java
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -16,279 +16,329 @@
 
 package android.telephony;
 
+import android.annotation.SystemApi;
+
 /**
- * Contains precise disconnect call causes generated by the
- * framework and the RIL.
- *
+ * Contains precise disconnect call causes generated by the framework and the RIL.
  * @hide
  */
+@SystemApi
 public class PreciseDisconnectCause {
 
-    /** The disconnect cause is not valid (Not received a disconnect cause)*/
+    /** The disconnect cause is not valid (Not received a disconnect cause).*/
     public static final int NOT_VALID                                        = -1;
-    /** No disconnect cause provided. Generally a local disconnect or an incoming missed call */
+    /** No disconnect cause provided. Generally a local disconnect or an incoming missed call. */
     public static final int NO_DISCONNECT_CAUSE_AVAILABLE                    = 0;
     /**
      * The destination cannot be reached because the number, although valid,
-     * is not currently assigned
+     * is not currently assigned.
      */
     public static final int UNOBTAINABLE_NUMBER                              = 1;
-    /** The user cannot be reached because the network through which the call has been
-     *  routed does not serve the destination desired
+    /**
+     * The user cannot be reached because the network through which the call has been routed does
+     * not serve the destination desired.
      */
     public static final int NO_ROUTE_TO_DESTINATION                          = 3;
-    /** The channel most recently identified is not acceptable to the sending entity for
-     *  use in this call
+    /**
+     * The channel most recently identified is not acceptable to the sending entity for use in this
+     * call.
      */
     public static final int CHANNEL_UNACCEPTABLE                             = 6;
-    /** The MS has tried to access a service that the MS's network operator or service
-     *  provider is not prepared to allow
+    /**
+     * The mobile station (MS) has tried to access a service that the MS's network operator or
+     * service provider is not prepared to allow.
      */
     public static final int OPERATOR_DETERMINED_BARRING                      = 8;
-    /** One of the users involved in the call has requested that the call is cleared */
+    /** One of the users involved in the call has requested that the call is cleared. */
     public static final int NORMAL                                           = 16;
-    /** The called user is unable to accept another call */
+    /** The called user is unable to accept another call. */
     public static final int BUSY                                             = 17;
-    /** The user does not respond to a call establishment message with either an alerting
-     *  or connect indication within the prescribed period of time allocated
+    /**
+     * The user does not respond to a call establishment message with either an alerting or connect
+     * indication within the prescribed period of time allocated.
      */
     public static final int NO_USER_RESPONDING                               = 18;
-    /** The user has provided an alerting indication but has not provided a connect
-     *  indication within a prescribed period of time
+    /**
+     * The user has provided an alerting indication but has not provided a connect indication
+     * within a prescribed period of time.
      */
     public static final int NO_ANSWER_FROM_USER                              = 19;
-    /** The equipment sending this cause does not wish to accept this call */
+    /** The equipment sending this cause does not wish to accept this call. */
     public static final int CALL_REJECTED                                    = 21;
-    /** The called number is no longer assigned */
+    /** The called number is no longer assigned. */
     public static final int NUMBER_CHANGED                                   = 22;
-    /** This cause is returned to the network when a mobile station clears an active
-     *  call which is being pre-empted by another call with higher precedence
+    /**
+     * This cause is returned to the network when a mobile station clears an active call which is
+     * being pre-empted by another call with higher precedence.
      */
     public static final int PREEMPTION                                       = 25;
-    /** The destination indicated by the mobile station cannot be reached because
-     *  the interface to the destination is not functioning correctly
+    /**
+     * The destination indicated by the mobile station cannot be reached because the interface to
+     * the destination is not functioning correctly.
      */
     public static final int DESTINATION_OUT_OF_ORDER                         = 27;
-    /** The called party number is not a valid format or is not complete */
+    /** The called party number is not a valid format or is not complete. */
     public static final int INVALID_NUMBER_FORMAT                            = 28;
-    /** The facility requested by user can not be provided by the network */
+    /** The facility requested by user can not be provided by the network. */
     public static final int FACILITY_REJECTED                                = 29;
-    /** Provided in response to a STATUS ENQUIRY message */
+    /** Provided in response to a STATUS ENQUIRY message. */
     public static final int STATUS_ENQUIRY                                   = 30;
-    /** Reports a normal disconnect only when no other normal cause applies */
+    /** Reports a normal disconnect only when no other normal cause applies. */
     public static final int NORMAL_UNSPECIFIED                               = 31;
-    /** There is no channel presently available to handle the call */
+    /** There is no channel presently available to handle the call. */
     public static final int NO_CIRCUIT_AVAIL                                 = 34;
-    /** The network is not functioning correctly and that the condition is likely
-     *  to last a relatively long period of time
+    /**
+     * The network is not functioning correctly and that the condition is likely to last a
+     * relatively long period of time.
      */
     public static final int NETWORK_OUT_OF_ORDER                             = 38;
     /**
-     * The network is not functioning correctly and the condition is not likely to last
-     * a long period of time
+     * The network is not functioning correctly and the condition is not likely to last a long
+     * period of time.
      */
     public static final int TEMPORARY_FAILURE                                = 41;
-    /** The switching equipment is experiencing a period of high traffic */
+    /** The switching equipment is experiencing a period of high traffic. */
     public static final int SWITCHING_CONGESTION                             = 42;
-    /** The network could not deliver access information to the remote user as requested */
+    /** The network could not deliver access information to the remote user as requested. */
     public static final int ACCESS_INFORMATION_DISCARDED                     = 43;
-    /** The channel cannot be provided */
+    /** The channel cannot be provided. */
     public static final int CHANNEL_NOT_AVAIL                                = 44;
-    /** This cause is used to report a resource unavailable event only when no other
-     *  cause in the resource unavailable class applies
+    /**
+     * This cause is used to report a resource unavailable event only when no other cause in the
+     * resource unavailable class applies.
      */
     public static final int RESOURCES_UNAVAILABLE_OR_UNSPECIFIED             = 47;
-    /** The requested quality of service (ITU-T X.213) cannot be provided */
+    /** The requested quality of service (ITU-T X.213) cannot be provided. */
     public static final int QOS_NOT_AVAIL                                    = 49;
-    /** The facility could not be provided by the network because the user has no
-     *  complete subscription
+    /**
+     * The facility could not be provided by the network because the user has no complete
+     * subscription.
      */
     public static final int REQUESTED_FACILITY_NOT_SUBSCRIBED                = 50;
-    /** Incoming calls are not allowed within this CUG */
+    /** Incoming calls are not allowed within this calling user group (CUG). */
     public static final int INCOMING_CALLS_BARRED_WITHIN_CUG                 = 55;
-    /** The mobile station is not authorized to use bearer capability requested */
+    /** The mobile station is not authorized to use bearer capability requested. */
     public static final int BEARER_CAPABILITY_NOT_AUTHORIZED                 = 57;
-    /** The requested bearer capability is not available at this time */
+    /** The requested bearer capability is not available at this time. */
     public static final int BEARER_NOT_AVAIL                                 = 58;
-    /** The service option is not availble at this time */
+    /** The service option is not availble at this time. */
     public static final int SERVICE_OPTION_NOT_AVAILABLE                     = 63;
-    /** The equipment sending this cause does not support the bearer capability requested */
+    /** The equipment sending this cause does not support the bearer capability requested. */
     public static final int BEARER_SERVICE_NOT_IMPLEMENTED                   = 65;
-    /** The call clearing is due to ACM being greater than or equal to ACMmax */
+    /** The call clearing is due to ACM being greater than or equal to ACMmax. */
     public static final int ACM_LIMIT_EXCEEDED                               = 68;
-    /** The equipment sending this cause does not support the requested facility */
+    /** The equipment sending this cause does not support the requested facility. */
     public static final int REQUESTED_FACILITY_NOT_IMPLEMENTED               = 69;
-    /** The equipment sending this cause only supports the restricted version of
-     *  the requested bearer capability
+    /**
+     * The equipment sending this cause only supports the restricted version of the requested bearer
+     * capability.
      */
     public static final int ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE        = 70;
-    /** The service requested is not implemented at network */
+    /** The service requested is not implemented at network. */
     public static final int SERVICE_OR_OPTION_NOT_IMPLEMENTED                = 79;
-    /** The equipment sending this cause has received a message with a transaction identifier
-     *  which is not currently in use on the MS-network interface
+    /**
+     * The equipment sending this cause has received a message with a transaction identifier
+     * which is not currently in use on the mobile station network interface.
      */
     public static final int INVALID_TRANSACTION_IDENTIFIER                   = 81;
-    /** The called user for the incoming CUG call is not a member of the specified CUG */
+    /**
+     * The called user for the incoming CUG call is not a member of the specified calling user
+     * group (CUG).
+     */
     public static final int USER_NOT_MEMBER_OF_CUG                           = 87;
-    /** The equipment sending this cause has received a request which can't be accomodated */
+    /** The equipment sending this cause has received a request which can't be accomodated. */
     public static final int INCOMPATIBLE_DESTINATION                         = 88;
-    /** This cause is used to report receipt of a message with semantically incorrect contents */
+    /** This cause is used to report receipt of a message with semantically incorrect contents. */
     public static final int SEMANTICALLY_INCORRECT_MESSAGE                   = 95;
-    /** The equipment sending this cause has received a message with a non-semantical
-     *  mandatory IE error
+    /**
+     * The equipment sending this cause has received a message with a non-semantical mandatory
+     * information element (IE) error.
      */
     public static final int INVALID_MANDATORY_INFORMATION                    = 96;
-    /** This is sent in response to a message which is not defined, or defined but not
-     *  implemented by the equipment sending this cause
+    /**
+     * This is sent in response to a message which is not defined, or defined but not implemented
+     * by the equipment sending this cause.
      */
     public static final int MESSAGE_TYPE_NON_IMPLEMENTED                     = 97;
-    /** The equipment sending this cause has received a message not compatible with the
-     *  protocol state
+    /**
+     * The equipment sending this cause has received a message not compatible with the protocol
+     * state.
      */
     public static final int MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE  = 98;
-    /** The equipment sending this cause has received a message which includes information
-     *  elements not recognized because its identifier is not defined or it is defined but not
-     *  implemented by the equipment sending the cause
+    /**
+     * The equipment sending this cause has received a message which includes information
+     * elements not recognized because its identifier is not defined or it is defined but not
+     * implemented by the equipment sending the cause.
      */
     public static final int INFORMATION_ELEMENT_NON_EXISTENT                 = 99;
-    /** The equipment sending this cause has received a message with conditional IE errors */
+    /** The equipment sending this cause has received a message with conditional IE errors. */
     public static final int CONDITIONAL_IE_ERROR                             = 100;
-    /** The message has been received which is incompatible with the protocol state */
+    /** The message has been received which is incompatible with the protocol state. */
     public static final int MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE       = 101;
-    /** The  procedure has been initiated by the expiry of a timer in association with
-     *  3GPP TS 24.008 error handling procedures
+    /**
+     * The procedure has been initiated by the expiry of a timer in association with
+     * 3GPP TS 24.008 error handling procedures.
      */
     public static final int RECOVERY_ON_TIMER_EXPIRED                        = 102;
-    /** This protocol error event is reported only when no other cause in the protocol
-     *  error class applies
+    /**
+     * This protocol error event is reported only when no other cause in the protocol error class
+     * applies.
      */
     public static final int PROTOCOL_ERROR_UNSPECIFIED                       = 111;
-    /** interworking with a network which does not provide causes for actions it takes
-     *  thus, the precise cause for a message which is being sent cannot be ascertained
+    /**
+     * Interworking with a network which does not provide causes for actions it takes thus, the
+     * precise cause for a message which is being sent cannot be ascertained.
      */
     public static final int INTERWORKING_UNSPECIFIED                         = 127;
-    /** The call is restricted */
+    /** The call is restricted. */
     public static final int CALL_BARRED                                      = 240;
-    /** The call is blocked by the Fixed Dialing Number list */
+    /** The call is blocked by the Fixed Dialing Number list. */
     public static final int FDN_BLOCKED                                      = 241;
-    /** The given IMSI is not known at the VLR */
-    /** TS 24.008 cause 4 */
+    /** The given IMSI is not known at the Visitor Location Register (VLR) TS 24.008 cause . */
     public static final int IMSI_UNKNOWN_IN_VLR                              = 242;
     /**
      * The network does not accept emergency call establishment using an IMEI or not accept attach
-     * procedure for emergency services using an IMEI
+     * procedure for emergency services using an IMEI.
      */
     public static final int IMEI_NOT_ACCEPTED                                = 243;
-    /** The call cannot be established because RADIO is OFF */
+    /** The call cannot be established because RADIO is OFF. */
     public static final int RADIO_OFF                                        = 247;
-    /** The call cannot be established because of no cell coverage */
+    /** The call cannot be established because of no cell coverage. */
     public static final int OUT_OF_SRV                                       = 248;
-    /** The call cannot be established because of no valid SIM */
+    /** The call cannot be established because of no valid SIM. */
     public static final int NO_VALID_SIM                                     = 249;
-    /** The call is dropped or failed internally by modem */
+    /** The call is dropped or failed internally by modem. */
     public static final int RADIO_INTERNAL_ERROR                             = 250;
-    /** Call failed because of UE timer expired while waiting for a response from network */
+    /** Call failed because of UE timer expired while waiting for a response from network. */
     public static final int NETWORK_RESP_TIMEOUT                             = 251;
-    /** Call failed because of a network reject */
+    /** Call failed because of a network reject. */
     public static final int NETWORK_REJECT                                   = 252;
-    /** Call failed because of radio access failure. ex. RACH failure */
+    /** Call failed because of radio access failure. ex. RACH failure. */
     public static final int RADIO_ACCESS_FAILURE                             = 253;
-    /** Call failed/dropped because of a RLF */
+    /** Call failed/dropped because of a Radio Link Failure (RLF). */
     public static final int RADIO_LINK_FAILURE                               = 254;
-    /** Call failed/dropped because of radio link lost */
+    /** Call failed/dropped because of radio link lost. */
     public static final int RADIO_LINK_LOST                                  = 255;
-    /** Call failed because of a radio uplink issue */
+    /** Call failed because of a radio uplink issue. */
     public static final int RADIO_UPLINK_FAILURE                             = 256;
-    /** Call failed because of a RRC connection setup failure */
+    /** Call failed because of a RRC (Radio Resource Control) connection setup failure. */
     public static final int RADIO_SETUP_FAILURE                              = 257;
-    /** Call failed/dropped because of RRC connection release from NW */
+    /** Call failed/dropped because of RRC (Radio Resource Control) connection release from NW. */
     public static final int RADIO_RELEASE_NORMAL                             = 258;
-    /** Call failed/dropped because of RRC abnormally released by modem/network */
+    /**
+     * Call failed/dropped because of RRC (Radio Resource Control) abnormally released by
+     * modem/network.
+     */
     public static final int RADIO_RELEASE_ABNORMAL                           = 259;
-    /** Call setup failed because of access class barring */
+    /** Call setup failed because of access class barring. */
     public static final int ACCESS_CLASS_BLOCKED                             = 260;
-    /** Call failed/dropped because of a network detach */
+    /** Call failed/dropped because of a network detach. */
     public static final int NETWORK_DETACH                                   = 261;
 
-    /** MS is locked until next power cycle */
+    /** Mobile station (MS) is locked until next power cycle. */
     public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE                    = 1000;
-    /** Drop call*/
+    /** Drop call. */
     public static final int CDMA_DROP                                        = 1001;
-    /** INTERCEPT order received, MS state idle entered */
+    /** INTERCEPT order received, Mobile station (MS) state idle entered. */
     public static final int CDMA_INTERCEPT                                   = 1002;
-    /** MS has been redirected, call is cancelled */
+    /** Mobile station (MS) has been redirected, call is cancelled. */
     public static final int CDMA_REORDER                                     = 1003;
-    /** Service option rejection */
+    /** Service option rejection. */
     public static final int CDMA_SO_REJECT                                   = 1004;
-    /** Requested service is rejected, retry delay is set */
+    /** Requested service is rejected, retry delay is set. */
     public static final int CDMA_RETRY_ORDER                                 = 1005;
-    /** Unable to obtain access to the CDMA system */
+    /** Unable to obtain access to the CDMA system. */
     public static final int CDMA_ACCESS_FAILURE                              = 1006;
-    /** Not a preempted call */
+    /** Not a preempted call. */
     public static final int CDMA_PREEMPTED                                   = 1007;
-    /** Not an emergency call */
+    /** Not an emergency call. */
     public static final int CDMA_NOT_EMERGENCY                               = 1008;
-    /** Access Blocked by CDMA network */
+    /** Access Blocked by CDMA network. */
     public static final int CDMA_ACCESS_BLOCKED                              = 1009;
 
     /** Mapped from ImsReasonInfo */
+    // TODO: remove ImsReasonInfo from preciseDisconnectCause
     /* The passed argument is an invalid */
+    /** @hide */
     public static final int LOCAL_ILLEGAL_ARGUMENT                           = 1200;
     // The operation is invoked in invalid call state
+    /** @hide */
     public static final int LOCAL_ILLEGAL_STATE                              = 1201;
     // IMS service internal error
+    /** @hide */
     public static final int LOCAL_INTERNAL_ERROR                             = 1202;
     // IMS service goes down (service connection is lost)
+    /** @hide */
     public static final int LOCAL_IMS_SERVICE_DOWN                           = 1203;
     // No pending incoming call exists
+    /** @hide */
     public static final int LOCAL_NO_PENDING_CALL                            = 1204;
     // Service unavailable; by power off
+    /** @hide */
     public static final int LOCAL_POWER_OFF                                  = 1205;
     // Service unavailable; by low battery
+    /** @hide */
     public static final int LOCAL_LOW_BATTERY                                = 1206;
     // Service unavailable; by out of service (data service state)
+    /** @hide */
     public static final int LOCAL_NETWORK_NO_SERVICE                         = 1207;
     /* Service unavailable; by no LTE coverage
      * (VoLTE is not supported even though IMS is registered)
      */
+    /** @hide */
     public static final int LOCAL_NETWORK_NO_LTE_COVERAGE                    = 1208;
     /** Service unavailable; by located in roaming area */
+    /** @hide */
     public static final int LOCAL_NETWORK_ROAMING                            = 1209;
     /** Service unavailable; by IP changed */
+    /** @hide */
     public static final int LOCAL_NETWORK_IP_CHANGED                         = 1210;
     /** Service unavailable; other */
+    /** @hide */
     public static final int LOCAL_SERVICE_UNAVAILABLE                        = 1211;
     /* Service unavailable; IMS connection is lost (IMS is not registered) */
+    /** @hide */
     public static final int LOCAL_NOT_REGISTERED                             = 1212;
     /** Max call exceeded */
+    /** @hide */
     public static final int LOCAL_MAX_CALL_EXCEEDED                          = 1213;
     /** Call decline */
+    /** @hide */
     public static final int LOCAL_CALL_DECLINE                               = 1214;
     /** SRVCC is in progress */
+    /** @hide */
     public static final int LOCAL_CALL_VCC_ON_PROGRESSING                    = 1215;
     /** Resource reservation is failed (QoS precondition) */
+    /** @hide */
     public static final int LOCAL_CALL_RESOURCE_RESERVATION_FAILED           = 1216;
     /** Retry CS call; VoLTE service can't be provided by the network or remote end
      *  Resolve the extra code(EXTRA_CODE_CALL_RETRY_*) if the below code is set
+     *  @hide
      */
     public static final int LOCAL_CALL_CS_RETRY_REQUIRED                     = 1217;
     /** Retry VoLTE call; VoLTE service can't be provided by the network temporarily */
+    /** @hide */
     public static final int LOCAL_CALL_VOLTE_RETRY_REQUIRED                  = 1218;
     /** IMS call is already terminated (in TERMINATED state) */
+    /** @hide */
     public static final int LOCAL_CALL_TERMINATED                            = 1219;
     /** Handover not feasible */
+    /** @hide */
     public static final int LOCAL_HO_NOT_FEASIBLE                            = 1220;
 
     /** 1xx waiting timer is expired after sending INVITE request (MO only) */
+    /** @hide */
     public static final int TIMEOUT_1XX_WAITING                              = 1221;
     /** User no answer during call setup operation (MO/MT)
      *  MO : 200 OK to INVITE request is not received,
      *  MT : No action from user after alerting the call
+     *  @hide
      */
     public static final int TIMEOUT_NO_ANSWER                                = 1222;
     /** User no answer during call update operation (MO/MT)
      *  MO : 200 OK to re-INVITE request is not received,
      *  MT : No action from user after alerting the call
+     *  @hide
      */
     public static final int TIMEOUT_NO_ANSWER_CALL_UPDATE                    = 1223;
 
@@ -296,102 +346,142 @@
      * STATUSCODE (SIP response code) (IMS -> Telephony)
      */
     /** SIP request is redirected */
+    /** @hide */
     public static final int SIP_REDIRECTED                                   = 1300;
     /** 4xx responses */
     /** 400 : Bad Request */
+    /** @hide */
     public static final int SIP_BAD_REQUEST                                  = 1310;
     /** 403 : Forbidden */
+    /** @hide */
     public static final int SIP_FORBIDDEN                                    = 1311;
     /** 404 : Not Found */
+    /** @hide */
     public static final int SIP_NOT_FOUND                                    = 1312;
     /** 415 : Unsupported Media Type
      *  416 : Unsupported URI Scheme
      *  420 : Bad Extension
      */
+    /** @hide */
     public static final int SIP_NOT_SUPPORTED                                = 1313;
     /** 408 : Request Timeout */
+    /** @hide */
     public static final int SIP_REQUEST_TIMEOUT                              = 1314;
     /** 480 : Temporarily Unavailable */
+    /** @hide */
     public static final int SIP_TEMPRARILY_UNAVAILABLE                       = 1315;
     /** 484 : Address Incomplete */
+    /** @hide */
     public static final int SIP_BAD_ADDRESS                                  = 1316;
     /** 486 : Busy Here
      *  600 : Busy Everywhere
      */
+    /** @hide */
     public static final int SIP_BUSY                                         = 1317;
     /** 487 : Request Terminated */
+    /** @hide */
     public static final int SIP_REQUEST_CANCELLED                            = 1318;
     /** 406 : Not Acceptable
      *  488 : Not Acceptable Here
      *  606 : Not Acceptable
      */
+    /** @hide */
     public static final int SIP_NOT_ACCEPTABLE                               = 1319;
     /** 410 : Gone
      *  604 : Does Not Exist Anywhere
      */
+    /** @hide */
     public static final int SIP_NOT_REACHABLE                                = 1320;
     /** Others */
+    /** @hide */
     public static final int SIP_CLIENT_ERROR                                 = 1321;
     /** 481 : Transaction Does Not Exist */
+    /** @hide */
     public static final int SIP_TRANSACTION_DOES_NOT_EXIST                   = 1322;
     /** 5xx responses
      *  501 : Server Internal Error
      */
+    /** @hide */
     public static final int SIP_SERVER_INTERNAL_ERROR                        = 1330;
     /** 503 : Service Unavailable */
+    /** @hide */
     public static final int SIP_SERVICE_UNAVAILABLE                          = 1331;
     /** 504 : Server Time-out */
+    /** @hide */
     public static final int SIP_SERVER_TIMEOUT                               = 1332;
     /** Others */
+    /** @hide */
     public static final int SIP_SERVER_ERROR                                 = 1333;
     /** 6xx responses
      *  603 : Decline
      */
+    /** @hide */
     public static final int SIP_USER_REJECTED                                = 1340;
     /** Others */
+    /** @hide */
     public static final int SIP_GLOBAL_ERROR                                 = 1341;
     /** Emergency failure */
+    /** @hide */
     public static final int EMERGENCY_TEMP_FAILURE                           = 1342;
+    /** @hide */
     public static final int EMERGENCY_PERM_FAILURE                           = 1343;
     /** Media resource initialization failed */
+    /** @hide */
     public static final int MEDIA_INIT_FAILED                                = 1400;
     /** RTP timeout (no audio / video traffic in the session) */
+    /** @hide */
     public static final int MEDIA_NO_DATA                                    = 1401;
     /** Media is not supported; so dropped the call */
+    /** @hide */
     public static final int MEDIA_NOT_ACCEPTABLE                             = 1402;
     /** Unknown media related errors */
+    /** @hide */
     public static final int MEDIA_UNSPECIFIED                                = 1403;
     /** User triggers the call end */
+    /** @hide */
     public static final int USER_TERMINATED                                  = 1500;
     /** No action while an incoming call is ringing */
+    /** @hide */
     public static final int USER_NOANSWER                                    = 1501;
     /** User ignores an incoming call */
+    /** @hide */
     public static final int USER_IGNORE                                      = 1502;
     /** User declines an incoming call */
+    /** @hide */
     public static final int USER_DECLINE                                     = 1503;
     /** Device declines/ends a call due to low battery */
+    /** @hide */
     public static final int LOW_BATTERY                                      = 1504;
     /** Device declines call due to blacklisted call ID */
+    /** @hide */
     public static final int BLACKLISTED_CALL_ID                              = 1505;
     /** The call is terminated by the network or remote user */
+    /** @hide */
     public static final int USER_TERMINATED_BY_REMOTE                        = 1510;
 
     /**
      * UT
      */
+    /** @hide */
     public static final int UT_NOT_SUPPORTED                                 = 1800;
+    /** @hide */
     public static final int UT_SERVICE_UNAVAILABLE                           = 1801;
+    /** @hide */
     public static final int UT_OPERATION_NOT_ALLOWED                         = 1802;
+    /** @hide */
     public static final int UT_NETWORK_ERROR                                 = 1803;
+    /** @hide */
     public static final int UT_CB_PASSWORD_MISMATCH                          = 1804;
 
     /**
      * ECBM
+     * @hide
      */
     public static final int ECBM_NOT_SUPPORTED                               = 1900;
 
     /**
      * Fail code used to indicate that Multi-endpoint is not supported by the Ims framework.
+     * @hide
      */
     public static final int MULTIENDPOINT_NOT_SUPPORTED                      = 1901;
 
@@ -405,56 +495,68 @@
      * active wifi call and at the edge of coverage and there is no qualified LTE network available
      * to handover the call to. We get a handover NOT_TRIGERRED message from the modem. This error
      * code is received as part of the handover message.
+     * @hide
      */
     public static final int CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE               = 2000;
 
     /**
      * MT call has ended due to a release from the network
      * because the call was answered elsewhere
+     * @hide
      */
     public static final int ANSWERED_ELSEWHERE                               = 2100;
 
     /**
      * For MultiEndpoint - Call Pull request has failed
+     * @hide
      */
     public static final int CALL_PULL_OUT_OF_SYNC                            = 2101;
 
     /**
      * For MultiEndpoint - Call has been pulled from primary to secondary
+     * @hide
      */
     public static final int CALL_PULLED                                      = 2102;
 
     /**
      * Supplementary services (HOLD/RESUME) failure error codes.
      * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
+     * @hide
      */
     public static final int SUPP_SVC_FAILED                                  = 2300;
+    /** @hide */
     public static final int SUPP_SVC_CANCELLED                               = 2301;
+    /** @hide */
     public static final int SUPP_SVC_REINVITE_COLLISION                      = 2302;
 
     /**
      * DPD Procedure received no response or send failed
+     * @hide
      */
     public static final int IWLAN_DPD_FAILURE                                = 2400;
 
     /**
      * Establishment of the ePDG Tunnel Failed
+     * @hide
      */
     public static final int EPDG_TUNNEL_ESTABLISH_FAILURE                    = 2500;
 
     /**
      * Re-keying of the ePDG Tunnel Failed; may not always result in teardown
+     * @hide
      */
     public static final int EPDG_TUNNEL_REKEY_FAILURE                        = 2501;
 
     /**
      * Connection to the packet gateway is lost
+     * @hide
      */
     public static final int EPDG_TUNNEL_LOST_CONNECTION                      = 2502;
 
     /**
      * The maximum number of calls allowed has been reached.  Used in a multi-endpoint scenario
      * where the number of calls across all connected devices has reached the maximum.
+     * @hide
      */
     public static final int MAXIMUM_NUMBER_OF_CALLS_REACHED                  = 2503;
 
@@ -462,21 +564,25 @@
      * Similar to {@link #CODE_LOCAL_CALL_DECLINE}, except indicates that a remote device has
      * declined the call.  Used in a multi-endpoint scenario where a remote device declined an
      * incoming call.
+     * @hide
      */
     public static final int REMOTE_CALL_DECLINE                              = 2504;
 
     /**
      * Indicates the call was disconnected due to the user reaching their data limit.
+     * @hide
      */
     public static final int DATA_LIMIT_REACHED                               = 2505;
 
     /**
      * Indicates the call was disconnected due to the user disabling cellular data.
+     * @hide
      */
     public static final int DATA_DISABLED                                    = 2506;
 
     /**
      * Indicates a call was disconnected due to loss of wifi signal.
+     * @hide
      */
     public static final int WIFI_LOST                                        = 2507;
 
@@ -499,7 +605,7 @@
     public static final int OEM_CAUSE_14                                     = 0xf00e;
     public static final int OEM_CAUSE_15                                     = 0xf00f;
 
-    /** Disconnected due to unspecified reasons */
+    /** Disconnected due to unspecified reasons. */
     public static final int ERROR_UNSPECIFIED                                = 0xffff;
 
     /** Private constructor to avoid class instantiation. */
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 13fbeaa..ca0c854 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -118,6 +118,13 @@
      */
     public static final int FREQUENCY_RANGE_MMWAVE = 4;
 
+    private static final List<Integer> FREQUENCY_RANGE_ORDER = Arrays.asList(
+            FREQUENCY_RANGE_UNKNOWN,
+            FREQUENCY_RANGE_LOW,
+            FREQUENCY_RANGE_MID,
+            FREQUENCY_RANGE_HIGH,
+            FREQUENCY_RANGE_MMWAVE);
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "DUPLEX_MODE_",
@@ -1835,4 +1842,13 @@
             mNetworkRegistrationStates.add(regState);
         }
     }
+
+    /**
+     * @hide
+     */
+    public static final int getBetterNRFrequencyRange(int range1, int range2) {
+        return FREQUENCY_RANGE_ORDER.indexOf(range1) > FREQUENCY_RANGE_ORDER.indexOf(range2)
+                ? range1
+                : range2;
+    }
 }
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 240b8a9..ef185c5 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -16,16 +16,14 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.CarrierConfigManager;
-import android.util.Log;
+import android.os.PersistableBundle;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -59,6 +57,8 @@
     /** @hide */
     @UnsupportedAppUsage
     public static final int NUM_SIGNAL_STRENGTH_BINS = 5;
+
+    /** SIGNAL_STRENGTH_NAMES is currently used by BatteryStats, but to-be-removed soon. */
     /** @hide */
     public static final String[] SIGNAL_STRENGTH_NAMES = {
         "none", "poor", "moderate", "good", "great"
@@ -72,66 +72,22 @@
     public static final int INVALID = Integer.MAX_VALUE;
 
     private static final int LTE_RSRP_THRESHOLDS_NUM = 4;
-    private static final int MAX_LTE_RSRP = -44;
-    private static final int MIN_LTE_RSRP = -140;
 
     private static final int WCDMA_RSCP_THRESHOLDS_NUM = 4;
-    private static final int MAX_WCDMA_RSCP = -24;
-    private static final int MIN_WCDMA_RSCP = -120;
 
     /* The type of signal measurement */
-    private static final String MEASUMENT_TYPE_RSCP = "rscp";
+    private static final String MEASUREMENT_TYPE_RSCP = "rscp";
 
-    /** Parameters reported by the Radio */
-    @UnsupportedAppUsage
-    private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
-    @UnsupportedAppUsage
-    private int mGsmBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
-    @UnsupportedAppUsage
-    private int mCdmaDbm;   // This value is the RSSI value
-    @UnsupportedAppUsage
-    private int mCdmaEcio;  // This value is the Ec/Io
-    @UnsupportedAppUsage
-    private int mEvdoDbm;   // This value is the EVDO RSSI value
-    @UnsupportedAppUsage
-    private int mEvdoEcio;  // This value is the EVDO Ec/Io
-    @UnsupportedAppUsage
-    private int mEvdoSnr;   // Valid values are 0-8.  8 is the highest signal to noise ratio
-    @UnsupportedAppUsage
-    private int mLteSignalStrength;
-    @UnsupportedAppUsage
-    private int mLteRsrp;
-    @UnsupportedAppUsage
-    private int mLteRsrq;
-    @UnsupportedAppUsage
-    private int mLteRssnr;
-    @UnsupportedAppUsage
-    private int mLteCqi;
-    @UnsupportedAppUsage
-    private int mTdScdmaRscp; // Valid values are -24...-120dBm or INVALID if unknown
-    private int mWcdmaSignalStrength;
-    private int mWcdmaRscpAsu;  // the WCDMA RSCP in ASU as reported from the HAL
-    @UnsupportedAppUsage
-    private int mWcdmaRscp;     // the WCDMA RSCP in dBm
+    CellSignalStrengthCdma mCdma;
+    CellSignalStrengthGsm mGsm;
+    CellSignalStrengthWcdma mWcdma;
+    CellSignalStrengthTdscdma mTdscdma;
+    CellSignalStrengthLte mLte;
 
     /** Parameters from the framework */
     @UnsupportedAppUsage
     private int mLteRsrpBoost; // offset to be reduced from the rsrp threshold while calculating
                                 // signal strength level
-    private boolean mIsGsm; // This value is set by the ServiceStateTracker
-                            // onSignalStrengthResult.
-    private boolean mUseOnlyRsrpForLteLevel; // Use only RSRP for the number of LTE signal bar.
-
-    // The threshold of LTE RSRP for determining the display level of LTE signal bar. Note that the
-    // min and max are fixed at MIN_LTE_RSRP (-140) and MAX_LTE_RSRP (-44).
-    private int mLteRsrpThresholds[] = new int[LTE_RSRP_THRESHOLDS_NUM];
-
-    // The type of default measurement for determining the display level of WCDMA signal bar.
-    private String mWcdmaDefaultSignalMeasurement;
-
-    // The threshold of WCDMA RSCP for determining the display level of WCDMA signal bar. Note that
-    // the min and max are fixed at MIN_WCDMA_RSCP (-120) and MAX_WCDMA_RSCP (-24).
-    private int mWcdmaRscpThresholds[] = new int[WCDMA_RSCP_THRESHOLDS_NUM];
 
     /**
      * Create a new SignalStrength from a intent notifier Bundle
@@ -153,47 +109,17 @@
     }
 
     /**
-     * Empty constructor
-     *
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public SignalStrength() {
-        this(true);
-    }
-
-    /**
      * This constructor is used to create SignalStrength with default
-     * values and set the gsmFlag with the value passed in the input
+     * values.
      *
-     * @param gsmFlag true if Gsm Phone,false if Cdma phone
      * @return newly created SignalStrength
      * @hide
      */
     @UnsupportedAppUsage
-    public SignalStrength(boolean gsmFlag) {
-        mGsmSignalStrength = 99;
-        mGsmBitErrorRate = -1;
-        mCdmaDbm = INVALID;
-        mCdmaEcio = -1;
-        mEvdoDbm = INVALID;
-        mEvdoEcio = -1;
-        mEvdoSnr = -1;
-        mLteSignalStrength = 99;
-        mLteRsrp = INVALID;
-        mLteRsrq = INVALID;
-        mLteRssnr = INVALID;
-        mLteCqi = INVALID;
-        mTdScdmaRscp = INVALID;
-        mWcdmaSignalStrength = 99;
-        mWcdmaRscp = INVALID;
-        mWcdmaRscpAsu = 255;
-        mLteRsrpBoost = 0;
-        mIsGsm = gsmFlag;
-        mUseOnlyRsrpForLteLevel = false;
-        mWcdmaDefaultSignalMeasurement = "";
-        setLteRsrpThresholds(getDefaultLteRsrpThresholds());
-        setWcdmaRscpThresholds(getDefaultWcdmaRscpThresholds());
+    public SignalStrength() {
+        this(new CellSignalStrengthCdma(), new CellSignalStrengthGsm(),
+                new CellSignalStrengthWcdma(), new CellSignalStrengthTdscdma(),
+                new CellSignalStrengthLte());
     }
 
     /**
@@ -202,68 +128,64 @@
      * @hide
      */
     public SignalStrength(
-            int gsmSignalStrength, int gsmBitErrorRate,
-            int cdmaDbm, int cdmaEcio,
-            int evdoDbm, int evdoEcio, int evdoSnr,
-            int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
-            int tdScdmaRscp, int wcdmaSignalStrength, int wcdmaRscpAsu,
-            // values Added by config
-            int lteRsrpBoost, boolean gsmFlag, boolean lteLevelBaseOnRsrp,
-            String wcdmaDefaultMeasurement) {
-        mGsmSignalStrength = gsmSignalStrength;
-        mGsmBitErrorRate = gsmBitErrorRate;
-        mCdmaDbm = cdmaDbm;
-        mCdmaEcio = cdmaEcio;
-        mEvdoDbm = evdoDbm;
-        mEvdoEcio = evdoEcio;
-        mEvdoSnr = evdoSnr;
-        mLteSignalStrength = lteSignalStrength;
-        mLteRsrp = lteRsrp;
-        mLteRsrq = lteRsrq;
-        mLteRssnr = lteRssnr;
-        mLteCqi = lteCqi;
-        mTdScdmaRscp = INVALID;
-        mWcdmaSignalStrength = wcdmaSignalStrength;
-        mWcdmaRscpAsu = wcdmaRscpAsu;
-        mWcdmaRscp = wcdmaRscpAsu - 120;
-        mLteRsrpBoost = lteRsrpBoost;
-        mIsGsm = gsmFlag;
-        mUseOnlyRsrpForLteLevel = lteLevelBaseOnRsrp;
-        mWcdmaDefaultSignalMeasurement = wcdmaDefaultMeasurement;
-        setLteRsrpThresholds(getDefaultLteRsrpThresholds());
-        setWcdmaRscpThresholds(getDefaultWcdmaRscpThresholds());
-        if (DBG) log("initialize: " + toString());
+            @NonNull CellSignalStrengthCdma cdma,
+            @NonNull CellSignalStrengthGsm gsm,
+            @NonNull CellSignalStrengthWcdma wcdma,
+            @NonNull CellSignalStrengthTdscdma tdscdma,
+            @NonNull CellSignalStrengthLte lte) {
+        mCdma = cdma;
+        mGsm = gsm;
+        mWcdma = wcdma;
+        mTdscdma = tdscdma;
+        mLte = lte;
+        mLteRsrpBoost = 0;
     }
 
     /**
-     * Constructor for only values provided by Radio HAL V1.0
+     * Constructor for Radio HAL V1.0
      *
      * @hide
      */
-    public SignalStrength(int gsmSignalStrength, int gsmBitErrorRate,
-            int cdmaDbm, int cdmaEcio,
-            int evdoDbm, int evdoEcio, int evdoSnr,
-            int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
-            int tdScdmaRscp) {
-        this(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
-                evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
-                lteRsrq, lteRssnr, lteCqi, tdScdmaRscp, 99, INVALID, 0, true, false, "");
+    public SignalStrength(android.hardware.radio.V1_0.SignalStrength signalStrength) {
+        this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
+                new CellSignalStrengthGsm(signalStrength.gw),
+                new CellSignalStrengthWcdma(),
+                new CellSignalStrengthTdscdma(signalStrength.tdScdma),
+                new CellSignalStrengthLte(signalStrength.lte));
     }
 
     /**
-     * Constructor for only values provided by Radio HAL V1.2
+     * Constructor for Radio HAL V1.2
      *
      * @hide
      */
-    public SignalStrength(int gsmSignalStrength, int gsmBitErrorRate,
-            int cdmaDbm, int cdmaEcio,
-            int evdoDbm, int evdoEcio, int evdoSnr,
-            int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
-            int tdScdmaRscp, int wcdmaSignalStrength, int wcdmaRscp) {
-        this(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
-                evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
-                lteRsrq, lteRssnr, lteCqi, tdScdmaRscp, wcdmaSignalStrength, wcdmaRscp, 0, true,
-                false, "");
+    public SignalStrength(android.hardware.radio.V1_2.SignalStrength signalStrength) {
+        this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
+                new CellSignalStrengthGsm(signalStrength.gsm),
+                new CellSignalStrengthWcdma(signalStrength.wcdma),
+                new CellSignalStrengthTdscdma(signalStrength.tdScdma),
+                new CellSignalStrengthLte(signalStrength.lte));
+    }
+
+    private CellSignalStrength getPrimary() {
+        // This behavior is intended to replicate the legacy behavior of getLevel() by prioritizing
+        // newer faster RATs for default/for display purposes.
+        if (mLte.isValid()) return mLte;
+        if (mCdma.isValid()) return mCdma;
+        if (mTdscdma.isValid()) return mTdscdma;
+        if (mWcdma.isValid()) return mWcdma;
+        if (mGsm.isValid()) return mGsm;
+        return mLte;
+    }
+
+    /** @hide */
+    public void updateLevel(PersistableBundle cc, ServiceState ss) {
+        mLteRsrpBoost = ss.getLteEarfcnRsrpBoost();
+        mCdma.updateLevel(cc, ss);
+        mGsm.updateLevel(cc, ss);
+        mWcdma.updateLevel(cc, ss);
+        mTdscdma.updateLevel(cc, ss);
+        mLte.updateLevel(cc, ss);
     }
 
     /**
@@ -283,28 +205,12 @@
      */
     @UnsupportedAppUsage
     protected void copyFrom(SignalStrength s) {
-        mGsmSignalStrength = s.mGsmSignalStrength;
-        mGsmBitErrorRate = s.mGsmBitErrorRate;
-        mCdmaDbm = s.mCdmaDbm;
-        mCdmaEcio = s.mCdmaEcio;
-        mEvdoDbm = s.mEvdoDbm;
-        mEvdoEcio = s.mEvdoEcio;
-        mEvdoSnr = s.mEvdoSnr;
-        mLteSignalStrength = s.mLteSignalStrength;
-        mLteRsrp = s.mLteRsrp;
-        mLteRsrq = s.mLteRsrq;
-        mLteRssnr = s.mLteRssnr;
-        mLteCqi = s.mLteCqi;
-        mTdScdmaRscp = s.mTdScdmaRscp;
-        mWcdmaSignalStrength = s.mWcdmaSignalStrength;
-        mWcdmaRscpAsu = s.mWcdmaRscpAsu;
-        mWcdmaRscp = s.mWcdmaRscp;
+        mCdma = new CellSignalStrengthCdma(s.mCdma);
+        mGsm = new CellSignalStrengthGsm(s.mGsm);
+        mWcdma = new CellSignalStrengthWcdma(s.mWcdma);
+        mTdscdma = new CellSignalStrengthTdscdma(s.mTdscdma);
+        mLte = new CellSignalStrengthLte(s.mLte);
         mLteRsrpBoost = s.mLteRsrpBoost;
-        mIsGsm = s.mIsGsm;
-        mUseOnlyRsrpForLteLevel = s.mUseOnlyRsrpForLteLevel;
-        mWcdmaDefaultSignalMeasurement = s.mWcdmaDefaultSignalMeasurement;
-        setLteRsrpThresholds(s.mLteRsrpThresholds);
-        setWcdmaRscpThresholds(s.mWcdmaRscpThresholds);
     }
 
     /**
@@ -316,56 +222,25 @@
     public SignalStrength(Parcel in) {
         if (DBG) log("Size of signalstrength parcel:" + in.dataSize());
 
-        mGsmSignalStrength = in.readInt();
-        mGsmBitErrorRate = in.readInt();
-        mCdmaDbm = in.readInt();
-        mCdmaEcio = in.readInt();
-        mEvdoDbm = in.readInt();
-        mEvdoEcio = in.readInt();
-        mEvdoSnr = in.readInt();
-        mLteSignalStrength = in.readInt();
-        mLteRsrp = in.readInt();
-        mLteRsrq = in.readInt();
-        mLteRssnr = in.readInt();
-        mLteCqi = in.readInt();
-        mTdScdmaRscp = in.readInt();
-        mWcdmaSignalStrength = in.readInt();
-        mWcdmaRscpAsu = in.readInt();
-        mWcdmaRscp = in.readInt();
+        mCdma = in.readParcelable(CellSignalStrengthCdma.class.getClassLoader());
+        mGsm = in.readParcelable(CellSignalStrengthGsm.class.getClassLoader());
+        mWcdma = in.readParcelable(CellSignalStrengthWcdma.class.getClassLoader());
+        mTdscdma = in.readParcelable(CellSignalStrengthTdscdma.class.getClassLoader());
+        mLte = in.readParcelable(CellSignalStrengthLte.class.getClassLoader());
         mLteRsrpBoost = in.readInt();
-        mIsGsm = in.readBoolean();
-        mUseOnlyRsrpForLteLevel = in.readBoolean();
-        mWcdmaDefaultSignalMeasurement = in.readString();
-        in.readIntArray(mLteRsrpThresholds);
-        in.readIntArray(mWcdmaRscpThresholds);
     }
 
     /**
      * {@link Parcelable#writeToParcel}
      */
     public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(mGsmSignalStrength);
-        out.writeInt(mGsmBitErrorRate);
-        out.writeInt(mCdmaDbm);
-        out.writeInt(mCdmaEcio);
-        out.writeInt(mEvdoDbm);
-        out.writeInt(mEvdoEcio);
-        out.writeInt(mEvdoSnr);
-        out.writeInt(mLteSignalStrength);
-        out.writeInt(mLteRsrp);
-        out.writeInt(mLteRsrq);
-        out.writeInt(mLteRssnr);
-        out.writeInt(mLteCqi);
-        out.writeInt(mTdScdmaRscp);
-        out.writeInt(mWcdmaSignalStrength);
-        out.writeInt(mWcdmaRscpAsu);
-        out.writeInt(mWcdmaRscp);
+        out.writeParcelable(mCdma, flags);
+        out.writeParcelable(mGsm, flags);
+        out.writeParcelable(mWcdma, flags);
+        out.writeParcelable(mTdscdma, flags);
+        out.writeParcelable(mLte, flags);
+
         out.writeInt(mLteRsrpBoost);
-        out.writeBoolean(mIsGsm);
-        out.writeBoolean(mUseOnlyRsrpForLteLevel);
-        out.writeString(mWcdmaDefaultSignalMeasurement);
-        out.writeIntArray(mLteRsrpThresholds);
-        out.writeIntArray(mWcdmaRscpThresholds);
     }
 
     /**
@@ -392,153 +267,21 @@
     };
 
     /**
-     * Validate the individual signal strength fields as per the range
-     * specified in ril.h
-     * Set to invalid any field that is not in the valid range
-     * Cdma, evdo, lte rsrp & rsrq values are sign converted
-     * when received from ril interface
+     * Get the GSM RSSI in ASU.
      *
-     * @return
-     *      Valid values for all signalstrength fields
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public void validateInput() {
-        if (DBG) log("Signal before validate=" + this);
-        // TS 27.007 8.5
-        mGsmSignalStrength = mGsmSignalStrength >= 0 ? mGsmSignalStrength : 99;
-        mWcdmaSignalStrength = (mWcdmaSignalStrength >= 0) ? mWcdmaSignalStrength : 99;
-        mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99;
-        // BER no change;
-
-        // WCDMA RSCP valid values are -120 through -24 as defined in TS 27.007 8.69
-        // but are reported in ASU which is 0 through 96, so we do the conversion here
-        mWcdmaRscpAsu =
-                ((mWcdmaRscpAsu - 120 >= MIN_WCDMA_RSCP) && (mWcdmaRscpAsu - 120 <= MAX_WCDMA_RSCP))
-                ? mWcdmaRscpAsu : 255;
-        mWcdmaRscp = ((mWcdmaRscp >= MIN_WCDMA_RSCP) && (mWcdmaRscp <= MAX_WCDMA_RSCP))
-                ? mWcdmaRscp : INVALID;
-
-        mCdmaDbm = mCdmaDbm > 0 ? -mCdmaDbm : -120;
-        mCdmaEcio = (mCdmaEcio >= 0) ? -mCdmaEcio : -160;
-
-        mEvdoDbm = (mEvdoDbm > 0) ? -mEvdoDbm : -120;
-        mEvdoEcio = (mEvdoEcio >= 0) ? -mEvdoEcio : -160;
-        mEvdoSnr = ((mEvdoSnr >= 0) && (mEvdoSnr <= 8)) ? mEvdoSnr : -1;
-
-        // TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC
-        mLteRsrp = ((-mLteRsrp >= MIN_LTE_RSRP) && (-mLteRsrp <= MAX_LTE_RSRP)) ? -mLteRsrp
-                                : SignalStrength.INVALID;
-        mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID;
-        mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr
-                : SignalStrength.INVALID;
-
-        mTdScdmaRscp = ((mTdScdmaRscp >= 0) && (mTdScdmaRscp <= 96))
-                ? (mTdScdmaRscp - 120) : SignalStrength.INVALID;
-        // Cqi no change
-        if (DBG) log("Signal after validate=" + this);
-    }
-
-    /**
-     * Fix {@link #mIsGsm} based on the signal strength data.
+     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      *
-     * @hide
-     */
-    public void fixType() {
-        mIsGsm = getCdmaRelatedSignalStrength() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-    }
-
-    /**
-     * @param true - Gsm, Lte phones
-     *        false - Cdma phones
-     *
-     * Used by voice phone to set the mIsGsm
-     *        flag
-     * @hide
-     */
-    public void setGsm(boolean gsmFlag) {
-        mIsGsm = gsmFlag;
-    }
-
-    /**
-     * @param useOnlyRsrpForLteLevel true if it uses only RSRP for the number of LTE signal bar,
-     * otherwise false.
-     *
-     * Used by phone to use only RSRP or not for the number of LTE signal bar.
-     * @hide
-     */
-    public void setUseOnlyRsrpForLteLevel(boolean useOnlyRsrpForLteLevel) {
-        mUseOnlyRsrpForLteLevel = useOnlyRsrpForLteLevel;
-    }
-
-    /**
-     * @param defaultMeasurement sets the type of WCDMA default signal measurement
-     *
-     * Used by phone to determine default measurement type for calculation WCDMA signal level.
-     * @hide
-     */
-    public void setWcdmaDefaultSignalMeasurement(String defaultMeasurement) {
-        mWcdmaDefaultSignalMeasurement = defaultMeasurement;
-    }
-
-    /**
-     * @param lteRsrpBoost - signal strength offset
-     *
-     * Used by phone to set the lte signal strength offset which will be
-     * reduced from rsrp threshold while calculating signal strength level
-     *
-     * @hide
-     */
-    public void setLteRsrpBoost(int lteRsrpBoost) {
-        mLteRsrpBoost = lteRsrpBoost;
-    }
-
-    /**
-     * Sets the threshold array for determining the display level of LTE signal bar.
-     *
-     * @param lteRsrpThresholds int array for determining the display level.
-     *
-     * @hide
-     */
-    public void setLteRsrpThresholds(int[] lteRsrpThresholds) {
-        if ((lteRsrpThresholds == null)
-                || (lteRsrpThresholds.length != LTE_RSRP_THRESHOLDS_NUM)) {
-            Log.wtf(LOG_TAG, "setLteRsrpThresholds - lteRsrpThresholds is invalid.");
-            return;
-        }
-        System.arraycopy(lteRsrpThresholds, 0, mLteRsrpThresholds, 0, LTE_RSRP_THRESHOLDS_NUM);
-    }
-
-    /**
-     * Get the GSM Signal Strength, valid values are (0-31, 99) as defined in TS
-     * 27.007 8.5
+     * @return RSSI in ASU 0..31, 99, or UNAVAILABLE
      */
     public int getGsmSignalStrength() {
-        return this.mGsmSignalStrength;
+        return mGsm.getAsuLevel();
     }
 
     /**
      * Get the GSM bit error rate (0-7, 99) as defined in TS 27.007 8.5
      */
     public int getGsmBitErrorRate() {
-        return this.mGsmBitErrorRate;
-    }
-
-    /**
-     * Sets the threshold array for determining the display level of WCDMA signal bar.
-     *
-     * @param wcdmaRscpThresholds int array for determining the display level.
-     *
-     * @hide
-     */
-    public void setWcdmaRscpThresholds(int[] wcdmaRscpThresholds) {
-        if ((wcdmaRscpThresholds == null)
-                || (wcdmaRscpThresholds.length != WCDMA_RSCP_THRESHOLDS_NUM)) {
-            Log.wtf(LOG_TAG, "setWcdmaRscpThresholds - wcdmaRscpThresholds is invalid.");
-            return;
-        }
-        System.arraycopy(wcdmaRscpThresholds, 0, mWcdmaRscpThresholds, 0,
-                WCDMA_RSCP_THRESHOLDS_NUM);
+        return mGsm.getBitErrorRate();
     }
 
     /**
@@ -547,14 +290,14 @@
      * @return the CDMA RSSI value or {@link #INVALID} if invalid
      */
     public int getCdmaDbm() {
-        return this.mCdmaDbm;
+        return mCdma.getCdmaDbm();
     }
 
     /**
      * Get the CDMA Ec/Io value in dB*10
      */
     public int getCdmaEcio() {
-        return this.mCdmaEcio;
+        return mCdma.getCdmaEcio();
     }
 
     /**
@@ -563,51 +306,51 @@
      * @return the EVDO RSSI value or {@link #INVALID} if invalid
      */
     public int getEvdoDbm() {
-        return this.mEvdoDbm;
+        return mCdma.getEvdoDbm();
     }
 
     /**
      * Get the EVDO Ec/Io value in dB*10
      */
     public int getEvdoEcio() {
-        return this.mEvdoEcio;
+        return mCdma.getEvdoEcio();
     }
 
     /**
      * Get the signal to noise ratio. Valid values are 0-8. 8 is the highest.
      */
     public int getEvdoSnr() {
-        return this.mEvdoSnr;
+        return mCdma.getEvdoSnr();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public int getLteSignalStrength() {
-        return mLteSignalStrength;
+        return mLte.getRssi();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public int getLteRsrp() {
-        return mLteRsrp;
+        return mLte.getRsrp();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public int getLteRsrq() {
-        return mLteRsrq;
+        return mLte.getRsrq();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public int getLteRssnr() {
-        return mLteRssnr;
+        return mLte.getRssnr();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public int getLteCqi() {
-        return mLteCqi;
+        return mLte.getCqi();
     }
 
     /** @hide */
@@ -624,9 +367,12 @@
      *     while 4 represents a very strong signal strength.
      */
     public int getLevel() {
-        int level = mIsGsm ? getGsmRelatedSignalStrength() : getCdmaRelatedSignalStrength();
-        if (DBG) log("getLevel=" + level);
-        return level;
+        int level = getPrimary().getLevel();
+        if (level < SIGNAL_STRENGTH_NONE_OR_UNKNOWN || level > SIGNAL_STRENGTH_GREAT) {
+            log("Invalid Level " + level + ", this=" + this);
+            return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        }
+        return getPrimary().getLevel();
     }
 
     /**
@@ -636,33 +382,7 @@
      */
     @UnsupportedAppUsage
     public int getAsuLevel() {
-        int asuLevel = 0;
-        if (mIsGsm) {
-            if (mLteRsrp != SignalStrength.INVALID) {
-                asuLevel = getLteAsuLevel();
-            } else if (mTdScdmaRscp != SignalStrength.INVALID) {
-                asuLevel = getTdScdmaAsuLevel();
-            } else if (mWcdmaRscp != SignalStrength.INVALID) {
-                asuLevel = getWcdmaAsuLevel();
-            } else {
-                asuLevel = getGsmAsuLevel();
-            }
-        } else {
-            int cdmaAsuLevel = getCdmaAsuLevel();
-            int evdoAsuLevel = getEvdoAsuLevel();
-            if (evdoAsuLevel == 0) {
-                /* We don't know evdo use, cdma */
-                asuLevel = cdmaAsuLevel;
-            } else if (cdmaAsuLevel == 0) {
-                /* We don't know cdma use, evdo */
-                asuLevel = evdoAsuLevel;
-            } else {
-                /* We know both, use the lowest level */
-                asuLevel = cdmaAsuLevel < evdoAsuLevel ? cdmaAsuLevel : evdoAsuLevel;
-            }
-        }
-        if (DBG) log("getAsuLevel=" + asuLevel);
-        return asuLevel;
+        return getPrimary().getAsuLevel();
     }
 
     /**
@@ -672,30 +392,7 @@
      */
     @UnsupportedAppUsage
     public int getDbm() {
-        int dBm = INVALID;
-
-        if(isGsm()) {
-            dBm = getLteDbm();
-            if (dBm == INVALID) {
-                if (getTdScdmaLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                    if (getWcdmaDbm() == INVALID) {
-                        dBm = getGsmDbm();
-                    } else {
-                        dBm = getWcdmaDbm();
-                    }
-                } else {
-                    dBm = getTdScdmaDbm();
-                }
-            }
-        } else {
-            int cdmaDbm = getCdmaDbm();
-            int evdoDbm = getEvdoDbm();
-
-            return (evdoDbm == -120) ? cdmaDbm : ((cdmaDbm == -120) ? evdoDbm
-                    : (cdmaDbm < evdoDbm ? cdmaDbm : evdoDbm));
-        }
-        if (DBG) log("getDbm=" + dBm);
-        return dBm;
+        return getPrimary().getDbm();
     }
 
     /**
@@ -705,17 +402,7 @@
      */
     @UnsupportedAppUsage
     public int getGsmDbm() {
-        int dBm;
-
-        int gsmSignalStrength = getGsmSignalStrength();
-        int asu = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
-        if (asu != -1) {
-            dBm = -113 + (2 * asu);
-        } else {
-            dBm = -1;
-        }
-        if (DBG) log("getGsmDbm=" + dBm);
-        return dBm;
+        return mGsm.getDbm();
     }
 
     /**
@@ -725,20 +412,7 @@
      */
     @UnsupportedAppUsage
     public int getGsmLevel() {
-        int level;
-
-        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-        // asu = 0 (-113dB or less) is very weak
-        // signal, its better to show 0 bars to the user in such cases.
-        // asu = 99 is a special case, where the signal strength is unknown.
-        int asu = getGsmSignalStrength();
-        if (asu <= 2 || asu == 99) level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (asu >= 12) level = SIGNAL_STRENGTH_GREAT;
-        else if (asu >= 8)  level = SIGNAL_STRENGTH_GOOD;
-        else if (asu >= 5)  level = SIGNAL_STRENGTH_MODERATE;
-        else level = SIGNAL_STRENGTH_POOR;
-        if (DBG) log("getGsmLevel=" + level);
-        return level;
+        return mGsm.getLevel();
     }
 
     /**
@@ -748,13 +422,7 @@
      */
     @UnsupportedAppUsage
     public int getGsmAsuLevel() {
-        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
-        // asu = 0 (-113dB or less) is very weak
-        // signal, its better to show 0 bars to the user in such cases.
-        // asu = 99 is a special case, where the signal strength is unknown.
-        int level = getGsmSignalStrength();
-        if (DBG) log("getGsmAsuLevel=" + level);
-        return level;
+        return mGsm.getAsuLevel();
     }
 
     /**
@@ -764,27 +432,7 @@
      */
     @UnsupportedAppUsage
     public int getCdmaLevel() {
-        final int cdmaDbm = getCdmaDbm();
-        final int cdmaEcio = getCdmaEcio();
-        int levelDbm;
-        int levelEcio;
-
-        if (cdmaDbm >= -75) levelDbm = SIGNAL_STRENGTH_GREAT;
-        else if (cdmaDbm >= -85) levelDbm = SIGNAL_STRENGTH_GOOD;
-        else if (cdmaDbm >= -95) levelDbm = SIGNAL_STRENGTH_MODERATE;
-        else if (cdmaDbm >= -100) levelDbm = SIGNAL_STRENGTH_POOR;
-        else levelDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-
-        // Ec/Io are in dB*10
-        if (cdmaEcio >= -90) levelEcio = SIGNAL_STRENGTH_GREAT;
-        else if (cdmaEcio >= -110) levelEcio = SIGNAL_STRENGTH_GOOD;
-        else if (cdmaEcio >= -130) levelEcio = SIGNAL_STRENGTH_MODERATE;
-        else if (cdmaEcio >= -150) levelEcio = SIGNAL_STRENGTH_POOR;
-        else levelEcio = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-
-        int level = (levelDbm < levelEcio) ? levelDbm : levelEcio;
-        if (DBG) log("getCdmaLevel=" + level);
-        return level;
+        return mCdma.getLevel();
     }
 
     /**
@@ -794,29 +442,7 @@
      */
     @UnsupportedAppUsage
     public int getCdmaAsuLevel() {
-        final int cdmaDbm = getCdmaDbm();
-        final int cdmaEcio = getCdmaEcio();
-        int cdmaAsuLevel;
-        int ecioAsuLevel;
-
-        if (cdmaDbm >= -75) cdmaAsuLevel = 16;
-        else if (cdmaDbm >= -82) cdmaAsuLevel = 8;
-        else if (cdmaDbm >= -90) cdmaAsuLevel = 4;
-        else if (cdmaDbm >= -95) cdmaAsuLevel = 2;
-        else if (cdmaDbm >= -100) cdmaAsuLevel = 1;
-        else cdmaAsuLevel = 99;
-
-        // Ec/Io are in dB*10
-        if (cdmaEcio >= -90) ecioAsuLevel = 16;
-        else if (cdmaEcio >= -100) ecioAsuLevel = 8;
-        else if (cdmaEcio >= -115) ecioAsuLevel = 4;
-        else if (cdmaEcio >= -130) ecioAsuLevel = 2;
-        else if (cdmaEcio >= -150) ecioAsuLevel = 1;
-        else ecioAsuLevel = 99;
-
-        int level = (cdmaAsuLevel < ecioAsuLevel) ? cdmaAsuLevel : ecioAsuLevel;
-        if (DBG) log("getCdmaAsuLevel=" + level);
-        return level;
+        return mCdma.getAsuLevel();
     }
 
     /**
@@ -826,26 +452,7 @@
      */
     @UnsupportedAppUsage
     public int getEvdoLevel() {
-        int evdoDbm = getEvdoDbm();
-        int evdoSnr = getEvdoSnr();
-        int levelEvdoDbm;
-        int levelEvdoSnr;
-
-        if (evdoDbm >= -65) levelEvdoDbm = SIGNAL_STRENGTH_GREAT;
-        else if (evdoDbm >= -75) levelEvdoDbm = SIGNAL_STRENGTH_GOOD;
-        else if (evdoDbm >= -90) levelEvdoDbm = SIGNAL_STRENGTH_MODERATE;
-        else if (evdoDbm >= -105) levelEvdoDbm = SIGNAL_STRENGTH_POOR;
-        else levelEvdoDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-
-        if (evdoSnr >= 7) levelEvdoSnr = SIGNAL_STRENGTH_GREAT;
-        else if (evdoSnr >= 5) levelEvdoSnr = SIGNAL_STRENGTH_GOOD;
-        else if (evdoSnr >= 3) levelEvdoSnr = SIGNAL_STRENGTH_MODERATE;
-        else if (evdoSnr >= 1) levelEvdoSnr = SIGNAL_STRENGTH_POOR;
-        else levelEvdoSnr = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-
-        int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
-        if (DBG) log("getEvdoLevel=" + level);
-        return level;
+        return mCdma.getEvdoLevel();
     }
 
     /**
@@ -855,28 +462,7 @@
      */
     @UnsupportedAppUsage
     public int getEvdoAsuLevel() {
-        int evdoDbm = getEvdoDbm();
-        int evdoSnr = getEvdoSnr();
-        int levelEvdoDbm;
-        int levelEvdoSnr;
-
-        if (evdoDbm >= -65) levelEvdoDbm = 16;
-        else if (evdoDbm >= -75) levelEvdoDbm = 8;
-        else if (evdoDbm >= -85) levelEvdoDbm = 4;
-        else if (evdoDbm >= -95) levelEvdoDbm = 2;
-        else if (evdoDbm >= -105) levelEvdoDbm = 1;
-        else levelEvdoDbm = 99;
-
-        if (evdoSnr >= 7) levelEvdoSnr = 16;
-        else if (evdoSnr >= 6) levelEvdoSnr = 8;
-        else if (evdoSnr >= 5) levelEvdoSnr = 4;
-        else if (evdoSnr >= 3) levelEvdoSnr = 2;
-        else if (evdoSnr >= 1) levelEvdoSnr = 1;
-        else levelEvdoSnr = 99;
-
-        int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
-        if (DBG) log("getEvdoAsuLevel=" + level);
-        return level;
+        return mCdma.getEvdoAsuLevel();
     }
 
     /**
@@ -886,7 +472,7 @@
      */
     @UnsupportedAppUsage
     public int getLteDbm() {
-        return mLteRsrp;
+        return mLte.getRsrp();
     }
 
     /**
@@ -896,83 +482,7 @@
      */
     @UnsupportedAppUsage
     public int getLteLevel() {
-        /*
-         * TS 36.214 Physical Layer Section 5.1.3
-         * TS 36.331 RRC
-         *
-         * RSSI = received signal + noise
-         * RSRP = reference signal dBm
-         * RSRQ = quality of signal dB = Number of Resource blocks*RSRP/RSSI
-         * SNR = gain = signal/noise ratio = -10log P1/P2 dB
-         */
-        int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1;
-
-        if (mLteRsrp > MAX_LTE_RSRP || mLteRsrp < MIN_LTE_RSRP) {
-            if (mLteRsrp != INVALID) {
-                Log.wtf(LOG_TAG, "getLteLevel - invalid lte rsrp: mLteRsrp=" + mLteRsrp);
-            }
-        } else if (mLteRsrp >= (mLteRsrpThresholds[3] - mLteRsrpBoost)) {
-            rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
-        } else if (mLteRsrp >= (mLteRsrpThresholds[2] - mLteRsrpBoost)) {
-            rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
-        } else if (mLteRsrp >= (mLteRsrpThresholds[1] - mLteRsrpBoost)) {
-            rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
-        } else if (mLteRsrp >= (mLteRsrpThresholds[0] - mLteRsrpBoost)) {
-            rsrpIconLevel = SIGNAL_STRENGTH_POOR;
-        } else {
-            rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        }
-
-        if (useOnlyRsrpForLteLevel()) {
-            log("getLTELevel - rsrp = " + rsrpIconLevel);
-            if (rsrpIconLevel != -1) {
-                return rsrpIconLevel;
-            }
-        }
-
-        /*
-         * Values are -200 dB to +300 (SNR*10dB) RS_SNR >= 13.0 dB =>4 bars 4.5
-         * dB <= RS_SNR < 13.0 dB => 3 bars 1.0 dB <= RS_SNR < 4.5 dB => 2 bars
-         * -3.0 dB <= RS_SNR < 1.0 dB 1 bar RS_SNR < -3.0 dB/No Service Antenna
-         * Icon Only
-         */
-        if (mLteRssnr > 300) snrIconLevel = -1;
-        else if (mLteRssnr >= 130) snrIconLevel = SIGNAL_STRENGTH_GREAT;
-        else if (mLteRssnr >= 45) snrIconLevel = SIGNAL_STRENGTH_GOOD;
-        else if (mLteRssnr >= 10) snrIconLevel = SIGNAL_STRENGTH_MODERATE;
-        else if (mLteRssnr >= -30) snrIconLevel = SIGNAL_STRENGTH_POOR;
-        else if (mLteRssnr >= -200)
-            snrIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-
-        if (DBG) log("getLTELevel - rsrp:" + mLteRsrp + " snr:" + mLteRssnr + " rsrpIconLevel:"
-                + rsrpIconLevel + " snrIconLevel:" + snrIconLevel
-                + " lteRsrpBoost:" + mLteRsrpBoost);
-
-        /* Choose a measurement type to use for notification */
-        if (snrIconLevel != -1 && rsrpIconLevel != -1) {
-            /*
-             * The number of bars displayed shall be the smaller of the bars
-             * associated with LTE RSRP and the bars associated with the LTE
-             * RS_SNR
-             */
-            return (rsrpIconLevel < snrIconLevel ? rsrpIconLevel : snrIconLevel);
-        }
-
-        if (snrIconLevel != -1) return snrIconLevel;
-
-        if (rsrpIconLevel != -1) return rsrpIconLevel;
-
-        /* Valid values are (0-31, 99) as defined in TS 27.007 8.5 */
-        if (mLteSignalStrength > 31) rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (mLteSignalStrength >= 12) rssiIconLevel = SIGNAL_STRENGTH_GREAT;
-        else if (mLteSignalStrength >= 8) rssiIconLevel = SIGNAL_STRENGTH_GOOD;
-        else if (mLteSignalStrength >= 5) rssiIconLevel = SIGNAL_STRENGTH_MODERATE;
-        else if (mLteSignalStrength >= 0) rssiIconLevel = SIGNAL_STRENGTH_POOR;
-
-        if (DBG) log("getLteLevel - rssi:" + mLteSignalStrength + " rssiIconLevel:"
-                + rssiIconLevel);
-        return rssiIconLevel;
-
+        return mLte.getLevel();
     }
 
     /**
@@ -983,41 +493,14 @@
      */
     @UnsupportedAppUsage
     public int getLteAsuLevel() {
-        int lteAsuLevel = 99;
-        int lteDbm = getLteDbm();
-        /*
-         * 3GPP 27.007 (Ver 10.3.0) Sec 8.69
-         * 0   -140 dBm or less
-         * 1   -139 dBm
-         * 2...96  -138... -44 dBm
-         * 97  -43 dBm or greater
-         * 255 not known or not detectable
-         */
-        /*
-         * validateInput will always give a valid range between -140 t0 -44 as
-         * per ril.h. so RSRP >= -43 & <-140 will fall under asu level 255
-         * and not 97 or 0
-         */
-        if (lteDbm == SignalStrength.INVALID) lteAsuLevel = 255;
-        else lteAsuLevel = lteDbm + 140;
-        if (DBG) log("Lte Asu level: "+lteAsuLevel);
-        return lteAsuLevel;
+        return mLte.getAsuLevel();
     }
 
     /**
      * @return true if this is for GSM
      */
     public boolean isGsm() {
-        return this.mIsGsm;
-    }
-
-    /**
-     * @return true if it uses only RSRP for the number of LTE signal bar, otherwise false.
-     *
-     * @hide
-     */
-    public boolean useOnlyRsrpForLteLevel() {
-        return this.mUseOnlyRsrpForLteLevel;
+        return !(getPrimary() instanceof CellSignalStrengthCdma);
     }
 
     /**
@@ -1027,7 +510,7 @@
      */
     @UnsupportedAppUsage
     public int getTdScdmaDbm() {
-        return this.mTdScdmaRscp;
+        return mTdscdma.getRscp();
     }
 
     /**
@@ -1040,19 +523,7 @@
      */
     @UnsupportedAppUsage
     public int getTdScdmaLevel() {
-        final int tdScdmaDbm = getTdScdmaDbm();
-        int level;
-
-        if ((tdScdmaDbm > -25) || (tdScdmaDbm == SignalStrength.INVALID))
-                level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (tdScdmaDbm >= -49) level = SIGNAL_STRENGTH_GREAT;
-        else if (tdScdmaDbm >= -73) level = SIGNAL_STRENGTH_GOOD;
-        else if (tdScdmaDbm >= -97) level = SIGNAL_STRENGTH_MODERATE;
-        else if (tdScdmaDbm >= -110) level = SIGNAL_STRENGTH_POOR;
-        else level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-
-        if (DBG) log("getTdScdmaLevel = " + level);
-        return level;
+        return mTdscdma.getLevel();
      }
 
     /**
@@ -1062,13 +533,7 @@
      */
     @UnsupportedAppUsage
     public int getTdScdmaAsuLevel() {
-        final int tdScdmaDbm = getTdScdmaDbm();
-        int tdScdmaAsuLevel;
-
-        if (tdScdmaDbm == INVALID) tdScdmaAsuLevel = 255;
-        else tdScdmaAsuLevel = tdScdmaDbm + 120;
-        if (DBG) log("TD-SCDMA Asu level: " + tdScdmaAsuLevel);
-        return tdScdmaAsuLevel;
+        return mTdscdma.getAsuLevel();
     }
 
     /**
@@ -1077,7 +542,7 @@
      * @hide
      */
     public int getWcdmaRscp() {
-        return mWcdmaRscp;
+        return mWcdma.getRscp();
     }
 
     /**
@@ -1094,14 +559,7 @@
          * 96     -24 dBm or greater
          * 255    not known or not detectable
          */
-        final int wcdmaDbm = getWcdmaDbm();
-        int wcdmaAsuLevel = 255;
-        // validateInput will always give a valid range between -120 to -24 as per ril.h. so RSCP
-        // outside range is already set to INVALID
-        if (wcdmaDbm == SignalStrength.INVALID) wcdmaAsuLevel =  255;
-        else wcdmaAsuLevel = wcdmaDbm + 120;
-        if (DBG) log("Wcdma Asu level: " + wcdmaAsuLevel);
-        return wcdmaAsuLevel;
+        return mWcdma.getAsuLevel();
     }
 
     /**
@@ -1110,7 +568,7 @@
      * @hide
      */
     public int getWcdmaDbm() {
-        return mWcdmaRscp;
+        return mWcdma.getDbm();
     }
 
     /**
@@ -1119,55 +577,7 @@
      * @hide
      */
     public int getWcdmaLevel() {
-        int level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-
-        if (mWcdmaDefaultSignalMeasurement == null) {
-            Log.wtf(LOG_TAG, "getWcdmaLevel - WCDMA default signal measurement is invalid.");
-            return level;
-        }
-
-        switch (mWcdmaDefaultSignalMeasurement) {
-            case MEASUMENT_TYPE_RSCP:
-                // RSCP valid values are (-120 through -24) as defined in TS 27.007 8.69
-                if (mWcdmaRscp < MIN_WCDMA_RSCP || mWcdmaRscp > MAX_WCDMA_RSCP) {
-                    if (mWcdmaRscp != INVALID) {
-                        Log.wtf(LOG_TAG, "getWcdmaLevel - invalid WCDMA RSCP: mWcdmaRscp="
-                                + mWcdmaRscp);
-                    }
-                } else if (mWcdmaRscp >= mWcdmaRscpThresholds[3]) {
-                    level = SIGNAL_STRENGTH_GREAT;
-                } else if (mWcdmaRscp >= mWcdmaRscpThresholds[2]) {
-                    level = SIGNAL_STRENGTH_GOOD;
-                } else if (mWcdmaRscp >= mWcdmaRscpThresholds[1]) {
-                    level = SIGNAL_STRENGTH_MODERATE;
-                } else if (mWcdmaRscp >= mWcdmaRscpThresholds[0]) {
-                    level = SIGNAL_STRENGTH_POOR;
-                }
-                if (DBG) log("getWcdmaLevel=" + level + " WcdmaRscp=" + mWcdmaRscp);
-                break;
-
-            default:
-                // RSSI valid values are (0..31) as defined in TS 27.007 8.5
-                if (mWcdmaSignalStrength < 0 || mWcdmaSignalStrength > 31) {
-                    if (mWcdmaSignalStrength != 99) {
-                        Log.wtf(LOG_TAG, "getWcdmaLevel - invalid WCDMA RSSI: mWcdmaSignalStrength="
-                                + mWcdmaSignalStrength);
-                    }
-                } else if (mWcdmaSignalStrength >= 18) {
-                    level = SIGNAL_STRENGTH_GREAT;
-                } else if (mWcdmaSignalStrength >= 13) {
-                    level = SIGNAL_STRENGTH_GOOD;
-                } else if (mWcdmaSignalStrength >= 8) {
-                    level = SIGNAL_STRENGTH_MODERATE;
-                } else if (mWcdmaSignalStrength >= 3) {
-                    level = SIGNAL_STRENGTH_POOR;
-                }
-                if (DBG) log("getWcdmaLevel=" + level + " WcdmaSignalStrength=" +
-                        mWcdmaSignalStrength);
-                break;
-
-        }
-        return level;
+        return mWcdma.getLevel();
     }
 
    /**
@@ -1175,18 +585,7 @@
      */
     @Override
     public int hashCode() {
-        int primeNum = 31;
-        return ((mGsmSignalStrength * primeNum)
-                + (mGsmBitErrorRate * primeNum)
-                + (mCdmaDbm * primeNum) + (mCdmaEcio * primeNum)
-                + (mEvdoDbm * primeNum) + (mEvdoEcio * primeNum) + (mEvdoSnr * primeNum)
-                + (mLteSignalStrength * primeNum) + (mLteRsrp * primeNum)
-                + (mLteRsrq * primeNum) + (mLteRssnr * primeNum) + (mLteCqi * primeNum)
-                + (mLteRsrpBoost * primeNum) + (mTdScdmaRscp * primeNum)
-                + (mWcdmaSignalStrength * primeNum) + (mWcdmaRscpAsu * primeNum)
-                + (mWcdmaRscp * primeNum) + (mIsGsm ? 1 : 0) + (mUseOnlyRsrpForLteLevel ? 1 : 0)
-                + (Objects.hashCode(mWcdmaDefaultSignalMeasurement))
-                + (Arrays.hashCode(mLteRsrpThresholds)) + (Arrays.hashCode(mWcdmaRscpThresholds)));
+        return Objects.hash(mCdma, mGsm, mWcdma, mTdscdma, mLte, mLteRsrpBoost);
     }
 
     /**
@@ -1194,40 +593,16 @@
      */
     @Override
     public boolean equals (Object o) {
-        SignalStrength s;
+        if (!(o instanceof SignalStrength)) return false;
 
-        try {
-            s = (SignalStrength) o;
-        } catch (ClassCastException ex) {
-            return false;
-        }
+        SignalStrength s = (SignalStrength) o;
 
-        if (o == null) {
-            return false;
-        }
-
-        return (mGsmSignalStrength == s.mGsmSignalStrength
-                && mGsmBitErrorRate == s.mGsmBitErrorRate
-                && mCdmaDbm == s.mCdmaDbm
-                && mCdmaEcio == s.mCdmaEcio
-                && mEvdoDbm == s.mEvdoDbm
-                && mEvdoEcio == s.mEvdoEcio
-                && mEvdoSnr == s.mEvdoSnr
-                && mLteSignalStrength == s.mLteSignalStrength
-                && mLteRsrp == s.mLteRsrp
-                && mLteRsrq == s.mLteRsrq
-                && mLteRssnr == s.mLteRssnr
-                && mLteCqi == s.mLteCqi
-                && mLteRsrpBoost == s.mLteRsrpBoost
-                && mTdScdmaRscp == s.mTdScdmaRscp
-                && mWcdmaSignalStrength == s.mWcdmaSignalStrength
-                && mWcdmaRscpAsu == s.mWcdmaRscpAsu
-                && mWcdmaRscp == s.mWcdmaRscp
-                && mIsGsm == s.mIsGsm
-                && mUseOnlyRsrpForLteLevel == s.mUseOnlyRsrpForLteLevel
-                && Objects.equals(mWcdmaDefaultSignalMeasurement, s.mWcdmaDefaultSignalMeasurement)
-                && Arrays.equals(mLteRsrpThresholds, s.mLteRsrpThresholds)
-                && Arrays.equals(mWcdmaRscpThresholds, s.mWcdmaRscpThresholds));
+        return mCdma.equals(s.mCdma)
+            && mGsm.equals(s.mGsm)
+            && mWcdma.equals(s.mWcdma)
+            && mTdscdma.equals(s.mTdscdma)
+            && mLte.equals(s.mLte)
+            && mLteRsrpBoost == s.mLteRsrpBoost;
     }
 
     /**
@@ -1235,63 +610,16 @@
      */
     @Override
     public String toString() {
-        return ("SignalStrength:"
-                + " " + mGsmSignalStrength
-                + " " + mGsmBitErrorRate
-                + " " + mCdmaDbm
-                + " " + mCdmaEcio
-                + " " + mEvdoDbm
-                + " " + mEvdoEcio
-                + " " + mEvdoSnr
-                + " " + mLteSignalStrength
-                + " " + mLteRsrp
-                + " " + mLteRsrq
-                + " " + mLteRssnr
-                + " " + mLteCqi
-                + " " + mLteRsrpBoost
-                + " " + mTdScdmaRscp
-                + " " + mWcdmaSignalStrength
-                + " " + mWcdmaRscpAsu
-                + " " + mWcdmaRscp
-                + " " + (mIsGsm ? "gsm|lte" : "cdma")
-                + " " + (mUseOnlyRsrpForLteLevel ? "use_only_rsrp_for_lte_level" :
-                         "use_rsrp_and_rssnr_for_lte_level")
-                + " " + mWcdmaDefaultSignalMeasurement
-                + " " + (Arrays.toString(mLteRsrpThresholds))
-                + " " + (Arrays.toString(mWcdmaRscpThresholds)));
-    }
-
-    /** Returns the signal strength related to GSM. */
-    private int getGsmRelatedSignalStrength() {
-        int level = getLteLevel();
-        if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-            level = getTdScdmaLevel();
-            if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                level = getWcdmaLevel();
-                if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                    level = getGsmLevel();
-                }
-            }
-        }
-        return level;
-    }
-
-    /** Returns the signal strength related to CDMA. */
-    private int getCdmaRelatedSignalStrength() {
-        int level;
-        int cdmaLevel = getCdmaLevel();
-        int evdoLevel = getEvdoLevel();
-        if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-            /* We don't know evdo, use cdma */
-            level = cdmaLevel;
-        } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-            /* We don't know cdma, use evdo */
-            level = evdoLevel;
-        } else {
-            /* We know both, use the lowest level */
-            level = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
-        }
-        return level;
+        return new StringBuilder().append("SignalStrength:{")
+            .append("mCdma=").append(mCdma)
+            .append(",mGsm=").append(mGsm)
+            .append(",mWcdma=").append(mWcdma)
+            .append(",mTdscdma=").append(mTdscdma)
+            .append(",mLte=").append(mLte)
+            .append(",mLteRsrpBoost=").append(mLteRsrpBoost)
+            .append(",primary=").append(getPrimary().getClass().getSimpleName())
+            .append("}")
+            .toString();
     }
 
     /**
@@ -1302,34 +630,13 @@
      */
     @UnsupportedAppUsage
     private void setFromNotifierBundle(Bundle m) {
-        mGsmSignalStrength = m.getInt("GsmSignalStrength");
-        mGsmBitErrorRate = m.getInt("GsmBitErrorRate");
-        mCdmaDbm = m.getInt("CdmaDbm");
-        mCdmaEcio = m.getInt("CdmaEcio");
-        mEvdoDbm = m.getInt("EvdoDbm");
-        mEvdoEcio = m.getInt("EvdoEcio");
-        mEvdoSnr = m.getInt("EvdoSnr");
-        mLteSignalStrength = m.getInt("LteSignalStrength");
-        mLteRsrp = m.getInt("LteRsrp");
-        mLteRsrq = m.getInt("LteRsrq");
-        mLteRssnr = m.getInt("LteRssnr");
-        mLteCqi = m.getInt("LteCqi");
+        mCdma = m.getParcelable("Cdma");
+        mGsm = m.getParcelable("Gsm");
+        mWcdma = m.getParcelable("Wcdma");
+        mTdscdma = m.getParcelable("Tdscdma");
+        mLte = m.getParcelable("Lte");
+
         mLteRsrpBoost = m.getInt("LteRsrpBoost");
-        mTdScdmaRscp = m.getInt("TdScdma");
-        mWcdmaSignalStrength = m.getInt("WcdmaSignalStrength");
-        mWcdmaRscpAsu = m.getInt("WcdmaRscpAsu");
-        mWcdmaRscp = m.getInt("WcdmaRscp");
-        mIsGsm = m.getBoolean("IsGsm");
-        mUseOnlyRsrpForLteLevel = m.getBoolean("UseOnlyRsrpForLteLevel");
-        mWcdmaDefaultSignalMeasurement = m.getString("WcdmaDefaultSignalMeasurement");
-        ArrayList<Integer> lteRsrpThresholds = m.getIntegerArrayList("lteRsrpThresholds");
-        for (int i = 0; i < lteRsrpThresholds.size(); i++) {
-            mLteRsrpThresholds[i] = lteRsrpThresholds.get(i);
-        }
-        ArrayList<Integer> wcdmaRscpThresholds = m.getIntegerArrayList("wcdmaRscpThresholds");
-        for (int i = 0; i < wcdmaRscpThresholds.size(); i++) {
-            mWcdmaRscpThresholds[i] = wcdmaRscpThresholds.get(i);
-        }
     }
 
     /**
@@ -1340,56 +647,13 @@
      */
     @UnsupportedAppUsage
     public void fillInNotifierBundle(Bundle m) {
-        m.putInt("GsmSignalStrength", mGsmSignalStrength);
-        m.putInt("GsmBitErrorRate", mGsmBitErrorRate);
-        m.putInt("CdmaDbm", mCdmaDbm);
-        m.putInt("CdmaEcio", mCdmaEcio);
-        m.putInt("EvdoDbm", mEvdoDbm);
-        m.putInt("EvdoEcio", mEvdoEcio);
-        m.putInt("EvdoSnr", mEvdoSnr);
-        m.putInt("LteSignalStrength", mLteSignalStrength);
-        m.putInt("LteRsrp", mLteRsrp);
-        m.putInt("LteRsrq", mLteRsrq);
-        m.putInt("LteRssnr", mLteRssnr);
-        m.putInt("LteCqi", mLteCqi);
+        m.putParcelable("Cdma", mCdma);
+        m.putParcelable("Gsm", mGsm);
+        m.putParcelable("Wcdma", mWcdma);
+        m.putParcelable("Tdscdma", mTdscdma);
+        m.putParcelable("Lte", mLte);
+
         m.putInt("LteRsrpBoost", mLteRsrpBoost);
-        m.putInt("TdScdma", mTdScdmaRscp);
-        m.putInt("WcdmaSignalStrength", mWcdmaSignalStrength);
-        m.putInt("WcdmaRscpAsu", mWcdmaRscpAsu);
-        m.putInt("WcdmaRscp", mWcdmaRscp);
-        m.putBoolean("IsGsm", mIsGsm);
-        m.putBoolean("UseOnlyRsrpForLteLevel", mUseOnlyRsrpForLteLevel);
-        m.putString("WcdmaDefaultSignalMeasurement", mWcdmaDefaultSignalMeasurement);
-        ArrayList<Integer> lteRsrpThresholds = new ArrayList<Integer>();
-        for (int value : mLteRsrpThresholds) {
-            lteRsrpThresholds.add(value);
-        }
-        m.putIntegerArrayList("lteRsrpThresholds", lteRsrpThresholds);
-        ArrayList<Integer> wcdmaRscpThresholds = new ArrayList<Integer>();
-        for (int value : mWcdmaRscpThresholds) {
-            wcdmaRscpThresholds.add(value);
-        }
-        m.putIntegerArrayList("wcdmaRscpThresholds", wcdmaRscpThresholds);
-    }
-
-    /**
-     * Gets the default threshold array for determining the display level of LTE signal bar.
-     *
-     * @return int array for determining the display level.
-     */
-    private int[] getDefaultLteRsrpThresholds() {
-        return CarrierConfigManager.getDefaultConfig().getIntArray(
-                CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY);
-    }
-
-    /**
-     * Gets the default threshold array for determining the display level of WCDMA signal bar.
-     *
-     * @return int array for determining the display level.
-     */
-    private int[] getDefaultWcdmaRscpThresholds() {
-        return CarrierConfigManager.getDefaultConfig().getIntArray(
-                CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
     }
 
     /**
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index dacc5d8..0a58fa0 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -80,6 +80,12 @@
     private CharSequence mCarrierName;
 
     /**
+     * The subscription carrier id.
+     * @see TelephonyManager#getSimCarrierId()
+     */
+    private int mCarrierId;
+
+    /**
      * The source of the name, NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
      * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
      */
@@ -132,10 +138,15 @@
     private UiccAccessRule[] mAccessRules;
 
     /**
-     * The ID of the SIM card. It is the ICCID of the active profile for a UICC card and the EID
-     * for an eUICC card.
+     * The string ID of the SIM card. It is the ICCID of the active profile for a UICC card and the
+     * EID for an eUICC card.
      */
-    private String mCardId;
+    private String mCardString;
+
+    /**
+     * The card ID of the SIM card. This maps uniquely to the card string.
+     */
+    private int mCardId;
 
     /**
      * Whether the subscription is opportunistic.
@@ -168,10 +179,10 @@
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
-            @Nullable UiccAccessRule[] accessRules, String cardId) {
+            @Nullable UiccAccessRule[] accessRules, String cardString) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
-                roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardId,
-                false, null, true);
+                roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString,
+                false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID);
     }
 
     /**
@@ -180,20 +191,22 @@
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
-            @Nullable UiccAccessRule[] accessRules, String cardId, boolean isOpportunistic,
-            @Nullable String groupUUID, boolean isMetered) {
+            @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
+            @Nullable String groupUUID, boolean isMetered, int carrierId) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
-                roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardId,
-                isOpportunistic, groupUUID, isMetered, false);
+                roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
+                isOpportunistic, groupUUID, isMetered, false, carrierId);
     }
+
     /**
      * @hide
      */
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
-            @Nullable UiccAccessRule[] accessRules, String cardId, boolean isOpportunistic,
-            @Nullable String groupUUID, boolean isMetered, boolean isGroupDisabled) {
+            @Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
+            boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
+            boolean isGroupDisabled, int carrierid) {
         this.mId = id;
         this.mIccId = iccId;
         this.mSimSlotIndex = simSlotIndex;
@@ -209,11 +222,13 @@
         this.mCountryIso = countryIso;
         this.mIsEmbedded = isEmbedded;
         this.mAccessRules = accessRules;
+        this.mCardString = cardString;
         this.mCardId = cardId;
         this.mIsOpportunistic = isOpportunistic;
         this.mGroupUUID = groupUUID;
         this.mIsMetered = isMetered;
         this.mIsGroupDisabled = isGroupDisabled;
+        this.mCarrierId = carrierid;
     }
 
 
@@ -239,6 +254,14 @@
     }
 
     /**
+     * @return the carrier id of this Subscription carrier.
+     * @see TelephonyManager#getSimCarrierId()
+     */
+    public int getCarrierId() {
+        return this.mCarrierId;
+    }
+
+    /**
      * @return the name displayed to the user that identifies this subscription
      */
     public CharSequence getDisplayName() {
@@ -508,10 +531,20 @@
     }
 
     /**
-     * @return the ID of the SIM card which contains the subscription.
+     * @return the card string of the SIM card which contains the subscription. The card string is
+     * the ICCID for UICCs or the EID for eUICCs.
      * @hide
      */
-    public String getCardId() {
+    public String getCardString() {
+        return this.mCardString;
+    }
+
+    /**
+     * @return the cardId of the SIM card which contains the subscription.
+     * @hide
+     */
+    @SystemApi
+    public int getCardId() {
         return this.mCardId;
     }
 
@@ -549,16 +582,18 @@
             Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
             boolean isEmbedded = source.readBoolean();
             UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR);
-            String cardId = source.readString();
+            String cardString = source.readString();
+            int cardId = source.readInt();
             boolean isOpportunistic = source.readBoolean();
             String groupUUID = source.readString();
             boolean isMetered = source.readBoolean();
             boolean isGroupDisabled = source.readBoolean();
+            int carrierid = source.readInt();
 
             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
                     nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
-                    isEmbedded, accessRules, cardId, isOpportunistic, groupUUID, isMetered,
-                    isGroupDisabled);
+                    isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
+                    isMetered, isGroupDisabled, carrierid);
         }
 
         @Override
@@ -584,11 +619,13 @@
         mIconBitmap.writeToParcel(dest, flags);
         dest.writeBoolean(mIsEmbedded);
         dest.writeTypedArray(mAccessRules, flags);
-        dest.writeString(mCardId);
+        dest.writeString(mCardString);
+        dest.writeInt(mCardId);
         dest.writeBoolean(mIsOpportunistic);
         dest.writeString(mGroupUUID);
         dest.writeBoolean(mIsMetered);
         dest.writeBoolean(mIsGroupDisabled);
+        dest.writeInt(mCarrierId);
     }
 
     @Override
@@ -614,23 +651,25 @@
     @Override
     public String toString() {
         String iccIdToPrint = givePrintableIccid(mIccId);
-        String cardIdToPrint = givePrintableIccid(mCardId);
+        String cardStringToPrint = givePrintableIccid(mCardString);
         return "{id=" + mId + ", iccId=" + iccIdToPrint + " simSlotIndex=" + mSimSlotIndex
-                + " displayName=" + mDisplayName + " carrierName=" + mCarrierName
-                + " nameSource=" + mNameSource + " iconTint=" + mIconTint + " mNumber=" + mNumber
+                + " carrierId=" + mCarrierId + " displayName=" + mDisplayName
+                + " carrierName=" + mCarrierName + " nameSource=" + mNameSource
+                + " iconTint=" + mIconTint + " mNumber=" + mNumber
                 + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
                 + " mnc " + mMnc + "mCountryIso=" + mCountryIso + " isEmbedded " + mIsEmbedded
                 + " accessRules " + Arrays.toString(mAccessRules)
-                + " cardId=" + cardIdToPrint + " isOpportunistic " + mIsOpportunistic
-                + " mGroupUUID=" + mGroupUUID + " isMetered=" + mIsMetered
-                + " mIsGroupDisabled=" + mIsGroupDisabled + "}";
+                + " cardString=" + cardStringToPrint + " cardId=" + mCardId
+                + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
+                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled + "}";
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
                 mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc,
-                mCountryIso, mCardId, mDisplayName, mCarrierName, mAccessRules, mIsGroupDisabled);
+                mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
+                mIsGroupDisabled, mCarrierId);
     }
 
     @Override
@@ -653,13 +692,15 @@
                 && mIsEmbedded == toCompare.mIsEmbedded
                 && mIsOpportunistic == toCompare.mIsOpportunistic
                 && mIsGroupDisabled == toCompare.mIsGroupDisabled
-                && Objects.equals(mGroupUUID, toCompare.mGroupUUID)
+                && mCarrierId == toCompare.mCarrierId
                 && mIsMetered == toCompare.mIsMetered
+                && Objects.equals(mGroupUUID, toCompare.mGroupUUID)
                 && Objects.equals(mIccId, toCompare.mIccId)
                 && Objects.equals(mNumber, toCompare.mNumber)
                 && Objects.equals(mMcc, toCompare.mMcc)
                 && Objects.equals(mMnc, toCompare.mMnc)
                 && Objects.equals(mCountryIso, toCompare.mCountryIso)
+                && Objects.equals(mCardString, toCompare.mCardString)
                 && Objects.equals(mCardId, toCompare.mCardId)
                 && TextUtils.equals(mDisplayName, toCompare.mDisplayName)
                 && TextUtils.equals(mCarrierName, toCompare.mCarrierName)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 6a22f7e..3235507 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -19,6 +19,7 @@
 import static android.net.NetworkPolicyManager.OVERRIDE_CONGESTED;
 import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
 
+import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.DurationMillisLong;
 import android.annotation.NonNull;
@@ -52,6 +53,7 @@
 import android.os.ServiceManager;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 
@@ -67,6 +69,7 @@
 import java.util.Locale;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * SubscriptionManager is the application interface to SubscriptionController
@@ -379,6 +382,14 @@
     public static final int SIM_PROVISIONED = 0;
 
     /**
+     * TelephonyProvider column name for subscription carrier id.
+     * @see TelephonyManager#getSimCarrierId()
+     * <p>Type: INTEGER (int) </p>
+     * @hide
+     */
+    public static final String CARRIER_ID = "carrier_id";
+
+    /**
      * TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
      * <P>Type: TEXT (String)</P>
      * @hide
@@ -2401,16 +2412,21 @@
      * together, some of them may be invisible to the users, etc.
      *
      * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
-     * permission or can manage all subscriptions in the list, according to their
-     * acess rules.
+     * permission or had carrier privilege permission on the subscriptions:
+     * {@link TelephonyManager#hasCarrierPrivileges()} or
+     * {@link #canManageSubscription(SubscriptionInfo)}
+     *
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
      *
      * @param subIdList list of subId that will be in the same group
      * @return groupUUID a UUID assigned to the subscription group. It returns
      * null if fails.
      *
      */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public String setSubscriptionGroup(int[] subIdList) {
+    public @Nullable String setSubscriptionGroup(@NonNull int[] subIdList) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         if (VDBG) {
             logd("[setSubscriptionGroup]+ subIdList:" + Arrays.toString(subIdList));
@@ -2430,6 +2446,80 @@
     }
 
     /**
+     * Remove a list of subscriptions from their subscription group.
+     * See {@link #setSubscriptionGroup(int[])} for more details.
+     *
+     * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     * permission or had carrier privilege permission on the subscriptions:
+     * {@link TelephonyManager#hasCarrierPrivileges()} or
+     * {@link #canManageSubscription(SubscriptionInfo)}
+     *
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
+     *
+     * @param subIdList list of subId that need removing from their groups.
+     * @return whether the operation succeeds.
+     *
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean removeSubscriptionsFromGroup(@NonNull int[] subIdList) {
+        String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+        if (VDBG) {
+            logd("[removeSubscriptionsFromGroup]+ subIdList:" + Arrays.toString(subIdList));
+        }
+
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                return iSub.removeSubscriptionsFromGroup(subIdList, pkgForDebug);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return false;
+    }
+
+    /**
+     * Get subscriptionInfo list of subscriptions that are in the same group of given subId.
+     * See {@link #setSubscriptionGroup(int[])} for more details.
+     *
+     * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE}
+     * permission or had carrier privilege permission on the subscription.
+     * {@link TelephonyManager#hasCarrierPrivileges()}
+     *
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
+     *
+     * @param subId of which list of subInfo from the same group will be returned.
+     * @return list of subscriptionInfo that belong to the same group, including the given
+     * subscription itself. It will return null if the subscription doesn't exist or it
+     * doesn't belong to any group.
+     *
+     */
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+    public @Nullable List<SubscriptionInfo> getSubscriptionsInGroup(int subId) {
+        String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+        if (VDBG) {
+            logd("[getSubscriptionsInGroup]+ subId:" + subId);
+        }
+
+        List<SubscriptionInfo> result = null;
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                result = iSub.getSubscriptionsInGroup(subId, pkgForDebug);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+
+        return result;
+    }
+
+    /**
      * Set metered by simInfo index
      *
      * @param isMetered whether it’s a metered subscription.
@@ -2444,6 +2534,42 @@
                 (iSub)-> iSub.setMetered(isMetered, subId));
     }
 
+    /**
+     * Whether system UI should hide a subscription. If it's a bundled opportunistic
+     * subscription, it shouldn't show up in anywhere in Settings app, dialer app,
+     * or status bar.
+     *
+     * @param info the subscriptionInfo to check against.
+     * @return true if this subscription should be hidden.
+     *
+     * @hide
+     */
+    public static boolean shouldHideSubscription(SubscriptionInfo info) {
+        return (info != null && !TextUtils.isEmpty(info.getGroupUuid()) && info.isOpportunistic());
+    }
+
+    /**
+     * Return a list of subscriptions that are available and visible to the user.
+     * Used by Settings app to show a list of subscriptions for user to pick.
+     *
+     * <p>
+     * Permissions android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE is required
+     * for getSelectableSubscriptionInfoList to be invoked.
+     * @return list of user selectable subscriptions.
+     *
+     * @hide
+     */
+    public @Nullable List<SubscriptionInfo> getSelectableSubscriptionInfoList() {
+        List<SubscriptionInfo> availableList = getAvailableSubscriptionInfoList();
+        if (availableList == null) {
+            return null;
+        } else {
+            return getAvailableSubscriptionInfoList().stream()
+                    .filter(subInfo -> !shouldHideSubscription(subInfo))
+                    .collect(Collectors.toList());
+        }
+    }
+
     private interface CallISubMethodHelper {
         int callMethod(ISub iSub) throws RemoteException;
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3649ecad..26d2459 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -625,8 +625,6 @@
      * The {@link #EXTRA_RINGING_CALL_STATE} extra indicates the ringing call state.
      * The {@link #EXTRA_FOREGROUND_CALL_STATE} extra indicates the foreground call state.
      * The {@link #EXTRA_BACKGROUND_CALL_STATE} extra indicates the background call state.
-     * The {@link #EXTRA_DISCONNECT_CAUSE} extra indicates the disconnect cause.
-     * The {@link #EXTRA_PRECISE_DISCONNECT_CAUSE} extra indicates the precise disconnect cause.
      *
      * <p class="note">
      * Requires the READ_PRECISE_PHONE_STATE permission.
@@ -634,12 +632,10 @@
      * @see #EXTRA_RINGING_CALL_STATE
      * @see #EXTRA_FOREGROUND_CALL_STATE
      * @see #EXTRA_BACKGROUND_CALL_STATE
-     * @see #EXTRA_DISCONNECT_CAUSE
-     * @see #EXTRA_PRECISE_DISCONNECT_CAUSE
      *
      * <p class="note">
      * Requires the READ_PRECISE_PHONE_STATE permission.
-     *
+     * @deprecated use {@link PhoneStateListener#LISTEN_PRECISE_CALL_STATE} instead
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -647,8 +643,28 @@
             "android.intent.action.PRECISE_CALL_STATE";
 
     /**
-     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
-     * for an integer containing the state of the current ringing call.
+     * Broadcast intent action indicating that call disconnect cause has changed.
+     *
+     * <p>
+     * The {@link #EXTRA_DISCONNECT_CAUSE} extra indicates the disconnect cause.
+     * The {@link #EXTRA_PRECISE_DISCONNECT_CAUSE} extra indicates the precise disconnect cause.
+     *
+     * <p class="note">
+     * Requires the READ_PRECISE_PHONE_STATE permission.
+     *
+     * @see #EXTRA_DISCONNECT_CAUSE
+     * @see #EXTRA_PRECISE_DISCONNECT_CAUSE
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_CALL_DISCONNECT_CAUSE_CHANGED =
+            "android.intent.action.CALL_DISCONNECT_CAUSE";
+
+    /**
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
+     * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
+     * containing the state of the current ringing call.
      *
      * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
      * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
@@ -670,8 +686,9 @@
     public static final String EXTRA_RINGING_CALL_STATE = "ringing_state";
 
     /**
-     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
-     * for an integer containing the state of the current foreground call.
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
+     * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
+     * containing the state of the current foreground call.
      *
      * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
      * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
@@ -693,8 +710,9 @@
     public static final String EXTRA_FOREGROUND_CALL_STATE = "foreground_state";
 
     /**
-     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
-     * for an integer containing the state of the current background call.
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
+     * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
+     * containing the state of the current background call.
      *
      * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
      * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
@@ -716,8 +734,9 @@
     public static final String EXTRA_BACKGROUND_CALL_STATE = "background_state";
 
     /**
-     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
-     * for an integer containing the disconnect cause.
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
+     * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
+     * containing the disconnect cause.
      *
      * @see DisconnectCause
      *
@@ -730,8 +749,9 @@
     public static final String EXTRA_DISCONNECT_CAUSE = "disconnect_cause";
 
     /**
-     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
-     * for an integer containing the disconnect cause provided by the RIL.
+     * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast and
+     * {@link PhoneStateListener#onPreciseCallStateChanged(PreciseCallState)} for an integer
+     * containing the disconnect cause provided by the RIL.
      *
      * @see PreciseDisconnectCause
      *
@@ -1223,81 +1243,79 @@
             "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
 
     /**
-     * Broadcast Action: The subscription precise carrier identity has changed.
-     * Similar like {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED}, this intent will be sent
-     * on the event of {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED}. However, its possible
-     * that precise carrier identity changes while
-     * {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} remains the same e.g, the same
-     * subscription switches to different IMSI could potentially change its precise carrier id.
-     *
-     * The intent will have the following extra values:
-     * <ul>
-     *   <li>{@link #EXTRA_PRECISE_CARRIER_ID} The up-to-date precise carrier id of the
-     *   current subscription.
-     *   </li>
-     *   <li>{@link #EXTRA_PRECISE_CARRIER_NAME} The up-to-date carrier name of the current
-     *   subscription.
-     *   </li>
-     *   <li>{@link #EXTRA_SUBSCRIPTION_ID} The subscription id associated with the changed carrier
-     *   identity.
-     *   </li>
-     * </ul>
-     * <p class="note">This is a protected intent that can only be sent by the system.
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED =
-            "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED";
-
-    /**
      * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates
-     * the updated carrier id {@link TelephonyManager#getSimCarrierId()} of
-     * the current subscription.
+     * the updated carrier id returned by {@link TelephonyManager#getSimCarrierId()}.
      * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
      * the carrier cannot be identified.
      */
     public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
 
     /**
-     * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates
-     * the updated mno carrier id of the current subscription.
-     * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
-     * the carrier cannot be identified.
-     *
-     *@hide
-     */
-    public static final String EXTRA_MNO_CARRIER_ID = "android.telephony.extra.MNO_CARRIER_ID";
-
-    /**
      * An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which
      * indicates the updated carrier name of the current subscription.
-     * {@see TelephonyManager#getSimCarrierIdName()}
+     * @see TelephonyManager#getSimCarrierIdName()
      * <p>Carrier name is a user-facing name of the carrier id {@link #EXTRA_CARRIER_ID},
      * usually the brand name of the subsidiary (e.g. T-Mobile).
      */
     public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
 
     /**
+     * Broadcast Action: The subscription precise carrier identity has changed.
+     * The precise carrier id can be used to further differentiate a carrier by different
+     * networks, by prepaid v.s.postpaid or even by 4G v.s.3G plan. Each carrier has a unique
+     * carrier id returned by {@link #getSimCarrierId()} but could have multiple precise carrier id.
+     * e.g, {@link #getSimCarrierId()} will always return Tracfone (id 2022) for a Tracfone SIM,
+     * while {@link #getSimPreciseCarrierId()} can return Tracfone AT&T or Tracfone T-Mobile based
+     * on the current subscription IMSI. For carriers without any fine-grained ids, precise carrier
+     * id is same as carrier id.
+     *
+     * <p>Similar like {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED}, this intent will be
+     * sent on the event of {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} while its also
+     * possible to be sent without {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} when
+     * precise carrier id changes with the same carrier id.
+     * e.g, the same subscription switches to different IMSI could potentially change its
+     * precise carrier id while carrier id remains the same.
+     * @see #getSimPreciseCarrierId()
+     * @see #getSimCarrierId()
+     *
+     * The intent will have the following extra values:
+     * <ul>
+     *   <li>{@link #EXTRA_PRECISE_CARRIER_ID} The up-to-date precise carrier id of the
+     *   current subscription.
+     *   </li>
+     *   <li>{@link #EXTRA_PRECISE_CARRIER_NAME} The up-to-date name of the precise carrier id.
+     *   </li>
+     *   <li>{@link #EXTRA_SUBSCRIPTION_ID} The subscription id associated with the changed carrier
+     *   identity.
+     *   </li>
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent by the system.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED =
+            "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED";
+
+    /**
      * An int extra used with {@link #ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED} which
-     * indicates the updated precise carrier id {@link TelephonyManager#getSimPreciseCarrierId()} of
-     * the current subscription. Note, its possible precise carrier id changes while
-     * {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} remains the same e.g, when
-     * subscription switch to different IMSI.
+     * indicates the updated precise carrier id returned by
+     * {@link TelephonyManager#getSimPreciseCarrierId()}. Note, its possible precise carrier id
+     * changes while {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} remains the same
+     * e.g, when subscription switch to different IMSIs.
      * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
      * the carrier cannot be identified.
-     * @hide
      */
     public static final String EXTRA_PRECISE_CARRIER_ID =
             "android.telephony.extra.PRECISE_CARRIER_ID";
 
     /**
      * An string extra used with {@link #ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED} which
-     * indicates the updated precise carrier name of the current subscription.
-     * {@see TelephonyManager#getSimPreciseCarrierIdName()}
-     * <p>it's a user-facing name of the precise carrier id {@link #EXTRA_PRECISE_CARRIER_ID},
-     * @hide
+     * indicates the updated precise carrier name returned by
+     * {@link TelephonyManager#getSimPreciseCarrierIdName()}.
+     * <p>it's a user-facing name of the precise carrier id {@link #EXTRA_PRECISE_CARRIER_ID}, e.g,
+     * Tracfone-AT&T.
      */
-    public static final String EXTRA_PRECISE_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
+    public static final String EXTRA_PRECISE_CARRIER_NAME =
+            "android.telephony.extra.PRECISE_CARRIER_NAME";
 
     /**
      * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} to indicate the
@@ -3129,6 +3147,29 @@
     }
 
     /**
+     * Gets information about currently inserted UICCs and eUICCs. See {@link UiccCardInfo} for more
+     * details on the kind of information available.
+     *
+     * @return UiccCardInfo an array of UiccCardInfo objects, representing information on the
+     * currently inserted UICCs and eUICCs.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public UiccCardInfo[] getUiccCardsInfo() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony == null) {
+                return null;
+            }
+            return telephony.getUiccCardsInfo();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Gets all the UICC slots. The objects in the array can be null if the slot info is not
      * available, which is possible between phone process starting and getting slot info from modem.
      *
@@ -4863,7 +4904,7 @@
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
     public void requestCellInfoUpdate(
-            @NonNull Executor executor, @NonNull CellInfoCallback callback) {
+            @NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony == null) return;
@@ -6647,7 +6688,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getCarrierPrivilegeStatus(mSubId) ==
+                return telephony.getCarrierPrivilegeStatus(subId) ==
                     CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
             }
         } catch (RemoteException ex) {
@@ -8533,7 +8574,7 @@
 
     /**
      * Returns carrier id name of the current subscription.
-     * <p>Carrier id name is a user-facing name of carrier id
+     * <p>Carrier id name is a user-facing name of carrier id returned by
      * {@link #getSimCarrierId()}, usually the brand name of the subsidiary
      * (e.g. T-Mobile). Each carrier could configure multiple {@link #getSimOperatorName() SPN} but
      * should have a single carrier name. Carrier name is not a canonical identity,
@@ -8543,7 +8584,7 @@
      * @return Carrier name of the current subscription. Return {@code null} if the subscription is
      * unavailable or the carrier cannot be identified.
      */
-    public CharSequence getSimCarrierIdName() {
+    public @Nullable CharSequence getSimCarrierIdName() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
@@ -8560,10 +8601,10 @@
      *
      * <p>The precise carrier id can be used to further differentiate a carrier by different
      * networks, by prepaid v.s.postpaid or even by 4G v.s.3G plan. Each carrier has a unique
-     * carrier id {@link #getSimCarrierId()} but can have multiple precise carrier id. e.g,
-     * {@link #getSimCarrierId()} will always return Tracfone (id 2022) for a Tracfone SIM, while
-     * {@link #getSimPreciseCarrierId()} can return Tracfone AT&T or Tracfone T-Mobile based on the
-     * current subscription IMSI.
+     * carrier id returned by {@link #getSimCarrierId()} but could have multiple precise carrier id.
+     * e.g, {@link #getSimCarrierId()} will always return Tracfone (id 2022) for a Tracfone SIM,
+     * while {@link #getSimPreciseCarrierId()} can return Tracfone AT&T or Tracfone T-Mobile based
+     * on the current subscription IMSI.
      *
      * <p>For carriers without any fine-grained carrier ids, return {@link #getSimCarrierId()}
      * <p>Precise carrier ids are defined in the same way as carrier id
@@ -8573,8 +8614,6 @@
      * @return Returns fine-grained carrier id of the current subscription.
      * Return {@link #UNKNOWN_CARRIER_ID} if the subscription is unavailable or the carrier cannot
      * be identified.
-     *
-     * @hide
      */
     public int getSimPreciseCarrierId() {
         try {
@@ -8590,16 +8629,14 @@
 
     /**
      * Similar like {@link #getSimCarrierIdName()}, returns user-facing name of the
-     * precise carrier id {@link #getSimPreciseCarrierId()}
+     * precise carrier id returned by {@link #getSimPreciseCarrierId()}.
      *
      * <p>The returned name is unlocalized.
      *
      * @return user-facing name of the subscription precise carrier id. Return {@code null} if the
      * subscription is unavailable or the carrier cannot be identified.
-     *
-     * @hide
      */
-    public CharSequence getSimPreciseCarrierIdName() {
+    public @Nullable CharSequence getSimPreciseCarrierIdName() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
@@ -8612,6 +8649,62 @@
     }
 
     /**
+     * Returns carrier id based on sim MCCMNC (returned by {@link #getSimOperator()}) only.
+     * This is used for fallback when configurations/logic for exact carrier id
+     * {@link #getSimCarrierId()} are not found.
+     *
+     * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+     * can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier
+     * was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id
+     * by default. After carrier id table update, a new carrier id was assigned. If apps don't
+     * take the update with the new id, it might be helpful to always fallback by using carrier
+     * id based on MCCMNC if there is no match.
+     *
+     * @return matching carrier id from sim MCCMNC. Return {@link #UNKNOWN_CARRIER_ID} if the
+     * subscription is unavailable or the carrier cannot be identified.
+     */
+    public int getCarrierIdFromSimMccMnc() {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getCarrierIdFromMccMnc(getSlotIndex(), getSimOperator(), true);
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+        return UNKNOWN_CARRIER_ID;
+    }
+
+     /**
+      * Returns carrier id based on MCCMNC (returned by {@link #getSimOperator()}) only. This is
+      * used for fallback when configurations/logic for exact carrier id {@link #getSimCarrierId()}
+      * are not found.
+      *
+      * Android carrier id table <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/carrier_list.textpb">here</a>
+      * can be updated out-of-band, its possible a MVNO (Mobile Virtual Network Operator) carrier
+      * was not fully recognized and assigned to its MNO (Mobile Network Operator) carrier id
+      * by default. After carrier id table update, a new carrier id was assigned. If apps don't
+      * take the update with the new id, it might be helpful to always fallback by using carrier
+      * id based on MCCMNC if there is no match.
+      *
+      * @return matching carrier id from passing MCCMNC. Return {@link #UNKNOWN_CARRIER_ID} if the
+      * subscription is unavailable or the carrier cannot be identified.
+      * @hide
+      */
+     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+     public int getCarrierIdFromMccMnc(String mccmnc) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getCarrierIdFromMccMnc(getSlotIndex(), mccmnc, false);
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+        return UNKNOWN_CARRIER_ID;
+    }
+
+    /**
      * Return a list of certs in hex string from loaded carrier privileges access rules.
      *
      * @return a list of certificate in hex string. return {@code null} if there is no certs
@@ -8635,48 +8728,6 @@
     }
 
     /**
-     * Returns MNO carrier id of the current subscription’s MCCMNC.
-     * <p>MNO carrier id can be solely identified by subscription mccmnc. This is mainly used
-     * for MNO fallback when exact carrier id {@link #getSimCarrierId()}
-     * configurations are not found.
-     *
-     * @return MNO carrier id of the current subscription. Return the value same as carrier id
-     * {@link #getSimCarrierId()}, if MNO carrier id cannot be identified.
-     * @hide
-     */
-    public int getSimMNOCarrierId() {
-        try {
-            ITelephony service = getITelephony();
-            if (service != null) {
-                return service.getSubscriptionMNOCarrierId(getSubId());
-            }
-        } catch (RemoteException ex) {
-            // This could happen if binder process crashes.
-        }
-        return UNKNOWN_CARRIER_ID;
-    }
-
-     /**
-      * Returns carrier id based on MCCMNC only. This is for fallback when exact carrier id
-      * {@link #getSimCarrierId()} configurations are not found
-      *
-      * @return matching carrier id from passing mccmnc.
-      * @hide
-      */
-     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-     public int getCarrierIdFromMccMnc(String mccmnc) {
-        try {
-            ITelephony service = getITelephony();
-            if (service != null) {
-                return service.getCarrierIdFromMccMnc(getSlotIndex(), mccmnc);
-            }
-        } catch (RemoteException ex) {
-            // This could happen if binder process crashes.
-        }
-        return UNKNOWN_CARRIER_ID;
-    }
-
-    /**
      * Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}.
      * All uicc applications are uniquely identified by application ID, represented by the hex
      * string. e.g, A00000015141434C00. See ETSI 102.221 and 101.220
diff --git a/telephony/java/android/telephony/UiccCardInfo.aidl b/telephony/java/android/telephony/UiccCardInfo.aidl
new file mode 100644
index 0000000..882c233
--- /dev/null
+++ b/telephony/java/android/telephony/UiccCardInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable UiccCardInfo;
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
new file mode 100644
index 0000000..45e4704
--- /dev/null
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * The UiccCardInfo represents information about a currently inserted UICC or embedded eUICC.
+ * @hide
+ */
+@SystemApi
+public class UiccCardInfo implements Parcelable {
+
+    private final boolean mIsEuicc;
+    private final int mCardId;
+    private final String mEid;
+    private final String mIccId;
+    private final int mSlotIndex;
+
+    public static final Creator<UiccCardInfo> CREATOR = new Creator<UiccCardInfo>() {
+        @Override
+        public UiccCardInfo createFromParcel(Parcel in) {
+            return new UiccCardInfo(in);
+        }
+
+        @Override
+        public UiccCardInfo[] newArray(int size) {
+            return new UiccCardInfo[size];
+        }
+    };
+
+    private UiccCardInfo(Parcel in) {
+        mIsEuicc = in.readByte() != 0;
+        mCardId = in.readInt();
+        mEid = in.readString();
+        mIccId = in.readString();
+        mSlotIndex = in.readInt();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeByte((byte) (mIsEuicc ? 1 : 0));
+        dest.writeInt(mCardId);
+        dest.writeString(mEid);
+        dest.writeString(mIccId);
+        dest.writeInt(mSlotIndex);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public UiccCardInfo(boolean isEuicc, int cardId, String eid, String iccId, int slotIndex) {
+        this.mIsEuicc = isEuicc;
+        this.mCardId = cardId;
+        this.mEid = eid;
+        this.mIccId = iccId;
+        this.mSlotIndex = slotIndex;
+    }
+
+    /**
+     * Return whether the UiccCardInfo is an eUICC.
+     * @return true if the UICC is an eUICC.
+     */
+    public boolean isEuicc() {
+        return mIsEuicc;
+    }
+
+    /**
+     * Get the card ID of the UICC. See {@link TelephonyManager#getCardIdForDefaultEuicc()} for more
+     * details on card ID.
+     */
+    public int getCardId() {
+        return mCardId;
+    }
+
+    /**
+     * Get the embedded ID (EID) of the eUICC. If the UiccCardInfo is not an eUICC
+     * (see {@link #isEuicc()}), returns null.
+     */
+    public String getEid() {
+        if (!mIsEuicc) {
+            return null;
+        }
+        return mEid;
+    }
+
+    /**
+     * Get the ICCID of the UICC.
+     */
+    public String getIccId() {
+        return mIccId;
+    }
+
+    /**
+     * Gets the slot index for the slot that the UICC is currently inserted in.
+     */
+    public int getSlotIndex() {
+        return mSlotIndex;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+
+        UiccCardInfo that = (UiccCardInfo) obj;
+        return ((mIsEuicc == that.mIsEuicc)
+                && (mCardId == that.mCardId)
+                && (Objects.equals(mEid, that.mEid))
+                && (Objects.equals(mIccId, that.mIccId))
+                && (mSlotIndex == that.mSlotIndex));
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mIsEuicc, mCardId, mEid, mIccId, mSlotIndex);
+    }
+
+    @Override
+    public String toString() {
+        return "UiccCardInfo (mIsEuicc="
+                + mIsEuicc
+                + ", mCardId="
+                + mCardId
+                + ", mEid="
+                + mEid
+                + ", mIccId="
+                + mIccId
+                + ", mSlotIndex="
+                + mSlotIndex
+                + ")";
+    }
+}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index b5a8758..200b540 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -969,7 +969,7 @@
      */
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("[ApnSettingV5] ")
+        sb.append("[ApnSettingV6] ")
                 .append(mEntryName)
                 .append(", ").append(mId)
                 .append(", ").append(mOperatorNumeric)
@@ -996,6 +996,7 @@
         sb.append(", ").append(mPermanentFailed);
         sb.append(", ").append(mNetworkTypeBitmask);
         sb.append(", ").append(mApnSetId);
+        sb.append(", ").append(mCarrierId);
         return sb.toString();
     }
 
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 1db5850..74d1e83 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -16,7 +16,6 @@
 
 package android.telephony.data;
 
-import android.annotation.CallSuper;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -60,7 +59,6 @@
     private static final String TAG = DataService.class.getSimpleName();
 
     public static final String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
-    public static final String DATA_SERVICE_EXTRA_SLOT_ID = "android.telephony.data.extra.SLOT_ID";
 
     /** {@hide} */
     @IntDef(prefix = "REQUEST_REASON_", value = {
@@ -116,7 +114,7 @@
      * must extend this class to support data connection. Note that each instance of data service
      * provider is associated with one physical SIM slot.
      */
-    public class DataServiceProvider {
+    public abstract class DataServiceProvider implements AutoCloseable {
 
         private final int mSlotId;
 
@@ -250,12 +248,12 @@
         }
 
         /**
-         * Called when the instance of data service is destroyed (e.g. got unbind or binder died).
+         * Called when the instance of data service is destroyed (e.g. got unbind or binder died)
+         * or when the data service provider is removed. The extended class should implement this
+         * method to perform cleanup works.
          */
-        @CallSuper
-        protected void onDestroy() {
-            mDataCallListChangedCallbacks.clear();
-        }
+        @Override
+        public abstract void close();
     }
 
     private static final class SetupDataCallRequest {
@@ -345,7 +343,7 @@
                     break;
                 case DATA_SERVICE_REMOVE_DATA_SERVICE_PROVIDER:
                     if (serviceProvider != null) {
-                        serviceProvider.onDestroy();
+                        serviceProvider.close();
                         mServiceMap.remove(slotId);
                     }
                     break;
@@ -353,7 +351,7 @@
                     for (int i = 0; i < mServiceMap.size(); i++) {
                         serviceProvider = mServiceMap.get(i);
                         if (serviceProvider != null) {
-                            serviceProvider.onDestroy();
+                            serviceProvider.close();
                         }
                     }
                     mServiceMap.clear();
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 57d9cce..45b4849 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -151,7 +151,7 @@
 
         /**
          * Called when the qualified networks updater is removed. The extended class should
-         * implement this method to perform clean up works.
+         * implement this method to perform cleanup works.
          */
         @Override
         public abstract void close();
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index f124595..4d95e55 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -331,7 +331,80 @@
      */
     public static final int CODE_SIP_USER_MARKED_UNWANTED = 365;
 
-    /*
+    /**
+     * SIP Response : 405
+     * Method not allowed for the address in the Request URI
+     */
+    public static final int CODE_SIP_METHOD_NOT_ALLOWED = 366;
+
+    /**
+     * SIP Response : 407
+     * The request requires user authentication
+     */
+    public static final int CODE_SIP_PROXY_AUTHENTICATION_REQUIRED = 367;
+
+    /**
+     * SIP Response : 413
+     * Request body too large
+     */
+    public static final int CODE_SIP_REQUEST_ENTITY_TOO_LARGE = 368;
+
+    /**
+     * SIP Response : 414
+     * Request-URI too large
+     */
+    public static final int CODE_SIP_REQUEST_URI_TOO_LARGE = 369;
+
+    /**
+     * SIP Response : 421
+     * Specific extension is required, which is not present in the HEADER
+     */
+    public static final int CODE_SIP_EXTENSION_REQUIRED = 370;
+
+    /**
+     * SIP Response : 422
+     * The session expiration field too small
+     */
+    public static final int CODE_SIP_INTERVAL_TOO_BRIEF = 371;
+
+    /**
+     * SIP Response : 481
+     * Request received by the server does not match any dialog or transaction
+     */
+    public static final int CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST = 372;
+
+    /**
+     * SIP Response : 482
+     * Server has detected a loop
+     */
+    public static final int CODE_SIP_LOOP_DETECTED = 373;
+
+    /**
+     * SIP Response : 483
+     * Max-Forwards value reached
+     */
+    public static final int CODE_SIP_TOO_MANY_HOPS = 374;
+
+    /**
+     * SIP Response : 485
+     * Request-URI is ambiguous
+     *
+     */
+    public static final int CODE_SIP_AMBIGUOUS = 376;
+
+    /**
+     * SIP Response : 491
+     * Server has pending request for same dialog
+     */
+    public static final int CODE_SIP_REQUEST_PENDING = 377;
+
+    /**
+     * SIP Response : 493
+     * The request cannot be decrypted by recipient
+     */
+    public static final int CODE_SIP_UNDECIPHERABLE = 378;
+
+    /**
      * MEDIA (IMS -> Telephony)
      */
     /**
@@ -384,6 +457,24 @@
      * The call has been terminated by the network or remote user.
      */
     public static final int CODE_USER_TERMINATED_BY_REMOTE = 510;
+    /**
+    * Upgrade Downgrade request rejected by
+    * Remote user if the request is MO initiated
+    * Local user if the request is MT initiated
+    */
+    public static final int CODE_USER_REJECTED_SESSION_MODIFICATION = 511;
+
+    /**
+    * Upgrade Downgrade request cacncelled by the user who initiated it
+    */
+    public static final int CODE_USER_CANCELLED_SESSION_MODIFICATION = 512;
+
+    /**
+     * UPGRADE DOWNGRADE operation failed
+     * This can happen due to failure from SIP/RTP/SDP generation or a Call end is
+     * triggered/received while Reinvite is in progress.
+     */
+    public static final int CODE_SESSION_MODIFICATION_FAILED = 1517;
 
     /*
      * UT
@@ -484,6 +575,16 @@
     public static final int CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE = 1100;
 
     /**
+     * For MultiEndPoint - Call was rejected elsewhere
+     */
+    public static final int CODE_REJECTED_ELSEWHERE = 1017;
+
+    /**
+     * Supplementary services (HOLD/RESUME) failure error codes.
+     * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
+     */
+
+    /**
      * Supplementary Services (HOLD/RESUME) - the command failed.
      */
     public static final int CODE_SUPP_SVC_FAILED = 1201;
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index b0c875e..0fdca5d 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -79,10 +79,7 @@
     public static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
     public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
     public static final int EVENT_RESTART_RADIO = BASE + 26;
-    public static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 29;
-    public static final int CMD_SET_USER_DATA_ENABLE = BASE + 30;
-    public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
     public static final int EVENT_ICC_CHANGED = BASE + 33;
     public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
     public static final int EVENT_DATA_SETUP_COMPLETE_ERROR = BASE + 35;
@@ -93,14 +90,12 @@
     public static final int CMD_NET_STAT_POLL = BASE + 40;
     public static final int EVENT_DATA_RAT_CHANGED = BASE + 41;
     public static final int CMD_CLEAR_PROVISIONING_SPINNER = BASE + 42;
-    public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 43;
     public static final int EVENT_REDIRECTION_DETECTED = BASE + 44;
     public static final int EVENT_PCO_DATA_RECEIVED = BASE + 45;
-    public static final int EVENT_SET_CARRIER_DATA_ENABLED = BASE + 46;
+    public static final int EVENT_DATA_ENABLED_CHANGED = BASE + 46;
     public static final int EVENT_DATA_RECONNECT = BASE + 47;
     public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48;
     public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
-    public static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = BASE + 50;
 
     /***** Constants *****/
 
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 442fc34..40c7a9a 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -53,5 +53,6 @@
     void onPhoneCapabilityChanged(in PhoneCapability capability);
     void onRadioPowerStateChanged(in int state);
     void onPreferredDataSubIdChanged(in int subId);
+    void onCallDisconnectCauseChanged(in int disconnectCause, in int preciseDisconnectCause);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index f9db4b0..65d1a920 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -210,6 +210,10 @@
      */
     List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage);
 
+    boolean removeSubscriptionsFromGroup(in int[] subIdList, String callingPackage);
+
+    List<SubscriptionInfo> getSubscriptionsInGroup(int subId, String callingPackage);
+
     int getSlotIndex(int subId);
 
     int[] getSubId(int slotIndex);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5a06f6a..99d362a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -56,6 +56,7 @@
 import java.util.List;
 import java.util.Map;
 
+import android.telephony.UiccCardInfo;
 import android.telephony.UiccSlotInfo;
 
 /**
@@ -1337,18 +1338,6 @@
     String getSubscriptionCarrierName(int subId);
 
     /**
-     * Returns MNO carrier id of the current subscription’s MCCMNC.
-     * <p>MNO carrier id can be solely identified by subscription mccmnc. This is mainly used
-     * for MNO fallback when exact carrier id {@link #getSimCarrierId()}
-     * configurations are not found.
-     *
-     * @return MNO carrier id of the current subscription. Return the value same as carrier id
-     * {@link #getSimCarrierId()}, if MNO carrier id cannot be identified.
-     * @hide
-     */
-    int getSubscriptionMNOCarrierId(int subId);
-
-    /**
      * Returns fine-grained carrier id of the current subscription.
      *
      * <p>The precise carrier id can be used to further differentiate a carrier by different
@@ -1383,10 +1372,13 @@
      * Returns carrier id based on MCCMNC only. This will return a MNO carrier id used for fallback
      * check when exact carrier id {@link #getSimCarrierId()} configurations are not found
      *
+     * @param isSubscriptionMccMnc. If {@true} it means this is a query for subscription mccmnc
+     * {@false} otherwise.
+     *
      * @return carrier id from passing mccmnc.
      * @hide
      */
-    int getCarrierIdFromMccMnc(int slotIndex, String mccmnc);
+    int getCarrierIdFromMccMnc(int slotIndex, String mccmnc, boolean isSubscriptionMccMnc);
 
     /**
      * Action set from carrier signalling broadcast receivers to enable/disable metered apns
@@ -1495,6 +1487,17 @@
     int getCardIdForDefaultEuicc(int subId, String callingPackage); 
 
     /**
+     * Gets information about currently inserted UICCs and eUICCs. See {@link UiccCardInfo} for more
+     * details on the kind of information available.
+     *
+     * @return UiccCardInfo an array of UiccCardInfo objects, representing information on the
+     * currently inserted UICCs and eUICCs.
+     *
+     * @hide
+     */
+    UiccCardInfo[] getUiccCardsInfo();
+
+    /**
      * Get slot info for all the UICC slots.
      * @return UiccSlotInfo array.
      * @hide
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 436dd85..151b559 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -1048,12 +1048,17 @@
             4,    // Protocol size: 4
             0, 2  // Opcode: reply (2)
     };
-    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
+    private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
+    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
 
     private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
     private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
     private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
     private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
+    private static final byte[] IPV4_SOURCE_ADDR         = {10, 0, 0, 3};
+    private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1};
+    private static final byte[] BUG_PROBE_SOURCE_ADDR1   = {0, 0, 1, 2};
+    private static final byte[] BUG_PROBE_SOURCE_ADDR2   = {3, 4, 0, 0};
     private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
 
     // Helper to initialize a default apfFilter.
@@ -1399,10 +1404,16 @@
         assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
         assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
 
+        // Verify ARP reply packets from different source ip
+        assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR));
+        assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
+        assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR));
+        assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR));
+
         // Verify unicast ARP reply packet is always accepted.
-        assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR));
-        assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR));
-        assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR));
+        assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR));
+        assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR));
+        assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
 
         // Verify GARP reply packets are always filtered
         assertDrop(program, garpReply());
@@ -1431,19 +1442,20 @@
         apfFilter.shutdown();
     }
 
-    private static byte[] arpRequestBroadcast(byte[] tip) {
+    private static byte[] arpReply(byte[] sip, byte[] tip) {
         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
         put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
+        put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip);
         put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
         return packet.array();
     }
 
-    private static byte[] arpReplyUnicast(byte[] tip) {
+    private static byte[] arpRequestBroadcast(byte[] tip) {
         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
-        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
+        put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
+        put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER);
         put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
         return packet.array();
     }
diff --git a/tests/net/java/android/net/dhcp/DhcpServerTest.java b/tests/net/java/android/net/dhcp/DhcpServerTest.java
index df34c73..ab9bd84 100644
--- a/tests/net/java/android/net/dhcp/DhcpServerTest.java
+++ b/tests/net/java/android/net/dhcp/DhcpServerTest.java
@@ -25,7 +25,6 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -48,7 +47,6 @@
 import android.net.dhcp.DhcpLeaseRepository.OutOfAddressesException;
 import android.net.dhcp.DhcpServer.Clock;
 import android.net.dhcp.DhcpServer.Dependencies;
-import android.net.util.InterfaceParams;
 import android.net.util.SharedLog;
 import android.os.test.TestLooper;
 import android.support.test.filters.SmallTest;
@@ -74,9 +72,6 @@
 public class DhcpServerTest {
     private static final String PROP_DEXMAKER_SHARE_CLASSLOADER = "dexmaker.share_classloader";
     private static final String TEST_IFACE = "testiface";
-    private static final MacAddress TEST_IFACE_MAC = MacAddress.fromString("11:22:33:44:55:66");
-    private static final InterfaceParams TEST_IFACEPARAMS =
-            new InterfaceParams(TEST_IFACE, 1, TEST_IFACE_MAC);
 
     private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
     private static final LinkAddress TEST_SERVER_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
@@ -149,7 +144,7 @@
                 .build();
 
         mLooper = new TestLooper();
-        mServer = new DhcpServer(mLooper.getLooper(), TEST_IFACEPARAMS, servingParams,
+        mServer = new DhcpServer(mLooper.getLooper(), TEST_IFACE, servingParams,
                 new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps);
 
         mServer.start();
diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/tests/net/java/android/net/ip/IpServerTest.java
index cff0b54..2c675c6 100644
--- a/tests/net/java/android/net/ip/IpServerTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -404,7 +404,7 @@
 
     private void assertDhcpStarted(IpPrefix expectedPrefix) {
         verify(mDependencies, times(1)).makeDhcpServer(
-                eq(mLooper.getLooper()), eq(TEST_IFACE_PARAMS), any(), eq(mSharedLog));
+                eq(mLooper.getLooper()), eq(IFACE_NAME), any(), eq(mSharedLog));
         verify(mDhcpServer, times(1)).start();
         final DhcpServingParams params = mDhcpParamsCaptor.getValue();
         // Last address byte is random
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index bca9be7..e6b43d2 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -240,7 +240,7 @@
                 }
 
                 @Override
-                public DhcpServer makeDhcpServer(Looper looper, InterfaceParams iface,
+                public DhcpServer makeDhcpServer(Looper looper, String ifName,
                         DhcpServingParams params, SharedLog log) {
                     return mDhcpServer;
                 }
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 39ca80b..968376b 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -78,7 +78,7 @@
 
 static uint32_t ParseFormatAttribute(const StringPiece& str) {
   uint32_t mask = 0;
-  for (StringPiece part : util::Tokenize(str, '|')) {
+  for (const StringPiece& part : util::Tokenize(str, '|')) {
     StringPiece trimmed_part = util::TrimWhitespace(part);
     uint32_t type = ParseFormatType(trimmed_part);
     if (type == 0) {
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 82d9e04..99420de 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -360,7 +360,7 @@
     return util::make_unique<BinaryPrimitive>(flags);
   }
 
-  for (StringPiece part : util::Tokenize(str, '|')) {
+  for (const StringPiece& part : util::Tokenize(str, '|')) {
     StringPiece trimmed_part = util::TrimWhitespace(part);
 
     bool flag_set = false;
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 411ad74..0b43c5d 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -486,7 +486,7 @@
     }
 
     Printer r_txt_printer(&fout_text);
-    for (const auto res : xmlres->file.exported_symbols) {
+    for (const auto& res : xmlres->file.exported_symbols) {
       r_txt_printer.Print("default int id ");
       r_txt_printer.Println(res.name.entry);
     }
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 8d91b00..a4610b2 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -113,7 +113,7 @@
 void AnnotationProcessor::Print(Printer* printer) const {
   if (has_comments_) {
     std::string result = comment_.str();
-    for (StringPiece line : util::Tokenize(result, '\n')) {
+    for (const StringPiece& line : util::Tokenize(result, '\n')) {
       printer->Println(line);
     }
     printer->Println(" */");
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 5a8ff09..a407c22 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -165,7 +165,7 @@
 
 std::string PackageToPath(const StringPiece& package) {
   std::string out_path;
-  for (StringPiece part : util::Tokenize(package, '.')) {
+  for (const StringPiece& part : util::Tokenize(package, '.')) {
     AppendPath(&out_path, part);
   }
   return out_path;
diff --git a/tools/incident_report/printer.h b/tools/incident_report/printer.h
index ed93fa1..63e276b 100644
--- a/tools/incident_report/printer.h
+++ b/tools/incident_report/printer.h
@@ -22,7 +22,7 @@
 class Out
 {
 public:
-    Out(int fd);
+    explicit Out(int fd);
     ~Out();
 
     void printf(const char* format, ...);
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
index 1d4c435..d368136 100644
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
+++ b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
@@ -28,6 +28,7 @@
 
 import java.io.IOException;
 import java.io.PrintStream;
+import java.net.URLEncoder;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -38,7 +39,9 @@
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
 
 /**
@@ -108,10 +111,25 @@
                 "startline",
                 "startcol",
                 "endline",
-                "endcol"
+                "endcol",
+                "properties"
         );
     }
 
+    private String encodeAnnotationProperties(AnnotationMirror annotation) {
+        StringBuilder sb = new StringBuilder();
+        for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e
+                : annotation.getElementValues().entrySet()) {
+            if (sb.length() > 0) {
+                sb.append("&");
+            }
+            sb.append(e.getKey().getSimpleName())
+                    .append("=")
+                    .append(URLEncoder.encode(e.getValue().toString()));
+        }
+        return sb.toString();
+    }
+
     /**
      * Maps an annotated element to the source position of the @UnsupportedAppUsage annotation
      * attached to it. It returns CSV in the format:
@@ -137,7 +155,8 @@
                 lines.getLineNumber(pair.fst.pos().getStartPosition()),
                 lines.getColumnNumber(pair.fst.pos().getStartPosition()),
                 lines.getLineNumber(pair.fst.pos().getEndPosition(pair.snd.endPositions)),
-                lines.getColumnNumber(pair.fst.pos().getEndPosition(pair.snd.endPositions)));
+                lines.getColumnNumber(pair.fst.pos().getEndPosition(pair.snd.endPositions)),
+                encodeAnnotationProperties(unsupportedAppUsage));
     }
 
     /**
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 703a67b..5725f0c 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -96,6 +96,7 @@
 
 cc_library_shared {
     name: "libstatslog",
+    host_supported: true,
     generated_sources: ["statslog.cpp"],
     generated_headers: ["statslog.h"],
     cflags: [
@@ -105,8 +106,19 @@
     export_generated_headers: ["statslog.h"],
     shared_libs: [
         "liblog",
-        "libutils",
         "libcutils",
     ],
     static_libs: ["libstatssocket"],
+    target: {
+        android: {
+            shared_libs: [
+                "libutils",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libutils",
+            ],
+        },
+    },
 }
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index ebdcdfd..61174d9 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -47,7 +47,8 @@
       fields(that.fields),
       primaryFields(that.primaryFields),
       exclusiveField(that.exclusiveField),
-      uidField(that.uidField) {}
+      uidField(that.uidField),
+      binaryFields(that.binaryFields) {}
 
 AtomDecl::AtomDecl(int c, const string& n, const string& m)
     :code(c),
@@ -116,6 +117,9 @@
             if (field->message_type()->full_name() ==
                 "android.os.statsd.AttributionNode") {
               return JAVA_TYPE_ATTRIBUTION_CHAIN;
+            } else if (field->options().GetExtension(os::statsd::log_mode) ==
+                       os::statsd::LogMode::MODE_BYTES) {
+                return JAVA_TYPE_BYTE_ARRAY;
             } else {
                 return JAVA_TYPE_OBJECT;
             }
@@ -185,6 +189,8 @@
   for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
        it != fields.end(); it++) {
     const FieldDescriptor *field = it->second;
+    bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
+                         os::statsd::LogMode::MODE_BYTES;
 
     java_type_t javaType = java_type(field);
 
@@ -198,12 +204,19 @@
                   field->name().c_str());
       errorCount++;
       continue;
-    } else if (javaType == JAVA_TYPE_BYTE_ARRAY) {
+    } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
       print_error(field, "Raw bytes type not allowed for field: %s\n",
                   field->name().c_str());
       errorCount++;
       continue;
     }
+
+    if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
+      print_error(field, "Cannot mark field %s as bytes.\n",
+                  field->name().c_str());
+      errorCount++;
+      continue;
+    }
   }
 
   // Check that if there's an attribution chain, it's at position 1.
@@ -228,12 +241,16 @@
        it != fields.end(); it++) {
     const FieldDescriptor *field = it->second;
     java_type_t javaType = java_type(field);
+    bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
+                         os::statsd::LogMode::MODE_BYTES;
 
     AtomField atField(field->name(), javaType);
     if (javaType == JAVA_TYPE_ENUM) {
       // All enums are treated as ints when it comes to function signatures.
       signature->push_back(JAVA_TYPE_INT);
       collate_enums(*field->enum_type(), &atField);
+    } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
+      signature->push_back(JAVA_TYPE_BYTE_ARRAY);
     } else {
       signature->push_back(javaType);
     }
@@ -275,6 +292,10 @@
             errorCount++;
         }
     }
+    // Binary field validity is already checked above.
+    if (isBinaryField) {
+        atomDecl->binaryFields.push_back(it->first);
+    }
   }
 
   return errorCount;
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 5d2c302..a8b270c 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -86,6 +86,8 @@
 
     int uidField = 0;
 
+    vector<int> binaryFields;
+
     AtomDecl();
     AtomDecl(const AtomDecl& that);
     AtomDecl(int code, const string& name, const string& message);
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index e519909..2478b91 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -68,6 +68,8 @@
             return "double";
         case JAVA_TYPE_STRING:
             return "char const*";
+        case JAVA_TYPE_BYTE_ARRAY:
+            return "char const*";
         default:
             return "UNKNOWN";
     }
@@ -90,6 +92,8 @@
             return "double";
         case JAVA_TYPE_STRING:
             return "java.lang.String";
+        case JAVA_TYPE_BYTE_ARRAY:
+            return "byte[]";
         default:
             return "UNKNOWN";
     }
@@ -104,7 +108,9 @@
     fprintf(out, "#include <mutex>\n");
     fprintf(out, "#include <chrono>\n");
     fprintf(out, "#include <thread>\n");
+    fprintf(out, "#ifdef __ANDROID__\n");
     fprintf(out, "#include <cutils/properties.h>\n");
+    fprintf(out, "#endif\n");
     fprintf(out, "#include <stats_event_list.h>\n");
     fprintf(out, "#include <log/log.h>\n");
     fprintf(out, "#include <statslog.h>\n");
@@ -115,7 +121,11 @@
     fprintf(out, "namespace util {\n");
     fprintf(out, "// the single event tag id for all stats logs\n");
     fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
+    fprintf(out, "#ifdef __ANDROID__\n");
     fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
+    fprintf(out, "#else\n");
+    fprintf(out, "const static bool kStatsdEnabled = false;\n");
+    fprintf(out, "#endif\n");
 
     std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
                                              "audio_state_changed",
@@ -200,13 +210,40 @@
     }
 
     fprintf(out, "    return options;\n");
-    fprintf(out, "  }\n");
+    fprintf(out, "}\n");
 
     fprintf(out,
             "const std::map<int, StateAtomFieldOptions> "
             "AtomsInfo::kStateAtomsFieldOptions = "
             "getStateAtomFieldOptions();\n");
 
+    fprintf(out,
+            "static std::map<int, std::vector<int>> "
+            "getBinaryFieldAtoms() {\n");
+    fprintf(out, "    std::map<int, std::vector<int>> options;\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (atom->binaryFields.size() == 0) {
+            continue;
+        }
+        fprintf(out,
+                "\n    // Adding binary fields for atom "
+                "(%d)%s\n",
+                atom->code, atom->name.c_str());
+
+        for (const auto& field : atom->binaryFields) {
+            fprintf(out, "    options[static_cast<int>(%s)].push_back(%d);\n",
+                    make_constant_name(atom->name).c_str(), field);
+        }
+    }
+
+    fprintf(out, "    return options;\n");
+    fprintf(out, "}\n");
+
+    fprintf(out,
+            "const std::map<int, std::vector<int>> "
+            "AtomsInfo::kBytesFieldAtoms = "
+            "getBinaryFieldAtoms();\n");
 
     fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
     fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
@@ -235,6 +272,9 @@
                                  chainField.name.c_str(), chainField.name.c_str());
                     }
                 }
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out, ", %s arg%d, size_t arg%d_length",
+                        cpp_type_name(*arg), argIndex, argIndex);
             } else {
                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
             }
@@ -277,6 +317,10 @@
                 fprintf(out, "        event.end();\n");
                 fprintf(out, "    }\n");
                 fprintf(out, "    event.end();\n\n");
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out,
+                        "    event.AppendCharArray(arg%d, arg%d_length);\n",
+                        argIndex, argIndex);
             } else {
                 if (*arg == JAVA_TYPE_STRING) {
                     fprintf(out, "    if (arg%d == NULL) {\n", argIndex);
@@ -317,6 +361,9 @@
                                 chainField.name.c_str(), chainField.name.c_str());
                    }
                }
+           } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+               fprintf(out, ", %s arg%d, size_t arg%d_length",
+                       cpp_type_name(*arg), argIndex, argIndex);
            } else {
                fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
            }
@@ -343,6 +390,8 @@
                                 chainField.name.c_str(), chainField.name.c_str());
                    }
                }
+           } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+               fprintf(out, ", arg%d, arg%d_length", argIndex, argIndex);
            } else {
                fprintf(out, ", arg%d", argIndex);
            }
@@ -491,6 +540,10 @@
                          chainField.name.c_str(), chainField.name.c_str());
                 }
             }
+        } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
+            fprintf(out, ", %s %s, size_t %s_length",
+                    cpp_type_name(field->javaType), field->name.c_str(),
+                    field->name.c_str());
         } else {
             fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
         }
@@ -518,6 +571,9 @@
                             chainField.name.c_str(), chainField.name.c_str());
                     }
                 }
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out, ", %s arg%d, size_t arg%d_length",
+                        cpp_type_name(*arg), argIndex, argIndex);
             } else {
                 fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
             }
@@ -600,6 +656,9 @@
     fprintf(out,
             "  const static std::map<int, StateAtomFieldOptions> "
             "kStateAtomsFieldOptions;\n");
+    fprintf(out,
+            "  const static std::map<int, std::vector<int>> "
+            "kBytesFieldAtoms;");
     fprintf(out, "};\n");
 
     fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
@@ -632,6 +691,8 @@
         field != atom.fields.end(); field++) {
         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
             fprintf(out, ", android.os.WorkSource workSource");
+        } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
+            fprintf(out, ", byte[] %s", field->name.c_str());
         } else {
             fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
         }
@@ -821,6 +882,8 @@
             return "jdouble";
         case JAVA_TYPE_STRING:
             return "jstring";
+        case JAVA_TYPE_BYTE_ARRAY:
+            return "jbyteArray";
         default:
             return "UNKNOWN";
     }
@@ -868,6 +931,9 @@
             case JAVA_TYPE_ATTRIBUTION_CHAIN:
               result += "_AttributionChain";
               break;
+            case JAVA_TYPE_BYTE_ARRAY:
+                result += "_bytes";
+                break;
             default:
                 result += "_UNKNOWN";
                 break;
@@ -893,6 +959,8 @@
             return "D";
         case JAVA_TYPE_STRING:
             return "Ljava/lang/String;";
+        case JAVA_TYPE_BYTE_ARRAY:
+            return "[B";
         default:
             return "UNKNOWN";
     }
@@ -960,6 +1028,32 @@
                 fprintf(out, "    } else {\n");
                 fprintf(out, "        str%d = NULL;\n", argIndex);
                 fprintf(out, "    }\n");
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                hadStringOrChain = true;
+                fprintf(out, "    jbyte* jbyte_array%d;\n", argIndex);
+                fprintf(out, "    const char* str%d;\n", argIndex);
+                fprintf(out, "    int str%d_length = 0;\n", argIndex);
+                fprintf(out,
+                        "    if (arg%d != NULL && env->GetArrayLength(arg%d) > "
+                        "0) {\n",
+                        argIndex, argIndex);
+                fprintf(out,
+                        "        jbyte_array%d = "
+                        "env->GetByteArrayElements(arg%d, NULL);\n",
+                        argIndex, argIndex);
+                fprintf(out,
+                        "        str%d_length = env->GetArrayLength(arg%d);\n",
+                        argIndex, argIndex);
+                fprintf(out,
+                        "        str%d = "
+                        "reinterpret_cast<char*>(env->GetByteArrayElements(arg%"
+                        "d, NULL));\n",
+                        argIndex, argIndex);
+                fprintf(out, "    } else {\n");
+                fprintf(out, "        jbyte_array%d = NULL;\n", argIndex);
+                fprintf(out, "        str%d = NULL;\n", argIndex);
+                fprintf(out, "    }\n");
+
             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 hadStringOrChain = true;
                 for (auto chainField : attributionDecl.fields) {
@@ -1026,8 +1120,15 @@
                     }
                 }
             } else {
-                const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
+                const char* argName = (*arg == JAVA_TYPE_STRING ||
+                                       *arg == JAVA_TYPE_BYTE_ARRAY)
+                                              ? "str"
+                                              : "arg";
                 fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
+
+                if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                    fprintf(out, ", %s%d_length", argName, argIndex);
+                }
             }
             argIndex++;
         }
@@ -1043,6 +1144,13 @@
                 fprintf(out, "        env->ReleaseStringUTFChars(arg%d, str%d);\n",
                         argIndex, argIndex);
                 fprintf(out, "    }\n");
+            } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+                fprintf(out, "    if (str%d != NULL) { \n", argIndex);
+                fprintf(out,
+                        "        env->ReleaseByteArrayElements(arg%d, "
+                        "jbyte_array%d, 0);\n",
+                        argIndex, argIndex);
+                fprintf(out, "    }\n");
             } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
                     if (chainField.javaType == JAVA_TYPE_INT) {
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 264a865..188b765 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -109,6 +109,28 @@
   oneof event { BadAttributionNodePositionAtom bad = 1; }
 }
 
+message GoodEventWithBinaryFieldAtom {
+    oneof event { GoodBinaryFieldAtom field1 = 1; }
+}
+
+message ComplexField {
+    optional string str = 1;
+}
+
+message GoodBinaryFieldAtom {
+    optional int32 field1 = 1;
+    optional ComplexField bf = 2 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+message BadEventWithBinaryFieldAtom {
+    oneof event { BadBinaryFieldAtom field1 = 1; }
+}
+
+message BadBinaryFieldAtom {
+    optional int32 field1 = 1;
+    optional ComplexField bf = 2;
+}
+
 message BadStateAtoms {
     oneof event {
         BadStateAtom1 bad1 = 1;
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 1936d96..ad3bffac 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -212,5 +212,19 @@
     EXPECT_EQ(0, errorCount);
 }
 
+TEST(CollationTest, PassOnGoodBinaryFieldAtom) {
+    Atoms atoms;
+    int errorCount =
+            collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), &atoms);
+    EXPECT_EQ(0, errorCount);
+}
+
+TEST(CollationTest, FailOnBadBinaryFieldAtom) {
+    Atoms atoms;
+    int errorCount =
+            collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), &atoms);
+    EXPECT_TRUE(errorCount > 0);
+}
+
 }  // namespace stats_log_api_gen
 }  // namespace android
\ No newline at end of file