Merge "Ensure that debug builds crash again if there is a BinderProxy leak."
diff --git a/Android.bp b/Android.bp
index 7d75f62..1f4c59a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -102,3 +102,29 @@
     dxflags: ["--core-library"],
     installable: false,
 }
+
+python_defaults {
+    name: "base_default",
+    version: {
+        py2: {
+            enabled: true,
+            embedded_launcher: true,
+        },
+        py3: {
+            enabled: false,
+            embedded_launcher: false,
+        },
+    },
+}
+
+python_binary_host {
+    name: "fontchain_linter",
+    defaults: ["base_default"],
+    main: "tools/fonts/fontchain_linter.py",
+    srcs: [
+        "tools/fonts/fontchain_linter.py",
+    ],
+    libs: [
+        "fontTools",
+    ],
+}
diff --git a/Android.mk b/Android.mk
index 4e036b5..825d192 100644
--- a/Android.mk
+++ b/Android.mk
@@ -138,6 +138,7 @@
 	../../system/bt/binder/android/bluetooth/IBluetoothPbap.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothPbapClient.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothSap.aidl \
+	../../system/bt/binder/android/bluetooth/IBluetoothSocketManager.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothStateChangeCallback.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothHeadsetClient.aidl \
 	../../system/bt/binder/android/bluetooth/IBluetoothHidDevice.aidl \
@@ -518,15 +519,19 @@
 	telephony/java/com/android/ims/internal/IImsEcbmListener.aidl \
         telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl \
         telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl \
+        telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl \
         telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl \
+	telephony/java/com/android/ims/internal/IImsRcsFeature.aidl \
 	telephony/java/com/android/ims/internal/IImsService.aidl \
 	telephony/java/com/android/ims/internal/IImsServiceController.aidl \
-	telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl \
+	telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl \
+        telephony/java/com/android/ims/internal/IImsSmsFeature.aidl \
 	telephony/java/com/android/ims/internal/IImsStreamMediaSession.aidl \
 	telephony/java/com/android/ims/internal/IImsUt.aidl \
 	telephony/java/com/android/ims/internal/IImsUtListener.aidl \
 	telephony/java/com/android/ims/internal/IImsVideoCallCallback.aidl \
 	telephony/java/com/android/ims/internal/IImsVideoCallProvider.aidl \
+        telephony/java/com/android/ims/internal/ISmsListener.aidl \
         telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl \
         telephony/java/com/android/ims/internal/uce/uceservice/IUceListener.aidl \
         telephony/java/com/android/ims/internal/uce/options/IOptionsService.aidl \
@@ -654,6 +659,7 @@
 	frameworks/base/telephony/java/android/telephony/NeighboringCellInfo.aidl \
 	frameworks/base/telephony/java/android/telephony/ModemActivityInfo.aidl \
 	frameworks/base/telephony/java/android/telephony/UiccAccessRule.aidl \
+	frameworks/base/telephony/java/android/telephony/data/DataProfile.aidl \
 	frameworks/base/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl \
 	frameworks/base/telephony/java/android/telephony/euicc/EuiccInfo.aidl \
 	frameworks/base/location/java/android/location/Location.aidl \
diff --git a/api/current.txt b/api/current.txt
index a8250e2..2b9e372 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25529,7 +25529,6 @@
     method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
     method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
     method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
   public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
@@ -30727,6 +30726,7 @@
   }
 
   public final class Debug {
+    method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
     method public static deprecated void changeDebugPort(int);
     method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
     method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -38004,6 +38004,16 @@
     field public final int errno;
   }
 
+  public class Int32Ref {
+    ctor public Int32Ref(int);
+    field public int value;
+  }
+
+  public class Int64Ref {
+    ctor public Int64Ref(long);
+    field public long value;
+  }
+
   public final class Os {
     method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -38073,7 +38083,8 @@
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
     method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
-    method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+    method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+    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;
@@ -38098,7 +38109,8 @@
     method public static int umask(int);
     method public static android.system.StructUtsname uname();
     method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
-    method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+    method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+    method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
     method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -38674,6 +38686,7 @@
     method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
+    method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
     method public void hold();
     method public boolean isRttActive();
     method public void mergeConference();
@@ -38718,6 +38731,8 @@
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+    method public void onHandoverComplete(android.telecom.Call);
+    method public void onHandoverFailed(android.telecom.Call, int);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
     method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -38726,6 +38741,10 @@
     method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+    field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+    field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
+    field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+    field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
   }
 
   public static class Call.Details {
@@ -38793,7 +38812,9 @@
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
     method public int describeContents();
+    method public android.bluetooth.BluetoothDevice getActiveBluetoothDevice();
     method public int getRoute();
+    method public java.util.Collection<android.bluetooth.BluetoothDevice> getSupportedBluetoothDevices();
     method public int getSupportedRouteMask();
     method public boolean isMuted();
     method public void writeToParcel(android.os.Parcel, int);
@@ -38925,6 +38946,7 @@
     method public final void putExtras(android.os.Bundle);
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
+    method public void requestBluetoothAudio(java.lang.String);
     method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
@@ -39056,8 +39078,11 @@
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -39115,6 +39140,7 @@
     method public void onCanAddCallChanged(boolean);
     method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onSilenceRinger();
+    method public final void requestBluetoothAudio(java.lang.String);
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -39179,6 +39205,9 @@
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+    field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
     field public static final java.lang.String SCHEME_SIP = "sip";
@@ -39339,6 +39368,7 @@
   }
 
   public class TelecomManager {
+    method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
     method public void acceptRingingCall();
     method public void acceptRingingCall(int);
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -39504,6 +39534,7 @@
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
     field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
+    field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
diff --git a/api/system-current.txt b/api/system-current.txt
index 3b0da5e..1620e65 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -27725,7 +27725,6 @@
     method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
     method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
     method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
   }
 
   public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
@@ -33450,6 +33449,7 @@
   }
 
   public final class Debug {
+    method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
     method public static deprecated void changeDebugPort(int);
     method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
     method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -41218,6 +41218,16 @@
     field public final int errno;
   }
 
+  public class Int32Ref {
+    ctor public Int32Ref(int);
+    field public int value;
+  }
+
+  public class Int64Ref {
+    ctor public Int64Ref(long);
+    field public long value;
+  }
+
   public final class Os {
     method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -41287,7 +41297,8 @@
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
     method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
-    method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+    method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+    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;
@@ -41312,7 +41323,8 @@
     method public static int umask(int);
     method public static android.system.StructUtsname uname();
     method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
-    method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+    method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+    method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
     method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -41907,6 +41919,7 @@
     method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
+    method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
     method public void hold();
     method public boolean isRttActive();
     method public void mergeConference();
@@ -41953,6 +41966,8 @@
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+    method public void onHandoverComplete(android.telecom.Call);
+    method public void onHandoverFailed(android.telecom.Call, int);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
     method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -41961,6 +41976,10 @@
     method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+    field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+    field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
+    field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+    field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
   }
 
   public static class Call.Details {
@@ -42032,7 +42051,9 @@
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
     method public int describeContents();
+    method public android.bluetooth.BluetoothDevice getActiveBluetoothDevice();
     method public int getRoute();
+    method public java.util.Collection<android.bluetooth.BluetoothDevice> getSupportedBluetoothDevices();
     method public int getSupportedRouteMask();
     method public boolean isMuted();
     method public void writeToParcel(android.os.Parcel, int);
@@ -42171,6 +42192,7 @@
     method public final void putExtras(android.os.Bundle);
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
+    method public void requestBluetoothAudio(java.lang.String);
     method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
@@ -42302,8 +42324,11 @@
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -42364,6 +42389,7 @@
     method public deprecated void onPhoneCreated(android.telecom.Phone);
     method public deprecated void onPhoneDestroyed(android.telecom.Phone);
     method public void onSilenceRinger();
+    method public final void requestBluetoothAudio(java.lang.String);
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -42502,6 +42528,7 @@
     method public final android.telecom.CallAudioState getCallAudioState();
     method public final java.util.List<android.telecom.Call> getCalls();
     method public final void removeListener(android.telecom.Phone.Listener);
+    method public void requestBluetoothAudio(java.lang.String);
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
   }
@@ -42549,6 +42576,9 @@
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+    field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
     field public static final java.lang.String SCHEME_SIP = "sip";
@@ -42750,6 +42780,7 @@
   }
 
   public class TelecomManager {
+    method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
     method public void acceptRingingCall();
     method public void acceptRingingCall(int);
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -42935,6 +42966,7 @@
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
     field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
+    field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
@@ -43872,6 +43904,39 @@
 
 }
 
+package android.telephony.data {
+
+  public final class DataProfile implements android.os.Parcelable {
+    ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean);
+    ctor public DataProfile(android.os.Parcel);
+    method public int describeContents();
+    method public java.lang.String getApn();
+    method public int getAuthType();
+    method public int getBearerBitmap();
+    method public int getMaxConns();
+    method public int getMaxConnsTime();
+    method public int getMtu();
+    method public java.lang.String getMvnoMatchData();
+    method public java.lang.String getMvnoType();
+    method public java.lang.String getPassword();
+    method public int getProfileId();
+    method public java.lang.String getProtocol();
+    method public java.lang.String getRoamingProtocol();
+    method public int getSupportedApnTypesBitmap();
+    method public int getType();
+    method public java.lang.String getUserName();
+    method public int getWaitTime();
+    method public boolean isEnabled();
+    method public boolean isModemCognitive();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
+    field public static final int TYPE_3GPP = 1; // 0x1
+    field public static final int TYPE_3GPP2 = 2; // 0x2
+    field public static final int TYPE_COMMON = 0; // 0x0
+  }
+
+}
+
 package android.telephony.gsm {
 
   public class GsmCellLocation extends android.telephony.CellLocation {
diff --git a/api/test-current.txt b/api/test-current.txt
index 97bc448..33d96a7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -30837,6 +30837,7 @@
   }
 
   public final class Debug {
+    method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
     method public static deprecated void changeDebugPort(int);
     method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
     method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -38211,6 +38212,16 @@
     field public final int errno;
   }
 
+  public class Int32Ref {
+    ctor public Int32Ref(int);
+    field public int value;
+  }
+
+  public class Int64Ref {
+    ctor public Int64Ref(long);
+    field public long value;
+  }
+
   public final class Os {
     method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -38280,7 +38291,8 @@
     method public static void remove(java.lang.String) throws android.system.ErrnoException;
     method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
     method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
-    method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+    method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+    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;
@@ -38305,7 +38317,8 @@
     method public static int umask(int);
     method public static android.system.StructUtsname uname();
     method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
-    method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+    method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+    method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
     method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
     method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -38881,6 +38894,7 @@
     method public android.telecom.Call.RttCall getRttCall();
     method public int getState();
     method public android.telecom.InCallService.VideoCall getVideoCall();
+    method public void handoverTo(android.telecom.PhoneAccountHandle, int, android.os.Bundle);
     method public void hold();
     method public boolean isRttActive();
     method public void mergeConference();
@@ -38925,6 +38939,8 @@
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
+    method public void onHandoverComplete(android.telecom.Call);
+    method public void onHandoverFailed(android.telecom.Call, int);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
     method public void onRttInitiationFailure(android.telecom.Call, int);
@@ -38933,6 +38949,10 @@
     method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
     method public void onStateChanged(android.telecom.Call, int);
     method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
+    field public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; // 0x1
+    field public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3; // 0x3
+    field public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2; // 0x2
+    field public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4; // 0x4
   }
 
   public static class Call.Details {
@@ -39001,7 +39021,9 @@
     ctor public CallAudioState(boolean, int, int);
     method public static java.lang.String audioRouteToString(int);
     method public int describeContents();
+    method public android.bluetooth.BluetoothDevice getActiveBluetoothDevice();
     method public int getRoute();
+    method public java.util.Collection<android.bluetooth.BluetoothDevice> getSupportedBluetoothDevices();
     method public int getSupportedRouteMask();
     method public boolean isMuted();
     method public void writeToParcel(android.os.Parcel, int);
@@ -39136,6 +39158,7 @@
     method public final void putExtras(android.os.Bundle);
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
+    method public void requestBluetoothAudio(java.lang.String);
     method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void sendRemoteRttRequest();
     method public final void sendRttInitiationFailure(int);
@@ -39280,8 +39303,11 @@
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onHandoverFailed(android.telecom.ConnectionRequest, int);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -39339,6 +39365,7 @@
     method public void onCanAddCallChanged(boolean);
     method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onSilenceRinger();
+    method public final void requestBluetoothAudio(java.lang.String);
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -39403,6 +39430,9 @@
     field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
     field public static final java.lang.String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
     field public static final java.lang.String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
+    field public static final java.lang.String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_FROM = "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
+    field public static final java.lang.String EXTRA_SUPPORTS_HANDOVER_TO = "android.telecom.extra.SUPPORTS_HANDOVER_TO";
     field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
     field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
     field public static final java.lang.String SCHEME_SIP = "sip";
@@ -39563,6 +39593,7 @@
   }
 
   public class TelecomManager {
+    method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
     method public void acceptRingingCall();
     method public void acceptRingingCall(int);
     method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
@@ -39728,6 +39759,7 @@
     field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
     field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
     field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
+    field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
     field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
     field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
@@ -40714,6 +40746,7 @@
   }
 
   public final class FileInfo implements android.os.Parcelable {
+    ctor public FileInfo(android.net.Uri, java.lang.String);
     method public int describeContents();
     method public java.lang.String getMimeType();
     method public android.net.Uri getUri();
@@ -40827,6 +40860,14 @@
     field public static final android.os.Parcelable.Creator<android.telephony.mbms.StreamingServiceInfo> CREATOR;
   }
 
+  public final class UriPathPair implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.net.Uri getContentUri();
+    method public android.net.Uri getFilePathUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.mbms.UriPathPair> CREATOR;
+  }
+
 }
 
 package android.telephony.mbms.vendor {
@@ -40858,6 +40899,23 @@
     method public void stopStreaming(int, java.lang.String) throws android.os.RemoteException;
   }
 
+  public class VendorUtils {
+    ctor public VendorUtils();
+    method public static android.content.ComponentName getAppReceiverFromPackageName(android.content.Context, java.lang.String);
+    field public static final java.lang.String ACTION_CLEANUP = "android.telephony.mbms.action.CLEANUP";
+    field public static final java.lang.String ACTION_DOWNLOAD_RESULT_INTERNAL = "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
+    field public static final java.lang.String ACTION_FILE_DESCRIPTOR_REQUEST = "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
+    field public static final java.lang.String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
+    field public static final java.lang.String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
+    field public static final java.lang.String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
+    field public static final java.lang.String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
+    field public static final java.lang.String EXTRA_PAUSED_URI_LIST = "android.telephony.mbms.extra.PAUSED_URI_LIST";
+    field public static final java.lang.String EXTRA_SERVICE_ID = "android.telephony.mbms.extra.SERVICE_ID";
+    field public static final java.lang.String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
+    field public static final java.lang.String EXTRA_TEMP_FILE_ROOT = "android.telephony.mbms.extra.TEMP_FILE_ROOT";
+    field public static final java.lang.String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
+  }
+
 }
 
 package android.test {
diff --git a/cmds/appwidget/appwidget b/cmds/appwidget/appwidget
index 6105009..26ab173 100755
--- a/cmds/appwidget/appwidget
+++ b/cmds/appwidget/appwidget
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "appwidget" on the device, which has a very rudimentary shell.
 base=/system
 export CLASSPATH=$base/framework/appwidget.jar
diff --git a/cmds/bmgr/bmgr b/cmds/bmgr/bmgr
index 6b4bbe2d..60b5833 100755
--- a/cmds/bmgr/bmgr
+++ b/cmds/bmgr/bmgr
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "bmgr" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/cmds/bu/bu b/cmds/bu/bu
index e8dbc31..e50b53d 100755
--- a/cmds/bu/bu
+++ b/cmds/bu/bu
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "bu" on the device
 #
 base=/system
diff --git a/cmds/content/content b/cmds/content/content
index a8e056d..f1bfe17 100755
--- a/cmds/content/content
+++ b/cmds/content/content
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "content" on the device, which has a very rudimentary shell.
 base=/system
 export CLASSPATH=$base/framework/content.jar
diff --git a/cmds/dpm/dpm b/cmds/dpm/dpm
index c2e5cbb..e0efdc1 100755
--- a/cmds/dpm/dpm
+++ b/cmds/dpm/dpm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "dpm" on the device
 #
 base=/system
diff --git a/cmds/ime/ime b/cmds/ime/ime
index 96c56d3..1a1fdd9 100755
--- a/cmds/ime/ime
+++ b/cmds/ime/ime
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "pm" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/cmds/input/input b/cmds/input/input
index 7f1a18e..54ab947 100755
--- a/cmds/input/input
+++ b/cmds/input/input
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "input" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/cmds/locksettings/locksettings b/cmds/locksettings/locksettings
index c963b23..0ef4fa9 100755
--- a/cmds/locksettings/locksettings
+++ b/cmds/locksettings/locksettings
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "locksettings" on the device
 #
 base=/system
diff --git a/cmds/media/media b/cmds/media/media
index 1194442..5c0eb2f 100755
--- a/cmds/media/media
+++ b/cmds/media/media
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "media_cmd" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/cmds/pm/pm b/cmds/pm/pm
index 8183838..53f85b2 100755
--- a/cmds/pm/pm
+++ b/cmds/pm/pm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "pm" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/cmds/requestsync/requestsync b/cmds/requestsync/requestsync
index 9315675..2d5d0e4 100755
--- a/cmds/requestsync/requestsync
+++ b/cmds/requestsync/requestsync
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "requestsync" on the device
 #
 base=/system
diff --git a/cmds/sm/sm b/cmds/sm/sm
index 8fba007..4bc859e0 100755
--- a/cmds/sm/sm
+++ b/cmds/sm/sm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "sm" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/cmds/svc/svc b/cmds/svc/svc
index 27111cd..07b50fe 100755
--- a/cmds/svc/svc
+++ b/cmds/svc/svc
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "am" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/cmds/telecom/telecom b/cmds/telecom/telecom
index 9efdcfd..a19036b 100755
--- a/cmds/telecom/telecom
+++ b/cmds/telecom/telecom
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "telecom" on the device
 #
 base=/system
diff --git a/cmds/uiautomator/cmds/uiautomator/uiautomator b/cmds/uiautomator/cmds/uiautomator/uiautomator
index 86a1dba..889c2b5 100755
--- a/cmds/uiautomator/cmds/uiautomator/uiautomator
+++ b/cmds/uiautomator/cmds/uiautomator/uiautomator
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 #
 # Copyright (C) 2012 The Android Open Source Project
 #
diff --git a/cmds/vr/vr b/cmds/vr/vr
index a279007..dbde02a 100755
--- a/cmds/vr/vr
+++ b/cmds/vr/vr
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "vr" on the device
 #
 base=/system
diff --git a/cmds/webview_zygote/Android.mk b/cmds/webview_zygote/Android.mk
index 66e762c..955e58e 100644
--- a/cmds/webview_zygote/Android.mk
+++ b/cmds/webview_zygote/Android.mk
@@ -21,6 +21,8 @@
 
 LOCAL_SRC_FILES := webview_zygote.cpp
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libandroid_runtime \
 	libbinder \
diff --git a/cmds/wm/wm b/cmds/wm/wm
index f7a5bc7..16d6bd6 100755
--- a/cmds/wm/wm
+++ b/cmds/wm/wm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
 # Script to start "wm" on the device, which has a very rudimentary
 # shell.
 #
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index 8c79809..384540a 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -3948,9 +3948,6 @@
 android.telephony.VoLteServiceState
 android.telephony.VoLteServiceState$1
 android.telephony.gsm.GsmCellLocation
-android.telephony.ims.ImsServiceProxy$INotifyStatusChanged
-android.telephony.ims.ImsServiceProxyCompat
-android.telephony.ims.feature.IMMTelFeature
 android.telephony.ims.stub.ImsConfigImplBase
 android.telephony.ims.stub.ImsEcbmImplBase
 android.telephony.ims.stub.ImsUtImplBase
@@ -5197,7 +5194,7 @@
 com.android.ims.internal.IImsService
 com.android.ims.internal.IImsService$Stub
 com.android.ims.internal.IImsServiceController
-com.android.ims.internal.IImsServiceFeatureListener
+com.android.ims.internal.IImsServiceFeatureCallback
 com.android.ims.internal.IImsUt
 com.android.ims.internal.IImsUt$Stub
 com.android.ims.internal.IImsUtListener
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0ff3215..0d89c6f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,8 +16,6 @@
 
 package android.app;
 
-import static android.os.Build.VERSION_CODES.O;
-
 import static java.lang.Character.MIN_VALUE;
 
 import android.annotation.CallSuper;
@@ -976,18 +974,6 @@
     @CallSuper
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
-
-        if (getApplicationInfo().targetSdkVersion > O && mActivityInfo.isFixedOrientation()) {
-            final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
-            final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
-            ta.recycle();
-
-            if (isTranslucentOrFloating) {
-                throw new IllegalStateException(
-                        "Only fullscreen opaque activities can request orientation");
-            }
-        }
-
         if (mLastNonConfigurationInstances != null) {
             mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
         }
@@ -4358,7 +4344,7 @@
             throw new IllegalArgumentException("requestCode should be >= 0");
         }
         if (mHasCurrentPermissionsRequest) {
-            Log.w(TAG, "Can reqeust only one set of permissions at a time");
+            Log.w(TAG, "Can request only one set of permissions at a time");
             // Dispatch the callback with empty arrays which means a cancellation.
             onRequestPermissionsResult(requestCode, new String[0], new int[0]);
             return;
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
index d15dd6d..01c045b 100644
--- a/core/java/android/app/DexLoadReporter.java
+++ b/core/java/android/app/DexLoadReporter.java
@@ -19,7 +19,6 @@
 import android.os.FileUtils;
 import android.os.RemoteException;
 import android.os.SystemProperties;
-import android.system.ErrnoException;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -27,8 +26,6 @@
 import dalvik.system.BaseDexClassLoader;
 import dalvik.system.VMRuntime;
 
-import libcore.io.Libcore;
-
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -156,23 +153,12 @@
             return;
         }
 
-        File realDexPath;
-        try {
-            // Secondary dex profiles are stored in the oat directory, next to the real dex file
-            // and have the same name with 'cur.prof' appended. We use the realpath because that
-            // is what installd is using when processing the dex file.
-            // NOTE: Keep in sync with installd.
-            realDexPath = new File(Libcore.os.realpath(dexPath));
-        } catch (ErrnoException ex) {
-            Slog.e(TAG, "Failed to get the real path of secondary dex " + dexPath
-                    + ":" + ex.getMessage());
-            // Do not continue with registration if we could not retrieve the real path.
-            return;
-        }
-
+        // Secondary dex profiles are stored in the oat directory, next to dex file
+        // and have the same name with 'cur.prof' appended.
         // NOTE: Keep this in sync with installd expectations.
-        File secondaryProfileDir = new File(realDexPath.getParent(), "oat");
-        File secondaryProfile = new File(secondaryProfileDir, realDexPath.getName() + ".cur.prof");
+        File dexPathFile = new File(dexPath);
+        File secondaryProfileDir = new File(dexPathFile.getParent(), "oat");
+        File secondaryProfile = new File(secondaryProfileDir, dexPathFile.getName() + ".cur.prof");
 
         // Create the profile if not already there.
         // Returns true if the file was created, false if the file already exists.
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 063ad24..97187d6 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -23,16 +23,17 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructStat;
+import android.system.StructTimespec;
 import android.util.Log;
 
-import com.google.android.collect.Maps;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ExponentiallyBucketedHistogram;
 import com.android.internal.util.XmlUtils;
 
 import dalvik.system.BlockGuard;
 
+import libcore.io.IoUtils;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.BufferedInputStream;
@@ -50,8 +51,6 @@
 import java.util.WeakHashMap;
 import java.util.concurrent.CountDownLatch;
 
-import libcore.io.IoUtils;
-
 final class SharedPreferencesImpl implements SharedPreferences {
     private static final String TAG = "SharedPreferencesImpl";
     private static final boolean DEBUG = false;
@@ -80,7 +79,7 @@
     private boolean mLoaded = false;
 
     @GuardedBy("mLock")
-    private long mStatTimestamp;
+    private StructTimespec mStatTimestamp;
 
     @GuardedBy("mLock")
     private long mStatSize;
@@ -138,7 +137,7 @@
             Log.w(TAG, "Attempt to read preferences file " + mFile + " without permission");
         }
 
-        Map map = null;
+        Map<String, Object> map = null;
         StructStat stat = null;
         try {
             stat = Os.stat(mFile.getPath());
@@ -147,7 +146,7 @@
                 try {
                     str = new BufferedInputStream(
                             new FileInputStream(mFile), 16*1024);
-                    map = XmlUtils.readMapXml(str);
+                    map = (Map<String, Object>) XmlUtils.readMapXml(str);
                 } catch (Exception e) {
                     Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e);
                 } finally {
@@ -162,7 +161,7 @@
             mLoaded = true;
             if (map != null) {
                 mMap = map;
-                mStatTimestamp = stat.st_mtime;
+                mStatTimestamp = stat.st_mtim;
                 mStatSize = stat.st_size;
             } else {
                 mMap = new HashMap<>();
@@ -209,16 +208,18 @@
         }
 
         synchronized (mLock) {
-            return mStatTimestamp != stat.st_mtime || mStatSize != stat.st_size;
+            return !stat.st_mtim.equals(mStatTimestamp) || mStatSize != stat.st_size;
         }
     }
 
+    @Override
     public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
         synchronized(mLock) {
             mListeners.put(listener, CONTENT);
         }
     }
 
+    @Override
     public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
         synchronized(mLock) {
             mListeners.remove(listener);
@@ -240,6 +241,7 @@
         }
     }
 
+    @Override
     public Map<String, ?> getAll() {
         synchronized (mLock) {
             awaitLoadedLocked();
@@ -248,6 +250,7 @@
         }
     }
 
+    @Override
     @Nullable
     public String getString(String key, @Nullable String defValue) {
         synchronized (mLock) {
@@ -257,6 +260,7 @@
         }
     }
 
+    @Override
     @Nullable
     public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
         synchronized (mLock) {
@@ -266,6 +270,7 @@
         }
     }
 
+    @Override
     public int getInt(String key, int defValue) {
         synchronized (mLock) {
             awaitLoadedLocked();
@@ -273,6 +278,7 @@
             return v != null ? v : defValue;
         }
     }
+    @Override
     public long getLong(String key, long defValue) {
         synchronized (mLock) {
             awaitLoadedLocked();
@@ -280,6 +286,7 @@
             return v != null ? v : defValue;
         }
     }
+    @Override
     public float getFloat(String key, float defValue) {
         synchronized (mLock) {
             awaitLoadedLocked();
@@ -287,6 +294,7 @@
             return v != null ? v : defValue;
         }
     }
+    @Override
     public boolean getBoolean(String key, boolean defValue) {
         synchronized (mLock) {
             awaitLoadedLocked();
@@ -295,6 +303,7 @@
         }
     }
 
+    @Override
     public boolean contains(String key) {
         synchronized (mLock) {
             awaitLoadedLocked();
@@ -302,6 +311,7 @@
         }
     }
 
+    @Override
     public Editor edit() {
         // TODO: remove the need to call awaitLoadedLocked() when
         // requesting an editor.  will require some work on the
@@ -346,71 +356,81 @@
     }
 
     public final class EditorImpl implements Editor {
-        private final Object mLock = new Object();
+        private final Object mEditorLock = new Object();
 
-        @GuardedBy("mLock")
-        private final Map<String, Object> mModified = Maps.newHashMap();
+        @GuardedBy("mEditorLock")
+        private final Map<String, Object> mModified = new HashMap<>();
 
-        @GuardedBy("mLock")
+        @GuardedBy("mEditorLock")
         private boolean mClear = false;
 
+        @Override
         public Editor putString(String key, @Nullable String value) {
-            synchronized (mLock) {
+            synchronized (mEditorLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
+        @Override
         public Editor putStringSet(String key, @Nullable Set<String> values) {
-            synchronized (mLock) {
+            synchronized (mEditorLock) {
                 mModified.put(key,
                         (values == null) ? null : new HashSet<String>(values));
                 return this;
             }
         }
+        @Override
         public Editor putInt(String key, int value) {
-            synchronized (mLock) {
+            synchronized (mEditorLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
+        @Override
         public Editor putLong(String key, long value) {
-            synchronized (mLock) {
+            synchronized (mEditorLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
+        @Override
         public Editor putFloat(String key, float value) {
-            synchronized (mLock) {
+            synchronized (mEditorLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
+        @Override
         public Editor putBoolean(String key, boolean value) {
-            synchronized (mLock) {
+            synchronized (mEditorLock) {
                 mModified.put(key, value);
                 return this;
             }
         }
 
+        @Override
         public Editor remove(String key) {
-            synchronized (mLock) {
+            synchronized (mEditorLock) {
                 mModified.put(key, this);
                 return this;
             }
         }
 
+        @Override
         public Editor clear() {
-            synchronized (mLock) {
+            synchronized (mEditorLock) {
                 mClear = true;
                 return this;
             }
         }
 
+        @Override
         public void apply() {
             final long startTime = System.currentTimeMillis();
 
             final MemoryCommitResult mcr = commitToMemory();
             final Runnable awaitCommit = new Runnable() {
+                    @Override
                     public void run() {
                         try {
                             mcr.writtenToDiskLatch.await();
@@ -428,6 +448,7 @@
             QueuedWork.addFinisher(awaitCommit);
 
             Runnable postWriteRunnable = new Runnable() {
+                    @Override
                     public void run() {
                         awaitCommit.run();
                         QueuedWork.removeFinisher(awaitCommit);
@@ -470,13 +491,13 @@
                     listeners = new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
                 }
 
-                synchronized (mLock) {
+                synchronized (mEditorLock) {
                     boolean changesMade = false;
 
                     if (mClear) {
-                        if (!mMap.isEmpty()) {
+                        if (!mapToWriteToDisk.isEmpty()) {
                             changesMade = true;
-                            mMap.clear();
+                            mapToWriteToDisk.clear();
                         }
                         mClear = false;
                     }
@@ -488,18 +509,18 @@
                         // setting a value to "null" for a given key is specified to be
                         // equivalent to calling remove on that key.
                         if (v == this || v == null) {
-                            if (!mMap.containsKey(k)) {
+                            if (!mapToWriteToDisk.containsKey(k)) {
                                 continue;
                             }
-                            mMap.remove(k);
+                            mapToWriteToDisk.remove(k);
                         } else {
-                            if (mMap.containsKey(k)) {
-                                Object existingValue = mMap.get(k);
+                            if (mapToWriteToDisk.containsKey(k)) {
+                                Object existingValue = mapToWriteToDisk.get(k);
                                 if (existingValue != null && existingValue.equals(v)) {
                                     continue;
                                 }
                             }
-                            mMap.put(k, v);
+                            mapToWriteToDisk.put(k, v);
                         }
 
                         changesMade = true;
@@ -521,6 +542,7 @@
                     mapToWriteToDisk);
         }
 
+        @Override
         public boolean commit() {
             long startTime = 0;
 
@@ -563,11 +585,7 @@
                 }
             } else {
                 // Run this function on the main thread.
-                ActivityThread.sMainThreadHandler.post(new Runnable() {
-                        public void run() {
-                            notifyListeners(mcr);
-                        }
-                    });
+                ActivityThread.sMainThreadHandler.post(() -> notifyListeners(mcr));
             }
         }
     }
@@ -593,6 +611,7 @@
         final boolean isFromSyncCommit = (postWriteRunnable == null);
 
         final Runnable writeToDiskRunnable = new Runnable() {
+                @Override
                 public void run() {
                     synchronized (mWritingToDiskLock) {
                         writeToFile(mcr, isFromSyncCommit);
@@ -645,7 +664,7 @@
         return str;
     }
 
-    // Note: must hold mWritingToDiskLock
+    @GuardedBy("mWritingToDiskLock")
     private void writeToFile(MemoryCommitResult mcr, boolean isFromSyncCommit) {
         long startTime = 0;
         long existsTime = 0;
@@ -744,7 +763,7 @@
             try {
                 final StructStat stat = Os.stat(mFile.getPath());
                 synchronized (mLock) {
-                    mStatTimestamp = stat.st_mtime;
+                    mStatTimestamp = stat.st_mtim;
                     mStatSize = stat.st_size;
                 }
             } catch (ErrnoException e) {
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 0f006b6..8686944 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -152,6 +152,9 @@
             public void onClick(View view) {
                 if (mTimePicker.validateInput()) {
                     TimePickerDialog.this.onClick(TimePickerDialog.this, BUTTON_POSITIVE);
+                    // Clearing focus forces the dialog to commit any pending
+                    // changes, e.g. typed text in a NumberPicker.
+                    mTimePicker.clearFocus();
                     dismiss();
                 }
             }
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index e3d763a..6692e13 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -350,13 +350,22 @@
      * application can be registered at time. When no longer used, application
      * should be unregistered using
      * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
+     * The registration status should be tracked by the application by handling callback from
+     * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
+     * to the return value of this method.
      *
      * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record.
+     * The HID Device SDP record is required.
      * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings.
+     * The Incoming QoS Settings is not required. Use null or default
+     * BluetoothHidDeviceAppQosSettings.Builder for default values.
      * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings.
+     * The Outgoing QoS Settings is not required. Use null or default
+     * BluetoothHidDeviceAppQosSettings.Builder for default values.
      * @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be
      * sent.
-     * @return
+     * The BluetoothHidDeviceCallback object is required.
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
             BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
@@ -394,12 +403,15 @@
      * {@link #registerApp
      * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
      * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)}
+     * The registration status should be tracked by the application by handling callback from
+     * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
+     * to the return value of this method.
      *
      * @param config {@link BluetoothHidDeviceAppConfiguration} object as obtained from {@link
      * BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
      * BluetoothHidDeviceAppConfiguration,
      * boolean)}
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
         Log.v(TAG, "unregisterApp()");
@@ -426,7 +438,7 @@
      * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
      * descriptor.
      * @param data Report data, not including Report Id.
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
         boolean result = false;
@@ -452,7 +464,7 @@
      * @param type Report Type, as in request.
      * @param id Report Id, as in request.
      * @param data Report data, not including Report Id.
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
         Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
@@ -478,7 +490,7 @@
      * from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
      *
      * @param error Error to be sent for SET_REPORT via HANDSHAKE.
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean reportError(BluetoothDevice device, byte error) {
         Log.v(TAG, "reportError(): device=" + device + " error=" + error);
@@ -524,10 +536,13 @@
     }
 
     /**
-     * Initiates connection to host which currently has Virtual Cable
-     * established with device.
+     * Initiates connection to host which is currently paired with this device.
+     * If the application is not registered, #connect(BluetoothDevice) will fail.
+     * The connection state should be tracked by the application by handling callback from
+     * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
+     * to the return value of this method.
      *
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean connect(BluetoothDevice device) {
         Log.v(TAG, "connect(): device=" + device);
@@ -550,8 +565,11 @@
 
     /**
      * Disconnects from currently connected host.
+     * The connection state should be tracked by the application by handling callback from
+     * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
+     * to the return value of this method.
      *
-     * @return
+     * @return true if the command is successfully sent; otherwise false.
      */
     public boolean disconnect(BluetoothDevice device) {
         Log.v(TAG, "disconnect(): device=" + device);
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index ccc3ef4..881ae98 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -45,6 +45,21 @@
 
     public static final int MAX = (int) 0xffffffff;
 
+    /**
+     * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel.
+     * The QoS Settings is optional.
+     * Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
+     * {@see <a href="https://www.bluetooth.com/specifications/profiles-overview">
+     *     https://www.bluetooth.com/specifications/profiles-overview
+     *     </a>
+     *     Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D }
+     * @param serviceType L2CAP service type
+     * @param tokenRate L2CAP token rate
+     * @param tokenBucketSize L2CAP token bucket size
+     * @param peakBandwidth L2CAP peak bandwidth
+     * @param latency L2CAP latency
+     * @param delayVariation L2CAP delay variation
+     */
     public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize,
             int peakBandwidth, int latency, int delayVariation) {
         this.serviceType = serviceType;
@@ -59,7 +74,12 @@
     public boolean equals(Object o) {
         if (o instanceof BluetoothHidDeviceAppQosSettings) {
             BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o;
-            return false;
+            return this.serviceType == qos.serviceType
+                    && this.tokenRate == qos.tokenRate
+                    && this.tokenBucketSize == qos.tokenBucketSize
+                    && this.peakBandwidth == qos.peakBandwidth
+                    && this.latency == qos.latency
+                    && this.delayVariation == qos.delayVariation;
         }
         return false;
     }
@@ -106,4 +126,85 @@
                 serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
         };
     }
+
+    /**
+     * A helper to build the BluetoothHidDeviceAppQosSettings object.
+     */
+    public static class Builder {
+        // Optional parameters - initialized to default values
+        private int mServiceType = SERVICE_BEST_EFFORT;
+        private int mTokenRate = 0;
+        private int mTokenBucketSize = 0;
+        private int mPeakBandwidth = 0;
+        private int mLatency = MAX;
+        private int mDelayVariation = MAX;
+
+        /**
+         * Set the service type.
+         * @param val service type. Should be one of {SERVICE_NO_TRAFFIC, SERVICE_BEST_EFFORT,
+         * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified service type.
+         */
+        public Builder serviceType(int val) {
+            mServiceType = val;
+            return this;
+        }
+        /**
+         * Set the token rate.
+         * @param val token rate
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified token rate.
+         */
+        public Builder tokenRate(int val) {
+            mTokenRate = val;
+            return this;
+        }
+
+        /**
+         * Set the bucket size.
+         * @param val bucket size
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size.
+         */
+        public Builder tokenBucketSize(int val) {
+            mTokenBucketSize = val;
+            return this;
+        }
+
+        /**
+         * Set the peak bandwidth.
+         * @param val peak bandwidth
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth.
+         */
+        public Builder peakBandwidth(int val) {
+            mPeakBandwidth = val;
+            return this;
+        }
+        /**
+         * Set the latency.
+         * @param val latency
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified latency.
+         */
+        public Builder latency(int val) {
+            mLatency = val;
+            return this;
+        }
+
+        /**
+         * Set the delay variation.
+         * @param val delay variation
+         * @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation.
+         */
+        public Builder delayVariation(int val) {
+            mDelayVariation = val;
+            return this;
+        }
+
+        /**
+         * Build the BluetoothHidDeviceAppQosSettings object.
+         * @return BluetoothHidDeviceAppQosSettings object with current settings.
+         */
+        public BluetoothHidDeviceAppQosSettings build() {
+            return new BluetoothHidDeviceAppQosSettings(mServiceType, mTokenRate, mTokenBucketSize,
+                    mPeakBandwidth, mLatency, mDelayVariation);
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index f01c493..4669637 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Arrays;
+
 /**
  * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth
  * HID Device application.
@@ -39,6 +41,18 @@
     public final byte subclass;
     public final byte[] descriptors;
 
+    /**
+     * Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
+     * @param name Name of this Bluetooth HID device. Maximum length is 50 bytes.
+     * @param description Description for this Bluetooth HID device. Maximum length is 50 bytes.
+     * @param provider Provider of this Bluetooth HID device. Maximum length is 50 bytes.
+     * @param subclass Subclass of this Bluetooth HID device.
+     * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+     *     www.usb.org/developers/hidpage/HID1_11.pdf Section 4.2</a>
+     * @param descriptors Descriptors of this Bluetooth HID device.
+     * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+     *     www.usb.org/developers/hidpage/HID1_11.pdf Chapter 6</a> Maximum length is 2048 bytes.
+     */
     public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
             byte subclass, byte[] descriptors) {
         this.name = name;
@@ -52,7 +66,11 @@
     public boolean equals(Object o) {
         if (o instanceof BluetoothHidDeviceAppSdpSettings) {
             BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o;
-            return false;
+            return this.name.equals(sdp.name)
+                    && this.description.equals(sdp.description)
+                    && this.provider.equals(sdp.provider)
+                    && this.subclass == sdp.subclass
+                    && Arrays.equals(this.descriptors, sdp.descriptors);
         }
         return false;
     }
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 4035ee1..0569913 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -375,7 +375,7 @@
             IBluetooth bluetoothProxy =
                     BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
             if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
-            mPfd = bluetoothProxy.connectSocket(mDevice, mType,
+            mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
                     mUuid, mPort, getSecurityFlags());
             synchronized (this) {
                 if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
@@ -417,7 +417,7 @@
             return -1;
         }
         try {
-            mPfd = bluetoothProxy.createSocketChannel(mType, mServiceName,
+            mPfd = bluetoothProxy.getSocketManager().createSocketChannel(mType, mServiceName,
                     mUuid, mPort, getSecurityFlags());
         } catch (RemoteException e) {
             Log.e(TAG, Log.getStackTraceString(new Throwable()));
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 18f9e53..8659140 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -20,7 +20,6 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Configuration.NativeConfig;
-import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Printer;
@@ -439,6 +438,7 @@
      * @hide
      */
     public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x400000;
+
     /**
      * @hide Bit in {@link #flags}: If set, this component will only be seen
      * by the system user.  Only works with broadcast receivers.  Set from the
@@ -976,20 +976,12 @@
      * Returns true if the activity's orientation is fixed.
      * @hide
      */
-    public boolean isFixedOrientation() {
+    boolean isFixedOrientation() {
         return isFixedOrientationLandscape() || isFixedOrientationPortrait()
                 || screenOrientation == SCREEN_ORIENTATION_LOCKED;
     }
 
     /**
-     * Returns true if the specified orientation is considered fixed.
-     * @hide
-     */
-    static public boolean isFixedOrientation(int orientation) {
-        return isFixedOrientationLandscape(orientation) || isFixedOrientationPortrait(orientation);
-    }
-
-    /**
      * Returns true if the activity's orientation is fixed to landscape.
      * @hide
      */
@@ -1168,25 +1160,6 @@
         dest.writeFloat(maxAspectRatio);
     }
 
-    /**
-     * Determines whether the {@link Activity} is considered translucent or floating.
-     * @hide
-     */
-    public static boolean isTranslucentOrFloating(TypedArray attributes) {
-        final boolean isTranslucent =
-                attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent,
-                        false);
-        final boolean isSwipeToDismiss = !attributes.hasValue(
-                com.android.internal.R.styleable.Window_windowIsTranslucent)
-                && attributes.getBoolean(
-                        com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
-        final boolean isFloating =
-                attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating,
-                        false);
-
-        return isFloating || isTranslucent || isSwipeToDismiss;
-    }
-
     public static final Parcelable.Creator<ActivityInfo> CREATOR
             = new Parcelable.Creator<ActivityInfo>() {
         public ActivityInfo createFromParcel(Parcel source) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0ccebc1c..6bf1425 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -619,6 +619,35 @@
      */
     public static final int NETID_UNSET = 0;
 
+    /**
+     * Private DNS Mode values.
+     *
+     * The "private_dns_mode" global setting stores a String value which is
+     * expected to be one of the following.
+     */
+
+    /**
+     * @hide
+     */
+    public static final String PRIVATE_DNS_MODE_OFF = "off";
+    /**
+     * @hide
+     */
+    public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
+    /**
+     * @hide
+     */
+    public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+    /**
+     * The default Private DNS mode.
+     *
+     * This may change from release to release or may become dependent upon
+     * the capabilities of the underlying platform.
+     *
+     * @hide
+     */
+    public static final String PRIVATE_DNS_DEFAULT_MODE = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+
     private final IConnectivityManager mService;
     /**
      * A kludge to facilitate static access where a Context pointer isn't available, like in the
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 46bb346..394ac42 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+
 import com.android.internal.util.BitUtils;
 
 /**
@@ -80,7 +81,7 @@
         StringBuilder buffer = new StringBuilder("ConnectivityMetricsEvent(");
         buffer.append(String.format("%tT.%tL", timestamp, timestamp));
         if (netId != 0) {
-            buffer.append(", ").append(netId);
+            buffer.append(", ").append("netId=").append(netId);
         }
         if (ifname != null) {
             buffer.append(", ").append(ifname);
diff --git a/core/java/android/net/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl
index 6f07b31..aeaf09d 100644
--- a/core/java/android/net/IIpConnectivityMetrics.aidl
+++ b/core/java/android/net/IIpConnectivityMetrics.aidl
@@ -30,11 +30,11 @@
     int logEvent(in ConnectivityMetricsEvent event);
 
     /**
-     * At most one callback can be registered (by DevicePolicyManager).
+     * Callback can be registered by DevicePolicyManager or NetworkWatchlistService only.
      * @return status {@code true} if registering/unregistering of the callback was successful,
      *         {@code false} otherwise (might happen if IIpConnectivityMetrics is not available,
      *         if it happens make sure you call it when the service is up in the caller)
      */
-    boolean registerNetdEventCallback(in INetdEventCallback callback);
-    boolean unregisterNetdEventCallback();
+    boolean addNetdEventCallback(in int callerType, in INetdEventCallback callback);
+    boolean removeNetdEventCallback(in int callerType);
 }
diff --git a/core/java/android/net/INetdEventCallback.aidl b/core/java/android/net/INetdEventCallback.aidl
index 49436be..1fd9423 100644
--- a/core/java/android/net/INetdEventCallback.aidl
+++ b/core/java/android/net/INetdEventCallback.aidl
@@ -19,6 +19,10 @@
 /** {@hide} */
 oneway interface INetdEventCallback {
 
+    // Possible addNetdEventCallback callers.
+    const int CALLBACK_CALLER_DEVICE_POLICY = 0;
+    const int CALLBACK_CALLER_NETWORK_WATCHLIST = 1;
+
     /**
      * Reports a single DNS lookup function call.
      * This method must not block or perform long-running operations.
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 16b1452..d6e62cf 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -15,6 +15,7 @@
  */
 package android.net;
 
+import android.annotation.NonNull;
 import android.annotation.StringDef;
 import android.os.Build;
 import android.os.Parcel;
@@ -27,8 +28,10 @@
 import java.util.Arrays;
 
 /**
- * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
- * RFC 4301.
+ * This class represents a single algorithm that can be used by an {@link IpSecTransform}.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
+ * Internet Protocol</a>
  */
 public final class IpSecAlgorithm implements Parcelable {
     /**
@@ -39,16 +42,16 @@
     public static final String CRYPT_AES_CBC = "cbc(aes)";
 
     /**
-     * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new
-     * applications and is provided for legacy compatibility with 3gpp infrastructure.
+     * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
+     * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
      *
      * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
      */
     public static final String AUTH_HMAC_MD5 = "hmac(md5)";
 
     /**
-     * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in
-     * new applications and is provided for legacy compatibility with 3gpp infrastructure.
+     * SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in
+     * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
      *
      * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
      */
@@ -69,7 +72,7 @@
     public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
 
     /**
-     * SHA512 HMAC Authentication/Integrity Algorithm
+     * SHA512 HMAC Authentication/Integrity Algorithm.
      *
      * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
      */
@@ -78,7 +81,11 @@
     /**
      * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
      *
-     * <p>Valid lengths for this key are {128, 192, 256}.
+     * <p>Valid lengths for keying material are {160, 224, 288}.
+     *
+     * <p>As per <a href="https://tools.ietf.org/html/rfc4106#section-8.1">RFC4106 (Section
+     * 8.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit
+     * salt. RFC compliance requires that the salt must be unique per invocation with the same key.
      *
      * <p>Valid ICV (truncation) lengths are {64, 96, 128}.
      */
@@ -101,48 +108,47 @@
     private final int mTruncLenBits;
 
     /**
-     * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
-     * algorithm
+     * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
+     * defined as constants in this class.
      *
-     * @param algorithm type for IpSec.
-     * @param key non-null Key padded to a multiple of 8 bits.
+     * @param algorithm name of the algorithm.
+     * @param key key padded to a multiple of 8 bits.
      */
-    public IpSecAlgorithm(String algorithm, byte[] key) {
+    public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) {
         this(algorithm, key, key.length * 8);
     }
 
     /**
-     * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
-     * algorithm
+     * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
+     * defined as constants in this class.
      *
-     * @param algoName precise name of the algorithm to be used.
-     * @param key non-null Key padded to a multiple of 8 bits.
-     * @param truncLenBits the number of bits of output hash to use; only meaningful for
-     *     Authentication or Authenticated Encryption (equivalent to ICV length).
+     * <p>This constructor only supports algorithms that use a truncation length. i.e.
+     * Authentication and Authenticated Encryption algorithms.
+     *
+     * @param algorithm name of the algorithm.
+     * @param key key padded to a multiple of 8 bits.
+     * @param truncLenBits number of bits of output hash to use.
      */
-    public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) {
-        if (!isTruncationLengthValid(algoName, truncLenBits)) {
+    public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) {
+        if (!isTruncationLengthValid(algorithm, truncLenBits)) {
             throw new IllegalArgumentException("Unknown algorithm or invalid length");
         }
-        mName = algoName;
+        mName = algorithm;
         mKey = key.clone();
         mTruncLenBits = Math.min(truncLenBits, key.length * 8);
     }
 
-    /** Retrieve the algorithm name */
+    /** Get the algorithm name */
     public String getName() {
         return mName;
     }
 
-    /** Retrieve the key for this algorithm */
+    /** Get the key for this algorithm */
     public byte[] getKey() {
         return mKey.clone();
     }
 
-    /**
-     * Retrieve the truncation length, in bits, for the key in this algo. By default this will be
-     * the length in bits of the key.
-     */
+    /** Get the truncation length of this algorithm, in bits */
     public int getTruncationLengthBits() {
         return mTruncLenBits;
     }
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index 61b13a9..e6cd3fc 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -20,7 +20,12 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
-/** @hide */
+/**
+ * This class encapsulates all the configuration parameters needed to create IPsec transforms and
+ * policies.
+ *
+ * @hide
+ */
 public final class IpSecConfig implements Parcelable {
     private static final String TAG = "IpSecConfig";
 
@@ -38,6 +43,9 @@
     // for outbound packets. It may also be used to select packets.
     private Network mNetwork;
 
+    /**
+     * This class captures the parameters that specifically apply to inbound or outbound traffic.
+     */
     public static class Flow {
         // Minimum requirements for identifying a transform
         // SPI identifying the IPsec flow in packet processing
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index d7b3256..a9e60ec 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -19,6 +19,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
@@ -37,22 +38,28 @@
 import java.net.Socket;
 
 /**
- * This class contains methods for managing IPsec sessions, which will perform kernel-space
- * encryption and decryption of socket or Network traffic.
+ * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply
+ * confidentiality (encryption) and integrity (authentication) to IP traffic.
  *
- * <p>An IpSecManager may be obtained by calling {@link
- * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
- * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
+ * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create
+ * transport mode security associations and apply them to individual sockets. Applications looking
+ * to create a VPN should use {@link VpnService}.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
+ * Internet Protocol</a>
  */
 @SystemService(Context.IPSEC_SERVICE)
 public final class IpSecManager {
     private static final String TAG = "IpSecManager";
 
     /**
-     * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
+     * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
      *
      * <p>No IPsec packet may contain an SPI of 0.
+     *
+     * @hide
      */
+    @TestApi
     public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
 
     /** @hide */
@@ -66,10 +73,12 @@
     public static final int INVALID_RESOURCE_ID = 0;
 
     /**
-     * Indicates that the combination of remote InetAddress and SPI was non-unique for a given
-     * request. If encountered, selection of a new SPI is required before a transform may be
-     * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
-     * or reserved using reserveSecurityParameterIndex.
+     * Thrown to indicate that a requested SPI is in use.
+     *
+     * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on
+     * one device. If this error is encountered, a new SPI is required before a transform may be
+     * created. This error can be avoided by calling {@link
+     * IpSecManager#reserveSecurityParameterIndex}.
      */
     public static final class SpiUnavailableException extends AndroidException {
         private final int mSpi;
@@ -78,24 +87,26 @@
          * Construct an exception indicating that a transform with the given SPI is already in use
          * or otherwise unavailable.
          *
-         * @param msg Description indicating the colliding SPI
+         * @param msg description indicating the colliding SPI
          * @param spi the SPI that could not be used due to a collision
          */
         SpiUnavailableException(String msg, int spi) {
-            super(msg + "(spi: " + spi + ")");
+            super(msg + " (spi: " + spi + ")");
             mSpi = spi;
         }
 
-        /** Retrieve the SPI that caused a collision */
+        /** Get the SPI that caused a collision. */
         public int getSpi() {
             return mSpi;
         }
     }
 
     /**
-     * Indicates that the requested system resource for IPsec, such as a socket or other system
-     * resource is unavailable. If this exception is thrown, try releasing allocated objects of the
-     * type requested.
+     * Thrown to indicate that an IPsec resource is unavailable.
+     *
+     * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link
+     * IpSecTransform}, or other system resources. If this exception is thrown, users should release
+     * allocated objects of the type requested.
      */
     public static final class ResourceUnavailableException extends AndroidException {
 
@@ -106,6 +117,13 @@
 
     private final IIpSecService mService;
 
+    /**
+     * This class represents a reserved SPI.
+     *
+     * <p>Objects of this type are used to track reserved security parameter indices. They can be
+     * obtained by calling {@link IpSecManager#reserveSecurityParameterIndex} and must be released
+     * by calling {@link #close()} when they are no longer needed.
+     */
     public static final class SecurityParameterIndex implements AutoCloseable {
         private final IIpSecService mService;
         private final InetAddress mRemoteAddress;
@@ -113,7 +131,7 @@
         private int mSpi = INVALID_SECURITY_PARAMETER_INDEX;
         private int mResourceId;
 
-        /** Return the underlying SPI held by this object */
+        /** Get the underlying SPI held by this object. */
         public int getSpi() {
             return mSpi;
         }
@@ -135,8 +153,9 @@
             mCloseGuard.close();
         }
 
+        /** Check that the SPI was closed properly. */
         @Override
-        protected void finalize() {
+        protected void finalize() throws Throwable {
             if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
             }
@@ -197,13 +216,13 @@
     }
 
     /**
-     * Reserve an SPI for traffic bound towards the specified remote address.
+     * Reserve a random SPI for traffic bound to or from the specified remote address.
      *
      * <p>If successful, this SPI is guaranteed available until released by a call to {@link
      * SecurityParameterIndex#close()}.
      *
      * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
-     * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
+     * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress
      * @return the reserved SecurityParameterIndex
      * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
      *     for this user
@@ -223,17 +242,18 @@
     }
 
     /**
-     * Reserve an SPI for traffic bound towards the specified remote address.
+     * Reserve the requested SPI for traffic bound to or from the specified remote address.
      *
      * <p>If successful, this SPI is guaranteed available until released by a call to {@link
      * SecurityParameterIndex#close()}.
      *
      * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT}
-     * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress.
-     * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
+     * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress
+     * @param requestedSpi the requested SPI, or '0' to allocate a random SPI
      * @return the reserved SecurityParameterIndex
      * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
      *     for this user
+     * @throws SpiUnavailableException indicating that the requested SPI could not be reserved
      */
     public SecurityParameterIndex reserveSecurityParameterIndex(
             int direction, InetAddress remoteAddress, int requestedSpi)
@@ -245,16 +265,28 @@
     }
 
     /**
-     * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
-     * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
-     * transform. For security reasons, attempts to send traffic to any IP address other than the
-     * address associated with that transform will throw an IOException. In addition, if the
-     * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
-     * send() or receive() until the transform is removed from the socket by calling {@link
-     * #removeTransportModeTransform(Socket, IpSecTransform)};
+     * Apply an IPsec transform to a stream socket.
+     *
+     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
+     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
+     * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
+     * unprotected traffic can resume on that socket.
+     *
+     * <p>For security reasons, the destination address of any traffic on the socket must match the
+     * remote {@code  InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
+     * other IP address will result in an IOException. In addition, reads and writes on the socket
+     * will throw IOException if the user deactivates the transform (by calling {@link
+     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
+     *
+     * <h4>Rekey Procedure</h4> <p>When applying a new tranform to a socket, the previous transform
+     * will be removed. However, inbound traffic on the old transform will continue to be decrypted
+     * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap
+     * allows rekey procedures where both transforms are valid until both endpoints are using the
+     * new transform and all in-flight packets have been received.
      *
      * @param socket a stream socket
-     * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+     * @param transform a transport mode {@code IpSecTransform}
+     * @throws IOException indicating that the transform could not be applied
      * @hide
      */
     public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
@@ -265,16 +297,28 @@
     }
 
     /**
-     * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec
-     * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
-     * transform. For security reasons, attempts to send traffic to any IP address other than the
-     * address associated with that transform will throw an IOException. In addition, if the
-     * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
-     * send() or receive() until the transform is removed from the socket by calling {@link
-     * #removeTransportModeTransform(DatagramSocket, IpSecTransform)};
+     * Apply an IPsec transform to a datagram socket.
+     *
+     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
+     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
+     * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
+     * unprotected traffic can resume on that socket.
+     *
+     * <p>For security reasons, the destination address of any traffic on the socket must match the
+     * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
+     * other IP address will result in an IOException. In addition, reads and writes on the socket
+     * will throw IOException if the user deactivates the transform (by calling {@link
+     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
+     *
+     * <h4>Rekey Procedure</h4> <p>When applying a new tranform to a socket, the previous transform
+     * will be removed. However, inbound traffic on the old transform will continue to be decrypted
+     * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap
+     * allows rekey procedures where both transforms are valid until both endpoints are using the
+     * new transform and all in-flight packets have been received.
      *
      * @param socket a datagram socket
-     * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+     * @param transform a transport mode {@code IpSecTransform}
+     * @throws IOException indicating that the transform could not be applied
      * @hide
      */
     public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
@@ -285,16 +329,28 @@
     }
 
     /**
-     * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
-     * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
-     * transform. For security reasons, attempts to send traffic to any IP address other than the
-     * address associated with that transform will throw an IOException. In addition, if the
-     * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
-     * send() or receive() until the transform is removed from the socket by calling {@link
-     * #removeTransportModeTransform(FileDescriptor, IpSecTransform)};
+     * Apply an IPsec transform to a socket.
+     *
+     * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the
+     * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When
+     * the transform is removed from the socket by calling {@link #removeTransportModeTransform},
+     * unprotected traffic can resume on that socket.
+     *
+     * <p>For security reasons, the destination address of any traffic on the socket must match the
+     * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any
+     * other IP address will result in an IOException. In addition, reads and writes on the socket
+     * will throw IOException if the user deactivates the transform (by calling {@link
+     * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}.
+     *
+     * <h4>Rekey Procedure</h4> <p>When applying a new tranform to a socket, the previous transform
+     * will be removed. However, inbound traffic on the old transform will continue to be decrypted
+     * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap
+     * allows rekey procedures where both transforms are valid until both endpoints are using the
+     * new transform and all in-flight packets have been received.
      *
      * @param socket a socket file descriptor
-     * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+     * @param transform a transport mode {@code IpSecTransform}
+     * @throws IOException indicating that the transform could not be applied
      */
     public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
             throws IOException {
@@ -323,6 +379,7 @@
      * Applications should probably not use this API directly. Instead, they should use {@link
      * VpnService} to provide VPN capability in a more generic fashion.
      *
+     * TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
      * @param net a {@link Network} that will be tunneled via IP Sec.
      * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
      * @hide
@@ -330,14 +387,19 @@
     public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
 
     /**
-     * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
-     * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
-     * communication in the clear in the event socket reuse is desired. This operation will succeed
-     * regardless of the underlying state of a transform. If a transform is removed, communication
-     * on all sockets to which that transform was applied will fail until this method is called.
+     * Remove an IPsec transform from a stream socket.
      *
-     * @param socket a socket that previously had a transform applied to it.
+     * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
+     * regardless of the state of the transform. Removing a transform from a socket allows the
+     * socket to be reused for communication in the clear.
+     *
+     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
+     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
+     * is called.
+     *
+     * @param socket a socket that previously had a transform applied to it
      * @param transform the IPsec Transform that was previously applied to the given socket
+     * @throws IOException indicating that the transform could not be removed from the socket
      * @hide
      */
     public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
@@ -348,14 +410,19 @@
     }
 
     /**
-     * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not
-     * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
-     * communication in the clear in the event socket reuse is desired. This operation will succeed
-     * regardless of the underlying state of a transform. If a transform is removed, communication
-     * on all sockets to which that transform was applied will fail until this method is called.
+     * Remove an IPsec transform from a datagram socket.
      *
-     * @param socket a socket that previously had a transform applied to it.
+     * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
+     * regardless of the state of the transform. Removing a transform from a socket allows the
+     * socket to be reused for communication in the clear.
+     *
+     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
+     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
+     * is called.
+     *
+     * @param socket a socket that previously had a transform applied to it
      * @param transform the IPsec Transform that was previously applied to the given socket
+     * @throws IOException indicating that the transform could not be removed from the socket
      * @hide
      */
     public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
@@ -366,14 +433,19 @@
     }
 
     /**
-     * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
-     * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
-     * communication in the clear in the event socket reuse is desired. This operation will succeed
-     * regardless of the underlying state of a transform. If a transform is removed, communication
-     * on all sockets to which that transform was applied will fail until this method is called.
+     * Remove an IPsec transform from a socket.
      *
-     * @param socket a socket file descriptor that previously had a transform applied to it.
+     * <p>Once removed, traffic on the socket will not be encrypted. This operation will succeed
+     * regardless of the state of the transform. Removing a transform from a socket allows the
+     * socket to be reused for communication in the clear.
+     *
+     * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling
+     * {@link IpSecTransform#close()}, then communication on the socket will fail until this method
+     * is called.
+     *
+     * @param socket a socket that previously had a transform applied to it
      * @param transform the IPsec Transform that was previously applied to the given socket
+     * @throws IOException indicating that the transform could not be removed from the socket
      */
     public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
             throws IOException {
@@ -382,7 +454,7 @@
         }
     }
 
-    /* Call down to activate a transform */
+    /* Call down to remove a transform */
     private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {
         try {
             mService.removeTransportModeTransform(pfd, transform.getResourceId());
@@ -397,6 +469,7 @@
      * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
      * lost, all traffic will drop.
      *
+     * TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked.
      * @param net a network that currently has transform applied to it.
      * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
      *     network
@@ -405,11 +478,18 @@
     public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
 
     /**
-     * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for
-     * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic.
+     * This class provides access to a UDP encapsulation Socket.
      *
-     * <p>The socket provided by this class cannot be re-bound or closed via the inner
-     * FileDescriptor. Instead, disposing of this socket requires a call to close().
+     * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2
+     * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
+     * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
+     * caller. The caller should not close the {@code FileDescriptor} returned by {@link
+     * #getSocket}, but should use {@link #close} instead.
+     *
+     * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
+     * of the next user who binds to that port. To prevent this scenario, these sockets are held
+     * open by the system so that they may only be closed by calling {@link #close} or when the user
+     * process exits.
      */
     public static final class UdpEncapsulationSocket implements AutoCloseable {
         private final ParcelFileDescriptor mPfd;
@@ -443,7 +523,7 @@
             mCloseGuard.open("constructor");
         }
 
-        /** Access the inner UDP Encapsulation Socket */
+        /** Get the wrapped socket. */
         public FileDescriptor getSocket() {
             if (mPfd == null) {
                 return null;
@@ -451,22 +531,19 @@
             return mPfd.getFileDescriptor();
         }
 
-        /** Retrieve the port number of the inner encapsulation socket */
+        /** Get the bound port of the wrapped socket. */
         public int getPort() {
             return mPort;
         }
 
-        @Override
         /**
-         * Release the resources that have been reserved for this Socket.
+         * Close this socket.
          *
-         * <p>This method closes the underlying socket, reducing a user's allocated sockets in the
-         * system. This must be done as part of cleanup following use of a socket. Failure to do so
-         * will cause the socket to count against a total allocation limit for IpSec and eventually
-         * fail due to resource limits.
-         *
-         * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
+         * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's
+         * resource limits, and forgetting to close them eventually will result in {@link
+         * ResourceUnavailableException} being thrown.
          */
+        @Override
         public void close() throws IOException {
             try {
                 mService.closeUdpEncapsulationSocket(mResourceId);
@@ -483,6 +560,7 @@
             mCloseGuard.close();
         }
 
+        /** Check that the socket was closed properly. */
         @Override
         protected void finalize() throws Throwable {
             if (mCloseGuard != null) {
@@ -499,21 +577,14 @@
     };
 
     /**
-     * Open a socket that is bound to a free UDP port on the system.
+     * Open a socket for UDP encapsulation and bind to the given port.
      *
-     * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
-     * the caller. This provides safe access to a socket on a port that can later be used as a UDP
-     * Encapsulation port.
+     * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
      *
-     * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
-     * socket port. Explicitly opening this port is only necessary if communication is desired on
-     * that port.
-     *
-     * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this
-     *     method will bind to the specified port or fail. To retrieve the port number, call {@link
-     *     android.system.Os#getsockname(FileDescriptor)}.
-     * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime
-     *     of the object.
+     * @param port a local UDP port
+     * @return a socket that is bound to the given port
+     * @throws IOException indicating that the socket could not be opened or bound
+     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
      */
     // Returning a socket in this fashion that has been created and bound by the system
     // is the only safe way to ensure that a socket is both accessible to the user and
@@ -533,17 +604,16 @@
     }
 
     /**
-     * Open a socket that is bound to a port selected by the system.
+     * Open a socket for UDP encapsulation.
      *
-     * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
-     * the caller. This provides safe access to a socket on a port that can later be used as a UDP
-     * Encapsulation port.
+     * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket.
      *
-     * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
-     * socket port. Explicitly opening this port is only necessary if communication is desired on
-     * that port.
+     * <p>The local port of the returned socket can be obtained by calling {@link
+     * UdpEncapsulationSocket#getPort()}.
      *
-     * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port
+     * @return a socket that is bound to a local port
+     * @throws IOException indicating that the socket could not be opened or bound
+     * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open
      */
     // Returning a socket in this fashion that has been created and bound by the system
     // is the only safe way to ensure that a socket is both accessible to the user and
@@ -556,7 +626,7 @@
     }
 
     /**
-     * Retrieve an instance of an IpSecManager within you application context
+     * Construct an instance of IpSecManager within an application context.
      *
      * @param context the application context for this manager
      * @hide
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 48b5bd5..cda4ec7 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -38,27 +38,29 @@
 import java.net.InetAddress;
 
 /**
- * This class represents an IpSecTransform, which encapsulates both properties and state of IPsec.
+ * This class represents an IPsec transform, which comprises security associations in one or both
+ * directions.
  *
- * <p>IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout
- * the lifetime of the underlying transform. If a transform object leaves scope, the underlying
- * transform may be disabled automatically, with likely undesirable results.
+ * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform}
+ * object encapsulates the properties and state of an inbound and outbound IPsec security
+ * association. That includes, but is not limited to, algorithm choice, key material, and allocated
+ * system resources.
  *
- * <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array
- * of traffic or may represent a transport mode transform operating on a Socket or Sockets.
+ * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the
+ * Internet Protocol</a>
  */
 public final class IpSecTransform implements AutoCloseable {
     private static final String TAG = "IpSecTransform";
 
     /**
-     * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
-     * to traffic towards the host.
+     * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute
+     * applies to traffic towards the host.
      */
     public static final int DIRECTION_IN = 0;
 
     /**
-     * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
-     * to traffic from the host.
+     * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute
+     * applies to traffic from the host.
      */
     public static final int DIRECTION_OUT = 1;
 
@@ -77,16 +79,16 @@
     public static final int ENCAP_NONE = 0;
 
     /**
-     * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad
-     * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP.
+     * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP
+     * header and payload. This prevents traffic from being interpreted as ESP or IKEv2.
      *
      * @hide
      */
     public static final int ENCAP_ESPINUDP_NON_IKE = 1;
 
     /**
-     * IpSec traffic will be encapsulated within UDP as per <a
-     * href="https://tools.ietf.org/html/rfc3948">RFC3498</a>.
+     * IPsec traffic will be encapsulated within UDP as per
+     * <a href="https://tools.ietf.org/html/rfc3948">RFC 3498</a>.
      *
      * @hide
      */
@@ -165,13 +167,14 @@
     }
 
     /**
-     * Deactivate an IpSecTransform and free all resources for that transform that are managed by
-     * the system for this Transform.
+     * Deactivate this {@code IpSecTransform} and free allocated resources.
      *
-     * <p>Deactivating a transform while it is still applied to any Socket will result in sockets
-     * refusing to send or receive data. This method will silently succeed if the specified
-     * transform has already been removed; thus, it is always safe to attempt cleanup when a
-     * transform is no longer needed.
+     * <p>Deactivating a transform while it is still applied to a socket will result in errors on
+     * that socket. Make sure to remove transforms by calling {@link
+     * IpSecManager#removeTransportModeTransform}. Note, removing an {@code IpSecTransform} from a
+     * socket will not deactivate it (because one transform may be applied to multiple sockets).
+     *
+     * <p>It is safe to call this method on a transform that has already been deactivated.
      */
     public void close() {
         Log.d(TAG, "Removing Transform with Id " + mResourceId);
@@ -197,6 +200,7 @@
         }
     }
 
+    /** Check that the transform was closed properly. */
     @Override
     protected void finalize() throws Throwable {
         if (mCloseGuard != null) {
@@ -264,65 +268,63 @@
     }
 
     /**
-     * Builder object to facilitate the creation of IpSecTransform objects.
-     *
-     * <p>Apply additional properties to the transform and then call a build() method to return an
-     * IpSecTransform object.
-     *
-     * @see Builder#buildTransportModeTransform(InetAddress)
+     * This class is used to build {@link IpSecTransform} objects.
      */
     public static class Builder {
         private Context mContext;
         private IpSecConfig mConfig;
 
         /**
-         * Add an encryption algorithm to the transform for the given direction.
+         * Set the encryption algorithm for the given direction.
          *
-         * <p>If encryption is set for a given direction without also providing an SPI for that
-         * direction, creation of an IpSecTransform will fail upon calling a build() method.
+         * <p>If encryption is set for a direction without also providing an SPI for that direction,
+         * creation of an {@code IpSecTransform} will fail when attempting to build the transform.
          *
-         * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
+         * <p>Encryption is mutually exclusive with authenticated encryption.
          *
-         * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+         * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
          * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
          */
         public IpSecTransform.Builder setEncryption(
                 @TransformDirection int direction, IpSecAlgorithm algo) {
+            // TODO: throw IllegalArgumentException if algo is not an encryption algorithm.
             mConfig.setEncryption(direction, algo);
             return this;
         }
 
         /**
-         * Add an authentication/integrity algorithm to the transform.
+         * Set the authentication (integrity) algorithm for the given direction.
          *
-         * <p>If authentication is set for a given direction without also providing an SPI for that
-         * direction, creation of an IpSecTransform will fail upon calling a build() method.
+         * <p>If authentication is set for a direction without also providing an SPI for that
+         * direction, creation of an {@code IpSecTransform} will fail when attempting to build the
+         * transform.
          *
-         * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
+         * <p>Authentication is mutually exclusive with authenticated encryption.
          *
-         * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+         * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
          * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
          */
         public IpSecTransform.Builder setAuthentication(
                 @TransformDirection int direction, IpSecAlgorithm algo) {
+            // TODO: throw IllegalArgumentException if algo is not an authentication algorithm.
             mConfig.setAuthentication(direction, algo);
             return this;
         }
 
         /**
-         * Add an authenticated encryption algorithm to the transform for the given direction.
+         * Set the authenticated encryption algorithm for the given direction.
          *
          * <p>If an authenticated encryption algorithm is set for a given direction without also
-         * providing an SPI for that direction, creation of an IpSecTransform will fail upon calling
-         * a build() method.
+         * providing an SPI for that direction, creation of an {@code IpSecTransform} will fail when
+         * attempting to build the transform.
          *
          * <p>The Authenticated Encryption (AE) class of algorithms are also known as Authenticated
          * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as
-         * referred to in RFC 4301)
+         * referred to in <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>).
          *
          * <p>Authenticated encryption is mutually exclusive with encryption and authentication.
          *
-         * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+         * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
          * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to
          *     be applied.
          */
@@ -333,19 +335,16 @@
         }
 
         /**
-         * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
-         * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
-         * given destination address.
+         * Set the SPI for the given direction.
          *
-         * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
-         * possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int,
-         * InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being
-         * activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}.
+         * <p>Because IPsec operates at the IP layer, this 32-bit identifier uniquely identifies
+         * packets to a given destination address. To prevent SPI collisions, values should be
+         * reserved by calling {@link IpSecManager#reserveSecurityParameterIndex}.
          *
-         * <p>Unless an SPI is set for a given direction, traffic in that direction will be
-         * sent/received without any IPsec applied.
+         * <p>If the SPI and algorithms are omitted for one direction, traffic in that direction
+         * will not be encrypted or authenticated.
          *
-         * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+         * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT}
          * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
          *     traffic
          */
@@ -356,11 +355,10 @@
         }
 
         /**
-         * Specify the network on which this transform will emit its traffic; (otherwise it will
-         * emit on the default network).
+         * Set the {@link Network} which will carry tunneled traffic.
          *
-         * <p>Restricts the transformed traffic to a particular {@link Network}. This is required in
-         * tunnel mode.
+         * <p>Restricts the transformed traffic to a particular {@link Network}. This is required
+         * for tunnel mode, otherwise tunneled traffic would be sent on the default network.
          *
          * @hide
          */
@@ -371,15 +369,18 @@
         }
 
         /**
-         * Add UDP encapsulation to an IPv4 transform
+         * Add UDP encapsulation to an IPv4 transform.
          *
-         * <p>This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for
-         * details on how UDP should be applied to IPsec.
+         * <p>This allows IPsec traffic to pass through a NAT.
          *
-         * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and
-         *     receiving encapsulating traffic.
-         * @param remotePort the UDP port number of the remote that will send and receive
-         *     encapsulated traffic. In the case of IKE, this is likely port 4500.
+         * @see <a href="https://tools.ietf.org/html/rfc3948">RFC 3948, UDP Encapsulation of IPsec
+         * ESP Packets</a>
+         * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.23">RFC 7296 section 2.23,
+         * NAT Traversal of IKEv2</a>
+         *
+         * @param localSocket a socket for sending and receiving encapsulated traffic
+         * @param remotePort the UDP port number of the remote host that will send and receive
+         *     encapsulated traffic. In the case of IKEv2, this should be port 4500.
          */
         public IpSecTransform.Builder setIpv4Encapsulation(
                 IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
@@ -393,12 +394,15 @@
         // TODO: Probably a better exception to throw for NATTKeepalive failure
         // TODO: Specify the needed NATT keepalive permission.
         /**
-         * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded
-         * request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot
-         * be activated, then the transform will fail to activate and throw an IOException.
+         * Set NAT-T keepalives to be sent with a given interval.
          *
-         * @param intervalSeconds the maximum number of seconds between keepalive packets, no less
-         *     than 20s and no more than 3600s.
+         * <p>This will set power-efficient keepalive packets to be sent by the system. If NAT-T
+         * keepalive is requested but cannot be activated, then creation of an {@link
+         * IpSecTransform} will fail when calling the build method.
+         *
+         * @param intervalSeconds the maximum number of seconds between keepalive packets. Must be
+         *     between 20s and 3600s.
+         *
          * @hide
          */
         @SystemApi
@@ -408,36 +412,29 @@
         }
 
         /**
-         * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform.
-         * Some parameters have interdependencies that are checked at build time. If a well-formed
-         * transform cannot be created from the supplied parameters, this method will throw an
-         * Exception.
+         * Build a transport mode {@link IpSecTransform}.
          *
-         * <p>Upon a successful return from this call, the provided IpSecTransform will be active
-         * and may be applied to sockets. If too many IpSecTransform objects are active for a given
-         * user this operation will fail and throw ResourceUnavailableException. To avoid these
-         * exceptions, unused Transform objects must be cleaned up by calling {@link
-         * IpSecTransform#close()} when they are no longer needed.
+         * <p>This builds and activates a transport mode transform. Note that an active transform
+         * will not affect any network traffic until it has been applied to one or more sockets.
          *
-         * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this
-         *     socket will cause the transform to be applied.
-         *     <p>Note that an active transform will not impact any network traffic until it has
-         *     been applied to one or more Sockets. Calling this method is a necessary precondition
-         *     for applying it to a socket, but is not sufficient to actually apply IPsec.
+         * @see IpSecManager#applyTransportModeTransform
+         *
+         * @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use
+         *     this transform
          * @throws IllegalArgumentException indicating that a particular combination of transform
-         *     properties is invalid.
-         * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms
-         *     may be allocated
-         * @throws SpiUnavailableException if the SPI collides with an existing transform
-         *     (unlikely).
-         * @throws ResourceUnavailableException if the current user currently has exceeded the
-         *     number of allowed active transforms.
+         *     properties is invalid
+         * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms are
+         *     active
+         * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI
+         *     collides with an existing transform
+         * @throws IOException indicating other errors
          */
         public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress)
                 throws IpSecManager.ResourceUnavailableException,
                         IpSecManager.SpiUnavailableException, IOException {
             mConfig.setMode(MODE_TRANSPORT);
             mConfig.setRemoteAddress(remoteAddress.getHostAddress());
+            // FIXME: modifying a builder after calling build can change the built transform.
             return new IpSecTransform(mContext, mConfig).activate();
         }
 
@@ -465,9 +462,9 @@
         }
 
         /**
-         * Create a new IpSecTransform.Builder to construct an IpSecTransform
+         * Create a new IpSecTransform.Builder.
          *
-         * @param context current Context
+         * @param context current context
          */
         public Builder(@NonNull Context context) {
             Preconditions.checkNotNull(context);
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index 05c8afb..6e4a231 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -16,18 +16,18 @@
 
 package android.net;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.FileDescriptor;
-import java.net.SocketOptions;
-
 import android.system.ErrnoException;
+import android.system.Int32Ref;
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructLinger;
 import android.system.StructTimeval;
-import android.util.MutableInt;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketOptions;
 
 /**
  * Socket implementation used for android.net.LocalSocket and
@@ -62,7 +62,7 @@
             FileDescriptor myFd = fd;
             if (myFd == null) throw new IOException("socket closed");
 
-            MutableInt avail = new MutableInt(0);
+            Int32Ref avail = new Int32Ref(0);
             try {
                 Os.ioctlInt(myFd, OsConstants.FIONREAD, avail);
             } catch (ErrnoException e) {
@@ -167,7 +167,7 @@
             if (myFd == null) throw new IOException("socket closed");
 
             // Loop until the output buffer is empty.
-            MutableInt pending = new MutableInt(0);
+            Int32Ref pending = new Int32Ref(0);
             while (true) {
                 try {
                     // See linux/net/unix/af_unix.c
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
new file mode 100644
index 0000000..f6a69ba
--- /dev/null
+++ b/core/java/android/net/MacAddress.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.BitUtils;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.StringJoiner;
+
+/**
+ * Represents a mac address.
+ *
+ * @hide
+ */
+public final class MacAddress implements Parcelable {
+
+    private static final int ETHER_ADDR_LEN = 6;
+    private static final byte[] ETHER_ADDR_BROADCAST = addr(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
+
+    /** The broadcast mac address.  */
+    public static final MacAddress BROADCAST_ADDRESS = new MacAddress(ETHER_ADDR_BROADCAST);
+
+    /** The zero mac address. */
+    public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0);
+
+    /** Represents categories of mac addresses. */
+    public enum MacAddressType {
+        UNICAST,
+        MULTICAST,
+        BROADCAST;
+    }
+
+    private static final long VALID_LONG_MASK = BROADCAST_ADDRESS.mAddr;
+    private static final long LOCALLY_ASSIGNED_MASK = new MacAddress("2:0:0:0:0:0").mAddr;
+    private static final long MULTICAST_MASK = new MacAddress("1:0:0:0:0:0").mAddr;
+    private static final long OUI_MASK = new MacAddress("ff:ff:ff:0:0:0").mAddr;
+    private static final long NIC_MASK = new MacAddress("0:0:0:ff:ff:ff").mAddr;
+    private static final MacAddress BASE_ANDROID_MAC = new MacAddress("da:a1:19:0:0:0");
+
+    // Internal representation of the mac address as a single 8 byte long.
+    // The encoding scheme sets the two most significant bytes to 0. The 6 bytes of the
+    // mac address are encoded in the 6 least significant bytes of the long, where the first
+    // byte of the array is mapped to the 3rd highest logical byte of the long, the second
+    // byte of the array is mapped to the 4th highest logical byte of the long, and so on.
+    private final long mAddr;
+
+    private MacAddress(long addr) {
+        mAddr = addr;
+    }
+
+    /** Creates a MacAddress for the given byte representation. */
+    public MacAddress(byte[] addr) {
+        this(longAddrFromByteAddr(addr));
+    }
+
+    /** Creates a MacAddress for the given string representation. */
+    public MacAddress(String addr) {
+        this(longAddrFromByteAddr(byteAddrFromStringAddr(addr)));
+    }
+
+    /** Returns the MacAddressType of this MacAddress. */
+    public MacAddressType addressType() {
+        if (equals(BROADCAST_ADDRESS)) {
+            return MacAddressType.BROADCAST;
+        }
+        if (isMulticastAddress()) {
+            return MacAddressType.MULTICAST;
+        }
+        return MacAddressType.UNICAST;
+    }
+
+    /** Returns true if this MacAddress corresponds to a multicast address. */
+    public boolean isMulticastAddress() {
+        return (mAddr & MULTICAST_MASK) != 0;
+    }
+
+    /** Returns true if this MacAddress corresponds to a locally assigned address. */
+    public boolean isLocallyAssigned() {
+        return (mAddr & LOCALLY_ASSIGNED_MASK) != 0;
+    }
+
+    /** Returns a byte array representation of this MacAddress. */
+    public byte[] toByteArray() {
+        return byteAddrFromLongAddr(mAddr);
+    }
+
+    @Override
+    public String toString() {
+        return stringAddrFromByteAddr(byteAddrFromLongAddr(mAddr));
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) ((mAddr >> 32) ^ mAddr);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o instanceof MacAddress) && ((MacAddress) o).mAddr == mAddr;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mAddr);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<MacAddress> CREATOR =
+            new Parcelable.Creator<MacAddress>() {
+                public MacAddress createFromParcel(Parcel in) {
+                    return new MacAddress(in.readLong());
+                }
+
+                public MacAddress[] newArray(int size) {
+                    return new MacAddress[size];
+                }
+            };
+
+    /** Return true if the given byte array is not null and has the length of a mac address. */
+    public static boolean isMacAddress(byte[] addr) {
+        return addr != null && addr.length == ETHER_ADDR_LEN;
+    }
+
+    /**
+     * Return the MacAddressType of the mac address represented by the given byte array,
+     * or null if the given byte array does not represent an mac address.
+     */
+    public static MacAddressType macAddressType(byte[] addr) {
+        if (!isMacAddress(addr)) {
+            return null;
+        }
+        return new MacAddress(addr).addressType();
+    }
+
+    /** DOCME */
+    public static byte[] byteAddrFromStringAddr(String addr) {
+        if (addr == null) {
+            throw new IllegalArgumentException("cannot convert the null String");
+        }
+        String[] parts = addr.split(":");
+        if (parts.length != ETHER_ADDR_LEN) {
+            throw new IllegalArgumentException(addr + " was not a valid MAC address");
+        }
+        byte[] bytes = new byte[ETHER_ADDR_LEN];
+        for (int i = 0; i < ETHER_ADDR_LEN; i++) {
+            int x = Integer.valueOf(parts[i], 16);
+            if (x < 0 || 0xff < x) {
+                throw new IllegalArgumentException(addr + "was not a valid MAC address");
+            }
+            bytes[i] = (byte) x;
+        }
+        return bytes;
+    }
+
+    /** DOCME */
+    public static String stringAddrFromByteAddr(byte[] addr) {
+        if (!isMacAddress(addr)) {
+            return null;
+        }
+        StringJoiner j = new StringJoiner(":");
+        for (byte b : addr) {
+            j.add(Integer.toHexString(BitUtils.uint8(b)));
+        }
+        return j.toString();
+    }
+
+    /** @hide */
+    public static byte[] byteAddrFromLongAddr(long addr) {
+        byte[] bytes = new byte[ETHER_ADDR_LEN];
+        int index = ETHER_ADDR_LEN;
+        while (index-- > 0) {
+            bytes[index] = (byte) addr;
+            addr = addr >> 8;
+        }
+        return bytes;
+    }
+
+    /** @hide */
+    public static long longAddrFromByteAddr(byte[] addr) {
+        if (!isMacAddress(addr)) {
+            throw new IllegalArgumentException(
+                    Arrays.toString(addr) + " was not a valid MAC address");
+        }
+        long longAddr = 0;
+        for (byte b : addr) {
+            longAddr = (longAddr << 8) + BitUtils.uint8(b);
+        }
+        return longAddr;
+    }
+
+    /** @hide */
+    public static long longAddrFromStringAddr(String addr) {
+        if (addr == null) {
+            throw new IllegalArgumentException("cannot convert the null String");
+        }
+        String[] parts = addr.split(":");
+        if (parts.length != ETHER_ADDR_LEN) {
+            throw new IllegalArgumentException(addr + " was not a valid MAC address");
+        }
+        long longAddr = 0;
+        int index = ETHER_ADDR_LEN;
+        while (index-- > 0) {
+            int x = Integer.valueOf(parts[index], 16);
+            if (x < 0 || 0xff < x) {
+                throw new IllegalArgumentException(addr + "was not a valid MAC address");
+            }
+            longAddr = x + (longAddr << 8);
+        }
+        return longAddr;
+    }
+
+    /** @hide */
+    public static String stringAddrFromLongAddr(long addr) {
+        addr = Long.reverseBytes(addr) >> 16;
+        StringJoiner j = new StringJoiner(":");
+        for (int i = 0; i < ETHER_ADDR_LEN; i++) {
+            j.add(Integer.toHexString((byte) addr));
+            addr = addr >> 8;
+        }
+        return j.toString();
+    }
+
+    /**
+     * Returns a randomely generated mac address with the Android OUI value "DA-A1-19".
+     * The locally assigned bit is always set to 1.
+     */
+    public static MacAddress getRandomAddress() {
+        return getRandomAddress(BASE_ANDROID_MAC, new Random());
+    }
+
+    /**
+     * Returns a randomely generated mac address using the given Random object and the same
+     * OUI values as the given MacAddress. The locally assigned bit is always set to 1.
+     */
+    public static MacAddress getRandomAddress(MacAddress base, Random r) {
+        long longAddr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong()) | LOCALLY_ASSIGNED_MASK;
+        return new MacAddress(longAddr);
+    }
+
+    // Convenience function for working around the lack of byte literals.
+    private static byte[] addr(int... in) {
+        if (in.length != ETHER_ADDR_LEN) {
+            throw new IllegalArgumentException(Arrays.toString(in)
+                    + " was not an array with length equal to " + ETHER_ADDR_LEN);
+        }
+        byte[] out = new byte[ETHER_ADDR_LEN];
+        for (int i = 0; i < ETHER_ADDR_LEN; i++) {
+            out[i] = (byte) in[i];
+        }
+        return out;
+    }
+}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index ee75fd4..f468e5d 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -31,16 +31,10 @@
 import java.util.StringJoiner;
 
 /**
- * Representation of the capabilities of a network. This object serves two
- * purposes:
- * <ul>
- * <li>An expression of the current capabilities of an active network, typically
- * expressed through
+ * Representation of the capabilities of an active network. Instances are
+ * typically obtained through
  * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
  * or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
- * <li>An expression of the future capabilities of a desired network, typically
- * expressed through {@link NetworkRequest}.
- * </ul>
  * <p>
  * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
  * network selection. Rather than indicate a need for Wi-Fi because an
@@ -79,7 +73,7 @@
      */
     public void clearAll() {
         mNetworkCapabilities = mTransportTypes = 0;
-        mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0;
+        mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
         mNetworkSpecifier = null;
         mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
     }
@@ -359,6 +353,7 @@
 
     /**
      * Sets all the capabilities set on this {@code NetworkCapability} instance.
+     * This overwrites any existing capabilities.
      *
      * @hide
      */
@@ -582,6 +577,7 @@
 
     /**
      * Sets all the transports set on this {@code NetworkCapability} instance.
+     * This overwrites any existing transports.
      *
      * @hide
      */
@@ -780,7 +776,7 @@
      * Signal strength. This is a signed integer, and higher values indicate better signal.
      * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
      */
-    private int mSignalStrength;
+    private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
 
     /**
      * Sets the signal strength. This is a signed integer, with higher values indicating a stronger
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 25b1705..97ded2d 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -32,7 +33,7 @@
      * The {@link NetworkCapabilities} that define this request.
      * @hide
      */
-    public final NetworkCapabilities networkCapabilities;
+    public final @NonNull NetworkCapabilities networkCapabilities;
 
     /**
      * Identifies the request.  NetworkRequests should only be constructed by
@@ -307,7 +308,7 @@
         return 0;
     }
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(networkCapabilities, flags);
+        networkCapabilities.writeToParcel(dest, flags);
         dest.writeInt(legacyType);
         dest.writeInt(requestId);
         dest.writeString(type.name());
@@ -315,7 +316,7 @@
     public static final Creator<NetworkRequest> CREATOR =
         new Creator<NetworkRequest>() {
             public NetworkRequest createFromParcel(Parcel in) {
-                NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null);
+                NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in);
                 int legacyType = in.readInt();
                 int requestId = in.readInt();
                 Type type = Type.valueOf(in.readString());  // IllegalArgumentException if invalid.
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 95e3802..b00cb48 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Slog;
 
 /**
  * Snapshot of network state.
@@ -43,6 +44,16 @@
         this.network = network;
         this.subscriberId = subscriberId;
         this.networkId = networkId;
+
+        // This object is an atomic view of a network, so the various components
+        // should always agree on roaming state.
+        if (networkInfo != null && networkCapabilities != null) {
+            if (networkInfo.isRoaming() == networkCapabilities
+                    .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
+                Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
+                        + " and " + networkCapabilities);
+            }
+        }
     }
 
     public NetworkState(Parcel in) {
diff --git a/core/java/android/net/metrics/ConnectStats.java b/core/java/android/net/metrics/ConnectStats.java
index 2495cab..b320b75 100644
--- a/core/java/android/net/metrics/ConnectStats.java
+++ b/core/java/android/net/metrics/ConnectStats.java
@@ -119,7 +119,8 @@
 
     @Override
     public String toString() {
-        StringBuilder builder = new StringBuilder("ConnectStats(").append(netId).append(", ");
+        StringBuilder builder =
+                new StringBuilder("ConnectStats(").append("netId=").append(netId).append(", ");
         for (int t : BitUtils.unpackBits(transports)) {
             builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
         }
diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index eb61c15..8ff8e4f 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -20,44 +20,72 @@
 
 import android.net.NetworkCapabilities;
 
+import com.android.internal.util.BitUtils;
+
+import java.util.StringJoiner;
+
 /**
  * An event recorded by ConnectivityService when there is a change in the default network.
  * {@hide}
  */
 public class DefaultNetworkEvent {
 
-    // The ID of the network that has become the new default or NETID_UNSET if none.
+    // The creation time in milliseconds of this DefaultNetworkEvent.
+    public final long creationTimeMs;
+    // The network ID of the network or NETID_UNSET if none.
     public int netId = NETID_UNSET;
-    // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
-    // defined in NetworkCapabilities.java.
-    public int[] transportTypes = new int[0];
-    // The ID of the network that was the default before or NETID_UNSET if none.
-    public int prevNetId = NETID_UNSET;
-    // Whether the previous network had IPv4/IPv6 connectivity.
-    public boolean prevIPv4;
-    public boolean prevIPv6;
+    // The list of transport types, as defined in NetworkCapabilities.java.
+    public int transports;
+    // The list of transport types of the last previous default network.
+    public int previousTransports;
+    // Whether the network has IPv4/IPv6 connectivity.
+    public boolean ipv4;
+    public boolean ipv6;
+    // The initial network score when this network became the default network.
+    public int initialScore;
+    // The initial network score when this network stopped being the default network.
+    public int finalScore;
+    // The total duration in milliseconds this network was the default network.
+    public long durationMs;
+    // The total duration in milliseconds this network was the default network and was validated.
+    public long validatedMs;
+
+    public DefaultNetworkEvent(long timeMs) {
+        creationTimeMs = timeMs;
+    }
+
+    /** Update the durationMs of this DefaultNetworkEvent for the given current time. */
+    public void updateDuration(long timeMs) {
+        durationMs = timeMs - creationTimeMs;
+    }
 
     @Override
     public String toString() {
-        String prevNetwork = String.valueOf(prevNetId);
-        String newNetwork = String.valueOf(netId);
-        if (prevNetId != 0) {
-            prevNetwork += ":" + ipSupport();
+        StringJoiner j = new StringJoiner(", ", "DefaultNetworkEvent(", ")");
+        j.add("netId=" + netId);
+        for (int t : BitUtils.unpackBits(transports)) {
+            j.add(NetworkCapabilities.transportNameOf(t));
         }
-        if (netId != 0) {
-            newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes);
+        j.add("ip=" + ipSupport());
+        if (initialScore > 0) {
+            j.add("initial_score=" + initialScore);
         }
-        return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork);
+        if (finalScore > 0) {
+            j.add("final_score=" + finalScore);
+        }
+        j.add(String.format("duration=%.0fs", durationMs / 1000.0));
+        j.add(String.format("validation=%4.1f%%", (validatedMs * 100.0) / durationMs));
+        return j.toString();
     }
 
     private String ipSupport() {
-        if (prevIPv4 && prevIPv6) {
+        if (ipv4 && ipv6) {
             return "IPv4v6";
         }
-        if (prevIPv6) {
+        if (ipv6) {
             return "IPv6";
         }
-        if (prevIPv4) {
+        if (ipv4) {
             return "IPv4";
         }
         return "NONE";
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index 81b098b..5aa705b 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -85,7 +85,8 @@
 
     @Override
     public String toString() {
-        StringBuilder builder = new StringBuilder("DnsEvent(").append(netId).append(", ");
+        StringBuilder builder =
+                new StringBuilder("DnsEvent(").append("netId=").append(netId).append(", ");
         for (int t : BitUtils.unpackBits(transports)) {
             builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
         }
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 4df3bf0..1999e78 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -60,29 +60,25 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType {}
 
-    public final int netId;
     public final @EventType int eventType;
     public final long durationMs;
 
-    public NetworkEvent(int netId, @EventType int eventType, long durationMs) {
-        this.netId = netId;
+    public NetworkEvent(@EventType int eventType, long durationMs) {
         this.eventType = eventType;
         this.durationMs = durationMs;
     }
 
-    public NetworkEvent(int netId, @EventType int eventType) {
-        this(netId, eventType, 0);
+    public NetworkEvent(@EventType int eventType) {
+        this(eventType, 0);
     }
 
     private NetworkEvent(Parcel in) {
-        netId = in.readInt();
         eventType = in.readInt();
         durationMs = in.readLong();
     }
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(netId);
         out.writeInt(eventType);
         out.writeLong(durationMs);
     }
@@ -105,8 +101,8 @@
 
     @Override
     public String toString() {
-        return String.format("NetworkEvent(%d, %s, %dms)",
-                netId, Decoder.constants.get(eventType), durationMs);
+        return String.format("NetworkEvent(%s, %dms)",
+                Decoder.constants.get(eventType), durationMs);
     }
 
     final static class Decoder {
diff --git a/core/java/android/net/metrics/WakeupEvent.java b/core/java/android/net/metrics/WakeupEvent.java
index cbf3fc8..af9a73c 100644
--- a/core/java/android/net/metrics/WakeupEvent.java
+++ b/core/java/android/net/metrics/WakeupEvent.java
@@ -16,6 +16,10 @@
 
 package android.net.metrics;
 
+import android.net.MacAddress;
+
+import java.util.StringJoiner;
+
 /**
  * An event logged when NFLOG notifies userspace of a wakeup packet for
  * watched interfaces.
@@ -23,12 +27,35 @@
  */
 public class WakeupEvent {
     public String iface;
-    public long timestampMs;
     public int uid;
+    public int ethertype;
+    public MacAddress dstHwAddr;
+    public String srcIp;
+    public String dstIp;
+    public int ipNextHeader;
+    public int srcPort;
+    public int dstPort;
+    public long timestampMs;
 
     @Override
     public String toString() {
-        return String.format("WakeupEvent(%tT.%tL, %s, uid: %d)",
-                timestampMs, timestampMs, iface, uid);
+        StringJoiner j = new StringJoiner(", ", "WakeupEvent(", ")");
+        j.add(String.format("%tT.%tL", timestampMs, timestampMs));
+        j.add(iface);
+        j.add("uid: " + Integer.toString(uid));
+        j.add("eth=0x" + Integer.toHexString(ethertype));
+        j.add("dstHw=" + dstHwAddr);
+        if (ipNextHeader > 0) {
+            j.add("ipNxtHdr=" + ipNextHeader);
+            j.add("srcIp=" + srcIp);
+            j.add("dstIp=" + dstIp);
+            if (srcPort > -1) {
+                j.add("srcPort=" + srcPort);
+            }
+            if (dstPort > -1) {
+                j.add("dstPort=" + dstPort);
+            }
+        }
+        return j.toString();
     }
 }
diff --git a/core/java/android/net/metrics/WakeupStats.java b/core/java/android/net/metrics/WakeupStats.java
index 97e83f9..23c1f20 100644
--- a/core/java/android/net/metrics/WakeupStats.java
+++ b/core/java/android/net/metrics/WakeupStats.java
@@ -18,6 +18,9 @@
 
 import android.os.Process;
 import android.os.SystemClock;
+import android.util.SparseIntArray;
+
+import java.util.StringJoiner;
 
 /**
  * An event logged per interface and that aggregates WakeupEvents for that interface.
@@ -38,6 +41,13 @@
     public long noUidWakeups = 0;
     public long durationSec = 0;
 
+    public long l2UnicastCount = 0;
+    public long l2MulticastCount = 0;
+    public long l2BroadcastCount = 0;
+
+    public final SparseIntArray ethertypes = new SparseIntArray();
+    public final SparseIntArray ipNextHeaders = new SparseIntArray();
+
     public WakeupStats(String iface) {
         this.iface = iface;
     }
@@ -68,20 +78,56 @@
                 }
                 break;
         }
+
+        switch (ev.dstHwAddr.addressType()) {
+            case UNICAST:
+                l2UnicastCount++;
+                break;
+            case MULTICAST:
+                l2MulticastCount++;
+                break;
+            case BROADCAST:
+                l2BroadcastCount++;
+                break;
+            default:
+                break;
+        }
+
+        increment(ethertypes, ev.ethertype);
+        if (ev.ipNextHeader >= 0) {
+            increment(ipNextHeaders, ev.ipNextHeader);
+        }
     }
 
     @Override
     public String toString() {
         updateDuration();
-        return new StringBuilder()
-                .append("WakeupStats(").append(iface)
-                .append(", total: ").append(totalWakeups)
-                .append(", root: ").append(rootWakeups)
-                .append(", system: ").append(systemWakeups)
-                .append(", apps: ").append(applicationWakeups)
-                .append(", non-apps: ").append(nonApplicationWakeups)
-                .append(", no uid: ").append(noUidWakeups)
-                .append(", ").append(durationSec).append("s)")
-                .toString();
+        StringJoiner j = new StringJoiner(", ", "WakeupStats(", ")");
+        j.add(iface);
+        j.add("" + durationSec + "s");
+        j.add("total: " + totalWakeups);
+        j.add("root: " + rootWakeups);
+        j.add("system: " + systemWakeups);
+        j.add("apps: " + applicationWakeups);
+        j.add("non-apps: " + nonApplicationWakeups);
+        j.add("no uid: " + noUidWakeups);
+        j.add(String.format("l2 unicast/multicast/broadcast: %d/%d/%d",
+                l2UnicastCount, l2MulticastCount, l2BroadcastCount));
+        for (int i = 0; i < ethertypes.size(); i++) {
+            int eth = ethertypes.keyAt(i);
+            int count = ethertypes.valueAt(i);
+            j.add(String.format("ethertype 0x%x: %d", eth, count));
+        }
+        for (int i = 0; i < ipNextHeaders.size(); i++) {
+            int proto = ipNextHeaders.keyAt(i);
+            int count = ipNextHeaders.valueAt(i);
+            j.add(String.format("ipNxtHdr %d: %d", proto, count));
+        }
+        return j.toString();
+    }
+
+    private static void increment(SparseIntArray counters, int key) {
+        int newcount = counters.get(key, 0) + 1;
+        counters.put(key, newcount);
     }
 }
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2efde23..3286e6e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -16,11 +16,14 @@
 
 package android.os;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppGlobals;
 import android.content.Context;
 import android.util.Log;
 
 import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.TypedProperties;
 
 import dalvik.system.VMDebug;
@@ -2336,4 +2339,24 @@
     public static String getCaller() {
         return getCaller(Thread.currentThread().getStackTrace(), 0);
     }
+
+    /**
+     * Attach a library as a jvmti agent to the current runtime.
+     *
+     * @param library library containing the agent
+     * @param options options passed to the agent
+     *
+     * @throws IOException If the agent could not be attached
+     */
+    public static void attachJvmtiAgent(@NonNull String library, @Nullable String options)
+            throws IOException {
+        Preconditions.checkNotNull(library);
+        Preconditions.checkArgument(!library.contains("="));
+
+        if (options == null) {
+            VMDebug.attachAgent(library);
+        } else {
+            VMDebug.attachAgent(library + "=" + options);
+        }
+    }
 }
diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java
index 3544ea1..a080c8d 100644
--- a/core/java/android/os/HidlSupport.java
+++ b/core/java/android/os/HidlSupport.java
@@ -179,4 +179,9 @@
         }
         return Objects.equals(lft.asBinder(), ((IHwInterface) rgt).asBinder());
     }
+
+    /**
+     * Return PID of process if sharable to clients.
+     */
+    public static native int getPidIfSharable();
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index e426356..6746120 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -35,6 +35,10 @@
      * DO NOT MOVE - UserManager.h depends on the ordering of this function.
      */
     int getCredentialOwnerProfile(int userHandle);
+    int getProfileParentId(int userHandle);
+    /*
+     * END OF DO NOT MOVE
+     */
 
     UserInfo createUser(in String name, int flags);
     UserInfo createProfileForUser(in String name, int flags, int userHandle,
diff --git a/core/java/android/os/ParcelFileDescriptor.aidl b/core/java/android/os/ParcelFileDescriptor.aidl
index 5857aae..6bbd99e 100644
--- a/core/java/android/os/ParcelFileDescriptor.aidl
+++ b/core/java/android/os/ParcelFileDescriptor.aidl
@@ -17,4 +17,4 @@
 
 package android.os;
 
-parcelable ParcelFileDescriptor;
+parcelable ParcelFileDescriptor cpp_header "android/os/parcel_file_descriptor.h";
diff --git a/core/java/android/os/ParcelUuid.aidl b/core/java/android/os/ParcelUuid.aidl
index f7e080a..6f36297 100644
--- a/core/java/android/os/ParcelUuid.aidl
+++ b/core/java/android/os/ParcelUuid.aidl
@@ -16,4 +16,4 @@
 
 package android.os;
 
-parcelable ParcelUuid;
+parcelable ParcelUuid cpp_header "android/os/parcel_uuid.h";
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b5d62e5..0874d93 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -151,6 +151,9 @@
      */
     public static final int OTA_UPDATE_UID = 1061;
 
+    /** {@hide} */
+    public static final int NOBODY_UID = 9999;
+
     /**
      * Defines the start of a range of UIDs (and GIDs), going from this
      * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index 2281fb6..b9b9a18 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -19,6 +19,7 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 
+import java.io.PrintWriter;
 import java.util.function.Consumer;
 
 /**
@@ -399,6 +400,13 @@
         }
     }
 
+    /** @hide */
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size());
+        pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
+        pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
+    }
+
     private void logExcessiveCallbacks() {
         final long size = mCallbacks.size();
         final long TOO_MANY = 3000;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 6a4fef2..4c04f78 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -27,6 +27,8 @@
  * Representation of a user on the device.
  */
 public final class UserHandle implements Parcelable {
+    // NOTE: keep logic in sync with system/core/libcutils/multiuser.c
+
     /**
      * @hide Range of uids allocated for a user.
      */
@@ -88,6 +90,19 @@
      */
     public static final boolean MU_ENABLED = true;
 
+    /** @hide */
+    public static final int ERR_GID = -1;
+    /** @hide */
+    public static final int AID_ROOT = android.os.Process.ROOT_UID;
+    /** @hide */
+    public static final int AID_APP_START = android.os.Process.FIRST_APPLICATION_UID;
+    /** @hide */
+    public static final int AID_APP_END = android.os.Process.LAST_APPLICATION_UID;
+    /** @hide */
+    public static final int AID_SHARED_GID_START = android.os.Process.FIRST_SHARED_APPLICATION_GID;
+    /** @hide */
+    public static final int AID_CACHE_GID_START = android.os.Process.FIRST_APPLICATION_CACHE_GID;
+
     final int mHandle;
 
     /**
@@ -192,13 +207,20 @@
         return getUid(userId, Process.SHARED_USER_GID);
     }
 
-    /**
-     * Returns the shared app gid for a given uid or appId.
-     * @hide
-     */
-    public static int getSharedAppGid(int id) {
-        return Process.FIRST_SHARED_APPLICATION_GID + (id % PER_USER_RANGE)
-                - Process.FIRST_APPLICATION_UID;
+    /** @hide */
+    public static int getSharedAppGid(int uid) {
+        return getSharedAppGid(getUserId(uid), getAppId(uid));
+    }
+
+    /** @hide */
+    public static int getSharedAppGid(int userId, int appId) {
+        if (appId >= AID_APP_START && appId <= AID_APP_END) {
+            return (appId - AID_APP_START) + AID_SHARED_GID_START;
+        } else if (appId >= AID_ROOT && appId <= AID_APP_START) {
+            return appId;
+        } else {
+            return -1;
+        }
     }
 
     /**
@@ -214,13 +236,18 @@
         return appId;
     }
 
-    /**
-     * Returns the cache GID for a given UID or appId.
-     * @hide
-     */
-    public static int getCacheAppGid(int id) {
-        return Process.FIRST_APPLICATION_CACHE_GID + (id % PER_USER_RANGE)
-                - Process.FIRST_APPLICATION_UID;
+    /** @hide */
+    public static int getCacheAppGid(int uid) {
+        return getCacheAppGid(getUserId(uid), getAppId(uid));
+    }
+
+    /** @hide */
+    public static int getCacheAppGid(int userId, int appId) {
+        if (appId >= AID_APP_START && appId <= AID_APP_END) {
+            return getUid(userId, (appId - AID_APP_START) + AID_CACHE_GID_START);
+        } else {
+            return -1;
+        }
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
old mode 100755
new mode 100644
index cbeeabe..6560a8f
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -194,6 +194,24 @@
             "android.settings.AIRPLANE_MODE_SETTINGS";
 
     /**
+     * Activity Action: Show mobile data usage list.
+     * <p>
+     * Input: {@link EXTRA_NETWORK_TEMPLATE} and {@link EXTRA_SUB_ID} should be included to specify
+     * how and what mobile data statistics should be collected.
+     * <p>
+     * Output: Nothing
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MOBILE_DATA_USAGE =
+            "android.settings.MOBILE_DATA_USAGE";
+
+    /** @hide */
+    public static final String EXTRA_NETWORK_TEMPLATE = "network_template";
+    /** @hide */
+    public static final String EXTRA_SUB_ID = "sub_id";
+
+    /**
      * Activity Action: Modify Airplane mode settings using a voice command.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
@@ -9158,11 +9176,20 @@
         public static final String DEFAULT_DNS_SERVER = "default_dns_server";
 
         /**
-         * Whether to disable DNS over TLS (boolean)
+         * The requested Private DNS mode (string), and an accompanying specifier (string).
+         *
+         * Currently, the specifier holds the chosen provider name when the mode requests
+         * a specific provider. It may be used to store the provider name even when the
+         * mode changes so that temporarily disabling and re-enabling the specific
+         * provider mode does not necessitate retyping the provider hostname.
          *
          * @hide
          */
-        public static final String DNS_TLS_DISABLED = "dns_tls_disabled";
+        public static final String PRIVATE_DNS_MODE = "private_dns_mode";
+        /**
+         * @hide
+         */
+        public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
 
         /** {@hide} */
         public static final String
@@ -9197,6 +9224,9 @@
         /** {@hide} */
         public static final String
                 BLUETOOTH_PAN_PRIORITY_PREFIX = "bluetooth_pan_priority_";
+        /** {@hide} */
+        public static final String
+                BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
 
         /**
          * Activity manager specific settings.
@@ -9518,6 +9548,14 @@
         }
 
         /**
+         * Get the key that retrieves a bluetooth hearing aid priority.
+         * @hide
+         */
+        public static final String getBluetoothHearingAidPriorityKey(String address) {
+            return BLUETOOTH_HEARING_AID_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
+        }
+
+        /**
          * Get the key that retrieves a bluetooth map priority.
          * @hide
          */
@@ -9937,7 +9975,8 @@
         public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
 
         /**
-         * Whether the Volte is enabled
+         * Whether the Volte is enabled. If this setting is not set then we use the Carrier Config
+         * value {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
          * <p>
          * Type: int (0 for false, 1 for true)
          * @hide
@@ -10204,7 +10243,9 @@
             DOCK_AUDIO_MEDIA_ENABLED,
             ENCODED_SURROUND_OUTPUT,
             LOW_POWER_MODE_TRIGGER_LEVEL,
-            BLUETOOTH_ON
+            BLUETOOTH_ON,
+            PRIVATE_DNS_MODE,
+            PRIVATE_DNS_SPECIFIER
         };
 
         private static final ContentProviderHolder sProviderHolder =
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index af26a88..21b72f3 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -530,7 +530,7 @@
      * axis distances.  Warning: this fudge factor is finely tuned, be sure to
      * run all focus tests if you dare tweak it.
      */
-    int getWeightedDistanceFor(int majorAxisDistance, int minorAxisDistance) {
+    long getWeightedDistanceFor(long majorAxisDistance, long minorAxisDistance) {
         return 13 * majorAxisDistance * majorAxisDistance
                 + minorAxisDistance * minorAxisDistance;
     }
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index c7e8dee..cca66d6 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -605,9 +605,10 @@
     public void setStoppedState(IBinder token, boolean stopped) {
         synchronized (mLock) {
             int count = mViews.size();
-            for (int i = 0; i < count; i++) {
+            for (int i = count - 1; i >= 0; i--) {
                 if (token == null || mParams.get(i).token == token) {
                     ViewRootImpl root = mRoots.get(i);
+                    // Client might remove the view by "stopped" event.
                     root.setWindowStopped(stopped);
                 }
             }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index c123a80..15c18ac 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -51,6 +51,9 @@
 import java.util.List;
 import java.util.Objects;
 
+// TODO: use java.lang.ref.Cleaner once Android supports Java 9
+import sun.misc.Cleaner;
+
 /**
  * The {@link AutofillManager} provides ways for apps and custom views to integrate with the
  * Autofill Framework lifecycle.
@@ -225,6 +228,9 @@
     private IAutoFillManagerClient mServiceClient;
 
     @GuardedBy("mLock")
+    private Cleaner mServiceClientCleaner;
+
+    @GuardedBy("mLock")
     private AutofillCallback mCallback;
 
     private final Context mContext;
@@ -958,10 +964,19 @@
         if (mServiceClient == null) {
             mServiceClient = new AutofillManagerClient(this);
             try {
-                final int flags = mService.addClient(mServiceClient, mContext.getUserId());
+                final int userId = mContext.getUserId();
+                final int flags = mService.addClient(mServiceClient, userId);
                 mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
                 sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
                 sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
+                final IAutoFillManager service = mService;
+                final IAutoFillManagerClient serviceClient = mServiceClient;
+                mServiceClientCleaner = Cleaner.create(this, () -> {
+                    try {
+                        service.removeClient(serviceClient, userId);
+                    } catch (RemoteException e) {
+                    }
+                });
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -1068,6 +1083,10 @@
             if (resetClient) {
                 // Reset connection to system
                 mServiceClient = null;
+                if (mServiceClientCleaner != null) {
+                    mServiceClientCleaner.clean();
+                    mServiceClientCleaner = null;
+                }
             }
         }
     }
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 627afa7..7f2c080 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -32,6 +32,7 @@
 interface IAutoFillManager {
     // Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
     int addClient(in IAutoFillManagerClient client, int userId);
+    void removeClient(in IAutoFillManagerClient client, int userId);
     int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
             in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
             String packageName);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index e7667ca..ec51659 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -18,10 +18,6 @@
         "-Wunused",
         "-Wunreachable-code",
 
-        // necessary for Clang as the GL bindings need to turn
-        // off a GCC warning that Clang doesn't know.
-        "-Wno-unknown-pragmas",
-
         // TODO: Linear blending should be enabled by default, but we are
         // TODO: making it an opt-in while it's a work in progress
         //"-DANDROID_ENABLE_LINEAR_BLENDING",
@@ -81,6 +77,7 @@
         "android_text_StaticLayout.cpp",
         "android_os_Debug.cpp",
         "android_os_GraphicsEnvironment.cpp",
+        "android_os_HidlSupport.cpp",
         "android_os_HwBinder.cpp",
         "android_os_HwBlob.cpp",
         "android_os_HwParcel.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8b6fc59..6bc6f63 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -154,6 +154,7 @@
 extern int register_android_nio_utils(JNIEnv* env);
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_GraphicsEnvironment(JNIEnv* env);
+extern int register_android_os_HidlSupport(JNIEnv* env);
 extern int register_android_os_HwBinder(JNIEnv *env);
 extern int register_android_os_HwBlob(JNIEnv *env);
 extern int register_android_os_HwParcel(JNIEnv *env);
@@ -1325,6 +1326,7 @@
     REG_JNI(register_android_os_SystemProperties),
     REG_JNI(register_android_os_Binder),
     REG_JNI(register_android_os_Parcel),
+    REG_JNI(register_android_os_HidlSupport),
     REG_JNI(register_android_os_HwBinder),
     REG_JNI(register_android_os_HwBlob),
     REG_JNI(register_android_os_HwParcel),
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 6163588..a9d75fd 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -17,7 +17,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index df1aa20..75a25fe 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -17,7 +17,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index 6d4f6ec..ee5b594 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index e630cfca..da7d0f0 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index ab9cbb1..391ae53 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 8f71a6d..09dce32 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES/gl.h>
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index f83d204..99922cf 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES2/gl2.h>
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index b649daf..adc635e 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES3/gl3.h>
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 07d920f..512f562 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -17,7 +17,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <stdint.h>
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index 723dd4c..5543fca 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -17,7 +17,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <GLES3/gl31.h>
diff --git a/core/jni/android_opengl_GLES32.cpp b/core/jni/android_opengl_GLES32.cpp
index 62a6e6c..2f1e31e 100644
--- a/core/jni/android_opengl_GLES32.cpp
+++ b/core/jni/android_opengl_GLES32.cpp
@@ -17,7 +17,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include <stdint.h>
diff --git a/core/jni/android_os_HidlSupport.cpp b/core/jni/android_os_HidlSupport.cpp
new file mode 100644
index 0000000..e3602d8
--- /dev/null
+++ b/core/jni/android_os_HidlSupport.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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 <hidl/HidlTransportSupport.h>
+#include <nativehelper/JNIHelp.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+static jint android_os_HidlSupport_getPidIfSharable(JNIEnv*, jclass) {
+    return android::hardware::details::getPidIfSharable();
+}
+
+static const JNINativeMethod gHidlSupportMethods[] = {
+    {"getPidIfSharable", "()I", (void*)android_os_HidlSupport_getPidIfSharable},
+};
+
+const char* const kHidlSupportPathName = "android/os/HidlSupport";
+
+int register_android_os_HidlSupport(JNIEnv* env)
+{
+    return RegisterMethodsOrDie(env, kHidlSupportPathName, gHidlSupportMethods, NELEM(gHidlSupportMethods));
+}
+
+}  // namespace android
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index ac23eca..40ff7e4 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -18,7 +18,6 @@
 // This source file is automatically generated
 
 #pragma GCC diagnostic ignored "-Wunused-variable"
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
diff --git a/core/jni/hwbinder/EphemeralStorage.cpp b/core/jni/hwbinder/EphemeralStorage.cpp
index 4996bc8..3b18f2b 100644
--- a/core/jni/hwbinder/EphemeralStorage.cpp
+++ b/core/jni/hwbinder/EphemeralStorage.cpp
@@ -111,6 +111,7 @@
                 break;                                                         \
             }
 
+__attribute__((no_sanitize("unsigned-integer-overflow")))
 void EphemeralStorage::release(JNIEnv *env) {
     for (size_t i = mItems.size(); i--;) {
         const Item &item = mItems[i];
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index fa645f4..ef6eb09 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -254,6 +254,7 @@
     SettingProto bluetooth_pbap_client_priority_prefix = 209;
     SettingProto bluetooth_sap_priority_prefix = 210;
     SettingProto bluetooth_pan_priority_prefix = 211;
+    SettingProto bluetooth_hearing_aid_priority_prefix = 345;
     SettingProto device_idle_constants = 212;
     SettingProto device_idle_constants_watch = 213;
     SettingProto app_idle_constants = 214;
diff --git a/core/tests/coretests/src/android/os/UserHandleTest.java b/core/tests/coretests/src/android/os/UserHandleTest.java
new file mode 100644
index 0000000..af559fd
--- /dev/null
+++ b/core/tests/coretests/src/android/os/UserHandleTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 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.os;
+
+import static android.os.UserHandle.ERR_GID;
+import static android.os.UserHandle.getAppId;
+import static android.os.UserHandle.getCacheAppGid;
+import static android.os.UserHandle.getSharedAppGid;
+import static android.os.UserHandle.getUid;
+import static android.os.UserHandle.getUserId;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class UserHandleTest {
+    // NOTE: keep logic in sync with system/core/libcutils/tests/multiuser_test.cpp
+
+    @Test
+    public void testMerge() throws Exception {
+        EXPECT_EQ(0, multiuser_get_uid(0, 0));
+        EXPECT_EQ(1000, multiuser_get_uid(0, 1000));
+        EXPECT_EQ(10000, multiuser_get_uid(0, 10000));
+        EXPECT_EQ(50000, multiuser_get_uid(0, 50000));
+        EXPECT_EQ(1000000, multiuser_get_uid(10, 0));
+        EXPECT_EQ(1001000, multiuser_get_uid(10, 1000));
+        EXPECT_EQ(1010000, multiuser_get_uid(10, 10000));
+        EXPECT_EQ(1050000, multiuser_get_uid(10, 50000));
+    }
+
+    @Test
+    public void testSplitUser() throws Exception {
+        EXPECT_EQ(0, multiuser_get_user_id(0));
+        EXPECT_EQ(0, multiuser_get_user_id(1000));
+        EXPECT_EQ(0, multiuser_get_user_id(10000));
+        EXPECT_EQ(0, multiuser_get_user_id(50000));
+        EXPECT_EQ(10, multiuser_get_user_id(1000000));
+        EXPECT_EQ(10, multiuser_get_user_id(1001000));
+        EXPECT_EQ(10, multiuser_get_user_id(1010000));
+        EXPECT_EQ(10, multiuser_get_user_id(1050000));
+    }
+
+    @Test
+    public void testSplitApp() throws Exception {
+        EXPECT_EQ(0, multiuser_get_app_id(0));
+        EXPECT_EQ(1000, multiuser_get_app_id(1000));
+        EXPECT_EQ(10000, multiuser_get_app_id(10000));
+        EXPECT_EQ(50000, multiuser_get_app_id(50000));
+        EXPECT_EQ(0, multiuser_get_app_id(1000000));
+        EXPECT_EQ(1000, multiuser_get_app_id(1001000));
+        EXPECT_EQ(10000, multiuser_get_app_id(1010000));
+        EXPECT_EQ(50000, multiuser_get_app_id(1050000));
+    }
+
+    @Test
+    public void testCache() throws Exception {
+        EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 0));
+        EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 1000));
+        EXPECT_EQ(20000, multiuser_get_cache_gid(0, 10000));
+        EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(0, 50000));
+        EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 0));
+        EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 1000));
+        EXPECT_EQ(1020000, multiuser_get_cache_gid(10, 10000));
+        EXPECT_EQ(ERR_GID, multiuser_get_cache_gid(10, 50000));
+    }
+
+    @Test
+    public void testShared() throws Exception {
+        EXPECT_EQ(0, multiuser_get_shared_gid(0, 0));
+        EXPECT_EQ(1000, multiuser_get_shared_gid(0, 1000));
+        EXPECT_EQ(50000, multiuser_get_shared_gid(0, 10000));
+        EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(0, 50000));
+        EXPECT_EQ(0, multiuser_get_shared_gid(10, 0));
+        EXPECT_EQ(1000, multiuser_get_shared_gid(10, 1000));
+        EXPECT_EQ(50000, multiuser_get_shared_gid(10, 10000));
+        EXPECT_EQ(ERR_GID, multiuser_get_shared_gid(10, 50000));
+    }
+
+    private static void EXPECT_EQ(int expected, int actual) {
+        assertEquals(expected, actual);
+    }
+
+    private static int multiuser_get_uid(int userId, int appId) {
+        return getUid(userId, appId);
+    }
+
+    private static int multiuser_get_cache_gid(int userId, int appId) {
+        return getCacheAppGid(userId, appId);
+    }
+
+    private static int multiuser_get_shared_gid(int userId, int appId) {
+        return getSharedAppGid(userId, appId);
+    }
+
+    private static int multiuser_get_user_id(int uid) {
+        return getUserId(uid);
+    }
+
+    private static int multiuser_get_app_id(int uid) {
+        return getAppId(uid);
+    }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 88f2b4b..9edaffe 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -121,6 +121,7 @@
                     Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
+                    Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
                     Settings.Global.BOOT_COUNT,
                     Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
                     Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
@@ -177,7 +178,6 @@
                     Settings.Global.DNS_RESOLVER_MIN_SAMPLES,
                     Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
                     Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
-                    Settings.Global.DNS_TLS_DISABLED,
                     Settings.Global.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY,
                     Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
                     Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
diff --git a/core/tests/overlaytests/Android.mk b/core/tests/overlaytests/Android.mk
index bf69442..b798d87 100644
--- a/core/tests/overlaytests/Android.mk
+++ b/core/tests/overlaytests/Android.mk
@@ -1,4 +1,15 @@
-# Dummy makefile to halt recursive directory traversal.
+# Copyright (C) 2017 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.
 
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
+include $(call all-subdir-makefiles)
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 92b6aa3..a79376c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -147,6 +147,7 @@
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
+        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.READ_SEARCH_INDEXABLES"/>
         <permission name="android.permission.REBOOT"/>
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 7b2fa76..76eb4e6 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -112,14 +112,29 @@
 # Run sanity tests on fonts on checkbuild
 checkbuild: fontchain_lint
 
-FONTCHAIN_LINTER := frameworks/base/tools/fonts/fontchain_lint.py
+FONTCHAIN_LINTER := $(HOST_OUT_EXECUTABLES)/fontchain_linter
 ifeq ($(MINIMAL_FONT_FOOTPRINT),true)
 CHECK_EMOJI := false
 else
 CHECK_EMOJI := true
 endif
 
+fontchain_lint_timestamp := $(call intermediates-dir-for,PACKAGING,fontchain_lint)/stamp
+
 .PHONY: fontchain_lint
-fontchain_lint: $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml $(PRODUCT_OUT)/system.img
-	PYTHONPATH=$$PYTHONPATH:external/fonttools/Lib \
-	python $(FONTCHAIN_LINTER) $(TARGET_OUT) $(CHECK_EMOJI) external/unicode
+fontchain_lint: $(fontchain_lint_timestamp)
+
+fontchain_lint_deps := \
+    external/unicode/DerivedAge.txt \
+    external/unicode/emoji-data.txt \
+    external/unicode/emoji-sequences.txt \
+    external/unicode/emoji-variation-sequences.txt \
+    external/unicode/emoji-zwj-sequences.txt \
+    external/unicode/additions/emoji-data.txt \
+    external/unicode/additions/emoji-sequences.txt \
+    external/unicode/additions/emoji-zwj-sequences.txt \
+
+$(fontchain_lint_timestamp): $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml $(PRODUCT_OUT)/system.img $(fontchain_lint_deps)
+	@echo Running fontchain lint
+	$(FONTCHAIN_LINTER) $(TARGET_OUT) $(CHECK_EMOJI) external/unicode
+	touch $@
diff --git a/legacy-test/src/com/android/internal/util/Predicate.java b/legacy-test/src/com/android/internal/util/Predicate.java
index 1b5eaff..e87f489 100644
--- a/legacy-test/src/com/android/internal/util/Predicate.java
+++ b/legacy-test/src/com/android/internal/util/Predicate.java
@@ -27,6 +27,7 @@
  * strongly encouraged to state this fact clearly in their API documentation.
  *
  * @deprecated Use {@code java.util.function.Predicate} instead.
+ *             This must not be used outside frameworks/base/test-runner.
  */
 @Deprecated
 public interface Predicate<T> {
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index bdc0fda..31eb948 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -34,6 +34,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Set;
+import java.util.Objects;
 
 /**
  * Contains metadata about an item, such as the title, artist, etc.
@@ -616,6 +617,71 @@
             };
 
     /**
+     * Compares the contents of this object to another MediaMetadata object. It
+     * does not compare Bitmaps and Ratings as the media player can choose to
+     * forgo these fields depending on how you retrieve the MediaMetadata.
+     *
+     * @param o The Metadata object to compare this object against
+     * @return Whether or not the two objects have matching fields (excluding
+     * Bitmaps and Ratings)
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof MediaMetadata)) {
+            return false;
+        }
+
+        final MediaMetadata m = (MediaMetadata) o;
+
+        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+            String key = METADATA_KEYS_TYPE.keyAt(i);
+            switch (METADATA_KEYS_TYPE.valueAt(i)) {
+                case METADATA_TYPE_TEXT:
+                    if (!Objects.equals(getString(key), m.getString(key))) {
+                        return false;
+                    }
+                    break;
+                case METADATA_TYPE_LONG:
+                    if (getLong(key) != m.getLong(key)) {
+                        return false;
+                    }
+                    break;
+                default:
+                    // Ignore ratings and bitmaps when comparing
+                    break;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hashCode = 17;
+
+        for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
+            String key = METADATA_KEYS_TYPE.keyAt(i);
+            switch (METADATA_KEYS_TYPE.valueAt(i)) {
+                case METADATA_TYPE_TEXT:
+                    hashCode = 31 * hashCode + Objects.hash(getString(key));
+                    break;
+                case METADATA_TYPE_LONG:
+                    hashCode = 31 * hashCode + Long.hashCode(getLong(key));
+                    break;
+                default:
+                    // Ignore ratings and bitmaps when comparing
+                    break;
+            }
+        }
+
+        return hashCode;
+    }
+
+    /**
      * Use to build MediaMetadata objects. The system defined metadata keys must
      * use the appropriate data type.
      */
diff --git a/media/mca/filterfw/Android.mk b/media/mca/filterfw/Android.mk
index 334f4e2..37f1e13 100644
--- a/media/mca/filterfw/Android.mk
+++ b/media/mca/filterfw/Android.mk
@@ -26,6 +26,8 @@
 
 LOCAL_MODULE := libfilterfw
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_WHOLE_STATIC_LIBRARIES := libfilterfw_jni \
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index fa50943..478297f 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -80,6 +80,9 @@
     // The minimum allowed max packet size is 255 according to the OBEX specification
     public static final int LOWER_LIMIT_MAX_PACKET_SIZE = 255;
 
+    // The length of OBEX Byte Sequency Header Id according to the OBEX specification
+    public static final int OBEX_BYTE_SEQ_HEADER_LEN = 0x03;
+
     /**
      * Temporary workaround to be able to push files to Windows 7.
      * TODO: Should be removed as soon as Microsoft updates their driver.
@@ -205,12 +208,15 @@
                     case 0x40:
                         boolean trimTail = true;
                         index++;
-                        length = 0xFF & headerArray[index];
-                        length = length << 8;
-                        index++;
-                        length += 0xFF & headerArray[index];
-                        length -= 3;
-                        index++;
+                        length = ((0xFF & headerArray[index]) << 8) +
+                                 (0xFF & headerArray[index + 1]);
+                        index += 2;
+                        if (length <= OBEX_BYTE_SEQ_HEADER_LEN) {
+                            Log.e(TAG, "Remote sent an OBEX packet with " +
+                                  "incorrect header length = " + length);
+                            break;
+                        }
+                        length -= OBEX_BYTE_SEQ_HEADER_LEN;
                         value = new byte[length];
                         System.arraycopy(headerArray, index, value, 0, length);
                         if (length == 0 || (length > 0 && (value[length - 1] != 0))) {
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index 56a675a..15ea367 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -195,7 +195,12 @@
             if(!handleObexPacket(packet)) {
                 return;
             }
-            if (!mHasBody) {
+            /* Don't Pre-Send continue when Remote requested for SRM
+             * Let the Application confirm.
+             */
+            if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
+                    + " not hasBody case: " + mHasBody);
+            if (!mHasBody && !mSrmEnabled) {
                 while ((!mGetOperation) && (!finalBitSet)) {
                     sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
                     if (mPrivateInput.available() > 0) {
@@ -204,8 +209,13 @@
                 }
             }
         }
-
-        while ((!mGetOperation) && (!finalBitSet) && (mPrivateInput.available() == 0)) {
+        /* Don't Pre-Send continue when Remote requested for SRM
+          * Let the Application confirm.
+          */
+        if (V) Log.v(TAG, "Get App confirmation if SRM ENABLED case: " + mSrmEnabled
+            + " not finalPacket: " + finalBitSet + " not GETOp Case: " + mGetOperation);
+        while ((!mSrmEnabled) && (!mGetOperation) && (!finalBitSet)
+                && (mPrivateInput.available() == 0)) {
             sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
             if (mPrivateInput.available() > 0) {
                 break;
diff --git a/packages/SettingsLib/res/drawable/ic_expand_more.xml b/packages/SettingsLib/res/drawable/ic_expand_more.xml
new file mode 100644
index 0000000..a8ff539
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_expand_more.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2017 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?android:attr/colorControlNormal">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M16.59,8.59L12.0,13.17 7.41,8.59 6.0,10.0l6.0,6.0 6.0,-6.0z"/>
+
+</vector>
diff --git a/packages/SettingsLib/res/layout/preference_category_divider.xml b/packages/SettingsLib/res/layout/preference_category_divider.xml
new file mode 100644
index 0000000..6644eec
--- /dev/null
+++ b/packages/SettingsLib/res/layout/preference_category_divider.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/two_target_divider"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:gravity="start|center_vertical"
+    android:orientation="horizontal">
+    <View
+        android:layout_height="1dp"
+        android:layout_width="match_parent"
+        android:background="?android:attr/dividerHorizontal" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml b/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml
new file mode 100644
index 0000000..70d0898
--- /dev/null
+++ b/packages/SettingsLib/res/layout/preference_category_material_settings_with_divider.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 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.
+  -->
+
+<!-- Similar to preference_category_material_settings.xml, except that this always adds
+     a divider above category. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <include layout="@layout/preference_category_divider"/>
+    <include layout="@layout/preference_category_material_settings"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e981e26..a73f800 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -505,11 +505,13 @@
     <!-- [CHAR LIMIT=NONE] Label for displaying Bluetooth Audio Codec Parameters while streaming -->
     <string name="bluetooth_select_a2dp_codec_streaming_label">Streaming: <xliff:g id="streaming_parameter">%1$s</xliff:g></string>
 
-    <!-- Title of the developer option for DNS over TLS. -->
-    <string name="dns_tls">DNS over TLS</string>
-    <!-- Summary to explain the developer option for DNS over TLS.  This allows the user to
-    request that the system attempt TLS with all DNS servers, or none. -->
-    <string name="dns_tls_summary">If enabled, attempt DNS over TLS on port 853.</string>
+    <!-- Developer option setting for Private DNS -->
+    <string name="select_private_dns_configuration_title">Private DNS</string>
+    <string name="select_private_dns_configuration_dialog_title">Select Private DNS Mode</string>
+    <string name="private_dns_mode_off">Off</string>
+    <string name="private_dns_mode_opportunistic">Opportunistic</string>
+    <string name="private_dns_mode_provider">Private DNS provider hostname</string>
+    <string name="private_dns_mode_provider_hostname_hint">Enter hostname of DNS provider</string>
 
     <!-- setting Checkbox summary whether to show options for wireless display certification  -->
     <string name="wifi_display_certification_summary">Show options for wireless display certification</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index dee5a93..e8c4884 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -19,6 +19,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkBadging;
 import android.os.BatteryManager;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.print.PrintManager;
 import android.provider.Settings;
@@ -30,6 +31,12 @@
 import java.text.NumberFormat;
 
 public class Utils {
+    /** Broadcast intent action when the location mode is about to change. */
+    private static final String MODE_CHANGING_ACTION =
+            "com.android.settings.location.MODE_CHANGING";
+    private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
+    private static final String NEW_MODE_KEY = "NEW_MODE";
+
     private static Signature[] sSystemSignature;
     private static String sPermissionControllerPackageName;
     private static String sServicesSystemSharedLibPackageName;
@@ -43,6 +50,18 @@
           com.android.internal.R.drawable.ic_signal_wifi_badged_4_bars
     };
 
+    public static boolean updateLocationMode(Context context, int oldMode, int newMode,
+            int userId) {
+        Intent intent = new Intent(MODE_CHANGING_ACTION);
+        intent.putExtra(CURRENT_MODE_KEY, oldMode);
+        intent.putExtra(NEW_MODE_KEY, newMode);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        context.sendBroadcastAsUser(intent, UserHandle.of(userId),
+                android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        return Settings.Secure.putIntForUser(context.getContentResolver(),
+                Settings.Secure.LOCATION_MODE, newMode, userId);
+    }
+
     /**
      * Return string resource that best describes combination of tethering
      * options available on this device.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 06d00be..27d461b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1836,20 +1836,10 @@
         }
 
         if (upgradeVersion < 116) {
-            if (mUserHandle == UserHandle.USER_SYSTEM) {
-                db.beginTransaction();
-                SQLiteStatement stmt = null;
-                try {
-                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
-                            + " VALUES(?,?);");
-                    loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
-                            ImsConfig.FeatureValueConstants.ON);
-                    db.setTransactionSuccessful();
-                } finally {
-                    db.endTransaction();
-                    if (stmt != null) stmt.close();
-                }
-            }
+            /*
+             * To control the default value by carrier config manager, initializing
+             * ENHANCED_4G_MODE_ENABLED has been removed.
+             */
             upgradeVersion = 116;
         }
 
@@ -2633,9 +2623,6 @@
 
             loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
 
-            loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
-                    ImsConfig.FeatureValueConstants.ON);
-
             /*
              * IMPORTANT: Do not add any more upgrade steps here as the global,
              * secure, and system settings are no longer stored in a database
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 819ee3e..d256b12 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -720,6 +720,9 @@
                 Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
                 GlobalSettingsProto.BLUETOOTH_PAN_PRIORITY_PREFIX);
         dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_HEARING_AID_PRIORITY_PREFIX);
+        dumpSetting(s, p,
                 Settings.Global.DEVICE_IDLE_CONSTANTS,
                 GlobalSettingsProto.DEVICE_IDLE_CONSTANTS);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index ca58080..e1371e8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -600,9 +600,7 @@
         @Override
         public void onTaskStackChanged() {
             if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
-            if (!checkCurrentUserId(mContext, DEBUG)) {
-                return;
-            }
+
             if (getState() != STATE_NO_PIP) {
                 boolean hasPip = false;
 
@@ -637,9 +635,7 @@
         @Override
         public void onActivityPinned(String packageName, int taskId) {
             if (DEBUG) Log.d(TAG, "onActivityPinned()");
-            if (!checkCurrentUserId(mContext, DEBUG)) {
-                return;
-            }
+
             StackInfo stackInfo = getPinnedStackInfo();
             if (stackInfo == null) {
                 Log.w(TAG, "Cannot find pinned stack");
@@ -664,9 +660,7 @@
         @Override
         public void onPinnedActivityRestartAttempt(boolean clearedTask) {
             if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
-            if (!checkCurrentUserId(mContext, DEBUG)) {
-                return;
-            }
+
             // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
             movePipToFullscreen();
         }
@@ -674,9 +668,7 @@
         @Override
         public void onPinnedStackAnimationEnded() {
             if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
-            if (!checkCurrentUserId(mContext, DEBUG)) {
-                return;
-            }
+
             switch (getState()) {
                 case STATE_PIP_MENU:
                     showPipMenu();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 874f0d9..6d6aa52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -39,6 +39,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.android.settingslib.Utils.updateLocationMode;
+
 /**
  * A controller to manage changes of location related states and update the views accordingly.
  */
@@ -106,12 +108,13 @@
         final ContentResolver cr = mContext.getContentResolver();
         // When enabling location, a user consent dialog will pop up, and the
         // setting won't be fully enabled until the user accepts the agreement.
+        int currentMode = Settings.Secure.getIntForUser(cr, Settings.Secure.LOCATION_MODE,
+                Settings.Secure.LOCATION_MODE_OFF, currentUserId);
         int mode = enabled
                 ? Settings.Secure.LOCATION_MODE_PREVIOUS : Settings.Secure.LOCATION_MODE_OFF;
         // QuickSettings always runs as the owner, so specifically set the settings
         // for the current foreground user.
-        return Settings.Secure
-                .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+        return updateLocationMode(mContext, currentMode, mode, currentUserId);
     }
 
     /**
diff --git a/proto/src/ipconnectivity.proto b/proto/src/ipconnectivity.proto
index 8dd35af..7979302 100644
--- a/proto/src/ipconnectivity.proto
+++ b/proto/src/ipconnectivity.proto
@@ -50,9 +50,10 @@
   optional int32 value = 2;
 };
 
-// An event record when the system default network disconnects or the system
-// switches to a new default network.
-// Next tag: 10.
+// An event recorded when the system default network disconnects or the system
+// switches to a new default network. An event is also recorded to cover gaps
+// without a default network.
+// Next tag: 12
 message DefaultNetworkEvent {
 
   // Reason why this network stopped being the default.
@@ -72,26 +73,34 @@
   };
 
   // Duration in milliseconds when this network was the default.
-  // Since version 4
+  // Since P.
   optional int64 default_network_duration_ms = 5;
 
-  // Duration in milliseconds without a default network before this network
-  // became the default.
-  // Since version 4
-  optional int64 no_default_network_duration_ms = 6;
+  // Duration in milliseconds when this default network Internet access was
+  // validated. This field is equal to 0 for DefaultNetworkEvents representing
+  // lack of a default network.
+  // Since P.
+  optional int64 validation_duration_ms = 11;
 
   // Network score of this network when it became the default network.
-  // Since version 4
+  // Or 0 if this event represents a period without a default network.
+  // Since P.
   optional int64 initial_score = 7;
 
   // Network score of this network when it stopped being the default network.
-  // Since version 4
+  // Or 0 if this event represents a period without a default network.
+  // Since P.
   optional int64 final_score = 8;
 
   // Best available information about IP support of this default network.
-  // Since version 4
+  // Or NONE if this event represents a period without a default network.
+  // Since P.
   optional IPSupport ip_support = 9;
 
+  // LinkLayer of the previous default network. Ignores any previous period
+  // without a default network.
+  // Since P
+  optional LinkLayer previous_default_network_link_layer = 10;
 
   // Deprecated fields
 
@@ -112,6 +121,11 @@
   // TRANSPORT_* constants as defined in NetworkCapabilities.
   // Deprecated since version 3. Replaced by top-level transports field.
   repeated int32 transport_types = 4 [deprecated = true];
+
+  // Duration in milliseconds without a default network. This field is non-zero
+  // only for DefaultNetworkEvents representing lack of a default network.
+  // Since P.
+  optional int64 no_default_network_duration_ms = 6 [deprecated = true];
 };
 
 // Logs IpReachabilityMonitor probe events and NUD_FAILED events.
@@ -475,7 +489,7 @@
 
 // Represents statistics from NFLOG wakeup events due to ingress packets.
 // Since oc-mr1.
-// Next tag: 8.
+// Next tag: 13.
 message WakeupStats {
   // The time duration in seconds covered by these stats, for deriving
   // exact wakeup rates.
@@ -503,6 +517,24 @@
 
   // The total number of wakeup packets with no associated socket or uid.
   optional int64 no_uid_wakeups = 7;
+
+  // Counts of all different ethertype values from wakeup packets received.
+  repeated Pair ethertype_counts = 8;
+
+  // Counts of all different IP next header values from wakeup packets received.
+  repeated Pair ip_next_header_counts = 9;
+
+  // The total number of wakeup packets whose destination hardware address was
+  // a unicast address.
+  optional int64 l2_unicast_count = 10;
+
+  // The total number of wakeup packets whose destination hardware address was
+  // a multicast address.
+  optional int64 l2_multicast_count = 11;
+
+  // The total number of wakeup packets whose destination hardware address was
+  // a broadcast address.
+  optional int64 l2_broadcast_count = 12;
 }
 
 // Represents one of the IP connectivity event defined in this file.
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index a4849fc..0e2c46b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4221,6 +4221,16 @@
 
     // ---- End O-DR1 Constants, all O-DR1 constants go above this line ----
 
+    // ACTION: Settings > Network & Internet > Mobile network > Mobile data
+    // CATEGORY: SETTINGS
+    // OS: O MR
+    ACTION_MOBILE_NETWORK_MOBILE_DATA_TOGGLE = 1081;
+
+    // ACTION: Settings > Network & Internet > Mobile network > Data usage
+    // CATEGORY: SETTINGS
+    // OS: O MR
+    ACTION_MOBILE_NETWORK_DATA_USAGE = 1082;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index cb91f93..e37347a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -499,6 +499,16 @@
         }
 
         @Override
+        public void removeClient(IAutoFillManagerClient client, int userId) {
+            synchronized (mLock) {
+                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+                if (service != null) {
+                    service.removeClientLocked(client);
+                }
+            }
+        }
+
+        @Override
         public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId,
                 int userId) {
             synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 751c054..5c63b90 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -261,6 +261,12 @@
         return isEnabled();
     }
 
+    void removeClientLocked(IAutoFillManagerClient client) {
+        if (mClients != null) {
+            mClients.unregister(client);
+        }
+    }
+
     void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
         if (!isEnabled()) {
             return;
@@ -478,6 +484,10 @@
         }
 
         sendStateToClients(true);
+        if (mClients != null) {
+            mClients.kill();
+            mClients = null;
+        }
     }
 
     CharSequence getServiceLabel() {
@@ -605,6 +615,9 @@
             }
         }
 
+        pw.print(prefix); pw.println("Clients");
+        mClients.dump(pw, prefix2);
+
         if (mEventHistory == null || mEventHistory.getEvents() == null
                 || mEventHistory.getEvents().size() == 0) {
             pw.print(prefix); pw.println("No event on last fill response");
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 75206e4..04279a3 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -195,6 +195,7 @@
     private LinkedList<ActiveLog> mActiveLogs;
     private LinkedList<Long> mCrashTimestamps;
     private int mCrashes;
+    private long mLastEnabledTime;
 
     // configuration from external IBinder call which is used to
     // synchronize with broadcast receiver.
@@ -2021,6 +2022,7 @@
         mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
                              quietMode ? 1 : 0, 0));
         addActiveLog(packageName, true);
+        mLastEnabledTime = SystemClock.elapsedRealtime();
     }
 
     private void addActiveLog(String packageName, boolean enable) {
@@ -2142,37 +2144,32 @@
             writer.println("  address: " + mAddress);
             writer.println("  name: " + mName);
             if (mEnable) {
-                long onDuration = System.currentTimeMillis() - mActiveLogs.getLast().getTime();
+                long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime;
                 String onDurationString = String.format("%02d:%02d:%02d.%03d",
                                           (int)(onDuration / (1000 * 60 * 60)),
                                           (int)((onDuration / (1000 * 60)) % 60),
                                           (int)((onDuration / 1000) % 60),
                                           (int)(onDuration % 1000));
-                writer.println("  time since enabled: " + onDurationString + "\n");
+                writer.println("  time since enabled: " + onDurationString);
             }
 
             if (mActiveLogs.size() == 0) {
-                writer.println("Bluetooth never enabled!");
+                writer.println("\nBluetooth never enabled!");
             } else {
-                writer.println("Enable log:");
+                writer.println("\nEnable log:");
                 for (ActiveLog log : mActiveLogs) {
                     writer.println("  " + log);
                 }
             }
 
-            writer.println("Bluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s"));
+            writer.println("\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s"));
             if (mCrashes == CRASH_LOG_MAX_SIZE) writer.println("(last " + CRASH_LOG_MAX_SIZE + ")");
             for (Long time : mCrashTimestamps) {
               writer.println("  " + timeToLog(time.longValue()));
             }
 
-            String bleAppString = "No BLE Apps registered.";
-            if (mBleApps.size() == 1) {
-                bleAppString = "1 BLE App registered:";
-            } else if (mBleApps.size() > 1) {
-                bleAppString = mBleApps.size() + " BLE Apps registered:";
-            }
-            writer.println("\n" + bleAppString);
+            writer.println("\n" + mBleApps.size() + " BLE app" +
+                            (mBleApps.size() == 1 ? "" : "s") + "registered");
             for (ClientDeathRecipient app : mBleApps.values()) {
                 writer.println("  " + app.getPackageName());
             }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 708bcdd..ce19a1c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2113,9 +2113,14 @@
                         final boolean valid =
                                 (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
                         final boolean wasValidated = nai.lastValidated;
+                        final boolean wasDefault = isDefaultNetwork(nai);
                         if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
                                 (msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
                         if (valid != nai.lastValidated) {
+                            if (wasDefault) {
+                                metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
+                                        SystemClock.elapsedRealtime(), valid);
+                            }
                             final int oldScore = nai.getCurrentScore();
                             nai.lastValidated = valid;
                             nai.everValidated |= valid;
@@ -2287,7 +2292,8 @@
                 // Let rematchAllNetworksAndRequests() below record a new default network event
                 // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
                 // whose timestamps tell how long it takes to recover a default network.
-                metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(null, nai);
+                long now = SystemClock.elapsedRealtime();
+                metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
             }
             notifyIfacesChangedForNetworkStats();
             // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -5041,7 +5047,7 @@
             makeDefault(newNetwork);
             // Log 0 -> X and Y -> X default network transitions, where X is the new default.
             metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
-                    newNetwork, oldDefaultNetwork);
+                    now, newNetwork, oldDefaultNetwork);
             // Have a new default network, release the transition wakelock in
             scheduleReleaseNetworkTransitionWakelock();
         }
@@ -5599,7 +5605,8 @@
     }
 
     private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
-        mMetricsLog.log(new NetworkEvent(nai.network.netId, evtype));
+        int[] transports = nai.networkCapabilities.getTransportTypes();
+        mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
     }
 
     private static boolean toBool(int encodedBoolean) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index b1d6f73..7c73818 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -20,6 +20,9 @@
 import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.NETWORK_STACK;
 import static android.Manifest.permission.SHUTDOWN;
+import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
@@ -92,6 +95,7 @@
 import android.telephony.PhoneStateListener;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -1946,9 +1950,9 @@
     public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        ContentResolver resolver = mContext.getContentResolver();
+        final ContentResolver cr = mContext.getContentResolver();
 
-        int sampleValidity = Settings.Global.getInt(resolver,
+        int sampleValidity = Settings.Global.getInt(cr,
                 Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
                 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
         if (sampleValidity < 0 || sampleValidity > 65535) {
@@ -1957,7 +1961,7 @@
             sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
         }
 
-        int successThreshold = Settings.Global.getInt(resolver,
+        int successThreshold = Settings.Global.getInt(cr,
                 Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
                 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
         if (successThreshold < 0 || successThreshold > 100) {
@@ -1966,9 +1970,9 @@
             successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
         }
 
-        int minSamples = Settings.Global.getInt(resolver,
+        int minSamples = Settings.Global.getInt(cr,
                 Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
-        int maxSamples = Settings.Global.getInt(resolver,
+        int maxSamples = Settings.Global.getInt(cr,
                 Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
         if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) {
             Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples +
@@ -1980,8 +1984,24 @@
 
         final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
         final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
-        final boolean useTls = Settings.Global.getInt(resolver,
-                Settings.Global.DNS_TLS_DISABLED, 0) == 0;
+        final boolean useTls = shouldUseTls(cr);
+        // TODO: Populate tlsHostname once it's decided how the hostname's IP
+        // addresses will be resolved:
+        //
+        //     [1] network-provided DNS servers are included here with the
+        //         hostname and netd will use the network-provided servers to
+        //         resolve the hostname and fix up its internal structures, or
+        //
+        //     [2] network-provided DNS servers are included here without the
+        //         hostname, the ConnectivityService layer resolves the given
+        //         hostname, and then reconfigures netd with this information.
+        //
+        // In practice, there will always be a need for ConnectivityService or
+        // the captive portal app to use the network-provided services to make
+        // some queries. This argues in favor of [1], in concert with another
+        // mechanism, perhaps setting a high bit in the netid, to indicate
+        // via existing DNS APIs which set of servers (network-provided or
+        // non-network-provided private DNS) should be queried.
         final String tlsHostname = "";
         final String[] tlsFingerprints = new String[0];
         try {
@@ -1992,6 +2012,15 @@
         }
     }
 
+    private static boolean shouldUseTls(ContentResolver cr) {
+        String privateDns = Settings.Global.getString(cr, Settings.Global.PRIVATE_DNS_MODE);
+        if (TextUtils.isEmpty(privateDns)) {
+            privateDns = PRIVATE_DNS_DEFAULT_MODE;
+        }
+        return privateDns.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) ||
+               privateDns.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+    }
+
     @Override
     public void addVpnUidRanges(int netId, UidRange[] ranges) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index e609bd7..831c9cb 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1356,31 +1356,6 @@
         }
     }
 
-    public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) {
-        if (!checkNotifyPermission("notifyOemHookRawEventForSubscriber")) {
-            return;
-        }
-
-        synchronized (mRecords) {
-            for (Record r : mRecords) {
-                if (VDBG) {
-                    log("notifyOemHookRawEventForSubscriber:  r=" + r + " subId=" + subId);
-                }
-                if ((r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT)) &&
-                        ((r.subId == subId) ||
-                        (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID))) {
-                    try {
-                        r.callback.onOemHookRawEvent(rawData);
-                    } catch (RemoteException ex) {
-                        mRemoveList.add(r.binder);
-                    }
-                }
-            }
-            handleRemoveListLocked();
-        }
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
@@ -1673,11 +1648,6 @@
                     android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
 
         }
-
-        if ((events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
-        }
     }
 
     private void handleRemoveListLocked() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d9944a7..70c08c9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3808,6 +3808,10 @@
                 gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                 gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
                 gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
+
+                // Replace any invalid GIDs
+                if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
+                if (gids[1] == UserHandle.ERR_GID) gids[1] = gids[2];
             }
             checkTime(startTime, "startProcess: building args");
             if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
@@ -3857,7 +3861,7 @@
             }
 
             if (app.info.isPrivilegedApp() &&
-                    !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) {
+                    SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
                 runtimeFlags |= Zygote.DISABLE_VERIFIER;
                 runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
             }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index fe006fc..253bdc5 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -133,7 +133,6 @@
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.IBinder;
@@ -897,7 +896,15 @@
 
         Entry ent = AttributeCache.instance().get(packageName,
                 realTheme, com.android.internal.R.styleable.Window, userId);
-        fullscreen = ent != null && !ActivityInfo.isTranslucentOrFloating(ent.array);
+        final boolean translucent = ent != null && (ent.array.getBoolean(
+                com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+                || (!ent.array.hasValue(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent)
+                        && ent.array.getBoolean(
+                                com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+                                        false)));
+        fullscreen = ent != null && !ent.array.getBoolean(
+                com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
         noDisplay = ent != null && ent.array.getBoolean(
                 com.android.internal.R.styleable.Window_windowNoDisplay, false);
 
@@ -2195,11 +2202,6 @@
     }
 
     void setRequestedOrientation(int requestedOrientation) {
-        if (ActivityInfo.isFixedOrientation(requestedOrientation) && !fullscreen
-                && appInfo.targetSdkVersion > O) {
-            throw new IllegalStateException("Only fullscreen activities can request orientation");
-        }
-
         final int displayId = getDisplayId();
         final Configuration displayConfig =
                 mStackSupervisor.getDisplayOverrideConfiguration(displayId);
diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index 8981db1..28c3585 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -18,9 +18,11 @@
 
 import android.net.LinkProperties;
 import android.net.metrics.DefaultNetworkEvent;
-import android.net.metrics.IpConnectivityLog;
+import android.os.SystemClock;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.BitUtils;
+import com.android.internal.util.RingBuffer;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
 
 import java.io.PrintWriter;
@@ -35,19 +37,49 @@
 
     private static final int ROLLING_LOG_SIZE = 64;
 
+    public final long creationTimeMs = SystemClock.elapsedRealtime();
+
     // Event buffer used for metrics upload. The buffer is cleared when events are collected.
     @GuardedBy("this")
     private final List<DefaultNetworkEvent> mEvents = new ArrayList<>();
 
+    // Rolling event buffer used for dumpsys and bugreports.
+    @GuardedBy("this")
+    private final RingBuffer<DefaultNetworkEvent> mEventsLog =
+            new RingBuffer(DefaultNetworkEvent.class, ROLLING_LOG_SIZE);
+
+    // Information about the current status of the default network.
+    @GuardedBy("this")
+    private DefaultNetworkEvent mCurrentDefaultNetwork;
+    @GuardedBy("this")
+    private boolean mIsCurrentlyValid;
+    @GuardedBy("this")
+    private long mLastValidationTimeMs;
+    // Transport information about the last default network.
+    @GuardedBy("this")
+    private int mLastTransports;
+
+    public DefaultNetworkMetrics() {
+        newDefaultNetwork(creationTimeMs, null);
+    }
+
     public synchronized void listEvents(PrintWriter pw) {
+        pw.println("default network events:");
         long localTimeMs = System.currentTimeMillis();
-        for (DefaultNetworkEvent ev : mEvents) {
-            pw.println(ev);
+        long timeMs = SystemClock.elapsedRealtime();
+        for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
+            printEvent(localTimeMs, pw, ev);
         }
+        mCurrentDefaultNetwork.updateDuration(timeMs);
+        if (mIsCurrentlyValid) {
+            updateValidationTime(timeMs);
+            mLastValidationTimeMs = timeMs;
+        }
+        printEvent(localTimeMs, pw, mCurrentDefaultNetwork);
     }
 
     public synchronized void listEventsAsProto(PrintWriter pw) {
-        for (DefaultNetworkEvent ev : mEvents) {
+        for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
             pw.print(IpConnectivityEventBuilder.toProto(ev));
         }
     }
@@ -59,20 +91,75 @@
         mEvents.clear();
     }
 
-    public synchronized void logDefaultNetworkEvent(
-            NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
-        DefaultNetworkEvent ev = new DefaultNetworkEvent();
-        if (newNai != null) {
-            ev.netId = newNai.network().netId;
-            ev.transportTypes = newNai.networkCapabilities.getTransportTypes();
-        }
-        if (prevNai != null) {
-            ev.prevNetId = prevNai.network().netId;
-            final LinkProperties lp = prevNai.linkProperties;
-            ev.prevIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
-            ev.prevIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+    public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) {
+        if (!isValid && mIsCurrentlyValid) {
+            mIsCurrentlyValid = false;
+            updateValidationTime(timeMs);
         }
 
+        if (isValid && !mIsCurrentlyValid) {
+            mIsCurrentlyValid = true;
+            mLastValidationTimeMs = timeMs;
+        }
+    }
+
+    private void updateValidationTime(long timeMs) {
+        mCurrentDefaultNetwork.validatedMs += timeMs - mLastValidationTimeMs;
+    }
+
+    public synchronized void logDefaultNetworkEvent(
+            long timeMs, NetworkAgentInfo newNai, NetworkAgentInfo oldNai) {
+        logCurrentDefaultNetwork(timeMs, oldNai);
+        newDefaultNetwork(timeMs, newNai);
+    }
+
+    private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) {
+        DefaultNetworkEvent ev = mCurrentDefaultNetwork;
+        ev.updateDuration(timeMs);
+        ev.previousTransports = mLastTransports;
+        // oldNai is null if the system had no default network before the transition.
+        if (oldNai != null) {
+            // The system acquired a new default network.
+            fillLinkInfo(ev, oldNai);
+            ev.finalScore = oldNai.getCurrentScore();
+            ev.validatedMs = ev.durationMs;
+        }
+        // Only change transport of the previous default network if the event currently logged
+        // corresponds to an existing default network, and not to the absence of a default network.
+        // This allows to log pairs of transports for successive default networks regardless of
+        // whether or not the system experienced a period without any default network.
+        if (ev.transports != 0) {
+            mLastTransports = ev.transports;
+        }
         mEvents.add(ev);
+        mEventsLog.append(ev);
+    }
+
+    private void newDefaultNetwork(long timeMs, NetworkAgentInfo newNai) {
+        DefaultNetworkEvent ev = new DefaultNetworkEvent(timeMs);
+        ev.durationMs = timeMs;
+        // newNai is null if the system has no default network after the transition.
+        if (newNai != null) {
+            fillLinkInfo(ev, newNai);
+            ev.initialScore = newNai.getCurrentScore();
+            if (newNai.lastValidated) {
+                mIsCurrentlyValid = true;
+                mLastValidationTimeMs = timeMs;
+            }
+        }
+        mCurrentDefaultNetwork = ev;
+    }
+
+    private static void fillLinkInfo(DefaultNetworkEvent ev, NetworkAgentInfo nai) {
+        LinkProperties lp = nai.linkProperties;
+        ev.netId = nai.network().netId;
+        ev.transports |= BitUtils.packBits(nai.networkCapabilities.getTransportTypes());
+        ev.ipv4 |= lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
+        ev.ipv6 |= lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+    }
+
+    private static void printEvent(long localTimeMs, PrintWriter pw, DefaultNetworkEvent ev) {
+        long localCreationTimeMs = localTimeMs - ev.durationMs;
+        pw.println(String.format("%tT.%tL: %s", localCreationTimeMs, localCreationTimeMs, ev));
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index 3d71ecb..397af7b 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -25,6 +25,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
 
+import android.net.ConnectivityManager;
 import android.net.ConnectivityMetricsEvent;
 import android.net.metrics.ApfProgramEvent;
 import android.net.metrics.ApfStats;
@@ -45,7 +46,6 @@
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.NetworkId;
 import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.Pair;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -127,6 +127,11 @@
         wakeupStats.nonApplicationWakeups = in.nonApplicationWakeups;
         wakeupStats.applicationWakeups = in.applicationWakeups;
         wakeupStats.noUidWakeups = in.noUidWakeups;
+        wakeupStats.l2UnicastCount = in.l2UnicastCount;
+        wakeupStats.l2MulticastCount = in.l2MulticastCount;
+        wakeupStats.l2BroadcastCount = in.l2BroadcastCount;
+        wakeupStats.ethertypeCounts = toPairArray(in.ethertypes);
+        wakeupStats.ipNextHeaderCounts = toPairArray(in.ipNextHeaders);
         final IpConnectivityEvent out = buildEvent(0, 0, in.iface);
         out.setWakeupStats(wakeupStats);
         return out;
@@ -135,11 +140,17 @@
     public static IpConnectivityEvent toProto(DefaultNetworkEvent in) {
         IpConnectivityLogClass.DefaultNetworkEvent ev =
                 new IpConnectivityLogClass.DefaultNetworkEvent();
-        ev.networkId = netIdOf(in.netId);
-        ev.previousNetworkId = netIdOf(in.prevNetId);
-        ev.transportTypes = in.transportTypes;
-        ev.previousNetworkIpSupport = ipSupportOf(in);
-        final IpConnectivityEvent out = buildEvent(in.netId, 0, null);
+        ev.finalScore = in.finalScore;
+        ev.initialScore = in.initialScore;
+        ev.ipSupport = ipSupportOf(in);
+        ev.defaultNetworkDurationMs = in.durationMs;
+        ev.validationDurationMs = in.validatedMs;
+        ev.previousDefaultNetworkLinkLayer = transportsToLinkLayer(in.previousTransports);
+        final IpConnectivityEvent out = buildEvent(in.netId, in.transports, null);
+        if (in.transports == 0) {
+            // Set link layer to NONE for events representing the absence of a default network.
+            out.linkLayer = IpConnectivityLogClass.NONE;
+        }
         out.setDefaultNetworkEvent(ev);
         return out;
     }
@@ -235,7 +246,6 @@
     private static void setNetworkEvent(IpConnectivityEvent out, NetworkEvent in) {
         IpConnectivityLogClass.NetworkEvent networkEvent =
                 new IpConnectivityLogClass.NetworkEvent();
-        networkEvent.networkId = netIdOf(in.netId);
         networkEvent.eventType = in.eventType;
         networkEvent.latencyMs = (int) in.durationMs;
         out.setNetworkEvent(networkEvent);
@@ -314,20 +324,14 @@
         return pairs;
     }
 
-    private static NetworkId netIdOf(int netid) {
-        final NetworkId ni = new NetworkId();
-        ni.networkId = netid;
-        return ni;
-    }
-
     private static int ipSupportOf(DefaultNetworkEvent in) {
-        if (in.prevIPv4 && in.prevIPv6) {
+        if (in.ipv4 && in.ipv6) {
             return IpConnectivityLogClass.DefaultNetworkEvent.DUAL;
         }
-        if (in.prevIPv6) {
+        if (in.ipv6) {
             return IpConnectivityLogClass.DefaultNetworkEvent.IPV6;
         }
-        if (in.prevIPv4) {
+        if (in.ipv4) {
             return IpConnectivityLogClass.DefaultNetworkEvent.IPV4;
         }
         return IpConnectivityLogClass.DefaultNetworkEvent.NONE;
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 24217e6..f427819 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -23,8 +23,6 @@
 import android.net.metrics.ApfProgramEvent;
 import android.net.metrics.IpConnectivityLog;
 import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcelable;
 import android.os.Process;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -45,6 +43,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.function.ToIntFunction;
 
@@ -214,86 +213,66 @@
     }
 
     /**
-     * Clears the event buffer and prints its content as a protobuf serialized byte array
+     * Clear the event buffer and prints its content as a protobuf serialized byte array
      * inside a base64 encoded string.
      */
-    private void cmdFlush(FileDescriptor fd, PrintWriter pw, String[] args) {
+    private void cmdFlush(PrintWriter pw) {
         pw.print(flushEncodedOutput());
     }
 
     /**
-     * Prints the content of the event buffer, either using the events ASCII representation
-     * or using protobuf text format.
+     * Print the content of the rolling event buffer in human readable format.
+     * Also print network dns/connect statistics and recent default network events.
      */
-    private void cmdList(FileDescriptor fd, PrintWriter pw, String[] args) {
-        final ArrayList<ConnectivityMetricsEvent> events;
-        synchronized (mLock) {
-            events = new ArrayList(mBuffer);
-        }
-
-        if (args.length > 1 && args[1].equals("proto")) {
-            for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
-                pw.print(ev.toString());
-            }
-            if (mNetdListener != null) {
-                mNetdListener.listAsProtos(pw);
-            }
-            mDefaultNetworkMetrics.listEventsAsProto(pw);
-            return;
-        }
-
+    private void cmdList(PrintWriter pw) {
+        pw.println("metrics events:");
+        final List<ConnectivityMetricsEvent> events = getEvents();
         for (ConnectivityMetricsEvent ev : events) {
             pw.println(ev.toString());
         }
+        pw.println("");
         if (mNetdListener != null) {
             mNetdListener.list(pw);
         }
+        pw.println("");
         mDefaultNetworkMetrics.listEvents(pw);
     }
 
-    /**
-     * Prints for bug reports the content of the rolling event log and the
-     * content of Netd event listener.
+    /*
+     * Print the content of the rolling event buffer in text proto format.
      */
-    private void cmdDumpsys(FileDescriptor fd, PrintWriter pw, String[] args) {
-        final ConnectivityMetricsEvent[] events;
-        synchronized (mLock) {
-            events = mEventLog.toArray();
-        }
-        for (ConnectivityMetricsEvent ev : events) {
-            pw.println(ev.toString());
+    private void cmdListAsProto(PrintWriter pw) {
+        final List<ConnectivityMetricsEvent> events = getEvents();
+        for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
+            pw.print(ev.toString());
         }
         if (mNetdListener != null) {
-            mNetdListener.list(pw);
+            mNetdListener.listAsProtos(pw);
         }
-        mDefaultNetworkMetrics.listEvents(pw);
+        mDefaultNetworkMetrics.listEventsAsProto(pw);
     }
 
-    private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
+    /*
+     * Return a copy of metrics events stored in buffer for metrics uploading.
+     */
+    private List<ConnectivityMetricsEvent> getEvents() {
         synchronized (mLock) {
-            pw.println("Buffered events: " + mBuffer.size());
-            pw.println("Buffer capacity: " + mCapacity);
-            pw.println("Dropped events: " + mDropped);
+            return Arrays.asList(mEventLog.toArray());
         }
-        if (mNetdListener != null) {
-            mNetdListener.dump(pw);
-        }
-    }
-
-    private void cmdDefault(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (args.length == 0) {
-            pw.println("No command");
-            return;
-        }
-        pw.println("Unknown command " + TextUtils.join(" ", args));
     }
 
     public final class Impl extends IIpConnectivityMetrics.Stub {
-        static final String CMD_FLUSH   = "flush";
-        static final String CMD_LIST    = "list";
-        static final String CMD_STATS   = "stats";
-        static final String CMD_DUMPSYS = "-a"; // dumpsys.cpp dumps services with "-a" as arguments
-        static final String CMD_DEFAULT = CMD_STATS;
+        // Dump and flushes the metrics event buffer in base64 encoded serialized proto output.
+        static final String CMD_FLUSH = "flush";
+        // Dump the rolling buffer of metrics event in human readable proto text format.
+        static final String CMD_PROTO = "proto";
+        // Dump the rolling buffer of metrics event and pretty print events using a human readable
+        // format. Also print network dns/connect statistics and default network event time series.
+        static final String CMD_LIST = "list";
+        // By default any other argument will fall into the default case which is remapped to the
+        // "list" command. This includes most notably bug reports collected by dumpsys.cpp with
+        // the "-a" argument.
+        static final String CMD_DEFAULT = CMD_LIST;
 
         @Override
         public int logEvent(ConnectivityMetricsEvent event) {
@@ -308,19 +287,15 @@
             final String cmd = (args.length > 0) ? args[0] : CMD_DEFAULT;
             switch (cmd) {
                 case CMD_FLUSH:
-                    cmdFlush(fd, pw, args);
+                    cmdFlush(pw);
                     return;
-                case CMD_DUMPSYS:
-                    cmdDumpsys(fd, pw, args);
+                case CMD_PROTO:
+                    cmdListAsProto(pw);
                     return;
-                case CMD_LIST:
-                    cmdList(fd, pw, args);
-                    return;
-                case CMD_STATS:
-                    cmdStats(fd, pw, args);
-                    return;
+                case CMD_LIST: // fallthrough
                 default:
-                    cmdDefault(fd, pw, args);
+                    cmdList(pw);
+                    return;
             }
         }
 
@@ -345,22 +320,22 @@
         }
 
         @Override
-        public boolean registerNetdEventCallback(INetdEventCallback callback) {
+        public boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
             enforceNetdEventListeningPermission();
             if (mNetdListener == null) {
                 return false;
             }
-            return mNetdListener.registerNetdEventCallback(callback);
+            return mNetdListener.addNetdEventCallback(callerType, callback);
         }
 
         @Override
-        public boolean unregisterNetdEventCallback() {
+        public boolean removeNetdEventCallback(int callerType) {
             enforceNetdEventListeningPermission();
             if (mNetdListener == null) {
                 // if the service is null, we aren't registered anyway
                 return true;
             }
-            return mNetdListener.unregisterNetdEventCallback();
+            return mNetdListener.removeNetdEventCallback(callerType);
         }
     };
 
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 05c6e69..6f2d77f 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.INetdEventCallback;
+import android.net.MacAddress;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.metrics.ConnectStats;
@@ -58,7 +59,6 @@
 
     private static final String TAG = NetdEventListenerService.class.getSimpleName();
     private static final boolean DBG = false;
-    private static final boolean VDBG = false;
 
     // Rate limit connect latency logging to 1 measurement per 15 seconds (5760 / day) with maximum
     // bursts of 5000 measurements.
@@ -98,21 +98,55 @@
     @GuardedBy("this")
     private final TokenBucket mConnectTb =
             new TokenBucket(CONNECT_LATENCY_FILL_RATE, CONNECT_LATENCY_BURST_LIMIT);
-    // Callback should only be registered/unregistered when logging is being enabled/disabled in DPM
-    // by the device owner. It's DevicePolicyManager's responsibility to ensure that.
-    @GuardedBy("this")
-    private INetdEventCallback mNetdEventCallback;
 
-    public synchronized boolean registerNetdEventCallback(INetdEventCallback callback) {
-        mNetdEventCallback = callback;
+
+    /**
+     * There are only 2 possible callbacks.
+     *
+     * mNetdEventCallbackList[CALLBACK_CALLER_DEVICE_POLICY].
+     * Callback registered/unregistered when logging is being enabled/disabled in DPM
+     * by the device owner. It's DevicePolicyManager's responsibility to ensure that.
+     *
+     * mNetdEventCallbackList[CALLBACK_CALLER_NETWORK_WATCHLIST]
+     * Callback registered/unregistered by NetworkWatchlistService.
+     */
+    @GuardedBy("this")
+    private static final int[] ALLOWED_CALLBACK_TYPES = {
+        INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY,
+        INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST
+    };
+
+    @GuardedBy("this")
+    private INetdEventCallback[] mNetdEventCallbackList =
+            new INetdEventCallback[ALLOWED_CALLBACK_TYPES.length];
+
+    public synchronized boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
+        if (!isValidCallerType(callerType)) {
+            Log.e(TAG, "Invalid caller type: " + callerType);
+            return false;
+        }
+        mNetdEventCallbackList[callerType] = callback;
         return true;
     }
 
-    public synchronized boolean unregisterNetdEventCallback() {
-        mNetdEventCallback = null;
+    public synchronized boolean removeNetdEventCallback(int callerType) {
+        if (!isValidCallerType(callerType)) {
+            Log.e(TAG, "Invalid caller type: " + callerType);
+            return false;
+        }
+        mNetdEventCallbackList[callerType] = null;
         return true;
     }
 
+    private static boolean isValidCallerType(int callerType) {
+        for (int i = 0; i < ALLOWED_CALLBACK_TYPES.length; i++) {
+            if (callerType == ALLOWED_CALLBACK_TYPES[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public NetdEventListenerService(Context context) {
         this(context.getSystemService(ConnectivityManager.class));
     }
@@ -164,13 +198,13 @@
     public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
             String hostname, String[] ipAddresses, int ipAddressesCount, int uid)
             throws RemoteException {
-        maybeVerboseLog("onDnsEvent(%d, %d, %d, %dms)", netId, eventType, returnCode, latencyMs);
-
         long timestamp = System.currentTimeMillis();
         getMetricsForNetwork(timestamp, netId).addDnsResult(eventType, returnCode, latencyMs);
 
-        if (mNetdEventCallback != null) {
-            mNetdEventCallback.onDnsEvent(hostname, ipAddresses, ipAddressesCount, timestamp, uid);
+        for (INetdEventCallback callback : mNetdEventCallbackList) {
+            if (callback != null) {
+                callback.onDnsEvent(hostname, ipAddresses, ipAddressesCount, timestamp, uid);
+            }
         }
     }
 
@@ -179,22 +213,23 @@
     // This method must not block or perform long-running operations.
     public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr,
             int port, int uid) throws RemoteException {
-        maybeVerboseLog("onConnectEvent(%d, %d, %dms)", netId, error, latencyMs);
-
         long timestamp = System.currentTimeMillis();
         getMetricsForNetwork(timestamp, netId).addConnectResult(error, latencyMs, ipAddr);
 
-        if (mNetdEventCallback != null) {
-            mNetdEventCallback.onConnectEvent(ipAddr, port, timestamp, uid);
+        for (INetdEventCallback callback : mNetdEventCallbackList) {
+            if (callback != null) {
+                // TODO(rickywai): Remove this checking to collect ip in watchlist.
+                if (callback ==
+                        mNetdEventCallbackList[INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY]) {
+                    callback.onConnectEvent(ipAddr, port, timestamp, uid);
+                }
+            }
         }
     }
 
     @Override
-    public synchronized void onWakeupEvent(String prefix, int uid, int gid, long timestampNs) {
-        maybeVerboseLog("onWakeupEvent(%s, %d, %d, %sns)", prefix, uid, gid, timestampNs);
-
-        // TODO: add ip protocol and port
-
+    public synchronized void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader,
+            byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, long timestampNs) {
         String iface = prefix.replaceFirst(WAKEUP_EVENT_IFACE_PREFIX, "");
         final long timestampMs;
         if (timestampNs > 0) {
@@ -203,15 +238,22 @@
             timestampMs = System.currentTimeMillis();
         }
 
-        addWakeupEvent(iface, timestampMs, uid);
-    }
-
-    @GuardedBy("this")
-    private void addWakeupEvent(String iface, long timestampMs, int uid) {
         WakeupEvent event = new WakeupEvent();
         event.iface = iface;
         event.timestampMs = timestampMs;
         event.uid = uid;
+        event.ethertype = ethertype;
+        event.dstHwAddr = new MacAddress(dstHw);
+        event.srcIp = srcIp;
+        event.dstIp = dstIp;
+        event.ipNextHeader = ipNextHeader;
+        event.srcPort = srcPort;
+        event.dstPort = dstPort;
+        addWakeupEvent(event);
+    }
+
+    private void addWakeupEvent(WakeupEvent event) {
+        String iface = event.iface;
         mWakeupEvents.append(event);
         WakeupStats stats = mWakeupStats.get(iface);
         if (stats == null) {
@@ -243,24 +285,21 @@
         mWakeupStats.clear();
     }
 
-    public synchronized void dump(PrintWriter writer) {
-        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
-        pw.println(TAG + ":");
-        pw.increaseIndent();
-        list(pw);
-        pw.decreaseIndent();
-    }
-
     public synchronized void list(PrintWriter pw) {
+        pw.println("dns/connect events:");
         for (int i = 0; i < mNetworkMetrics.size(); i++) {
             pw.println(mNetworkMetrics.valueAt(i).connectMetrics);
         }
         for (int i = 0; i < mNetworkMetrics.size(); i++) {
             pw.println(mNetworkMetrics.valueAt(i).dnsMetrics);
         }
+        pw.println("");
+        pw.println("network statistics:");
         for (NetworkMetricsSnapshot s : getNetworkMetricsSnapshots()) {
             pw.println(s);
         }
+        pw.println("");
+        pw.println("packet wakeup events:");
         for (int i = 0; i < mWakeupStats.size(); i++) {
             pw.println(mWakeupStats.valueAt(i));
         }
@@ -294,10 +333,6 @@
         if (DBG) Log.d(TAG, String.format(s, args));
     }
 
-    private static void maybeVerboseLog(String s, Object... args) {
-        if (VDBG) Log.d(TAG, String.format(s, args));
-    }
-
     /** Helper class for buffering summaries of NetworkMetrics at regular time intervals */
     static class NetworkMetricsSnapshot {
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 8b886d6..7684030 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -1129,7 +1129,8 @@
     }
 
     private void logNetworkEvent(int evtype) {
-        mMetricsLog.log(new NetworkEvent(mNetId, evtype));
+        int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
+        mMetricsLog.log(mNetId, transports, new NetworkEvent(evtype));
     }
 
     private int networkEventType(ValidationStage s, EvaluationResult r) {
@@ -1150,7 +1151,8 @@
 
     private void maybeLogEvaluationResult(int evtype) {
         if (mEvaluationTimer.isRunning()) {
-            mMetricsLog.log(new NetworkEvent(mNetId, evtype, mEvaluationTimer.stop()));
+            int[] transports = mNetworkAgentInfo.networkCapabilities.getTransportTypes();
+            mMetricsLog.log(mNetId, transports, new NetworkEvent(evtype, mEvaluationTimer.stop()));
             mEvaluationTimer.reset();
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index ef015e7..c6969ed 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -110,9 +110,9 @@
             return false;
         }
 
-        // We do not dexopt a priv-app package when pm.dexopt.priv-apps is false.
+        // We do not dexopt a priv-app package when pm.dexopt.priv-apps-oob is true.
         if (pkg.isPrivilegedApp()) {
-            return SystemProperties.getBoolean("pm.dexopt.priv-apps", true);
+            return !SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false);
         }
 
         return true;
@@ -128,6 +128,10 @@
     int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
             String[] instructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
+        if (pkg.applicationInfo.uid == -1) {
+            throw new IllegalArgumentException("Dexopt for " + pkg.packageName
+                    + " has invalid uid.");
+        }
         if (!canOptimizePackage(pkg)) {
             return DEX_OPT_SKIPPED;
         }
@@ -154,7 +158,13 @@
                 targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         final List<String> paths = pkg.getAllCodePaths();
-        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+
+        int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+        if (sharedGid == -1) {
+            Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID "
+                    + pkg.applicationInfo.uid, new Throwable());
+            sharedGid = android.os.Process.NOBODY_UID;
+        }
 
         // Get the class loader context dependencies.
         // For each code path in the package, this array contains the class loader context that
@@ -293,6 +303,9 @@
      */
     public int dexOptSecondaryDexPath(ApplicationInfo info, String path,
             PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
+        if (info.uid == -1) {
+            throw new IllegalArgumentException("Dexopt for path " + path + " has invalid uid.");
+        }
         synchronized (mInstallLock) {
             final long acquireTime = acquireWakeLockLI(info.uid);
             try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 242a76d..7f5beff 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3463,7 +3463,7 @@
         final int N = list.size();
         for (int i = 0; i < N; i++) {
             ResolveInfo info = list.get(i);
-            if (packageName.equals(info.activityInfo.packageName)) {
+            if (info.priority >= 0 && packageName.equals(info.activityInfo.packageName)) {
                 return true;
             }
         }
@@ -10270,7 +10270,7 @@
 
         if (Build.IS_DEBUGGABLE &&
                 pkg.isPrivilegedApp() &&
-                !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) {
+                SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
             PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
         }
 
@@ -18271,52 +18271,14 @@
             return;
         }
 
-        // Verify if we need to dexopt the app.
-        //
-        // NOTE: it is *important* to call dexopt after doRename which will sync the
-        // package data from PackageParser.Package and its corresponding ApplicationInfo.
-        //
-        // We only need to dexopt if the package meets ALL of the following conditions:
-        //   1) it is not forward locked.
-        //   2) it is not on on an external ASEC container.
-        //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
-        //
-        // Note that we do not dexopt instant apps by default. dexopt can take some time to
-        // complete, so we skip this step during installation. Instead, we'll take extra time
-        // the first time the instant app starts. It's preferred to do it this way to provide
-        // continuous progress to the useur instead of mysteriously blocking somewhere in the
-        // middle of running an instant app. The default behaviour can be overridden
-        // via gservices.
-        final boolean performDexopt = !forwardLocked
-            && !pkg.applicationInfo.isExternalAsec()
-            && (!instantApp || Global.getInt(mContext.getContentResolver(),
-                    Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0);
-
-        if (performDexopt) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-            // Do not run PackageDexOptimizer through the local performDexOpt
-            // method because `pkg` may not be in `mPackages` yet.
-            //
-            // Also, don't fail application installs if the dexopt step fails.
-            DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
-                REASON_INSTALL,
-                DexoptOptions.DEXOPT_BOOT_COMPLETE);
-            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
-                null /* instructionSets */,
-                getOrCreateCompilerPackageStats(pkg),
-                mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
-                dexoptOptions);
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        if (!instantApp) {
+            startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
+        } else {
+            if (DEBUG_DOMAIN_VERIFICATION) {
+                Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
+            }
         }
 
-        // Notify BackgroundDexOptService that the package has been changed.
-        // If this is an update of a package which used to fail to compile,
-        // BackgroundDexOptService will remove it from its blacklist.
-        // TODO: Layering violation
-        BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
-
-        startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
-
         try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
                 "installPackageLI")) {
             if (replace) {
@@ -18340,6 +18302,55 @@
             }
         }
 
+        // Check whether we need to dexopt the app.
+        //
+        // NOTE: it is IMPORTANT to call dexopt:
+        //   - after doRename which will sync the package data from PackageParser.Package and its
+        //     corresponding ApplicationInfo.
+        //   - after installNewPackageLIF or replacePackageLIF which will update result with the
+        //     uid of the application (pkg.applicationInfo.uid).
+        //     This update happens in place!
+        //
+        // We only need to dexopt if the package meets ALL of the following conditions:
+        //   1) it is not forward locked.
+        //   2) it is not on on an external ASEC container.
+        //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
+        //
+        // Note that we do not dexopt instant apps by default. dexopt can take some time to
+        // complete, so we skip this step during installation. Instead, we'll take extra time
+        // the first time the instant app starts. It's preferred to do it this way to provide
+        // continuous progress to the useur instead of mysteriously blocking somewhere in the
+        // middle of running an instant app. The default behaviour can be overridden
+        // via gservices.
+        final boolean performDexopt = (res.returnCode == PackageManager.INSTALL_SUCCEEDED)
+                && !forwardLocked
+                && !pkg.applicationInfo.isExternalAsec()
+                && (!instantApp || Global.getInt(mContext.getContentResolver(),
+                Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0);
+
+        if (performDexopt) {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+            // Do not run PackageDexOptimizer through the local performDexOpt
+            // method because `pkg` may not be in `mPackages` yet.
+            //
+            // Also, don't fail application installs if the dexopt step fails.
+            DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
+                    REASON_INSTALL,
+                    DexoptOptions.DEXOPT_BOOT_COMPLETE);
+            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+                    null /* instructionSets */,
+                    getOrCreateCompilerPackageStats(pkg),
+                    mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
+                    dexoptOptions);
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+
+        // Notify BackgroundDexOptService that the package has been changed.
+        // If this is an update of a package which used to fail to compile,
+        // BackgroundDexOptService will remove it from its blacklist.
+        // TODO: Layering violation
+        BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
+
         synchronized (mPackages) {
             final PackageSetting ps = mSettings.mPackages.get(pkgName);
             if (ps != null) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 781216c..19b0d9b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -52,18 +52,7 @@
     // Load the property for the given reason and check for validity. This will throw an
     // exception in case the reason or value are invalid.
     private static String getAndCheckValidity(int reason) {
-        String sysPropName = getSystemPropertyName(reason);
-        String sysPropValue;
-        // TODO: This is a temporary hack to keep marlin booting on aosp/master while we
-        // figure out how to deal with these system properties that currently appear on
-        // vendor.
-        if ("pm.dexopt.inactive".equals(sysPropName)) {
-            sysPropValue = "verify";
-        } else if ("pm.dexopt.shared".equals(sysPropName)) {
-            sysPropValue = "speed";
-        } else {
-            sysPropValue = SystemProperties.get(sysPropName);
-        }
+        String sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
         if (sysPropValue == null || sysPropValue.isEmpty() ||
                 !DexFile.isValidCompilerFilter(sysPropValue)) {
             throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 10ceba4..0ec61df 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -476,11 +476,17 @@
         }
 
         List<String> failedPackages = new ArrayList<>();
+        int index = 0;
         for (String packageName : packageNames) {
             if (clearProfileData) {
                 mInterface.clearApplicationProfileData(packageName);
             }
 
+            if (allPackages) {
+                pw.println(++index + "/" + packageNames.size() + ": " + packageName);
+                pw.flush();
+            }
+
             boolean result = secondaryDex
                     ? mInterface.performDexOptSecondary(packageName,
                             targetCompilerFilter, forceCompilation)
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 132b845..62f4a30 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -714,6 +714,19 @@
         }
     }
 
+    @Override
+    public int getProfileParentId(int userHandle) {
+        checkManageUsersPermission("get the profile parent");
+        synchronized (mUsersLock) {
+            UserInfo profileParent = getProfileParentLU(userHandle);
+            if (profileParent == null) {
+                return userHandle;
+            }
+
+            return profileParent.id;
+        }
+    }
+
     private UserInfo getProfileParentLU(int userHandle) {
         UserInfo profile = getUserInfoLU(userHandle);
         if (profile == null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2e4de8c..d176d94 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -72,8 +72,6 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 
-import static android.os.Build.VERSION_CODES.O;
-
 class AppTokenList extends ArrayList<AppWindowToken> {
 }
 
@@ -1293,15 +1291,6 @@
      */
     @Override
     int getOrientation(int candidate) {
-        // We do not allow non-fullscreen apps to influence orientation beyond O. While we do
-        // throw an exception in {@link Activity#onCreate} and
-        // {@link Activity#setRequestedOrientation}, we also ignore the orientation here so that
-        // other calculations aren't affected.
-        if (!fillsParent() && mTargetSdk > O) {
-            // Can't specify orientation if app doesn't fill parent.
-            return SCREEN_ORIENTATION_UNSET;
-        }
-
         if (candidate == SCREEN_ORIENTATION_BEHIND) {
             // Allow app to specify orientation regardless of its visibility state if the current
             // candidate want us to use orientation behind. I.e. the visible app on-top of this one
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 0085931..e097fac 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -107,7 +107,8 @@
             return false;
         }
         try {
-           if (mIpConnectivityMetrics.registerNetdEventCallback(mNetdEventCallback)) {
+           if (mIpConnectivityMetrics.addNetdEventCallback(
+                    INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY, mNetdEventCallback)) {
                 mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
                         /* allowIo */ false);
                 mHandlerThread.start();
@@ -138,7 +139,8 @@
                 // logging is forcefully disabled even if unregistering fails
                 return true;
             }
-            return mIpConnectivityMetrics.unregisterNetdEventCallback();
+            return mIpConnectivityMetrics.removeNetdEventCallback(
+                    INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY);
         } catch (RemoteException re) {
             Slog.wtf(TAG, "Failed to make remote calls to unregister the callback", re);
             return true;
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 5c2b66f..31a1abb 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -86,6 +86,14 @@
  */
 public class ApfFilter {
 
+    // Helper class for specifying functional filter parameters.
+    public static class ApfConfiguration {
+        public ApfCapabilities apfCapabilities;
+        public boolean multicastFilter;
+        public boolean ieee802_3Filter;
+        public int[] ethTypeBlackList;
+    }
+
     // Enums describing the outcome of receiving an RA packet.
     private static enum ProcessRaResult {
         MATCH,          // Received RA matched a known RA
@@ -261,17 +269,16 @@
     private int mIPv4PrefixLength;
 
     @VisibleForTesting
-    ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
-            IpClient.Callback ipClientCallback, boolean multicastFilter,
-            boolean ieee802_3Filter, int[] ethTypeBlackList, IpConnectivityLog log) {
-        mApfCapabilities = apfCapabilities;
+    ApfFilter(ApfConfiguration config, NetworkInterface networkInterface,
+            IpClient.Callback ipClientCallback, IpConnectivityLog log) {
+        mApfCapabilities = config.apfCapabilities;
         mIpClientCallback = ipClientCallback;
         mNetworkInterface = networkInterface;
-        mMulticastFilter = multicastFilter;
-        mDrop802_3Frames = ieee802_3Filter;
+        mMulticastFilter = config.multicastFilter;
+        mDrop802_3Frames = config.ieee802_3Filter;
 
         // Now fill the black list from the passed array
-        mEthTypeBlackList = filterEthTypeBlackList(ethTypeBlackList);
+        mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
 
         mMetricsLog = log;
 
@@ -1160,9 +1167,10 @@
      * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
      * filtering using APF programs.
      */
-    public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
-            NetworkInterface networkInterface, IpClient.Callback ipClientCallback,
-            boolean multicastFilter, boolean ieee802_3Filter, int[] ethTypeBlackList) {
+    public static ApfFilter maybeCreate(ApfConfiguration config,
+            NetworkInterface networkInterface, IpClient.Callback ipClientCallback) {
+        if (config == null) return null;
+        ApfCapabilities apfCapabilities =  config.apfCapabilities;
         if (apfCapabilities == null || networkInterface == null) return null;
         if (apfCapabilities.apfVersionSupported == 0) return null;
         if (apfCapabilities.maximumApfProgramSize < 512) {
@@ -1178,8 +1186,7 @@
             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
             return null;
         }
-        return new ApfFilter(apfCapabilities, networkInterface, ipClientCallback,
-                multicastFilter, ieee802_3Filter, ethTypeBlackList, new IpConnectivityLog());
+        return new ApfFilter(config, networkInterface, ipClientCallback, new IpConnectivityLog());
     }
 
     public synchronized void shutdown() {
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 2359fab..70983c8 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -310,12 +310,12 @@
                 return this;
             }
 
-            public Builder withIPv6AddrGenModeEUI64() {
+            public Builder withRandomMacAddress() {
                 mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
                 return this;
             }
 
-            public Builder withIPv6AddrGenModeStablePrivacy() {
+            public Builder withStableMacAddress() {
                 mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
                 return this;
             }
@@ -1429,15 +1429,15 @@
 
         @Override
         public void enter() {
+            ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
+            apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
+            apfConfig.multicastFilter = mMulticastFiltering;
             // Get the Configuration for ApfFilter from Context
-            final boolean filter802_3Frames =
+            apfConfig.ieee802_3Filter =
                     mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
-
-            final int[] ethTypeBlackList = mContext.getResources().getIntArray(
-                    R.array.config_apfEthTypeBlackList);
-
-            mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
-                    mCallback, mMulticastFiltering, filter802_3Frames, ethTypeBlackList);
+            apfConfig.ethTypeBlackList =
+                    mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
+            mApfFilter = ApfFilter.maybeCreate(apfConfig, mNetworkInterface, mCallback);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
             // rest of this IP configuration startup.
             if (mApfFilter == null) {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index b12cb32..3898145 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -88,16 +88,6 @@
                 return this;
             }
             @Override
-            public Builder withIPv6AddrGenModeEUI64() {
-                super.withIPv6AddrGenModeEUI64();
-                return this;
-            }
-            @Override
-            public Builder withIPv6AddrGenModeStablePrivacy() {
-                super.withIPv6AddrGenModeStablePrivacy();
-                return this;
-            }
-            @Override
             public Builder withNetwork(Network network) {
                 super.withNetwork(network);
                 return this;
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 5770c50..fcc6f52 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -586,6 +586,7 @@
                 PrintJobStateChangeListenerRecord record =
                         mPrintJobStateChangeListenerRecords.get(i);
                 if (record.listener.asBinder().equals(listener.asBinder())) {
+                    record.destroy();
                     mPrintJobStateChangeListenerRecords.remove(i);
                     break;
                 }
@@ -628,6 +629,7 @@
                 ListenerRecord<IPrintServicesChangeListener> record =
                         mPrintServicesChangeListenerRecords.get(i);
                 if (record.listener.asBinder().equals(listener.asBinder())) {
+                    record.destroy();
                     mPrintServicesChangeListenerRecords.remove(i);
                     break;
                 }
@@ -675,6 +677,7 @@
                 ListenerRecord<IRecommendationsChangeListener> record =
                         mPrintServiceRecommendationsChangeListenerRecords.get(i);
                 if (record.listener.asBinder().equals(listener.asBinder())) {
+                    record.destroy();
                     mPrintServiceRecommendationsChangeListenerRecords.remove(i);
                     break;
                 }
@@ -1222,6 +1225,10 @@
             listener.asBinder().linkToDeath(this, 0);
         }
 
+        public void destroy() {
+            listener.asBinder().unlinkToDeath(this, 0);
+        }
+
         @Override
         public void binderDied() {
             listener.asBinder().unlinkToDeath(this, 0);
@@ -1239,6 +1246,10 @@
             listener.asBinder().linkToDeath(this, 0);
         }
 
+        public void destroy() {
+            listener.asBinder().unlinkToDeath(this, 0);
+        }
+
         @Override
         public void binderDied() {
             listener.asBinder().unlinkToDeath(this, 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 23330f1..fb98897 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3150,7 +3150,7 @@
         // setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
         // feature is disabled because there are non-affiliated secondary users.
         getServices().removeUser(DpmMockContext.CALLER_USER_HANDLE);
-        when(getServices().iipConnectivityMetrics.registerNetdEventCallback(anyObject()))
+        when(getServices().iipConnectivityMetrics.addNetdEventCallback(anyInt(), anyObject()))
                 .thenReturn(true);
 
         // No logs were retrieved so far.
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index b09601e..77a0436 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -175,7 +175,7 @@
         token.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
         token.setFillsParent(false);
-        // Can specify orientation if app doesn't fill parent. Allowed for SDK <= 25.
+        // Can specify orientation if app doesn't fill parent.
         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation());
 
         token.setFillsParent(true);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 39c0de8..2f3c03c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -31,7 +31,6 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.util.ArraySet;
 
-import com.android.internal.util.Predicate;
 import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
 
 import org.junit.Test;
@@ -176,4 +175,16 @@
                 new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")};
         assertTrueForFiles(existsFiles, File::exists, " must exist");
     }
+
+    /**
+     * Private predicate definition.
+     *
+     * This is needed because com.android.internal.util.Predicate is deprecated
+     * and can only be used with classes fron android.test.runner. This cannot
+     * use java.util.function.Predicate because that is not present on all API
+     * versions that this test must run on.
+     */
+    private interface Predicate<T> {
+        boolean apply(T t);
+    }
 }
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index e8e0680..f81c89a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -856,6 +856,39 @@
      */
     public static abstract class Callback {
         /**
+         * @hide
+         */
+        @IntDef({HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_DEST_NOT_SUPPORTED,
+                HANDOVER_FAILURE_DEST_INVALID_PERM, HANDOVER_FAILURE_DEST_USER_REJECTED})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface HandoverFailureErrors {}
+
+        /**
+         * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the app
+         * to handover the call rejects handover.
+         */
+        public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1;
+
+        /**
+         * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there is
+         * an error associated with unsupported handover.
+         */
+        public static final int HANDOVER_FAILURE_DEST_NOT_SUPPORTED = 2;
+
+        /**
+         * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there
+         * are some permission errors associated with APIs doing handover.
+         */
+        public static final int HANDOVER_FAILURE_DEST_INVALID_PERM = 3;
+
+        /**
+         * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when user
+         * rejects handover.
+         */
+        public static final int HANDOVER_FAILURE_DEST_USER_REJECTED = 4;
+
+
+        /**
          * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
          *
          * @param call The {@code Call} invoking this method.
@@ -990,6 +1023,21 @@
          *               {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
          */
         public void onRttInitiationFailure(Call call, int reason) {}
+
+        /**
+         * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
+         * has completed successfully.
+         * @param call The call which had initiated handover.
+         */
+        public void onHandoverComplete(Call call) {}
+
+        /**
+         * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount}
+         * has failed.
+         * @param call The call which had initiated handover.
+         * @param failureReason Error reason for failure
+         */
+        public void onHandoverFailed(Call call, @HandoverFailureErrors int failureReason) {}
     }
 
     /**
@@ -1366,6 +1414,24 @@
     }
 
     /**
+     * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
+     * by {@code toHandle}.  The videoState specified indicates the desired video state after the
+     * handover.
+     * <p>
+     * A handover request is initiated by the user from one app to indicate a desire
+     * to handover a call to another.
+     *
+     * @param toHandle {@link PhoneAccountHandle} of the {@link ConnectionService} to handover
+     *                 this call to.
+     * @param videoState Indicates the video state desired after the handover.
+     * @param extras Bundle containing extra information to be passed to the
+     *               {@link ConnectionService}
+     */
+    public void handoverTo(PhoneAccountHandle toHandle, int videoState, Bundle extras) {
+        mInCallAdapter.handoverTo(mTelecomCallId, toHandle, videoState, extras);
+    }
+
+    /**
      * Terminate the RTT session on this call. The resulting state change will be notified via
      * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
      */
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index f601d8b..4b827d2 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -16,16 +16,35 @@
 
 package android.telecom;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  *  Encapsulates the telecom audio state, including the current audio routing, supported audio
  *  routing and mute.
  */
 public final class CallAudioState implements Parcelable {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value={ROUTE_EARPIECE, ROUTE_BLUETOOTH, ROUTE_WIRED_HEADSET, ROUTE_SPEAKER},
+            flag=true)
+    public @interface CallAudioRoute {}
+
     /** Direct the audio stream through the device's earpiece. */
     public static final int ROUTE_EARPIECE      = 0x00000001;
 
@@ -55,6 +74,8 @@
     private final boolean isMuted;
     private final int route;
     private final int supportedRouteMask;
+    private final BluetoothDevice activeBluetoothDevice;
+    private final Collection<BluetoothDevice> supportedBluetoothDevices;
 
     /**
      * Constructor for a {@link CallAudioState} object.
@@ -73,10 +94,21 @@
      * {@link #ROUTE_WIRED_HEADSET}
      * {@link #ROUTE_SPEAKER}
      */
-    public CallAudioState(boolean muted, int route, int supportedRouteMask) {
-        this.isMuted = muted;
+    public CallAudioState(boolean muted, @CallAudioRoute int route,
+            @CallAudioRoute int supportedRouteMask) {
+        this(muted, route, supportedRouteMask, null, Collections.emptyList());
+    }
+
+    /** @hide */
+    public CallAudioState(boolean isMuted, @CallAudioRoute int route,
+            @CallAudioRoute int supportedRouteMask,
+            @Nullable BluetoothDevice activeBluetoothDevice,
+            @NonNull Collection<BluetoothDevice> supportedBluetoothDevices) {
+        this.isMuted = isMuted;
         this.route = route;
         this.supportedRouteMask = supportedRouteMask;
+        this.activeBluetoothDevice = activeBluetoothDevice;
+        this.supportedBluetoothDevices = supportedBluetoothDevices;
     }
 
     /** @hide */
@@ -84,6 +116,8 @@
         isMuted = state.isMuted();
         route = state.getRoute();
         supportedRouteMask = state.getSupportedRouteMask();
+        activeBluetoothDevice = state.activeBluetoothDevice;
+        supportedBluetoothDevices = state.getSupportedBluetoothDevices();
     }
 
     /** @hide */
@@ -92,6 +126,8 @@
         isMuted = state.isMuted();
         route = state.getRoute();
         supportedRouteMask = state.getSupportedRouteMask();
+        activeBluetoothDevice = null;
+        supportedBluetoothDevices = Collections.emptyList();
     }
 
     @Override
@@ -103,17 +139,32 @@
             return false;
         }
         CallAudioState state = (CallAudioState) obj;
-        return isMuted() == state.isMuted() && getRoute() == state.getRoute() &&
-                getSupportedRouteMask() == state.getSupportedRouteMask();
+        if (supportedBluetoothDevices.size() != state.supportedBluetoothDevices.size()) {
+            return false;
+        }
+        for (BluetoothDevice device : supportedBluetoothDevices) {
+            if (!state.supportedBluetoothDevices.contains(device)) {
+                return false;
+            }
+        }
+        return Objects.equals(activeBluetoothDevice, state.activeBluetoothDevice) && isMuted() ==
+                state.isMuted() && getRoute() == state.getRoute() && getSupportedRouteMask() ==
+                state.getSupportedRouteMask();
     }
 
     @Override
     public String toString() {
+        String bluetoothDeviceList = supportedBluetoothDevices.stream()
+                .map(BluetoothDevice::getAddress).collect(Collectors.joining(", "));
+
         return String.format(Locale.US,
-                "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s]",
+                "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s, " +
+                        "activeBluetoothDevice: [%s], supportedBluetoothDevices: [%s]]",
                 isMuted,
                 audioRouteToString(route),
-                audioRouteToString(supportedRouteMask));
+                audioRouteToString(supportedRouteMask),
+                activeBluetoothDevice,
+                bluetoothDeviceList);
     }
 
     /**
@@ -126,6 +177,7 @@
     /**
      * @return The current audio route being used.
      */
+    @CallAudioRoute
     public int getRoute() {
         return route;
     }
@@ -133,11 +185,27 @@
     /**
      * @return Bit mask of all routes supported by this call.
      */
+    @CallAudioRoute
     public int getSupportedRouteMask() {
         return supportedRouteMask;
     }
 
     /**
+     * @return The {@link BluetoothDevice} through which audio is being routed.
+     *         Will not be {@code null} if {@link #getRoute()} returns {@link #ROUTE_BLUETOOTH}.
+     */
+    public BluetoothDevice getActiveBluetoothDevice() {
+        return activeBluetoothDevice;
+    }
+
+    /**
+     * @return {@link List} of {@link BluetoothDevice}s that can be used for this call.
+     */
+    public Collection<BluetoothDevice> getSupportedBluetoothDevices() {
+        return supportedBluetoothDevices;
+    }
+
+    /**
      * Converts the provided audio route into a human readable string representation.
      *
      * @param route to convert into a string.
@@ -177,7 +245,13 @@
             boolean isMuted = source.readByte() == 0 ? false : true;
             int route = source.readInt();
             int supportedRouteMask = source.readInt();
-            return new CallAudioState(isMuted, route, supportedRouteMask);
+            BluetoothDevice activeBluetoothDevice = source.readParcelable(
+                    ClassLoader.getSystemClassLoader());
+            List<BluetoothDevice> supportedBluetoothDevices = new ArrayList<>();
+            source.readParcelableList(supportedBluetoothDevices,
+                    ClassLoader.getSystemClassLoader());
+            return new CallAudioState(isMuted, route,
+                    supportedRouteMask, activeBluetoothDevice, supportedBluetoothDevices);
         }
 
         @Override
@@ -202,6 +276,8 @@
         destination.writeByte((byte) (isMuted ? 1 : 0));
         destination.writeInt(route);
         destination.writeInt(supportedRouteMask);
+        destination.writeParcelable(activeBluetoothDevice, 0);
+        destination.writeParcelableList(new ArrayList<>(supportedBluetoothDevices), 0);
     }
 
     private static void listAppend(StringBuffer buffer, String str) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 8ba934c..ffb5e93 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.Notification;
+import android.bluetooth.BluetoothDevice;
 import android.content.Intent;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
@@ -819,7 +820,7 @@
         public void onConnectionEvent(Connection c, String event, Bundle extras) {}
         /** @hide */
         public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
-        public void onAudioRouteChanged(Connection c, int audioRoute) {}
+        public void onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress) {}
         public void onRttInitiationSuccess(Connection c) {}
         public void onRttInitiationFailure(Connection c, int reason) {}
         public void onRttSessionRemotelyTerminated(Connection c) {}
@@ -2576,7 +2577,29 @@
      */
     public final void setAudioRoute(int route) {
         for (Listener l : mListeners) {
-            l.onAudioRouteChanged(this, route);
+            l.onAudioRouteChanged(this, route, null);
+        }
+    }
+
+    /**
+     *
+     * Request audio routing to a specific bluetooth device. Calling this method may result in
+     * the device routing audio to a different bluetooth device than the one specified if the
+     * bluetooth stack is unable to route audio to the requested device.
+     * A list of available devices can be obtained via
+     * {@link CallAudioState#getSupportedBluetoothDevices()}
+     *
+     * <p>
+     * Used by self-managed {@link ConnectionService}s which wish to use bluetooth audio for a
+     * self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.)
+     * <p>
+     * See also {@link InCallService#requestBluetoothAudio(String)}
+     * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
+     *                         {@link BluetoothDevice#getAddress()}.
+     */
+    public void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+        for (Listener l : mListeners) {
+            l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH, bluetoothAddress);
         }
     }
 
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index a81fba9..da8ac5e 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1294,10 +1294,10 @@
         }
 
         @Override
-        public void onAudioRouteChanged(Connection c, int audioRoute) {
+        public void onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress) {
             String id = mIdByConnection.get(c);
             if (id != null) {
-                mAdapter.setAudioRoute(id, audioRoute);
+                mAdapter.setAudioRoute(id, audioRoute, bluetoothAddress);
             }
         }
 
@@ -2033,6 +2033,43 @@
     }
 
     /**
+     * Called by Telecom on the initiating side of the handover to create an instance of a
+     * handover connection.
+     * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
+     *                               ConnectionService which needs to handover the call.
+     * @param request Details about the call which needs to be handover.
+     * @return Connection object corresponding to the handover call.
+     */
+    public Connection onCreateOutgoingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
+                                                         ConnectionRequest request) {
+        return null;
+    }
+
+    /**
+     * Called by Telecom on the receiving side of the handover to request the
+     * {@link ConnectionService} to create an instance of a handover connection.
+     * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
+     *                               ConnectionService which needs to handover the call.
+     * @param request Details about the call which needs to be handover.
+     * @return {@link Connection} object corresponding to the handover call.
+     */
+    public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
+                                                         ConnectionRequest request) {
+        return null;
+    }
+
+    /**
+     * Called by Telecom in response to a {@code TelecomManager#acceptHandover()}
+     * invocation which failed.
+     * @param request Details about the call which needs to be handover.
+     * @param error Reason for handover failure as defined in
+     *              {@link android.telecom.Call.Callback#HANDOVER_FAILURE_DEST_INVALID_PERM}
+     */
+    public void onHandoverFailed(ConnectionRequest request, int error) {
+        return;
+    }
+
+    /**
      * Create a {@code Connection} for a new unknown call. An unknown call is a call originating
      * from the ConnectionService that was neither a user-initiated outgoing call, nor an incoming
      * call created using
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 111fcc7..92a9dc2 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -520,11 +520,14 @@
      * @param callId The unique ID of the call.
      * @param audioRoute The new audio route (see {@code CallAudioState#ROUTE_*}).
      */
-    void setAudioRoute(String callId, int audioRoute) {
-        Log.v(this, "setAudioRoute: %s %s", callId, CallAudioState.audioRouteToString(audioRoute));
+    void setAudioRoute(String callId, int audioRoute, String bluetoothAddress) {
+        Log.v(this, "setAudioRoute: %s %s %s", callId,
+                CallAudioState.audioRouteToString(audioRoute),
+                bluetoothAddress);
         for (IConnectionServiceAdapter adapter : mAdapters) {
             try {
-                adapter.setAudioRoute(callId, audioRoute, Log.getExternalSession());
+                adapter.setAudioRoute(callId, audioRoute,
+                        bluetoothAddress, Log.getExternalSession());
             } catch (RemoteException ignored) {
             }
         }
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index b1617f4..3fbdeb1 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -298,8 +298,8 @@
                 case MSG_SET_AUDIO_ROUTE: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     try {
-                        mDelegate.setAudioRoute((String) args.arg1, args.argi1,
-                                (Session.Info) args.arg2);
+                        mDelegate.setAudioRoute((String) args.arg1, args.argi1, (String) args.arg2,
+                                (Session.Info) args.arg3);
                     } finally {
                         args.recycle();
                     }
@@ -548,12 +548,12 @@
 
         @Override
         public final void setAudioRoute(String connectionId, int audioRoute,
-                Session.Info sessionInfo) {
-
+                String bluetoothAddress, Session.Info sessionInfo) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = connectionId;
             args.argi1 = audioRoute;
-            args.arg2 = sessionInfo;
+            args.arg2 = bluetoothAddress;
+            args.arg3 = sessionInfo;
             mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, args).sendToTarget();
         }
 
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 9559a28..4bc2a9b 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.bluetooth.BluetoothDevice;
 import android.os.Bundle;
 import android.os.RemoteException;
 
@@ -128,7 +129,22 @@
      */
     public void setAudioRoute(int route) {
         try {
-            mAdapter.setAudioRoute(route);
+            mAdapter.setAudioRoute(route, null);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Request audio routing to a specific bluetooth device. Calling this method may result in
+     * the device routing audio to a different bluetooth device than the one specified. A list of
+     * available devices can be obtained via {@link CallAudioState#getSupportedBluetoothDevices()}
+     *
+     * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
+     * {@link BluetoothDevice#getAddress()}, or {@code null} if no device is preferred.
+     */
+    public void requestBluetoothAudio(String bluetoothAddress) {
+        try {
+            mAdapter.setAudioRoute(CallAudioState.ROUTE_BLUETOOTH, bluetoothAddress);
         } catch (RemoteException e) {
         }
     }
@@ -419,4 +435,21 @@
         } catch (RemoteException ignored) {
         }
     }
+
+
+    /**
+     * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified
+     * by destAcct.
+     * @param callId The callId of the Call which calls this function.
+     * @param destAcct ConnectionService to which the call should be handed over.
+     * @param videoState The video state desired after the handover.
+     * @param extras Extra information to be passed to ConnectionService
+     */
+    public void handoverTo(String callId, PhoneAccountHandle destAcct, int videoState,
+                           Bundle extras) {
+        try {
+            mAdapter.handoverTo(callId, destAcct, videoState, extras);
+        } catch (RemoteException ignored) {
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index e384d46..d558bba 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -16,9 +16,11 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
+import android.bluetooth.BluetoothDevice;
 import android.content.Intent;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
@@ -377,6 +379,22 @@
     }
 
     /**
+     * Request audio routing to a specific bluetooth device. Calling this method may result in
+     * the device routing audio to a different bluetooth device than the one specified if the
+     * bluetooth stack is unable to route audio to the requested device.
+     * A list of available devices can be obtained via
+     * {@link CallAudioState#getSupportedBluetoothDevices()}
+     *
+     * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
+     *                         {@link BluetoothDevice#getAddress()}.
+     */
+    public final void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+        if (mPhone != null) {
+            mPhone.requestBluetoothAudio(bluetoothAddress);
+        }
+    }
+
+    /**
      * Invoked when the {@code Phone} has been created. This is a signal to the in-call experience
      * to start displaying in-call information to the user. Each instance of {@code InCallService}
      * will have only one {@code Phone}, and this method will be called exactly once in the lifetime
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 066f6c2..421b1a4 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -17,7 +17,9 @@
 package android.telecom;
 
 import android.annotation.SystemApi;
+import android.bluetooth.BluetoothDevice;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.util.ArrayMap;
 
 import java.util.Collections;
@@ -295,6 +297,18 @@
     }
 
     /**
+     * Request audio routing to a specific bluetooth device. Calling this method may result in
+     * the device routing audio to a different bluetooth device than the one specified. A list of
+     * available devices can be obtained via {@link CallAudioState#getSupportedBluetoothDevices()}
+     *
+     * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
+     * {@link BluetoothDevice#getAddress()}, or {@code null} if no device is preferred.
+     */
+    public void requestBluetoothAudio(String bluetoothAddress) {
+        mInCallAdapter.requestBluetoothAudio(bluetoothAddress);
+    }
+
+    /**
      * Turns the proximity sensor on. When this request is made, the proximity sensor will
      * become active, and the touch screen and display will be turned off when the user's face
      * is detected to be in close proximity to the screen. This operation is a no-op on devices
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 691e7cf..74b9465 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -86,13 +86,11 @@
     /**
      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
      * indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
-     * connection (see {@link android.telecom.Call#EVENT_REQUEST_HANDOVER}) to this
-     * {@link PhoneAccount} from a {@link PhoneAccount} specifying
-     * {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
+     * connection (see {@code android.telecom.Call#handoverTo()}) to this {@link PhoneAccount} from
+     * a {@link PhoneAccount} specifying {@link #EXTRA_SUPPORTS_HANDOVER_FROM}.
      * <p>
      * A handover request is initiated by the user from the default dialer app to indicate a desire
      * to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
-     * @hide
      */
     public static final String EXTRA_SUPPORTS_HANDOVER_TO =
             "android.telecom.extra.SUPPORTS_HANDOVER_TO";
@@ -113,12 +111,11 @@
      * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
      * indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a
      * connection from this {@link PhoneAccount} to another {@link PhoneAccount}.
-     * (see {@link android.telecom.Call#EVENT_REQUEST_HANDOVER}) which specifies
+     * (see {@code android.telecom.Call#handoverTo()}) which specifies
      * {@link #EXTRA_SUPPORTS_HANDOVER_TO}.
      * <p>
      * A handover request is initiated by the user from the default dialer app to indicate a desire
      * to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another.
-     * @hide
      */
     public static final String EXTRA_SUPPORTS_HANDOVER_FROM =
             "android.telecom.extra.SUPPORTS_HANDOVER_FROM";
@@ -132,7 +129,6 @@
      * <p>
      * By default, Self-Managed {@link PhoneAccount}s do not log their calls to the call log.
      * Setting this extra to {@code true} provides a means for them to log their calls.
-     * @hide
      */
     public static final String EXTRA_LOG_SELF_MANAGED_CALLS =
             "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index f30d7bd..05480dc 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -1065,7 +1065,7 @@
      *
      * @param state The audio state of this {@code RemoteConnection}.
      * @hide
-     * @deprecated Use {@link #setCallAudioState(CallAudioState) instead.
+     * @deprecated Use {@link #setCallAudioState(CallAudioState)} instead.
      */
     @SystemApi
     @Deprecated
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 2cc4314..85906ad 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -398,7 +398,8 @@
         }
 
         @Override
-        public void setAudioRoute(String callId, int audioRoute, Session.Info sessionInfo) {
+        public void setAudioRoute(String callId, int audioRoute, String bluetoothAddress,
+                Session.Info sessionInfo) {
             if (hasConnection(callId)) {
                 // TODO(3pcalls): handle this for remote connections.
                 // Likely we don't want to do anything since it doesn't make sense for self-managed
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index aa2323d..4d2cb04 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1749,6 +1749,41 @@
         return false;
     }
 
+    /**
+     * Called from the recipient side of a handover to indicate a desire to accept the handover
+     * of an ongoing call to another {@link ConnectionService} identified by
+     * {@link PhoneAccountHandle} destAcct. For managed {@link ConnectionService}s, the specified
+     * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
+     * the user must have enabled the corresponding {@link PhoneAccount}.  This can be checked using
+     * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
+     * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to handover a call to it.
+     * <p>
+     * Once invoked, this method will cause the system to bind to the {@link ConnectionService}
+     * associated with the {@link PhoneAccountHandle} destAcct and call
+     * (See {@link ConnectionService#onCreateIncomingHandoverConnection}).
+     * <p>
+     * For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
+     * the {@link PhoneAccountHandle} destAcct does not correspond to a registered
+     * {@link PhoneAccount} or the associated {@link PhoneAccount} is not currently enabled by the
+     * user.
+     * <p>
+     * For a self-managed {@link ConnectionService}, a {@link SecurityException} will be thrown if
+     * the calling app does not have {@link android.Manifest.permission#MANAGE_OWN_CALLS}.
+     *
+     * @param srcAddr The {@link android.net.Uri} of the ongoing call to handover to the caller’s
+     *                {@link ConnectionService}.
+     * @param videoState Video state after the handover.
+     * @param destAcct The {@link PhoneAccountHandle} registered to the calling package.
+     */
+    public void acceptHandover(Uri srcAddr, int videoState, PhoneAccountHandle destAcct) {
+        try {
+            if (isServiceConnected()) {
+                getTelecomService().acceptHandover(srcAddr, videoState, destAcct);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException acceptHandover: " + e);
+        }
+    }
 
     private ITelecomService getTelecomService() {
         if (mTelecomServiceOverride != null) {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index d20da18..da2015f 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -103,7 +103,8 @@
 
     void removeExtras(String callId, in List<String> keys, in Session.Info sessionInfo);
 
-    void setAudioRoute(String callId, int audioRoute, in Session.Info sessionInfo);
+    void setAudioRoute(String callId, int audioRoute, String bluetoothAddress,
+            in Session.Info sessionInfo);
 
     void onConnectionEvent(String callId, String event, in Bundle extras,
     in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 73fa29a..23ac940 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -39,7 +39,7 @@
 
     void mute(boolean shouldMute);
 
-    void setAudioRoute(int route);
+    void setAudioRoute(int route, String bluetoothAddress);
 
     void playDtmfTone(String callId, char digit);
 
@@ -77,4 +77,7 @@
     void stopRtt(String callId);
 
     void setRttMode(String callId, int mode);
+
+    void handoverTo(String callId, in PhoneAccountHandle destAcct, int videoState,
+            in Bundle extras);
 }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 8ebac2c..3460754 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -274,4 +274,9 @@
      * @see TelecomServiceImpl#waitOnHandler
      */
     void waitOnHandlers();
+
+    /**
+     * @see TelecomServiceImpl#acceptHandover
+     */
+    void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2e621f1..0b58e761 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -209,6 +209,12 @@
     public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
 
     /**
+     * Determine whether user can edit voicemail number in Settings.
+     */
+    public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL =
+            "editable_voicemail_number_setting_bool";
+
+    /**
      * Since the default voicemail number is empty, if a SIM card does not have a voicemail number
      * available the user cannot use voicemail. This flag allows the user to edit the voicemail
      * number in such cases, and is false by default.
@@ -773,6 +779,14 @@
     public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
 
     /**
+     * Determines whether manage IMS conference calls is supported by a carrier.  When {@code true},
+     * manage IMS conference call is supported, {@code false otherwise}.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL =
+            "support_manage_ims_conference_call_bool";
+
+    /**
      * Determines whether High Definition audio property is displayed in the dialer UI.
      * If {@code false}, remove the HD audio property from the connection so that HD audio related
      * UI is not displayed. If {@code true}, keep HD audio property as it is configured.
@@ -813,6 +827,14 @@
     public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
 
     /**
+     * Default Enhanced 4G LTE mode enabled. When this is {@code true}, Enhanced 4G LTE mode by
+     * default is on, otherwise if {@code false}, Enhanced 4G LTE mode by default is off.
+     * @hide
+     */
+    public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL =
+            "enhanced_4g_lte_on_by_default_bool";
+
+    /**
      * Determine whether IMS apn can be shown.
      */
     public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
@@ -1607,6 +1629,33 @@
     public static final String KEY_FEATURE_ACCESS_CODES_STRING_ARRAY =
             "feature_access_codes_string_array";
 
+    /**
+     * Determines if the carrier wants to identify high definition calls in the call log.
+     * @hide
+     */
+    public static final String KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL =
+            "identify_high_definition_calls_in_call_log_bool";
+
+    /**
+     * Flag specifying whether to use the {@link ServiceState} roaming status, which can be
+     * affected by other carrier configs (e.g.
+     * {@link #KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY}), when setting the SPN display.
+     * <p>
+     * If {@code true}, the SPN display uses {@link ServiceState#getRoaming}.
+     * If {@code false} the SPN display checks if the current MCC/MNC is different from the
+     * SIM card's MCC/MNC.
+     *
+     * @see KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY
+     * @see KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY
+     * @see KEY_NON_ROAMING_OPERATOR_STRING_ARRAY
+     * @see KEY_ROAMING_OPERATOR_STRING_ARRAY
+     * @see KEY_FORCE_HOME_NETWORK_BOOL
+     *
+     * @hide
+     */
+    public static final String KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL =
+            "spn_display_rule_use_roaming_from_service_state_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -1666,6 +1715,7 @@
         sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL, true);
         sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
+        sDefaults.putBoolean(KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL, true);
         sDefaults.putBoolean(KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
         sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
@@ -1740,12 +1790,14 @@
         sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
+        sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL, false);
         sDefaults.putBoolean(KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL, false);
         sDefaults.putInt(KEY_IMS_CONFERENCE_SIZE_LIMIT_INT, 5);
         sDefaults.putBoolean(KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL, true);
         sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_ENHANCED_4G_LTE_BOOL, false);
+        sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL, false);
@@ -1880,6 +1932,8 @@
         sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
         sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false);
+        sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 6276626..376e6aa 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -101,9 +101,6 @@
      * @param alphal long alpha Operator Name String or Enhanced Operator Name String
      * @param alphas short alpha Operator Name String or Enhanced Operator Name String
      *
-     * @throws IllegalArgumentException if the input MCC is not a 3-digit code or the input MNC is
-     * not a 2 or 3-digit code.
-     *
      * @hide
      */
     public CellIdentityGsm (int lac, int cid, int arfcn, int bsic, String mccStr,
@@ -115,22 +112,29 @@
         // for inbound parcels
         mBsic = (bsic == 0xFF) ? Integer.MAX_VALUE : bsic;
 
+        // Only allow INT_MAX if unknown string mcc/mnc
         if (mccStr == null || mccStr.matches("^[0-9]{3}$")) {
             mMccStr = mccStr;
-        } else if (mccStr.isEmpty()) {
-            // If the mccStr parsed from Parcel is empty, set it as null.
+        } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) {
+            // If the mccStr is empty or unknown, set it as null.
             mMccStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MCC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+            // after the bug got fixed.
+            mMccStr = null;
+            log("invalid MCC format: " + mccStr);
         }
 
         if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
             mMncStr = mncStr;
-        } else if (mncStr.isEmpty()) {
-            // If the mncStr parsed from Parcel is empty, set it as null.
+        } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) {
+            // If the mncStr is empty or unknown, set it as null.
             mMncStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MNC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+            // after the bug got fixed.
+            mMncStr = null;
+            log("invalid MNC format: " + mncStr);
         }
 
         mAlphaLong = alphal;
@@ -198,7 +202,7 @@
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
      */
     public String getMobileNetworkOperator() {
-        return (mMncStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
+        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 74d2966..6ca5daf6 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -102,9 +102,6 @@
      * @param alphal long alpha Operator Name String or Enhanced Operator Name String
      * @param alphas short alpha Operator Name String or Enhanced Operator Name String
      *
-     * @throws IllegalArgumentException if the input MCC is not a 3-digit code or the input MNC is
-     * not a 2 or 3-digit code.
-     *
      * @hide
      */
     public CellIdentityLte (int ci, int pci, int tac, int earfcn, String mccStr,
@@ -114,22 +111,29 @@
         mTac = tac;
         mEarfcn = earfcn;
 
+        // Only allow INT_MAX if unknown string mcc/mnc
         if (mccStr == null || mccStr.matches("^[0-9]{3}$")) {
             mMccStr = mccStr;
-        } else if (mccStr.isEmpty()) {
-            // If the mccStr parsed from Parcel is empty, set it as null.
+        } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) {
+            // If the mccStr is empty or unknown, set it as null.
             mMccStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MCC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+            // after the bug got fixed.
+            mMccStr = null;
+            log("invalid MCC format: " + mccStr);
         }
 
         if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
             mMncStr = mncStr;
-        } else if (mncStr.isEmpty()) {
-            // If the mncStr parsed from Parcel is empty, set it as null.
+        } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) {
+            // If the mncStr is empty or unknown, set it as null.
             mMncStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MNC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+            // after the bug got fixed.
+            mMncStr = null;
+            log("invalid MNC format: " + mncStr);
         }
 
         mAlphaLong = alphal;
@@ -209,7 +213,7 @@
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
      */
     public String getMobileNetworkOperator() {
-        return (mMncStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
+        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 51b11aa..e4bb4f2 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -102,9 +102,6 @@
      * @param alphal long alpha Operator Name String or Enhanced Operator Name String
      * @param alphas short alpha Operator Name String or Enhanced Operator Name String
      *
-     * @throws IllegalArgumentException if the input MCC is not a 3-digit code or the input MNC is
-     * not a 2 or 3-digit code.
-     *
      * @hide
      */
     public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn,
@@ -114,22 +111,29 @@
         mPsc = psc;
         mUarfcn = uarfcn;
 
+        // Only allow INT_MAX if unknown string mcc/mnc
         if (mccStr == null || mccStr.matches("^[0-9]{3}$")) {
             mMccStr = mccStr;
-        } else if (mccStr.isEmpty()) {
-            // If the mccStr parsed from Parcel is empty, set it as null.
+        } else if (mccStr.isEmpty() || mccStr.equals(String.valueOf(Integer.MAX_VALUE))) {
+            // If the mccStr is empty or unknown, set it as null.
             mMccStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MCC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MCC format
+            // after the bug got fixed.
+            mMccStr = null;
+            log("invalid MCC format: " + mccStr);
         }
 
         if (mncStr == null || mncStr.matches("^[0-9]{2,3}$")) {
             mMncStr = mncStr;
-        } else if (mncStr.isEmpty()) {
-            // If the mncStr parsed from Parcel is empty, set it as null.
+        } else if (mncStr.isEmpty() || mncStr.equals(String.valueOf(Integer.MAX_VALUE))) {
+            // If the mncStr is empty or unknown, set it as null.
             mMncStr = null;
         } else {
-            throw new IllegalArgumentException("invalid MNC format");
+            // TODO: b/69384059 Should throw IllegalArgumentException for the invalid MNC format
+            // after the bug got fixed.
+            mMncStr = null;
+            log("invalid MNC format: " + mncStr);
         }
 
         mAlphaLong = alphal;
@@ -204,7 +208,7 @@
      * @return a 5 or 6 character string (MCC+MNC), null if any field is unknown
      */
     public String getMobileNetworkOperator() {
-        return (mMncStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
+        return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
     }
 
     /**
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index afff6d5..9ccfa94 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -204,16 +204,6 @@
     public static final int LISTEN_VOLTE_STATE                              = 0x00004000;
 
     /**
-     * Listen for OEM hook raw event
-     *
-     * @see #onOemHookRawEvent
-     * @hide
-     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
-     */
-    @Deprecated
-    public static final int LISTEN_OEM_HOOK_RAW_EVENT                       = 0x00008000;
-
-    /**
      * Listen for carrier network changes indicated by a carrier app.
      *
      * @see #onCarrierNetworkRequest
@@ -359,9 +349,6 @@
                     case LISTEN_DATA_ACTIVATION_STATE:
                         PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj);
                         break;
-                    case LISTEN_OEM_HOOK_RAW_EVENT:
-                        PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
-                        break;
                     case LISTEN_CARRIER_NETWORK_CHANGE:
                         PhoneStateListener.this.onCarrierNetworkChange((boolean)msg.obj);
                         break;
@@ -556,16 +543,6 @@
     }
 
     /**
-     * Callback invoked when OEM hook raw event is received. Requires
-     * the READ_PRIVILEGED_PHONE_STATE permission.
-     * @param rawData is the byte array of the OEM hook raw data.
-     * @hide
-     */
-    public void onOemHookRawEvent(byte[] rawData) {
-        // default implementation empty
-    }
-
-    /**
      * Callback invoked when telephony has received notice from a carrier
      * app that a network action that could result in connectivity loss
      * has been requested by an app using
@@ -677,10 +654,6 @@
             send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState);
         }
 
-        public void onOemHookRawEvent(byte[] rawData) {
-            send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData);
-        }
-
         public void onCarrierNetworkChange(boolean active) {
             send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active);
         }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 0d1764b..d2fd097 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -26,6 +26,7 @@
 import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -408,7 +409,15 @@
      * for #onSubscriptionsChanged to be invoked.
      */
     public static class OnSubscriptionsChangedListener {
-        private final Handler mHandler  = new Handler() {
+        private class OnSubscriptionsChangedListenerHandler extends Handler {
+            OnSubscriptionsChangedListenerHandler() {
+                super();
+            }
+
+            OnSubscriptionsChangedListenerHandler(Looper looper) {
+                super(looper);
+            }
+
             @Override
             public void handleMessage(Message msg) {
                 if (DBG) {
@@ -416,7 +425,22 @@
                 }
                 OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
             }
-        };
+        }
+
+        private final Handler mHandler;
+
+        public OnSubscriptionsChangedListener() {
+            mHandler = new OnSubscriptionsChangedListenerHandler();
+        }
+
+        /**
+         * Allow a listener to be created with a custom looper
+         * @param looper the looper that the underlining handler should run on
+         * @hide
+         */
+        public OnSubscriptionsChangedListener(Looper looper) {
+            mHandler = new OnSubscriptionsChangedListenerHandler(looper);
+        }
 
         /**
          * Callback invoked when there is any change to any SubscriptionInfo. Typically
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index 1b50861..66ff6e4 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -2805,6 +2805,26 @@
          *  @hide
          */
         public static final int CARRIER_DELETED_BUT_PRESENT_IN_XML = 6;
+
+        /**
+         * The owner of the APN.
+         * <p>Type: INTEGER</p>
+         * @hide
+         */
+        public static final String OWNED_BY = "owned_by";
+
+        /**
+         * Possible value for the OWNED_BY field.
+         * APN is owned by DPC.
+         * @hide
+         */
+        public static final int OWNED_BY_DPC = 0;
+        /**
+         * Possible value for the OWNED_BY field.
+         * APN is owned by other sources.
+         * @hide
+         */
+        public static final int OWNED_BY_OTHERS = 1;
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 73f5937..6b26dbb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -52,8 +52,9 @@
 import android.telephony.ims.feature.ImsFeature;
 import android.util.Log;
 
-import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
+import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.ITelecomService;
 import com.android.internal.telephony.CellNetworkScanResult;
@@ -407,9 +408,12 @@
      * Open the voicemail settings activity to make changes to voicemail configuration.
      *
      * <p>
+     * The {@link #EXTRA_PHONE_ACCOUNT_HANDLE} extra indicates which {@link PhoneAccountHandle} to
+     * configure voicemail.
      * The {@link #EXTRA_HIDE_PUBLIC_SETTINGS} hides settings the dialer will modify through public
      * API if set.
      *
+     * @see #EXTRA_PHONE_ACCOUNT_HANDLE
      * @see #EXTRA_HIDE_PUBLIC_SETTINGS
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@@ -771,8 +775,9 @@
             "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
 
     /**
-     * The extra used with an {@link #ACTION_SHOW_VOICEMAIL_NOTIFICATION} {@code Intent} to specify
-     * the {@link PhoneAccountHandle} the notification is for.
+     * The extra used with an {@link #ACTION_CONFIGURE_VOICEMAIL} and
+     * {@link #ACTION_SHOW_VOICEMAIL_NOTIFICATION} {@code Intent} to specify the
+     * {@link PhoneAccountHandle} the configuration or notification is for.
      * <p class="note">
      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
      */
@@ -4584,27 +4589,78 @@
     public @interface Feature {}
 
     /**
-     * Returns the {@link IImsServiceController} that corresponds to the given slot Id and IMS
-     * feature or {@link null} if the service is not available. If an ImsServiceController is
-     * available, the {@link IImsServiceFeatureListener} callback is registered as a listener for
-     * feature updates.
-     * @param slotIndex The SIM slot that we are requesting the {@link IImsServiceController} for.
-     * @param feature The IMS Feature we are requesting, corresponding to {@link ImsFeature}.
+     * Returns the {@link IImsMMTelFeature} that corresponds to the given slot Id and MMTel
+     * feature or {@link null} if the service is not available. If an MMTelFeature is available, the
+     * {@link IImsServiceFeatureCallback} callback is registered as a listener for feature updates.
+     * @param slotIndex The SIM slot that we are requesting the {@link IImsMMTelFeature} for.
      * @param callback Listener that will send updates to ImsManager when there are updates to
      * ImsServiceController.
-     * @return {@link IImsServiceController} interface for the feature specified or {@link null} if
+     * @return {@link IImsMMTelFeature} interface for the feature specified or {@code null} if
      * it is unavailable.
      * @hide
      */
-    public IImsServiceController getImsServiceControllerAndListen(int slotIndex, @Feature int feature,
-            IImsServiceFeatureListener callback) {
+    public @Nullable IImsMMTelFeature getImsMMTelFeatureAndListen(int slotIndex,
+            IImsServiceFeatureCallback callback) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getImsServiceControllerAndListen(slotIndex, feature, callback);
+                return telephony.getMMTelFeatureAndListen(slotIndex, callback);
             }
         } catch (RemoteException e) {
-            Rlog.e(TAG, "getImsServiceControllerAndListen, RemoteException: " + e.getMessage());
+            Rlog.e(TAG, "getImsMMTelFeatureAndListen, RemoteException: "
+                    + e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * Returns the {@link IImsMMTelFeature} that corresponds to the given slot Id and MMTel
+     * feature for emergency calling or {@link null} if the service is not available. If an
+     * MMTelFeature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
+     * listener for feature updates.
+     * @param slotIndex The SIM slot that we are requesting the {@link IImsMMTelFeature} for.
+     * @param callback Listener that will send updates to ImsManager when there are updates to
+     * ImsServiceController.
+     * @return {@link IImsMMTelFeature} interface for the feature specified or {@code null} if
+     * it is unavailable.
+     * @hide
+     */
+    public @Nullable IImsMMTelFeature getImsEmergencyMMTelFeatureAndListen(int slotIndex,
+            IImsServiceFeatureCallback callback) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getEmergencyMMTelFeatureAndListen(slotIndex, callback);
+            }
+        } catch (RemoteException e) {
+            Rlog.e(TAG, "getImsEmergencyMMTelFeatureAndListen, RemoteException: "
+                    + e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * Returns the {@link IImsRcsFeature} that corresponds to the given slot Id and RCS
+     * feature for emergency calling or {@link null} if the service is not available. If an
+     * RcsFeature is available, the {@link IImsServiceFeatureCallback} callback is registered as a
+     * listener for feature updates.
+     * @param slotIndex The SIM slot that we are requesting the {@link IImsRcsFeature} for.
+     * @param callback Listener that will send updates to ImsManager when there are updates to
+     * ImsServiceController.
+     * @return {@link IImsRcsFeature} interface for the feature specified or {@code null} if
+     * it is unavailable.
+     * @hide
+     */
+    public @Nullable IImsRcsFeature getImsRcsFeatureAndListen(int slotIndex,
+            IImsServiceFeatureCallback callback) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getRcsFeatureAndListen(slotIndex, callback);
+            }
+        } catch (RemoteException e) {
+            Rlog.e(TAG, "getImsRcsFeatureAndListen, RemoteException: "
+                    + e.getMessage());
         }
         return null;
     }
@@ -5634,29 +5690,6 @@
         return retVal;
     }
 
-    /**
-     * Returns the result and response from RIL for oem request
-     *
-     * @param oemReq the data is sent to ril.
-     * @param oemResp the respose data from RIL.
-     * @return negative value request was not handled or get error
-     *         0 request was handled succesfully, but no response data
-     *         positive value success, data length of response
-     * @hide
-     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
-     */
-    @Deprecated
-    public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
-        try {
-            ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.invokeOemRilRequestRaw(oemReq, oemResp);
-        } catch (RemoteException ex) {
-        } catch (NullPointerException ex) {
-        }
-        return -1;
-    }
-
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 92a21b6..7bcdcdc 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -73,8 +73,8 @@
         /**
          * Informs the user that there is some error about the scan.
          *
-         * This callback will be called whenever there is any error about the scan, but the scan
-         * won't stop unless the onComplete() callback is called.
+         * This callback will be called whenever there is any error about the scan, and the scan
+         * will be terminated. onComplete() will NOT be called.
          */
         public void onError(int error) {}
     }
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/telephony/java/android/telephony/data/DataProfile.aidl
similarity index 63%
rename from telephony/java/android/telephony/ims/feature/IRcsFeature.java
rename to telephony/java/android/telephony/data/DataProfile.aidl
index e28e1b3..65fdf91 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/telephony/java/android/telephony/data/DataProfile.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2017 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.
@@ -11,16 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package android.telephony.ims.feature;
+/** @hide */
+package android.telephony.data;
 
-/**
- * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
- * in the framework.
- * @hide
- */
-
-public interface IRcsFeature {
-}
+parcelable DataProfile;
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
new file mode 100644
index 0000000..41c1430
--- /dev/null
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.RILConstants;
+
+/**
+ * Description of a mobile data profile used for establishing
+ * data connections.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DataProfile implements Parcelable {
+
+    // The types indicating the data profile is used on GSM (3GPP) or CDMA (3GPP2) network.
+    public static final int TYPE_COMMON = 0;
+    public static final int TYPE_3GPP = 1;
+    public static final int TYPE_3GPP2 = 2;
+
+    private final int mProfileId;
+
+    private final String mApn;
+
+    private final String mProtocol;
+
+    private final int mAuthType;
+
+    private final String mUserName;
+
+    private final String mPassword;
+
+    private final int mType;
+
+    private final int mMaxConnsTime;
+
+    private final int mMaxConns;
+
+    private final int mWaitTime;
+
+    private final boolean mEnabled;
+
+    private final int mSupportedApnTypesBitmap;
+
+    private final String mRoamingProtocol;
+
+    private final int mBearerBitmap;
+
+    private final int mMtu;
+
+    private final String mMvnoType;
+
+    private final String mMvnoMatchData;
+
+    private final boolean mModemCognitive;
+
+    public DataProfile(int profileId, String apn, String protocol, int authType,
+                String userName, String password, int type, int maxConnsTime, int maxConns,
+                int waitTime, boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
+                int bearerBitmap, int mtu, String mvnoType, String mvnoMatchData,
+                boolean modemCognitive) {
+
+        this.mProfileId = profileId;
+        this.mApn = apn;
+        this.mProtocol = protocol;
+        if (authType == -1) {
+            authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE
+                    : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
+        }
+        this.mAuthType = authType;
+        this.mUserName = userName;
+        this.mPassword = password;
+        this.mType = type;
+        this.mMaxConnsTime = maxConnsTime;
+        this.mMaxConns = maxConns;
+        this.mWaitTime = waitTime;
+        this.mEnabled = enabled;
+
+        this.mSupportedApnTypesBitmap = supportedApnTypesBitmap;
+        this.mRoamingProtocol = roamingProtocol;
+        this.mBearerBitmap = bearerBitmap;
+        this.mMtu = mtu;
+        this.mMvnoType = mvnoType;
+        this.mMvnoMatchData = mvnoMatchData;
+        this.mModemCognitive = modemCognitive;
+    }
+
+    public DataProfile(Parcel source) {
+        mProfileId = source.readInt();
+        mApn = source.readString();
+        mProtocol = source.readString();
+        mAuthType = source.readInt();
+        mUserName = source.readString();
+        mPassword = source.readString();
+        mType = source.readInt();
+        mMaxConnsTime = source.readInt();
+        mMaxConns = source.readInt();
+        mWaitTime = source.readInt();
+        mEnabled = source.readBoolean();
+        mSupportedApnTypesBitmap = source.readInt();
+        mRoamingProtocol = source.readString();
+        mBearerBitmap = source.readInt();
+        mMtu = source.readInt();
+        mMvnoType = source.readString();
+        mMvnoMatchData = source.readString();
+        mModemCognitive = source.readBoolean();
+    }
+
+    /**
+     * @return Id of the data profile.
+     */
+    public int getProfileId() { return mProfileId; }
+
+    /**
+     * @return The APN to establish data connection.
+     */
+    public String getApn() { return mApn; }
+
+    /**
+     * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section
+     * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     */
+    public String getProtocol() { return mProtocol; }
+
+    /**
+     * @return The authentication protocol used for this PDP context
+     * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
+     */
+    public int getAuthType() { return mAuthType; }
+
+    /**
+     * @return The username for APN. Can be null.
+     */
+    public String getUserName() { return mUserName; }
+
+    /**
+     * @return The password for APN. Can be null.
+     */
+    public String getPassword() { return mPassword; }
+
+    /**
+     * @return The profile type. Could be one of TYPE_COMMON, TYPE_3GPP, or TYPE_3GPP2.
+     */
+    public int getType() { return mType; }
+
+    /**
+     * @return The period in seconds to limit the maximum connections.
+     */
+    public int getMaxConnsTime() { return mMaxConnsTime; }
+
+    /**
+     * @return The maximum connections allowed.
+     */
+    public int getMaxConns() { return mMaxConns; }
+
+    /**
+     * @return The required wait time in seconds after a successful UE initiated disconnect of a
+     * given PDN connection before the device can send a new PDN connection request for that given
+     * PDN.
+     */
+    public int getWaitTime() { return mWaitTime; }
+
+    /**
+     * @return True if the profile is enabled.
+     */
+    public boolean isEnabled() { return mEnabled; }
+
+    /**
+     * @return The supported APN types bitmap. See RIL_ApnTypes for the value of each bit.
+     */
+    public int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; }
+
+    /**
+     * @return  The connection protocol on roaming network, should be one of the PDP_type values in
+     * TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     */
+    public String getRoamingProtocol() { return mRoamingProtocol; }
+
+    /**
+     * @return The bearer bitmap. See RIL_RadioAccessFamily for the value of each bit.
+     */
+    public int getBearerBitmap() { return mBearerBitmap; }
+
+    /**
+     * @return The maximum transmission unit (MTU) size in bytes.
+     */
+    public int getMtu() { return mMtu; }
+
+    /**
+     * @return The MVNO type: possible values are "imsi", "gid", "spn".
+     */
+    public String getMvnoType() { return mMvnoType; }
+
+    /**
+     * @return The MVNO match data. For example,
+     * SPN: A MOBILE, BEN NL, ...
+     * IMSI: 302720x94, 2060188, ...
+     * GID: 4E, 33, ...
+     */
+    public String getMvnoMatchData() { return mMvnoMatchData; }
+
+    /**
+     * @return True if the data profile was sent to the modem through setDataProfile earlier.
+     */
+    public boolean isModemCognitive() { return mModemCognitive; }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "DataProfile=" + mProfileId + "/" + mApn + "/" + mProtocol + "/" + mAuthType
+                + "/" + mUserName + "/" + mPassword + "/" + mType + "/" + mMaxConnsTime
+                + "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/"
+                + mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/"
+                + mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof DataProfile == false) return false;
+        return (o == this || toString().equals(o.toString()));
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mProfileId);
+        dest.writeString(mApn);
+        dest.writeString(mProtocol);
+        dest.writeInt(mAuthType);
+        dest.writeString(mUserName);
+        dest.writeString(mPassword);
+        dest.writeInt(mType);
+        dest.writeInt(mMaxConnsTime);
+        dest.writeInt(mMaxConns);
+        dest.writeInt(mWaitTime);
+        dest.writeBoolean(mEnabled);
+        dest.writeInt(mSupportedApnTypesBitmap);
+        dest.writeString(mRoamingProtocol);
+        dest.writeInt(mBearerBitmap);
+        dest.writeInt(mMtu);
+        dest.writeString(mMvnoType);
+        dest.writeString(mMvnoMatchData);
+        dest.writeBoolean(mModemCognitive);
+    }
+
+    public static final Parcelable.Creator<DataProfile> CREATOR =
+            new Parcelable.Creator<DataProfile>() {
+        @Override
+        public DataProfile createFromParcel(Parcel source) {
+            return new DataProfile(source);
+        }
+
+        @Override
+        public DataProfile[] newArray(int size) {
+            return new DataProfile[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 9d91cc3..8230eaf 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -16,13 +16,11 @@
 
 package android.telephony.ims;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ims.feature.ImsFeature;
@@ -31,22 +29,13 @@
 import android.util.Log;
 import android.util.SparseArray;
 
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsFeatureStatusCallback;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
 import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
-import com.android.ims.internal.IImsUt;
 import com.android.internal.annotations.VisibleForTesting;
 
 import static android.Manifest.permission.MODIFY_PHONE_STATE;
-import static android.Manifest.permission.READ_PHONE_STATE;
-import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
 
 /**
  * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
@@ -92,247 +81,38 @@
      */
     public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService";
 
-    // A map of slot Id -> Set of features corresponding to that slot.
-    private final SparseArray<SparseArray<ImsFeature>> mFeatures = new SparseArray<>();
+    // A map of slot Id -> map of features (indexed by ImsFeature feature id) corresponding to that
+    // slot.
+    // We keep track of this to facilitate cleanup of the IImsFeatureStatusCallback and
+    // call ImsFeature#onFeatureRemoved.
+    private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
 
     /**
      * @hide
      */
-    // Implements all supported features as a flat interface.
     protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
 
         @Override
-        public void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
+        public IImsMMTelFeature createEmergencyMMTelFeature(int slotId,
+                IImsFeatureStatusCallback c) {
+            return createEmergencyMMTelFeatureInternal(slotId, c);
+        }
+
+        @Override
+        public IImsMMTelFeature createMMTelFeature(int slotId, IImsFeatureStatusCallback c) {
+            return createMMTelFeatureInternal(slotId, c);
+        }
+
+        @Override
+        public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
+            return createRcsFeatureInternal(slotId, c);
+        }
+
+        @Override
+        public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c)
                 throws RemoteException {
-            synchronized (mFeatures) {
-                enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createImsFeature");
-                onCreateImsFeatureInternal(slotId, feature, c);
-            }
+            ImsService.this.removeImsFeature(slotId, featureType, c);
         }
-
-        @Override
-        public void removeImsFeature(int slotId, int feature,  IImsFeatureStatusCallback c)
-                throws RemoteException {
-            synchronized (mFeatures) {
-                enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature");
-                onRemoveImsFeatureInternal(slotId, feature, c);
-            }
-        }
-
-        @Override
-        public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent,
-                IImsRegistrationListener listener) throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "startSession");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.startSession(incomingCallIntent, listener);
-                }
-            }
-            return 0;
-        }
-
-        @Override
-        public void endSession(int slotId, int featureType, int sessionId) throws RemoteException {
-            synchronized (mFeatures) {
-                enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "endSession");
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    feature.endSession(sessionId);
-                }
-            }
-        }
-
-        @Override
-        public boolean isConnected(int slotId, int featureType, int callSessionType, int callType)
-                throws RemoteException {
-            enforceReadPhoneStatePermission("isConnected");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.isConnected(callSessionType, callType);
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public boolean isOpened(int slotId, int featureType) throws RemoteException {
-            enforceReadPhoneStatePermission("isOpened");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.isOpened();
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
-            enforceReadPhoneStatePermission("getFeatureStatus");
-            int status = ImsFeature.STATE_NOT_AVAILABLE;
-            synchronized (mFeatures) {
-                SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
-                if (featureMap != null) {
-                    ImsFeature feature = getImsFeatureFromType(featureMap, featureType);
-                    if (feature != null) {
-                        status = feature.getFeatureState();
-                    }
-                }
-            }
-            return status;
-        }
-
-        @Override
-        public void addRegistrationListener(int slotId, int featureType,
-                IImsRegistrationListener listener) throws RemoteException {
-            enforceReadPhoneStatePermission("addRegistrationListener");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    feature.addRegistrationListener(listener);
-                }
-            }
-        }
-
-        @Override
-        public void removeRegistrationListener(int slotId, int featureType,
-                IImsRegistrationListener listener) throws RemoteException {
-            enforceReadPhoneStatePermission("removeRegistrationListener");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    feature.removeRegistrationListener(listener);
-                }
-            }
-        }
-
-        @Override
-        public ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
-                int callSessionType, int callType) throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallProfile");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.createCallProfile(sessionId, callSessionType,  callType);
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
-                ImsCallProfile profile, IImsCallSessionListener listener) throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallSession");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.createCallSession(sessionId, profile, listener);
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
-                String callId) throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getPendingCallSession");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.getPendingCallSession(sessionId, callId);
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public IImsUt getUtInterface(int slotId, int featureType)
-                throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getUtInterface");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.getUtInterface();
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public IImsConfig getConfigInterface(int slotId, int featureType)
-                throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getConfigInterface");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.getConfigInterface();
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public void turnOnIms(int slotId, int featureType) throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOnIms");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    feature.turnOnIms();
-                }
-            }
-        }
-
-        @Override
-        public void turnOffIms(int slotId, int featureType) throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOffIms");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    feature.turnOffIms();
-                }
-            }
-        }
-
-        @Override
-        public IImsEcbm getEcbmInterface(int slotId, int featureType)
-                throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getEcbmInterface");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.getEcbmInterface();
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public void setUiTTYMode(int slotId, int featureType, int uiTtyMode, Message onComplete)
-                throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "setUiTTYMode");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    feature.setUiTTYMode(uiTtyMode, onComplete);
-                }
-            }
-        }
-
-        @Override
-        public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType)
-                throws RemoteException {
-            enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getMultiEndpointInterface");
-            synchronized (mFeatures) {
-                MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
-                if (feature != null) {
-                    return feature.getMultiEndpointInterface();
-                }
-            }
-            return null;
-        }
-
     };
 
     /**
@@ -341,127 +121,93 @@
     @Override
     public IBinder onBind(Intent intent) {
         if(SERVICE_INTERFACE.equals(intent.getAction())) {
+            Log.i(LOG_TAG, "ImsService Bound.");
             return mImsServiceController;
         }
         return null;
     }
 
     /**
-     * Called from the ImsResolver to create the requested ImsFeature, as defined by the slot and
-     * featureType
-     * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
-     * @param featureType An integer representing the type of ImsFeature being created. This is
-     * defined in {@link ImsFeature}.
+     * @hide
      */
-    // Be sure to lock on mFeatures before accessing this method
-    private void onCreateImsFeatureInternal(int slotId, int featureType,
+    @VisibleForTesting
+    public SparseArray<ImsFeature> getFeatures(int slotId) {
+        return mFeaturesBySlot.get(slotId);
+    }
+
+    private IImsMMTelFeature createEmergencyMMTelFeatureInternal(int slotId,
             IImsFeatureStatusCallback c) {
-        SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
-        if (featureMap == null) {
-            featureMap = new SparseArray<>();
-            mFeatures.put(slotId, featureMap);
-        }
-        ImsFeature f = makeImsFeature(slotId, featureType);
+        MMTelFeature f = onCreateEmergencyMMTelImsFeature(slotId);
         if (f != null) {
-            f.setContext(this);
-            f.setSlotId(slotId);
-            f.addImsFeatureStatusCallback(c);
-            featureMap.put(featureType, f);
-        }
-
-    }
-    /**
-     * Called from the ImsResolver to remove an existing ImsFeature, as defined by the slot and
-     * featureType.
-     * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
-     * @param featureType An integer representing the type of ImsFeature being removed. This is
-     * defined in {@link ImsFeature}.
-     */
-    // Be sure to lock on mFeatures before accessing this method
-    private void onRemoveImsFeatureInternal(int slotId, int featureType,
-            IImsFeatureStatusCallback c) {
-        SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
-        if (featureMap == null) {
-            return;
-        }
-
-        ImsFeature featureToRemove = getImsFeatureFromType(featureMap, featureType);
-        if (featureToRemove != null) {
-            featureMap.remove(featureType);
-            featureToRemove.notifyFeatureRemoved(slotId);
-            // Remove reference to Binder
-            featureToRemove.removeImsFeatureStatusCallback(c);
-        }
-    }
-
-    // Be sure to lock on mFeatures before accessing this method
-    private MMTelFeature resolveMMTelFeature(int slotId, int featureType) {
-        SparseArray<ImsFeature> features = getImsFeatureMap(slotId);
-        MMTelFeature feature = null;
-        if (features != null) {
-            feature = resolveImsFeature(features, featureType, MMTelFeature.class);
-        }
-        return feature;
-    }
-
-    // Be sure to lock on mFeatures before accessing this method
-    private <T extends ImsFeature> T resolveImsFeature(SparseArray<ImsFeature> set, int featureType,
-            Class<T> className) {
-        ImsFeature feature = getImsFeatureFromType(set, featureType);
-        if (feature == null) {
+            setupFeature(f, slotId, ImsFeature.EMERGENCY_MMTEL, c);
+            return f.getBinder();
+        } else {
             return null;
         }
-        try {
-            return className.cast(feature);
-        } catch (ClassCastException e)
-        {
-            Log.e(LOG_TAG, "Can not cast ImsFeature! Exception: " + e.getMessage());
+    }
+
+    private IImsMMTelFeature createMMTelFeatureInternal(int slotId,
+            IImsFeatureStatusCallback c) {
+        MMTelFeature f = onCreateMMTelImsFeature(slotId);
+        if (f != null) {
+            setupFeature(f, slotId, ImsFeature.MMTEL, c);
+            return f.getBinder();
+        } else {
+            return null;
         }
-        return null;
     }
 
-    /**
-     * @hide
-     */
-    @VisibleForTesting
-    // Be sure to lock on mFeatures before accessing this method
-    public SparseArray<ImsFeature> getImsFeatureMap(int slotId) {
-        return mFeatures.get(slotId);
-    }
-
-    /**
-     * @hide
-     */
-    @VisibleForTesting
-    // Be sure to lock on mFeatures before accessing this method
-    public ImsFeature getImsFeatureFromType(SparseArray<ImsFeature> set, int featureType) {
-        return set.get(featureType);
-    }
-
-    private ImsFeature makeImsFeature(int slotId, int feature) {
-        switch (feature) {
-            case ImsFeature.EMERGENCY_MMTEL: {
-                return onCreateEmergencyMMTelImsFeature(slotId);
-            }
-            case ImsFeature.MMTEL: {
-                return onCreateMMTelImsFeature(slotId);
-            }
-            case ImsFeature.RCS: {
-                return onCreateRcsFeature(slotId);
-            }
+    private IImsRcsFeature createRcsFeatureInternal(int slotId,
+            IImsFeatureStatusCallback c) {
+        RcsFeature f = onCreateRcsFeature(slotId);
+        if (f != null) {
+            setupFeature(f, slotId, ImsFeature.RCS, c);
+            return f.getBinder();
+        } else {
+            return null;
         }
-        // Tried to create feature that is not defined.
-        return null;
     }
 
-    /**
-     * Check for both READ_PHONE_STATE and READ_PRIVILEGED_PHONE_STATE. READ_PHONE_STATE is a
-     * public permission and READ_PRIVILEGED_PHONE_STATE is only granted to system apps.
-     */
-    private void enforceReadPhoneStatePermission(String fn) {
-        if (checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
-                != PackageManager.PERMISSION_GRANTED) {
-            enforceCallingOrSelfPermission(READ_PHONE_STATE, fn);
+    private void setupFeature(ImsFeature f, int slotId, int featureType,
+            IImsFeatureStatusCallback c) {
+        f.setContext(this);
+        f.setSlotId(slotId);
+        f.addImsFeatureStatusCallback(c);
+        addImsFeature(slotId, featureType, f);
+    }
+
+    private void addImsFeature(int slotId, int featureType, ImsFeature f) {
+        synchronized (mFeaturesBySlot) {
+            // Get SparseArray for Features, by querying slot Id
+            SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+            if (features == null) {
+                // Populate new SparseArray of features if it doesn't exist for this slot yet.
+                features = new SparseArray<>();
+                mFeaturesBySlot.put(slotId, features);
+            }
+            features.put(featureType, f);
+        }
+    }
+
+    private void removeImsFeature(int slotId, int featureType,
+            IImsFeatureStatusCallback c) {
+        synchronized (mFeaturesBySlot) {
+            // get ImsFeature associated with the slot/feature
+            SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+            if (features == null) {
+                Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot "
+                        + slotId);
+                return;
+            }
+            ImsFeature f = features.get(featureType);
+            if (f == null) {
+                Log.w(LOG_TAG, "Can not remove ImsFeature. No feature with type "
+                        + featureType + " exists on slot " + slotId);
+                return;
+            }
+            f.removeImsFeatureStatusCallback(c);
+            f.onFeatureRemoved();
+            features.remove(featureType);
         }
     }
 
@@ -470,7 +216,7 @@
      * functionality. Must be able to handle emergency calls at any time as well.
      * @hide
      */
-    public MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId) {
+    public @Nullable MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId) {
         return null;
     }
 
@@ -479,7 +225,7 @@
      * functionality.
      * @hide
      */
-    public MMTelFeature onCreateMMTelImsFeature(int slotId) {
+    public @Nullable MMTelFeature onCreateMMTelImsFeature(int slotId) {
         return null;
     }
 
@@ -487,7 +233,7 @@
      * @return An implementation of RcsFeature that will be used by the system for RCS.
      * @hide
      */
-    public RcsFeature onCreateRcsFeature(int slotId) {
+    public @Nullable RcsFeature onCreateRcsFeature(int slotId) {
         return null;
     }
 }
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
deleted file mode 100644
index 038e295..0000000
--- a/telephony/java/android/telephony/ims/ImsServiceProxy.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2017 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.ims;
-
-import android.app.PendingIntent;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telephony.ims.feature.IRcsFeature;
-import android.telephony.ims.feature.ImsFeature;
-import android.util.Log;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
-import com.android.ims.internal.IImsUt;
-
-/**
- * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
- * the platform currently supports: MMTel and RCS.
- * @hide
- */
-
-public class ImsServiceProxy extends ImsServiceProxyCompat implements IRcsFeature {
-
-    protected String LOG_TAG = "ImsServiceProxy";
-    private final int mSupportedFeature;
-
-    // Start by assuming the proxy is available for usage.
-    private boolean mIsAvailable = true;
-    // ImsFeature Status from the ImsService. Cached.
-    private Integer mFeatureStatusCached = null;
-    private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
-    private final Object mLock = new Object();
-
-    public interface INotifyStatusChanged {
-        void notifyStatusChanged();
-    }
-
-    private final IImsServiceFeatureListener mListenerBinder =
-            new IImsServiceFeatureListener.Stub() {
-
-        @Override
-        public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
-            // The feature has been re-enabled. This may happen when the service crashes.
-            synchronized (mLock) {
-                if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
-                    Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
-                            feature);
-                    mIsAvailable = true;
-                }
-            }
-        }
-
-        @Override
-        public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
-            synchronized (mLock) {
-                if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
-                    Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
-                            feature);
-                    mIsAvailable = false;
-                }
-            }
-        }
-
-        @Override
-        public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
-            synchronized (mLock) {
-                Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
-                        " status: " + status);
-                if (mSlotId == slotId && feature == mSupportedFeature) {
-                    mFeatureStatusCached = status;
-                    if (mStatusCallback != null) {
-                        mStatusCallback.notifyStatusChanged();
-                    }
-                }
-            }
-        }
-    };
-
-    public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
-        super(slotId, binder);
-        mSupportedFeature = featureType;
-    }
-
-    public ImsServiceProxy(int slotId, int featureType) {
-        super(slotId, null /*IBinder*/);
-        mSupportedFeature = featureType;
-    }
-
-    public IImsServiceFeatureListener getListener() {
-        return mListenerBinder;
-    }
-
-    public void setBinder(IBinder binder) {
-        mBinder = binder;
-    }
-
-    @Override
-    public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
-            throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
-                    incomingCallIntent, listener);
-        }
-    }
-
-    @Override
-    public void endSession(int sessionId) throws RemoteException {
-        synchronized (mLock) {
-            // Only check to make sure the binder connection still exists. This method should
-            // still be able to be called when the state is STATE_NOT_AVAILABLE.
-            checkBinderConnection();
-            getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
-        }
-    }
-
-    @Override
-    public boolean isConnected(int callServiceType, int callType)
-            throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
-                    callServiceType, callType);
-        }
-    }
-
-    @Override
-    public boolean isOpened() throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
-        }
-    }
-
-    @Override
-    public void addRegistrationListener(IImsRegistrationListener listener)
-    throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
-                    listener);
-        }
-    }
-
-    @Override
-    public void removeRegistrationListener(IImsRegistrationListener listener)
-            throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
-                    listener);
-        }
-    }
-
-    @Override
-    public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
-            throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
-                    sessionId, callServiceType, callType);
-        }
-    }
-
-    @Override
-    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
-            IImsCallSessionListener listener) throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
-                    sessionId, profile, listener);
-        }
-    }
-
-    @Override
-    public IImsCallSession getPendingCallSession(int sessionId, String callId)
-            throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
-                    sessionId, callId);
-        }
-    }
-
-    @Override
-    public IImsUt getUtInterface() throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
-        }
-    }
-
-    @Override
-    public IImsConfig getConfigInterface() throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
-        }
-    }
-
-    @Override
-    public void turnOnIms() throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
-        }
-    }
-
-    @Override
-    public void turnOffIms() throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
-        }
-    }
-
-    @Override
-    public IImsEcbm getEcbmInterface() throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
-        }
-    }
-
-    @Override
-    public void setUiTTYMode(int uiTtyMode, Message onComplete)
-            throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
-                    onComplete);
-        }
-    }
-
-    @Override
-    public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
-        synchronized (mLock) {
-            checkServiceIsReady();
-            return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
-                    mSupportedFeature);
-        }
-    }
-
-    @Override
-    public int getFeatureStatus() {
-        synchronized (mLock) {
-            if (isBinderAlive() && mFeatureStatusCached != null) {
-                Log.i(LOG_TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
-                return mFeatureStatusCached;
-            }
-        }
-        // Don't synchronize on Binder call.
-        Integer status = retrieveFeatureStatus();
-        synchronized (mLock) {
-            if (status == null) {
-                return ImsFeature.STATE_NOT_AVAILABLE;
-            }
-            // Cache only non-null value for feature status.
-            mFeatureStatusCached = status;
-        }
-        Log.i(LOG_TAG, "getFeatureStatus - returning " + status);
-        return status;
-    }
-
-    /**
-     * Internal method used to retrieve the feature status from the corresponding ImsService.
-     */
-    private Integer retrieveFeatureStatus() {
-        if (mBinder != null) {
-            try {
-                return getServiceInterface(mBinder).getFeatureStatus(mSlotId, mSupportedFeature);
-            } catch (RemoteException e) {
-                // Status check failed, don't update cache
-            }
-        }
-        return null;
-    }
-
-    /**
-     * @param c Callback that will fire when the feature status has changed.
-     */
-    public void setStatusCallback(INotifyStatusChanged c) {
-        mStatusCallback = c;
-    }
-
-    /**
-     * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
-     * method returns false, it doesn't mean that the Binder connection is not available (use
-     * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
-     * at this time.
-     *
-     * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
-     * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_NOT_AVAILABLE}.
-     */
-    public boolean isBinderReady() {
-        return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
-    }
-
-    @Override
-    public boolean isBinderAlive() {
-        return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
-    }
-
-    protected void checkServiceIsReady() throws RemoteException {
-        if (!isBinderReady()) {
-            throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
-        }
-    }
-
-    private IImsServiceController getServiceInterface(IBinder b) {
-        return IImsServiceController.Stub.asInterface(b);
-    }
-}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
deleted file mode 100644
index bbd5f02..0000000
--- a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2017 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.ims;
-
-import android.app.PendingIntent;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telephony.ims.feature.IMMTelFeature;
-import android.telephony.ims.feature.ImsFeature;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsService;
-import com.android.ims.internal.IImsUt;
-
-/**
- * Compatibility class that implements the new ImsService IMMTelFeature interface, but
- * uses the old IImsService interface to support older devices that implement the deprecated
- * opt/net/ims interface.
- * @hide
- */
-
-public class ImsServiceProxyCompat implements IMMTelFeature {
-
-    private static final int SERVICE_ID = ImsFeature.MMTEL;
-
-    protected final int mSlotId;
-    protected IBinder mBinder;
-
-    public ImsServiceProxyCompat(int slotId, IBinder binder) {
-        mSlotId = slotId;
-        mBinder = binder;
-    }
-
-    @Override
-    public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
-            throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).open(mSlotId, ImsFeature.MMTEL, incomingCallIntent,
-                listener);
-    }
-
-    @Override
-    public void endSession(int sessionId) throws RemoteException {
-        checkBinderConnection();
-        getServiceInterface(mBinder).close(sessionId);
-    }
-
-    @Override
-    public boolean isConnected(int callServiceType, int callType)
-            throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).isConnected(SERVICE_ID,  callServiceType, callType);
-    }
-
-    @Override
-    public boolean isOpened() throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).isOpened(SERVICE_ID);
-    }
-
-    @Override
-    public void addRegistrationListener(IImsRegistrationListener listener)
-            throws RemoteException {
-        checkBinderConnection();
-        getServiceInterface(mBinder).addRegistrationListener(mSlotId, ImsFeature.MMTEL, listener);
-    }
-
-    @Override
-    public void removeRegistrationListener(IImsRegistrationListener listener)
-            throws RemoteException {
-        // Not Implemented in old ImsService. If the registration listener becomes invalid, the
-        // ImsService will remove.
-    }
-
-    @Override
-    public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
-            throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType, callType);
-    }
-
-    @Override
-    public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
-            IImsCallSessionListener listener) throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
-    }
-
-    @Override
-    public IImsCallSession getPendingCallSession(int sessionId, String callId)
-            throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
-    }
-
-    @Override
-    public IImsUt getUtInterface() throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).getUtInterface(SERVICE_ID);
-    }
-
-    @Override
-    public IImsConfig getConfigInterface() throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).getConfigInterface(mSlotId);
-    }
-
-    @Override
-    public void turnOnIms() throws RemoteException {
-        checkBinderConnection();
-        getServiceInterface(mBinder).turnOnIms(mSlotId);
-    }
-
-    @Override
-    public void turnOffIms() throws RemoteException {
-        checkBinderConnection();
-        getServiceInterface(mBinder).turnOffIms(mSlotId);
-    }
-
-    @Override
-    public IImsEcbm getEcbmInterface() throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).getEcbmInterface(SERVICE_ID);
-    }
-
-    @Override
-    public void setUiTTYMode(int uiTtyMode, Message onComplete)
-            throws RemoteException {
-        checkBinderConnection();
-        getServiceInterface(mBinder).setUiTTYMode(SERVICE_ID, uiTtyMode, onComplete);
-    }
-
-    @Override
-    public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
-        checkBinderConnection();
-        return getServiceInterface(mBinder).getMultiEndpointInterface(SERVICE_ID);
-    }
-
-    /**
-     * Base implementation, always returns READY for compatibility with old ImsService.
-     */
-    public int getFeatureStatus() {
-        return ImsFeature.STATE_READY;
-    }
-
-    /**
-     * @return false if the binder connection is no longer alive.
-     */
-    public boolean isBinderAlive() {
-        return mBinder != null && mBinder.isBinderAlive();
-    }
-
-    private IImsService getServiceInterface(IBinder b) {
-        return IImsService.Stub.asInterface(b);
-    }
-
-    protected void checkBinderConnection() throws RemoteException {
-        if (!isBinderAlive()) {
-            throw new RemoteException("ImsServiceProxy is not available for that feature.");
-        }
-    }
-}
diff --git a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
deleted file mode 100644
index d65e27e..0000000
--- a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2017 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.ims.feature;
-
-import android.app.PendingIntent;
-import android.os.Message;
-import android.os.RemoteException;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsUt;
-
-/**
- * MMTel interface for an ImsService. When updating this interface, ensure that base implementations
- * of your changes are also present in MMTelFeature for compatibility with older versions of the
- * MMTel feature.
- * @hide
- */
-
-public interface IMMTelFeature {
-
-    /**
-     * Notifies the MMTel feature that you would like to start a session. This should always be
-     * done before making/receiving IMS calls. The IMS service will register the device to the
-     * operator's network with the credentials (from ISIM) periodically in order to receive calls
-     * from the operator's network. When the IMS service receives a new call, it will send out an
-     * intent with the provided action string. The intent contains a call ID extra
-     * {@link IImsCallSession#getCallId} and it can be used to take a call.
-     *
-     * @param incomingCallIntent When an incoming call is received, the IMS service will call
-     * {@link PendingIntent#send} to send back the intent to the caller with
-     * {@link #INCOMING_CALL_RESULT_CODE} as the result code and the intent to fill in the call ID;
-     * It cannot be null.
-     * @param listener To listen to IMS registration events; It cannot be null
-     * @return an integer (greater than 0) representing the session id associated with the session
-     * that has been started.
-     */
-    int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
-            throws RemoteException;
-
-    /**
-     * End a previously started session using the associated sessionId.
-     * @param sessionId an integer (greater than 0) representing the ongoing session. See
-     * {@link #startSession}.
-     */
-    void endSession(int sessionId) throws RemoteException;
-
-    /**
-     * Checks if the IMS service has successfully registered to the IMS network with the specified
-     * service & call type.
-     *
-     * @param callServiceType a service type that is specified in {@link ImsCallProfile}
-     *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
-     *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
-     * @param callType a call type that is specified in {@link ImsCallProfile}
-     *        {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
-     *        {@link ImsCallProfile#CALL_TYPE_VOICE}
-     *        {@link ImsCallProfile#CALL_TYPE_VT}
-     *        {@link ImsCallProfile#CALL_TYPE_VS}
-     * @return true if the specified service id is connected to the IMS network; false otherwise
-     * @throws RemoteException
-     */
-    boolean isConnected(int callServiceType, int callType) throws RemoteException;
-
-    /**
-     * Checks if the specified IMS service is opened.
-     *
-     * @return true if the specified service id is opened; false otherwise
-     */
-    boolean isOpened() throws RemoteException;
-
-    /**
-     * Add a new registration listener for the client associated with the session Id.
-     * @param listener An implementation of IImsRegistrationListener.
-     */
-    void addRegistrationListener(IImsRegistrationListener listener)
-            throws RemoteException;
-
-    /**
-     * Remove a previously registered listener using {@link #addRegistrationListener} for the client
-     * associated with the session Id.
-     * @param listener A previously registered IImsRegistrationListener
-     */
-    void removeRegistrationListener(IImsRegistrationListener listener)
-            throws RemoteException;
-
-    /**
-     * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
-     *
-     * @param sessionId a session id which is obtained from {@link #startSession}
-     * @param callServiceType a service type that is specified in {@link ImsCallProfile}
-     *        {@link ImsCallProfile#SERVICE_TYPE_NONE}
-     *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
-     *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
-     * @param callType a call type that is specified in {@link ImsCallProfile}
-     *        {@link ImsCallProfile#CALL_TYPE_VOICE}
-     *        {@link ImsCallProfile#CALL_TYPE_VT}
-     *        {@link ImsCallProfile#CALL_TYPE_VT_TX}
-     *        {@link ImsCallProfile#CALL_TYPE_VT_RX}
-     *        {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
-     *        {@link ImsCallProfile#CALL_TYPE_VS}
-     *        {@link ImsCallProfile#CALL_TYPE_VS_TX}
-     *        {@link ImsCallProfile#CALL_TYPE_VS_RX}
-     * @return a {@link ImsCallProfile} object
-     */
-    ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
-            throws RemoteException;
-
-    /**
-     * Creates a {@link ImsCallSession} with the specified call profile.
-     * Use other methods, if applicable, instead of interacting with
-     * {@link ImsCallSession} directly.
-     *
-     * @param sessionId a session id which is obtained from {@link #startSession}
-     * @param profile a call profile to make the call
-     * @param listener An implementation of IImsCallSessionListener.
-     */
-    IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
-            IImsCallSessionListener listener) throws RemoteException;
-
-    /**
-     * Retrieves the call session associated with a pending call.
-     *
-     * @param sessionId a session id which is obtained from {@link #startSession}
-     * @param callId a call id to make the call
-     */
-    IImsCallSession getPendingCallSession(int sessionId, String callId) throws RemoteException;
-
-    /**
-     * @return The Ut interface for the supplementary service configuration.
-     */
-    IImsUt getUtInterface() throws RemoteException;
-
-    /**
-     * @return The config interface for IMS Configuration
-     */
-    IImsConfig getConfigInterface() throws RemoteException;
-
-    /**
-     * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
-     * @param sessionId a session id which is obtained from {@link #startSession}
-     */
-    void turnOnIms() throws RemoteException;
-
-    /**
-     * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
-     * @param sessionId a session id which is obtained from {@link #startSession}
-     */
-    void turnOffIms() throws RemoteException;
-
-    /**
-     * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
-     */
-    IImsEcbm getEcbmInterface() throws RemoteException;
-
-    /**
-     * Sets the current UI TTY mode for the MMTelFeature.
-     * @param uiTtyMode An integer containing the new UI TTY Mode.
-     * @param onComplete A {@link Message} to be used when the mode has been set.
-     * @throws RemoteException
-     */
-    void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException;
-
-    /**
-     * @return MultiEndpoint interface for DEP notifications
-     */
-    IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException;
-}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 9d880b7..ca4a210 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.content.Context;
 import android.content.Intent;
+import android.os.IInterface;
 import android.os.RemoteException;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
@@ -91,17 +92,12 @@
     public static final int STATE_INITIALIZING = 1;
     public static final int STATE_READY = 2;
 
-    private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
     private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap(
             new WeakHashMap<IImsFeatureStatusCallback, Boolean>());
     private @ImsState int mState = STATE_NOT_AVAILABLE;
     private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
     private Context mContext;
 
-    public interface INotifyFeatureRemoved {
-        void onFeatureRemoved(int slotId);
-    }
-
     public void setContext(Context context) {
         mContext = context;
     }
@@ -110,26 +106,6 @@
         mSlotId = slotId;
     }
 
-    public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
-        synchronized (mRemovedListeners) {
-            mRemovedListeners.add(listener);
-        }
-    }
-
-    public void removeFeatureRemovedListener(INotifyFeatureRemoved listener) {
-        synchronized (mRemovedListeners) {
-            mRemovedListeners.remove(listener);
-        }
-    }
-
-    // Not final for testing.
-    public void notifyFeatureRemoved(int slotId) {
-        synchronized (mRemovedListeners) {
-            mRemovedListeners.forEach(l -> l.onFeatureRemoved(slotId));
-            onFeatureRemoved();
-        }
-    }
-
     public int getFeatureState() {
         return mState;
     }
@@ -212,7 +188,17 @@
     }
 
     /**
+     * Called when the feature is ready to use.
+     */
+    public abstract void onFeatureReady();
+
+    /**
      * Called when the feature is being removed and must be cleaned up.
      */
     public abstract void onFeatureRemoved();
+
+    /**
+     * @return Binder instance
+     */
+    public abstract IInterface getBinder();
 }
diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
index a71f0bf..4e095e3a 100644
--- a/telephony/java/android/telephony/ims/feature/MMTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
@@ -18,104 +18,342 @@
 
 import android.app.PendingIntent;
 import android.os.Message;
+import android.os.RemoteException;
 
 import com.android.ims.ImsCallProfile;
 import com.android.ims.internal.IImsCallSession;
 import com.android.ims.internal.IImsCallSessionListener;
 import com.android.ims.internal.IImsConfig;
 import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMMTelFeature;
 import com.android.ims.internal.IImsMultiEndpoint;
 import com.android.ims.internal.IImsRegistrationListener;
 import com.android.ims.internal.IImsUt;
-
-import java.util.ArrayList;
-import java.util.List;
+import com.android.ims.internal.ImsCallSession;
 
 /**
- * Base implementation, which implements all methods in IMMTelFeature. Any class wishing to use
- * MMTelFeature should extend this class and implement all methods that the service supports.
+ * Base implementation for MMTel.
+ * Any class wishing to use MMTelFeature should extend this class and implement all methods that the
+ * service supports.
  *
  * @hide
  */
 
-public class MMTelFeature extends ImsFeature implements IMMTelFeature {
+public class MMTelFeature extends ImsFeature {
 
+    // Lock for feature synchronization
+    private final Object mLock = new Object();
+
+    private final IImsMMTelFeature mImsMMTelBinder = new IImsMMTelFeature.Stub() {
+
+        @Override
+        public int startSession(PendingIntent incomingCallIntent,
+                IImsRegistrationListener listener) throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.startSession(incomingCallIntent, listener);
+            }
+        }
+
+        @Override
+        public void endSession(int sessionId) throws RemoteException {
+            synchronized (mLock) {
+                MMTelFeature.this.endSession(sessionId);
+            }
+        }
+
+        @Override
+        public boolean isConnected(int callSessionType, int callType)
+                throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.isConnected(callSessionType, callType);
+            }
+        }
+
+        @Override
+        public boolean isOpened() throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.isOpened();
+            }
+        }
+
+        @Override
+        public int getFeatureStatus() throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.getFeatureState();
+            }
+        }
+
+        @Override
+        public void addRegistrationListener(IImsRegistrationListener listener)
+                throws RemoteException {
+            synchronized (mLock) {
+                MMTelFeature.this.addRegistrationListener(listener);
+            }
+        }
+
+        @Override
+        public void removeRegistrationListener(IImsRegistrationListener listener)
+                throws RemoteException {
+            synchronized (mLock) {
+                MMTelFeature.this.removeRegistrationListener(listener);
+            }
+        }
+
+        @Override
+        public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType)
+                throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.createCallProfile(sessionId, callSessionType,  callType);
+            }
+        }
+
+        @Override
+        public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+                IImsCallSessionListener listener) throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.createCallSession(sessionId, profile, listener);
+            }
+        }
+
+        @Override
+        public IImsCallSession getPendingCallSession(int sessionId, String callId)
+                throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.getPendingCallSession(sessionId, callId);
+            }
+        }
+
+        @Override
+        public IImsUt getUtInterface() throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.getUtInterface();
+            }
+        }
+
+        @Override
+        public IImsConfig getConfigInterface() throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.getConfigInterface();
+            }
+        }
+
+        @Override
+        public void turnOnIms() throws RemoteException {
+            synchronized (mLock) {
+                MMTelFeature.this.turnOnIms();
+            }
+        }
+
+        @Override
+        public void turnOffIms() throws RemoteException {
+            synchronized (mLock) {
+                MMTelFeature.this.turnOffIms();
+            }
+        }
+
+        @Override
+        public IImsEcbm getEcbmInterface() throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.getEcbmInterface();
+            }
+        }
+
+        @Override
+        public void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException {
+            synchronized (mLock) {
+                MMTelFeature.this.setUiTTYMode(uiTtyMode, onComplete);
+            }
+        }
+
+        @Override
+        public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+            synchronized (mLock) {
+                return MMTelFeature.this.getMultiEndpointInterface();
+            }
+        }
+    };
+
+    /**
+     * @hide
+     */
     @Override
+    public final IImsMMTelFeature getBinder() {
+        return mImsMMTelBinder;
+    }
+
+    /**
+     * Notifies the MMTel feature that you would like to start a session. This should always be
+     * done before making/receiving IMS calls. The IMS service will register the device to the
+     * operator's network with the credentials (from ISIM) periodically in order to receive calls
+     * from the operator's network. When the IMS service receives a new call, it will send out an
+     * intent with the provided action string. The intent contains a call ID extra
+     * {@link IImsCallSession#getCallId} and it can be used to take a call.
+     *
+     * @param incomingCallIntent When an incoming call is received, the IMS service will call
+     * {@link PendingIntent#send} to send back the intent to the caller with
+     * ImsManager#INCOMING_CALL_RESULT_CODE as the result code and the intent to fill in the call
+     * ID; It cannot be null.
+     * @param listener To listen to IMS registration events; It cannot be null
+     * @return an integer (greater than 0) representing the session id associated with the session
+     * that has been started.
+     */
     public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener) {
         return 0;
     }
 
-    @Override
+    /**
+     * End a previously started session using the associated sessionId.
+     * @param sessionId an integer (greater than 0) representing the ongoing session. See
+     * {@link #startSession}.
+     */
     public void endSession(int sessionId) {
     }
 
-    @Override
+    /**
+     * Checks if the IMS service has successfully registered to the IMS network with the specified
+     * service & call type.
+     *
+     * @param callSessionType a service type that is specified in {@link ImsCallProfile}
+     *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+     *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+     * @param callType a call type that is specified in {@link ImsCallProfile}
+     *        {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
+     *        {@link ImsCallProfile#CALL_TYPE_VOICE}
+     *        {@link ImsCallProfile#CALL_TYPE_VT}
+     *        {@link ImsCallProfile#CALL_TYPE_VS}
+     * @return true if the specified service id is connected to the IMS network; false otherwise
+     */
     public boolean isConnected(int callSessionType, int callType) {
         return false;
     }
 
-    @Override
+    /**
+     * Checks if the specified IMS service is opened.
+     *
+     * @return true if the specified service id is opened; false otherwise
+     */
     public boolean isOpened() {
         return false;
     }
 
-    @Override
+    /**
+     * Add a new registration listener for the client associated with the session Id.
+     * @param listener An implementation of IImsRegistrationListener.
+     */
     public void addRegistrationListener(IImsRegistrationListener listener) {
     }
 
-    @Override
+    /**
+     * Remove a previously registered listener using {@link #addRegistrationListener} for the client
+     * associated with the session Id.
+     * @param listener A previously registered IImsRegistrationListener
+     */
     public void removeRegistrationListener(IImsRegistrationListener listener) {
     }
 
-    @Override
+    /**
+     * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
+     *
+     * @param sessionId a session id which is obtained from {@link #startSession}
+     * @param callSessionType a service type that is specified in {@link ImsCallProfile}
+     *        {@link ImsCallProfile#SERVICE_TYPE_NONE}
+     *        {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+     *        {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+     * @param callType a call type that is specified in {@link ImsCallProfile}
+     *        {@link ImsCallProfile#CALL_TYPE_VOICE}
+     *        {@link ImsCallProfile#CALL_TYPE_VT}
+     *        {@link ImsCallProfile#CALL_TYPE_VT_TX}
+     *        {@link ImsCallProfile#CALL_TYPE_VT_RX}
+     *        {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
+     *        {@link ImsCallProfile#CALL_TYPE_VS}
+     *        {@link ImsCallProfile#CALL_TYPE_VS_TX}
+     *        {@link ImsCallProfile#CALL_TYPE_VS_RX}
+     * @return a {@link ImsCallProfile} object
+     */
     public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType) {
         return null;
     }
 
-    @Override
+    /**
+     * Creates an {@link ImsCallSession} with the specified call profile.
+     * Use other methods, if applicable, instead of interacting with
+     * {@link ImsCallSession} directly.
+     *
+     * @param sessionId a session id which is obtained from {@link #startSession}
+     * @param profile a call profile to make the call
+     * @param listener An implementation of IImsCallSessionListener.
+     */
     public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
             IImsCallSessionListener listener) {
         return null;
     }
 
-    @Override
+    /**
+     * Retrieves the call session associated with a pending call.
+     *
+     * @param sessionId a session id which is obtained from {@link #startSession}
+     * @param callId a call id to make the call
+     */
     public IImsCallSession getPendingCallSession(int sessionId, String callId) {
         return null;
     }
 
-    @Override
+    /**
+     * @return The Ut interface for the supplementary service configuration.
+     */
     public IImsUt getUtInterface() {
         return null;
     }
 
-    @Override
+    /**
+     * @return The config interface for IMS Configuration
+     */
     public IImsConfig getConfigInterface() {
         return null;
     }
 
-    @Override
+    /**
+     * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
+     */
     public void turnOnIms() {
     }
 
-    @Override
+    /**
+     * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
+     */
     public void turnOffIms() {
     }
 
-    @Override
+    /**
+     * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
+     */
     public IImsEcbm getEcbmInterface() {
         return null;
     }
 
-    @Override
+    /**
+     * Sets the current UI TTY mode for the MMTelFeature.
+     * @param uiTtyMode An integer containing the new UI TTY Mode.
+     * @param onComplete A {@link Message} to be used when the mode has been set.
+     */
     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
     }
 
-    @Override
+    /**
+     * @return MultiEndpoint interface for DEP notifications
+     */
     public IImsMultiEndpoint getMultiEndpointInterface() {
         return null;
     }
 
     @Override
+    public void onFeatureReady() {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public void onFeatureRemoved() {
 
     }
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 9cddc1b..40c5181 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -16,20 +16,37 @@
 
 package android.telephony.ims.feature;
 
+import com.android.ims.internal.IImsRcsFeature;
+
 /**
  * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
- * this class and provide implementations of the IRcsFeature methods that they support.
+ * this class and provide implementations of the RcsFeature methods that they support.
  * @hide
  */
 
-public class RcsFeature extends ImsFeature implements IRcsFeature {
+public class RcsFeature extends ImsFeature {
+
+    private final IImsRcsFeature mImsRcsBinder = new IImsRcsFeature.Stub() {
+        // Empty Default Implementation.
+    };
+
 
     public RcsFeature() {
         super();
     }
 
     @Override
+    public void onFeatureReady() {
+
+    }
+
+    @Override
     public void onFeatureRemoved() {
 
     }
+
+    @Override
+    public final IImsRcsFeature getBinder() {
+        return mImsRcsBinder;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/feature/SmsFeature.java b/telephony/java/android/telephony/ims/feature/SmsFeature.java
new file mode 100644
index 0000000..c1366db
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/SmsFeature.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 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.ims.feature;
+
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import com.android.ims.internal.IImsSmsFeature;
+import com.android.ims.internal.ISmsListener;
+
+/**
+ * Base implementation of SMS over IMS functionality.
+ *
+ * @hide
+ */
+public class SmsFeature extends ImsFeature {
+  /**
+   * SMS over IMS format is 3gpp.
+   */
+  public static final int IMS_SMS_FORMAT_3GPP = 1;
+
+  /**
+   * SMS over IMS format is 3gpp2.
+   */
+  public static final int IMS_SMS_FORMAT_3GPP2 = 2;
+
+  /**
+   * Message was sent successfully.
+   */
+  public static final int SEND_STATUS_OK = 1;
+
+  /**
+   * IMS provider failed to send the message and platform should not retry falling back to sending
+   * the message using the radio.
+   */
+  public static final int SEND_STATUS_ERROR = 2;
+
+  /**
+   * IMS provider failed to send the message and platform should retry again after setting TP-RD bit
+   * to high.
+   */
+  public static final int SEND_STATUS_ERROR_RETRY = 3;
+
+  /**
+   * IMS provider failed to send the message and platform should retry falling back to sending
+   * the message using the radio.
+   */
+  public static final int SEND_STATUS_ERROR_FALLBACK = 4;
+
+  /**
+   * Message was delivered successfully.
+   */
+  public static final int DELIVER_STATUS_OK = 1;
+
+  /**
+   * Message was not delivered.
+   */
+  public static final int DELIVER_STATUS_ERROR = 2;
+
+  // Lock for feature synchronization
+  private final Object mLock = new Object();
+  private ISmsListener mSmsListener;
+
+  private final IImsSmsFeature mIImsSmsBinder = new IImsSmsFeature.Stub() {
+    @Override
+    public void registerSmsListener(ISmsListener listener) {
+      synchronized (mLock) {
+        SmsFeature.this.registerSmsListener(listener);
+      }
+    }
+
+    @Override
+    public void sendSms(int format, int messageRef, boolean retry, byte[] pdu) {
+      synchronized (mLock) {
+        SmsFeature.this.sendSms(format, messageRef, retry, pdu);
+      }
+    }
+
+    @Override
+    public void acknowledgeSms(int messageRef, int result) {
+      synchronized (mLock) {
+        SmsFeature.this.acknowledgeSms(messageRef, result);
+      }
+    }
+
+    @Override
+    public int getSmsFormat() {
+      synchronized (mLock) {
+        return SmsFeature.this.getSmsFormat();
+      }
+    }
+  };
+
+  /**
+   * Registers a listener responsible for handling tasks like delivering messages.
+
+   * @param listener listener to register.
+   *
+   * @hide
+   */
+  @SystemApi
+  public final void registerSmsListener(ISmsListener listener) {
+    synchronized (mLock) {
+      mSmsListener = listener;
+    }
+  }
+
+  /**
+   * This method will be triggered by the platform when the user attempts to send an SMS. This
+   * method should be implemented by the IMS providers to provide implementation of sending an SMS
+   * over IMS.
+   *
+   * @param format the format of the message. One of {@link #IMS_SMS_FORMAT_3GPP} or
+   *                {@link #IMS_SMS_FORMAT_3GPP2}
+   * @param messageRef the message reference.
+   * @param retry whether it is a retry of an already attempted message or not.
+   * @param pdu PDUs representing the contents of the message.
+   */
+  public void sendSms(int format, int messageRef, boolean isRetry, byte[] pdu) {
+  }
+
+  /**
+   * This method will be triggered by the platform after {@link #deliverSms(int, byte[])} has been
+   * called to deliver the result to the IMS provider. It will also be triggered after
+   * {@link #setSentSmsResult(int, int)} has been called to provide the result of the operation.
+   *
+   * @param result Should be {@link #DELIVER_STATUS_OK} if the message was delivered successfully,
+   * {@link #DELIVER_STATUS_ERROR} otherwise.
+   * @param messageRef the message reference.
+   */
+  public void acknowledgeSms(int messageRef, int result) {
+
+  }
+
+  /**
+   * This method should be triggered by the IMS providers when there is an incoming message. The
+   * platform will deliver the message to the messages database and notify the IMS provider of the
+   * result by calling {@link #acknowledgeSms(int)}.
+   *
+   * This method must not be called before {@link #onFeatureReady()} is called.
+   *
+   * @param format the format of the message.One of {@link #IMS_SMS_FORMAT_3GPP} or
+   *                {@link #IMS_SMS_FORMAT_3GPP2}
+   * @param pdu PDUs representing the contents of the message.
+   * @throws IllegalStateException if called before {@link #onFeatureReady()}
+   */
+  public final void deliverSms(int format, byte[] pdu) throws IllegalStateException {
+    // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
+    // otherwise.
+    try {
+      mSmsListener.deliverSms(format, pdu);
+    } catch (RemoteException e) {
+    }
+  }
+
+  /**
+   * This method should be triggered by the IMS providers to pass the result of the sent message
+   * to the platform.
+   *
+   * This method must not be called before {@link #onFeatureReady()} is called.
+   *
+   * @param messageRef the message reference.
+   * @param result One of {@link #SEND_STATUS_OK}, {@link #SEND_STATUS_ERROR},
+   *                {@link #SEND_STATUS_ERROR_RETRY}, {@link #SEND_STATUS_ERROR_FALLBACK}
+   * @throws IllegalStateException if called before {@link #onFeatureReady()}
+   */
+  public final void setSentSmsResult(int messageRef, int result) throws IllegalStateException {
+    // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
+    // otherwise.
+    try {
+      mSmsListener.setSentSmsResult(messageRef, result);
+    } catch (RemoteException e) {
+    }
+  }
+
+  /**
+   * Sets the status report of the sent message.
+   *
+   * @param format Should be {@link #IMS_SMS_FORMAT_3GPP} or {@link #IMS_SMS_FORMAT_3GPP2}
+   * @param pdu PDUs representing the content of the status report.
+   * @throws IllegalStateException if called before {@link #onFeatureReady()}
+   */
+  public final void setSentSmsStatusReport(int format, byte[] pdu) {
+    // TODO: Guard against NPE/ Check if feature is ready and thrown an exception
+    // otherwise.
+    try {
+      mSmsListener.setSentSmsStatusReport(format, pdu);
+    } catch (RemoteException e) {
+    }
+  }
+
+  /**
+   * Returns the SMS format. Default is {@link #IMS_SMS_FORMAT_3GPP} unless overridden by IMS
+   * Provider.
+   *
+   * @return sms format.
+   */
+  public int getSmsFormat() {
+    return IMS_SMS_FORMAT_3GPP;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void onFeatureReady() {
+
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void onFeatureRemoved() {
+
+  }
+
+  /**
+   * @hide
+   */
+  @Override
+  public final IImsSmsFeature getBinder() {
+    return mIImsSmsBinder;
+  }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index dc74094..054a8b2 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -53,6 +53,15 @@
     }
 
     /**
+     * Retrieves the configuration of the call barring for specified service class.
+     */
+    @Override
+    public int queryCallBarringForServiceClass(int cbType, int serviceClass)
+            throws RemoteException {
+        return -1;
+    }
+
+    /**
      * Retrieves the configuration of the call forward.
      */
     @Override
@@ -117,6 +126,15 @@
     }
 
     /**
+     * Updates the configuration of the call barring for specified service class.
+     */
+    @Override
+    public int updateCallBarringForServiceClass(int cbType, int action, String[] barrList,
+            int serviceClass) throws RemoteException {
+        return -1;
+    }
+
+    /**
      * Updates the configuration of the call forward.
      */
     @Override
diff --git a/telephony/java/android/telephony/mbms/DownloadStateCallback.java b/telephony/java/android/telephony/mbms/DownloadStateCallback.java
index 892fbf0..9f60cc3 100644
--- a/telephony/java/android/telephony/mbms/DownloadStateCallback.java
+++ b/telephony/java/android/telephony/mbms/DownloadStateCallback.java
@@ -38,7 +38,7 @@
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ALL_UPDATES, PROGRESS_UPDATES, STATE_UPDATES})
+    @IntDef(flag = true, value = {ALL_UPDATES, PROGRESS_UPDATES, STATE_UPDATES})
     public @interface FilterFlag {}
 
     /**
diff --git a/telephony/java/android/telephony/mbms/FileInfo.java b/telephony/java/android/telephony/mbms/FileInfo.java
index 0d737b5..e064adb 100644
--- a/telephony/java/android/telephony/mbms/FileInfo.java
+++ b/telephony/java/android/telephony/mbms/FileInfo.java
@@ -17,10 +17,13 @@
 package android.telephony.mbms;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /**
  * Describes a single file that is available over MBMS.
  */
@@ -47,6 +50,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public FileInfo(Uri uri, String mimeType) {
         this.uri = uri;
         this.mimeType = mimeType;
@@ -82,4 +86,23 @@
     public String getMimeType() {
         return mimeType;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        FileInfo fileInfo = (FileInfo) o;
+        return Objects.equals(uri, fileInfo.uri) &&
+                Objects.equals(mimeType, fileInfo.mimeType);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(uri, mimeType);
+    }
 }
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index 9af1eb9..9ef188c 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -165,16 +165,16 @@
                 Log.w(LOG_TAG, "Download result did not include a result code. Ignoring.");
                 return false;
             }
+            if (!intent.hasExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST)) {
+                Log.w(LOG_TAG, "Download result did not include the associated request. Ignoring.");
+                return false;
+            }
             // We do not need to verify below extras if the result is not success.
             if (MbmsDownloadSession.RESULT_SUCCESSFUL !=
                     intent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
                     MbmsDownloadSession.RESULT_CANCELLED)) {
                 return true;
             }
-            if (!intent.hasExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST)) {
-                Log.w(LOG_TAG, "Download result did not include the associated request. Ignoring.");
-                return false;
-            }
             if (!intent.hasExtra(VendorUtils.EXTRA_TEMP_FILE_ROOT)) {
                 Log.w(LOG_TAG, "Download result did not include the temp file root. Ignoring.");
                 return false;
@@ -242,10 +242,12 @@
         int result = intent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
                 MbmsDownloadSession.RESULT_CANCELLED);
         intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT, result);
+        intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, request);
 
         if (result != MbmsDownloadSession.RESULT_SUCCESSFUL) {
             Log.i(LOG_TAG, "Download request indicated a failed download. Aborting.");
             context.sendBroadcast(intentForApp);
+            setResultCode(RESULT_OK);
             return;
         }
 
@@ -273,7 +275,6 @@
         intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_COMPLETED_FILE_URI,
                 stagedFileLocation);
         intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO, completedFileInfo);
-        intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, request);
 
         context.sendBroadcast(intentForApp);
         setResultCode(RESULT_OK);
diff --git a/telephony/java/android/telephony/mbms/UriPathPair.java b/telephony/java/android/telephony/mbms/UriPathPair.java
index 187e9ee..dd20a69 100644
--- a/telephony/java/android/telephony/mbms/UriPathPair.java
+++ b/telephony/java/android/telephony/mbms/UriPathPair.java
@@ -17,6 +17,7 @@
 package android.telephony.mbms;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.ContentResolver;
 import android.net.Uri;
 import android.os.Parcel;
@@ -29,6 +30,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class UriPathPair implements Parcelable {
     private final Uri mFilePathUri;
     private final Uri mContentUri;
diff --git a/telephony/java/android/telephony/mbms/vendor/VendorUtils.java b/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
index a43f122..f1cac8c 100644
--- a/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
+++ b/telephony/java/android/telephony/mbms/vendor/VendorUtils.java
@@ -17,6 +17,7 @@
 package android.telephony.mbms.vendor;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -34,6 +35,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public class VendorUtils {
 
     /**
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index 5984e78..250371f 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -109,6 +109,12 @@
     public void queryCallBarring(int cbType, Message result);
 
     /**
+     * Retrieves the configuration of the call barring for specified service class.
+     * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+     */
+    public void queryCallBarring(int cbType, Message result, int serviceClass);
+
+    /**
      * Retrieves the configuration of the call forward.
      * The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
      */
@@ -147,6 +153,12 @@
             Message result, String[] barrList);
 
     /**
+     * Modifies the configuration of the call barring for specified service class.
+     */
+    public void updateCallBarring(int cbType, int action, Message result,
+            String[] barrList, int serviceClass);
+
+    /**
      * Modifies the configuration of the call forward.
      */
     public void updateCallForward(int action, int condition, String number,
diff --git a/telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl b/telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl
new file mode 100644
index 0000000..52b3853
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsMMTelFeature.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 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.ims.internal;
+
+import android.app.PendingIntent;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+import android.os.Message;
+
+/**
+ * See MMTelFeature for more information.
+ * {@hide}
+ */
+interface IImsMMTelFeature {
+    int startSession(in PendingIntent incomingCallIntent,
+            in IImsRegistrationListener listener);
+    void endSession(int sessionId);
+    boolean isConnected(int callSessionType, int callType);
+    boolean isOpened();
+    int getFeatureStatus();
+    void addRegistrationListener(in IImsRegistrationListener listener);
+    void removeRegistrationListener(in IImsRegistrationListener listener);
+    ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType);
+    IImsCallSession createCallSession(int sessionId, in ImsCallProfile profile,
+            IImsCallSessionListener listener);
+    IImsCallSession getPendingCallSession(int sessionId, String callId);
+    IImsUt getUtInterface();
+    IImsConfig getConfigInterface();
+    void turnOnIms();
+    void turnOffIms();
+    IImsEcbm getEcbmInterface();
+    void setUiTTYMode(int uiTtyMode, in Message onComplete);
+    IImsMultiEndpoint getMultiEndpointInterface();
+}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsRcsFeature.aidl
similarity index 65%
copy from telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
copy to telephony/java/com/android/ims/internal/IImsRcsFeature.aidl
index df10700..b1cb23b 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRcsFeature.aidl
@@ -17,12 +17,9 @@
 package com.android.ims.internal;
 
 /**
- *  Interface from ImsResolver to ImsServiceProxy in ImsManager.
- * Callback to ImsManager when a feature changes in the ImsServiceController.
+ * See RcsFeature for more information.
  * {@hide}
  */
-oneway interface IImsServiceFeatureListener {
-    void imsFeatureCreated(int slotId, int feature);
-    void imsFeatureRemoved(int slotId, int feature);
-    void imsStatusChanged(int slotId, int feature, int status);
+interface IImsRcsFeature {
+    //Empty Default Implementation
 }
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index bb06d7e..857089f 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -16,49 +16,17 @@
 
 package com.android.ims.internal;
 
-import android.app.PendingIntent;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsFeatureStatusCallback;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsUt;
-
-import android.os.Message;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
 
 /**
- * See ImsService and IMMTelFeature for more information.
+ * See ImsService and MMTelFeature for more information.
  * {@hide}
  */
 interface IImsServiceController {
-    // ImsService Control
-    void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c);
-    void removeImsFeature(int slotId, int feature, IImsFeatureStatusCallback c);
-    // MMTel Feature
-    int startSession(int slotId, int featureType, in PendingIntent incomingCallIntent,
-            in IImsRegistrationListener listener);
-    void endSession(int slotId, int featureType, int sessionId);
-    boolean isConnected(int slotId, int featureType, int callSessionType, int callType);
-    boolean isOpened(int slotId, int featureType);
-    int getFeatureStatus(int slotId, int featureType);
-    void addRegistrationListener(int slotId, int featureType, in IImsRegistrationListener listener);
-    void removeRegistrationListener(int slotId, int featureType,
-            in IImsRegistrationListener listener);
-    ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
-            int callSessionType, int callType);
-    IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
-            in ImsCallProfile profile, IImsCallSessionListener listener);
-    IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
-            String callId);
-    IImsUt getUtInterface(int slotId, int featureType);
-    IImsConfig getConfigInterface(int slotId, int featureType);
-    void turnOnIms(int slotId, int featureType);
-    void turnOffIms(int slotId, int featureType);
-    IImsEcbm getEcbmInterface(int slotId, int featureType);
-    void setUiTTYMode(int slotId, int featureType, int uiTtyMode, in Message onComplete);
-    IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType);
+    IImsMMTelFeature createEmergencyMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
+    IImsMMTelFeature createMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
+    IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c);
+    void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c);
 }
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
similarity index 95%
rename from telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
rename to telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
index df10700..9a9cf53 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
@@ -21,7 +21,7 @@
  * Callback to ImsManager when a feature changes in the ImsServiceController.
  * {@hide}
  */
-oneway interface IImsServiceFeatureListener {
+oneway interface IImsServiceFeatureCallback {
     void imsFeatureCreated(int slotId, int feature);
     void imsFeatureRemoved(int slotId, int feature);
     void imsStatusChanged(int slotId, int feature, int status);
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl
similarity index 65%
copy from telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
copy to telephony/java/com/android/ims/internal/IImsSmsFeature.aidl
index df10700..5068128 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsSmsFeature.aidl
@@ -16,13 +16,16 @@
 
 package com.android.ims.internal;
 
+import com.android.ims.internal.ISmsListener;
+
 /**
- *  Interface from ImsResolver to ImsServiceProxy in ImsManager.
- * Callback to ImsManager when a feature changes in the ImsServiceController.
+ * See SmsFeature for more information.
+ *
  * {@hide}
  */
-oneway interface IImsServiceFeatureListener {
-    void imsFeatureCreated(int slotId, int feature);
-    void imsFeatureRemoved(int slotId, int feature);
-    void imsStatusChanged(int slotId, int feature, int status);
+interface IImsSmsFeature {
+    void registerSmsListener(in ISmsListener listener);
+    void sendSms(in int format, in int messageRef, in boolean retry, in byte[] pdu);
+    void acknowledgeSms(in int messageRef, in int result);
+    int getSmsFormat();
 }
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 4ab5ee3..4f97cc5 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -111,4 +111,15 @@
      * Sets the listener.
      */
     void setListener(in IImsUtListener listener);
+
+    /**
+     * Retrieves the configuration of the call barring for specified service class.
+     */
+    int queryCallBarringForServiceClass(int cbType, int serviceClass);
+
+    /**
+     * Updates the configuration of the call barring for specified service class.
+     */
+    int updateCallBarringForServiceClass(int cbType, int action, in String[] barrList,
+            int serviceClass);
 }
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/ISmsListener.aidl
similarity index 65%
copy from telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
copy to telephony/java/com/android/ims/internal/ISmsListener.aidl
index df10700..1266f04 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/ISmsListener.aidl
@@ -17,12 +17,11 @@
 package com.android.ims.internal;
 
 /**
- *  Interface from ImsResolver to ImsServiceProxy in ImsManager.
- * Callback to ImsManager when a feature changes in the ImsServiceController.
+ * See SmsFeature for more information.
  * {@hide}
  */
-oneway interface IImsServiceFeatureListener {
-    void imsFeatureCreated(int slotId, int feature);
-    void imsFeatureRemoved(int slotId, int feature);
-    void imsStatusChanged(int slotId, int feature, int status);
+interface ISmsListener {
+    void setSentSmsResult(in int messageRef, in int result);
+    void setSentSmsStatusReport(in int format, in byte[] pdu);
+    void deliverSms(in int format, in byte[] pdu);
 }
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index e9c5461..ac16139 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -45,7 +45,6 @@
     void onVoLteServiceStateChanged(in VoLteServiceState lteState);
     void onVoiceActivationStateChanged(int activationState);
     void onDataActivationStateChanged(int activationState);
-    void onOemHookRawEvent(in byte[] rawData);
     void onCarrierNetworkChange(in boolean active);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2ac11b5..fd6091a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -38,8 +38,9 @@
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyHistogram;
 import android.telephony.VisualVoicemailSmsFilterSettings;
-import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsMMTelFeature;
+import com.android.ims.internal.IImsRcsFeature;
+import com.android.ims.internal.IImsServiceFeatureCallback;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.OperatorInfo;
 
@@ -784,12 +785,27 @@
     int getTetherApnRequired();
 
     /**
-     *  Get ImsServiceController binder from ImsResolver that corresponds to the subId and feature
-     *  requested as well as registering the ImsServiceController for callbacks using the
-     *  IImsServiceFeatureListener interface.
+     *  Get IImsMMTelFeature binder from ImsResolver that corresponds to the subId and MMTel feature
+     *  as well as registering the MMTelFeature for callbacks using the IImsServiceFeatureCallback
+     *  interface.
      */
-    IImsServiceController getImsServiceControllerAndListen(int slotIndex, int feature,
-                IImsServiceFeatureListener callback);
+    IImsMMTelFeature getMMTelFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
+
+    /**
+     *  Get IImsMMTelFeature binder from ImsResolver that corresponds to the subId and MMTel feature
+     *  as well as registering the MMTelFeature for callbacks using the IImsServiceFeatureCallback
+     *  interface.
+     *  Used for emergency calling only.
+     */
+    IImsMMTelFeature getEmergencyMMTelFeatureAndListen(int slotId,
+            in IImsServiceFeatureCallback callback);
+
+    /**
+     *  Get IImsRcsFeature binder from ImsResolver that corresponds to the subId and RCS feature
+     *  as well as registering the RcsFeature for callbacks using the IImsServiceFeatureCallback
+     *  interface.
+     */
+    IImsRcsFeature getRcsFeatureAndListen(int slotId, in IImsServiceFeatureCallback callback);
 
     /**
      * Set the network selection mode to automatic.
@@ -1000,17 +1016,6 @@
             in List<String> cdmaNonRoamingList);
 
     /**
-     * Returns the result and response from RIL for oem request
-     *
-     * @param oemReq the data is sent to ril.
-     * @param oemResp the respose data from RIL.
-     * @return negative value request was not handled or get error
-     *         0 request was handled succesfully, but no response data
-     *         positive value success, data length of response
-     */
-    int invokeOemRilRequestRaw(in byte[] oemReq, out byte[] oemResp);
-
-    /**
      * Check if any mobile Radios need to be shutdown.
      *
      * @return true is any mobile radio needs to be shutdown
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 2c2206c..75d8f3f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -67,7 +67,6 @@
     void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
     void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
             int activationState, int activationType);
-    void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
     void notifySubscriptionInfoChanged();
     void notifyCarrierNetworkChange(in boolean active);
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
index 5f2e561..d27a758 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSmsAddress.java
@@ -18,6 +18,7 @@
 
 import android.util.SparseBooleanArray;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.SmsAddress;
 import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.util.HexDump;
@@ -113,8 +114,8 @@
      * share code and logic with GSM.  Also, gather all DTMF/BCD
      * processing code in one place.
      */
-
-    private static byte[] parseToDtmf(String address) {
+    @VisibleForTesting
+    public static byte[] parseToDtmf(String address) {
         int digits = address.length();
         byte[] result = new byte[digits];
         for (int i = 0; i < digits; i++) {
@@ -196,33 +197,46 @@
     public static CdmaSmsAddress parse(String address) {
         CdmaSmsAddress addr = new CdmaSmsAddress();
         addr.address = address;
-        addr.ton = CdmaSmsAddress.TON_UNKNOWN;
-        byte[] origBytes = null;
+        addr.ton = TON_UNKNOWN;
+        addr.digitMode = DIGIT_MODE_4BIT_DTMF;
+        addr.numberPlan = NUMBERING_PLAN_UNKNOWN;
+        addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+
+        byte[] origBytes;
         String filteredAddr = filterNumericSugar(address);
-        if (filteredAddr != null) {
-            origBytes = parseToDtmf(filteredAddr);
-        }
-        if (origBytes != null) {
-            addr.digitMode = DIGIT_MODE_4BIT_DTMF;
-            addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
-            if (address.indexOf('+') != -1) {
-                addr.ton = TON_INTERNATIONAL_OR_IP;
-            }
-        } else {
-            filteredAddr = filterWhitespace(address);
-            origBytes = UserData.stringToAscii(filteredAddr);
-            if (origBytes == null) {
-                return null;
-            }
+        if (address.contains("+") || filteredAddr == null) {
+            // 3GPP2 C.S0015-B section 3.4.3.3 Address Parameters
+            // NUMBER_MODE should set to 1 for network address and email address.
             addr.digitMode = DIGIT_MODE_8BIT_CHAR;
             addr.numberMode = NUMBER_MODE_DATA_NETWORK;
-            if (address.indexOf('@') != -1) {
+            filteredAddr = filterWhitespace(address);
+
+            if (address.contains("@")) {
+                // This is an email address
                 addr.ton = TON_NATIONAL_OR_EMAIL;
+            } else if (address.contains("+") && filterNumericSugar(address) != null) {
+                // This is an international number
+                // 3GPP2 C.S0015-B section 3.4.3.3 Address Parameters
+                // digit mode is set to 1 and number mode is set to 0, type of number should set
+                // to the value correspond to the value in 3GPP2 C.S005-D, table2.7.1.3.2.4-2
+                addr.ton = TON_INTERNATIONAL_OR_IP;
+                addr.numberPlan = NUMBERING_PLAN_ISDN_TELEPHONY;
+                addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+                filteredAddr = filterNumericSugar(address);
             }
+
+            origBytes = UserData.stringToAscii(filteredAddr);
+        } else {
+            // The address is not an international number and it only contains digit and *#
+            origBytes = parseToDtmf(filteredAddr);
         }
+
+        if (origBytes == null) {
+            return null;
+        }
+
         addr.origBytes = origBytes;
         addr.numberOfDigits = origBytes.length;
         return addr;
     }
-
 }
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
new file mode 100644
index 0000000..fcbb9da
--- /dev/null
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import android.net.MacAddress.MacAddressType;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.util.Arrays;
+import java.util.Random;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MacAddressTest {
+
+    static class AddrTypeTestCase {
+        byte[] addr;
+        MacAddressType expected;
+
+        static AddrTypeTestCase of(MacAddressType expected, int... addr) {
+            AddrTypeTestCase t = new AddrTypeTestCase();
+            t.expected = expected;
+            t.addr = toByteArray(addr);
+            return t;
+        }
+    }
+
+    @Test
+    public void testMacAddrTypes() {
+        AddrTypeTestCase[] testcases = {
+            AddrTypeTestCase.of(null),
+            AddrTypeTestCase.of(null, 0),
+            AddrTypeTestCase.of(null, 1, 2, 3, 4, 5),
+            AddrTypeTestCase.of(null, 1, 2, 3, 4, 5, 6, 7),
+            AddrTypeTestCase.of(MacAddressType.UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0),
+            AddrTypeTestCase.of(MacAddressType.BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+            AddrTypeTestCase.of(MacAddressType.MULTICAST, 1, 2, 3, 4, 5, 6),
+            AddrTypeTestCase.of(MacAddressType.MULTICAST, 11, 22, 33, 44, 55, 66),
+            AddrTypeTestCase.of(MacAddressType.MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd)
+        };
+
+        for (AddrTypeTestCase t : testcases) {
+            MacAddressType got = MacAddress.macAddressType(t.addr);
+            String msg = String.format("expected type of %s to be %s, but got %s",
+                    Arrays.toString(t.addr), t.expected, got);
+            assertEquals(msg, t.expected, got);
+
+            if (got != null) {
+                assertEquals(got, new MacAddress(t.addr).addressType());
+            }
+        }
+    }
+
+    @Test
+    public void testIsMulticastAddress() {
+        MacAddress[] multicastAddresses = {
+            MacAddress.BROADCAST_ADDRESS,
+            new MacAddress("07:00:d3:56:8a:c4"),
+            new MacAddress("33:33:aa:bb:cc:dd"),
+        };
+        MacAddress[] unicastAddresses = {
+            MacAddress.ALL_ZEROS_ADDRESS,
+            new MacAddress("00:01:44:55:66:77"),
+            new MacAddress("08:00:22:33:44:55"),
+            new MacAddress("06:00:00:00:00:00"),
+        };
+
+        for (MacAddress mac : multicastAddresses) {
+            String msg = mac.toString() + " expected to be a multicast address";
+            assertTrue(msg, mac.isMulticastAddress());
+        }
+        for (MacAddress mac : unicastAddresses) {
+            String msg = mac.toString() + " expected not to be a multicast address";
+            assertFalse(msg, mac.isMulticastAddress());
+        }
+    }
+
+    @Test
+    public void testIsLocallyAssignedAddress() {
+        MacAddress[] localAddresses = {
+            new MacAddress("06:00:00:00:00:00"),
+            new MacAddress("07:00:d3:56:8a:c4"),
+            new MacAddress("33:33:aa:bb:cc:dd"),
+        };
+        MacAddress[] universalAddresses = {
+            new MacAddress("00:01:44:55:66:77"),
+            new MacAddress("08:00:22:33:44:55"),
+        };
+
+        for (MacAddress mac : localAddresses) {
+            String msg = mac.toString() + " expected to be a locally assigned address";
+            assertTrue(msg, mac.isLocallyAssigned());
+        }
+        for (MacAddress mac : universalAddresses) {
+            String msg = mac.toString() + " expected not to be globally unique address";
+            assertFalse(msg, mac.isLocallyAssigned());
+        }
+    }
+
+    @Test
+    public void testMacAddressConversions() {
+        final int iterations = 10000;
+        for (int i = 0; i < iterations; i++) {
+            MacAddress mac = MacAddress.getRandomAddress();
+
+            String stringRepr = mac.toString();
+            byte[] bytesRepr = mac.toByteArray();
+
+            assertEquals(mac, new MacAddress(stringRepr));
+            assertEquals(mac, new MacAddress(bytesRepr));
+        }
+    }
+
+    @Test
+    public void testMacAddressRandomGeneration() {
+        final int iterations = 1000;
+        final String expectedAndroidOui = "da:a1:19";
+        for (int i = 0; i < iterations; i++) {
+            MacAddress mac = MacAddress.getRandomAddress();
+            String stringRepr = mac.toString();
+
+            assertTrue(stringRepr + " expected to be a locally assigned address",
+                    mac.isLocallyAssigned());
+            assertTrue(stringRepr + " expected to begin with " + expectedAndroidOui,
+                    stringRepr.startsWith(expectedAndroidOui));
+        }
+
+        final Random r = new Random();
+        final String anotherOui = "24:5f:78";
+        final String expectedLocalOui = "26:5f:78";
+        final MacAddress base = new MacAddress(anotherOui + ":0:0:0");
+        for (int i = 0; i < iterations; i++) {
+            MacAddress mac = MacAddress.getRandomAddress(base, r);
+            String stringRepr = mac.toString();
+
+            assertTrue(stringRepr + " expected to be a locally assigned address",
+                    mac.isLocallyAssigned());
+            assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
+                    stringRepr.startsWith(expectedLocalOui));
+        }
+    }
+
+    @Test
+    public void testConstructorInputValidation() {
+        String[] invalidStringAddresses = {
+            null,
+            "",
+            "abcd",
+            "1:2:3:4:5",
+            "1:2:3:4:5:6:7",
+            "10000:2:3:4:5:6",
+        };
+
+        for (String s : invalidStringAddresses) {
+            try {
+                MacAddress mac = new MacAddress(s);
+                fail("new MacAddress(" + s + ") should have failed, but returned " + mac);
+            } catch (IllegalArgumentException excepted) {
+            }
+        }
+
+        byte[][] invalidBytesAddresses = {
+            null,
+            {},
+            {1,2,3,4,5},
+            {1,2,3,4,5,6,7},
+        };
+
+        for (byte[] b : invalidBytesAddresses) {
+            try {
+                MacAddress mac = new MacAddress(b);
+                fail("new MacAddress(" + Arrays.toString(b)
+                        + ") should have failed, but returned " + mac);
+            } catch (IllegalArgumentException excepted) {
+            }
+        }
+    }
+
+    static byte[] toByteArray(int... in) {
+        byte[] out = new byte[in.length];
+        for (int i = 0; i < in.length; i++) {
+            out[i] = (byte) in[i];
+        }
+        return out;
+    }
+}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 99a2ad9..725ddb9 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -29,9 +29,7 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
-import android.net.apf.ApfCapabilities;
-import android.net.apf.ApfFilter;
-import android.net.apf.ApfGenerator;
+import android.net.apf.ApfFilter.ApfConfiguration;
 import android.net.apf.ApfGenerator.IllegalInstructionException;
 import android.net.apf.ApfGenerator.Register;
 import android.net.ip.IpManager;
@@ -99,12 +97,24 @@
     // least the minimum packet size.
     private final static int MIN_PKT_SIZE = 15;
 
+    private static final ApfCapabilities MOCK_APF_CAPABILITIES =
+      new ApfCapabilities(2, 1700, ARPHRD_ETHER);
+
     private final static boolean DROP_MULTICAST = true;
     private final static boolean ALLOW_MULTICAST = false;
 
     private final static boolean DROP_802_3_FRAMES = true;
     private final static boolean ALLOW_802_3_FRAMES = false;
 
+    private static ApfConfiguration getDefaultConfig() {
+        ApfFilter.ApfConfiguration config = new ApfConfiguration();
+        config.apfCapabilities = MOCK_APF_CAPABILITIES;
+        config.multicastFilter = ALLOW_MULTICAST;
+        config.ieee802_3Filter = ALLOW_802_3_FRAMES;
+        config.ethTypeBlackList = new int[0];
+        return config;
+    }
+
     private static String label(int code) {
         switch (code) {
             case PASS: return "PASS";
@@ -619,15 +629,13 @@
 
     private static class TestApfFilter extends ApfFilter {
         public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
-        private FileDescriptor mWriteSocket;
 
+        private FileDescriptor mWriteSocket;
         private final long mFixedTimeMs = SystemClock.elapsedRealtime();
 
-        public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
-                boolean ieee802_3Filter, int[] ethTypeBlackList,
+        public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback,
                 IpConnectivityLog log) throws Exception {
-            super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
-                    ipManagerCallback, multicastFilter, ieee802_3Filter, ethTypeBlackList, log);
+            super(config, NetworkInterface.getByName("lo"), ipManagerCallback, log);
         }
 
         // Pretend an RA packet has been received and show it to ApfFilter.
@@ -755,10 +763,10 @@
         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
         LinkProperties lp = new LinkProperties();
         lp.addLinkAddress(link);
-        final int[] ethTypeBlackList = {};
 
-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
-                ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
 
         byte[] program = ipManagerCallback.getApfProgram();
@@ -808,10 +816,9 @@
 
     @Test
     public void testApfFilterIPv6() throws Exception {
-        final int[] ethTypeBlackList = {};
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
-                ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         byte[] program = ipManagerCallback.getApfProgram();
 
         // Verify empty IPv6 packet is passed
@@ -846,15 +853,15 @@
         final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
         final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
         final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
-        final int[] ethTypeBlackList = {};
 
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
         LinkProperties lp = new LinkProperties();
         lp.addLinkAddress(link);
 
-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
-                DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
 
         byte[] program = ipManagerCallback.getApfProgram();
@@ -916,8 +923,9 @@
         // Verify it can be initialized to on
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
-        apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
-                DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
         program = ipManagerCallback.getApfProgram();
         assertDrop(program, mcastv4packet.array());
@@ -938,10 +946,9 @@
         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
         LinkProperties lp = new LinkProperties();
         lp.addLinkAddress(link);
-        final int[] ethTypeBlackList = {};
 
-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
-                ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
 
         byte[] program = ipManagerCallback.getApfProgram();
@@ -962,8 +969,8 @@
         // Now turn on the filter
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
-        apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
-                DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
         program = ipManagerCallback.getApfProgram();
 
@@ -993,8 +1000,8 @@
         final int[] ipv4BlackList = {ETH_P_IP};
         final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
 
-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
-                ALLOW_802_3_FRAMES, emptyBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
 
         byte[] program = ipManagerCallback.getApfProgram();
@@ -1015,8 +1022,8 @@
         // Now add IPv4 to the black list
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
-        apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
-                ALLOW_802_3_FRAMES, ipv4BlackList, mLog);
+        config.ethTypeBlackList = ipv4BlackList;
+        apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
         program = ipManagerCallback.getApfProgram();
 
@@ -1031,8 +1038,8 @@
         // Now let us have both IPv4 and IPv6 in the black list
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
-        apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
-                ALLOW_802_3_FRAMES, ipv4Ipv6BlackList, mLog);
+        config.ethTypeBlackList = ipv4Ipv6BlackList;
+        apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
         program = ipManagerCallback.getApfProgram();
 
@@ -1070,10 +1077,11 @@
 
     @Test
     public void testApfFilterArp() throws Exception {
-        final int[] ethTypeBlackList = {};
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
-        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
-                DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
 
         // Verify initially ARP request filter is off, and GARP filter is on.
         verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
@@ -1194,9 +1202,10 @@
     @Test
     public void testApfFilterRa() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
-        final int[] ethTypeBlackList = {};
-        TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
-                DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
         byte[] program = ipManagerCallback.getApfProgram();
 
         final int ROUTER_LIFETIME = 1000;
@@ -1338,10 +1347,11 @@
     public void testRaParsing() throws Exception {
         final int maxRandomPacketSize = 512;
         final Random r = new Random();
-        final int[] ethTypeBlackList = {};
         MockIpManagerCallback cb = new MockIpManagerCallback();
-        TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
-                DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
         for (int i = 0; i < 1000; i++) {
             byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
             r.nextBytes(packet);
@@ -1358,10 +1368,11 @@
     public void testRaProcessing() throws Exception {
         final int maxRandomPacketSize = 512;
         final Random r = new Random();
-        final int[] ethTypeBlackList = {};
         MockIpManagerCallback cb = new MockIpManagerCallback();
-        TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
-                DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+        ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
         for (int i = 0; i < 1000; i++) {
             byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
             r.nextBytes(packet);
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 9e97d84b..5c031eb 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -64,6 +64,13 @@
         return Arrays.asList(new Object[][] {{"8.8.4.4"}, {"2601::10"}});
     }
 
+    private static final byte[] AEAD_KEY = {
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+        0x73, 0x61, 0x6C, 0x74
+    };
     private static final byte[] CRYPT_KEY = {
         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
@@ -87,7 +94,7 @@
     private static final IpSecAlgorithm CRYPT_ALGO =
             new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
     private static final IpSecAlgorithm AEAD_ALGO =
-            new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, CRYPT_KEY, CRYPT_KEY.length * 4);
+            new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
 
     private static final int[] DIRECTIONS =
             new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT};
@@ -262,7 +269,7 @@
                         eq(new byte[] {}),
                         eq(0),
                         eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
-                        eq(CRYPT_KEY),
+                        eq(AEAD_KEY),
                         anyInt(),
                         anyInt(),
                         anyInt(),
@@ -283,7 +290,7 @@
                         eq(new byte[] {}),
                         eq(0),
                         eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
-                        eq(CRYPT_KEY),
+                        eq(AEAD_KEY),
                         anyInt(),
                         anyInt(),
                         anyInt(),
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 7b07038..8e579aa 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -23,7 +23,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -46,6 +50,8 @@
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -57,6 +63,8 @@
 public class IpSecServiceTest {
 
     private static final int DROID_SPI = 0xD1201D;
+    private static final int MAX_NUM_ENCAP_SOCKETS = 100;
+    private static final int MAX_NUM_SPIS = 100;
     private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
     private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
 
@@ -260,4 +268,115 @@
             }
         }
     }
+
+    /**
+     * This function checks if the number of encap UDP socket that one UID can reserve
+     * has a reasonable limit.
+     */
+    @Test
+    public void testSocketResourceTrackerLimitation() throws Exception {
+        List<IpSecUdpEncapResponse> openUdpEncapSockets = new ArrayList<IpSecUdpEncapResponse>();
+        // Reserve sockets until it fails.
+        for (int i = 0; i < MAX_NUM_ENCAP_SOCKETS; i++) {
+            IpSecUdpEncapResponse newUdpEncapSocket =
+                    mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+            assertNotNull(newUdpEncapSocket);
+            if (IpSecManager.Status.OK != newUdpEncapSocket.status) {
+                break;
+            }
+            openUdpEncapSockets.add(newUdpEncapSocket);
+        }
+        // Assert that the total sockets quota has a reasonable limit.
+        assertTrue(
+                openUdpEncapSockets.size() > 0
+                        && openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
+
+        // Try to reserve one more UDP encapsulation socket, and should fail.
+        IpSecUdpEncapResponse extraUdpEncapSocket =
+                mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+        assertNotNull(extraUdpEncapSocket);
+        assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
+
+        // Close one of the open UDP encapsulation scokets.
+        mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
+        openUdpEncapSockets.get(0).fileDescriptor.close();
+        openUdpEncapSockets.remove(0);
+
+        // Try to reserve one more UDP encapsulation socket, and should be successful.
+        extraUdpEncapSocket = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
+        assertNotNull(extraUdpEncapSocket);
+        assertEquals(IpSecManager.Status.OK, extraUdpEncapSocket.status);
+        openUdpEncapSockets.add(extraUdpEncapSocket);
+
+        // Close open UDP sockets.
+        for (IpSecUdpEncapResponse openSocket : openUdpEncapSockets) {
+            mIpSecService.closeUdpEncapsulationSocket(openSocket.resourceId);
+            openSocket.fileDescriptor.close();
+        }
+    }
+
+    /**
+     * This function checks if the number of SPI that one UID can reserve
+     * has a reasonable limit.
+     * This test does not test for both address families or duplicate SPIs because resource
+     * tracking code does not depend on them.
+     */
+    @Test
+    public void testSpiResourceTrackerLimitation() throws Exception {
+        List<IpSecSpiResponse> reservedSpis = new ArrayList<IpSecSpiResponse>();
+        // Return the same SPI for all SPI allocation since IpSecService only
+        // tracks the resource ID.
+        when(mMockNetd.ipSecAllocateSpi(
+                        anyInt(),
+                        eq(IpSecTransform.DIRECTION_OUT),
+                        anyString(),
+                        eq(InetAddress.getLoopbackAddress().getHostAddress()),
+                        anyInt()))
+                .thenReturn(DROID_SPI);
+        // Reserve spis until it fails.
+        for (int i = 0; i < MAX_NUM_SPIS; i++) {
+            IpSecSpiResponse newSpi =
+                    mIpSecService.reserveSecurityParameterIndex(
+                            0x1,
+                            InetAddress.getLoopbackAddress().getHostAddress(),
+                            DROID_SPI + i,
+                            new Binder());
+            assertNotNull(newSpi);
+            if (IpSecManager.Status.OK != newSpi.status) {
+                break;
+            }
+            reservedSpis.add(newSpi);
+        }
+        // Assert that the SPI quota has a reasonable limit.
+        assertTrue(reservedSpis.size() > 0 && reservedSpis.size() < MAX_NUM_SPIS);
+
+        // Try to reserve one more SPI, and should fail.
+        IpSecSpiResponse extraSpi =
+                mIpSecService.reserveSecurityParameterIndex(
+                        0x1,
+                        InetAddress.getLoopbackAddress().getHostAddress(),
+                        DROID_SPI + MAX_NUM_SPIS,
+                        new Binder());
+        assertNotNull(extraSpi);
+        assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraSpi.status);
+
+        // Release one reserved spi.
+        mIpSecService.releaseSecurityParameterIndex(reservedSpis.get(0).resourceId);
+        reservedSpis.remove(0);
+
+        // Should successfully reserve one more spi.
+        extraSpi =
+                mIpSecService.reserveSecurityParameterIndex(
+                        0x1,
+                        InetAddress.getLoopbackAddress().getHostAddress(),
+                        DROID_SPI + MAX_NUM_SPIS,
+                        new Binder());
+        assertNotNull(extraSpi);
+        assertEquals(IpSecManager.Status.OK, extraSpi.status);
+
+        // Release reserved SPIs.
+        for (IpSecSpiResponse spiResp : reservedSpis) {
+            mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
+        }
+    }
 }
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index ad6ebf9..0656c5f 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -198,37 +198,33 @@
 
     @Test
     public void testDefaultNetworkEventSerialization() {
-        DefaultNetworkEvent ev = new DefaultNetworkEvent();
+        DefaultNetworkEvent ev = new DefaultNetworkEvent(1001);
         ev.netId = 102;
-        ev.prevNetId = 101;
-        ev.transportTypes = new int[]{1, 2, 3};
-        ev.prevIPv4 = true;
-        ev.prevIPv6 = true;
+        ev.transports = 2;
+        ev.previousTransports = 4;
+        ev.ipv4 = true;
+        ev.initialScore = 20;
+        ev.finalScore = 60;
+        ev.durationMs = 54;
+        ev.validatedMs = 27;
 
         String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 4",
                 "  network_id: 102",
                 "  time_ms: 0",
-                "  transports: 0",
+                "  transports: 2",
                 "  default_network_event <",
-                "    default_network_duration_ms: 0",
-                "    final_score: 0",
-                "    initial_score: 0",
-                "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 102",
-                "    >",
+                "    default_network_duration_ms: 54",
+                "    final_score: 60",
+                "    initial_score: 20",
+                "    ip_support: 1",
                 "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 101",
-                "    >",
-                "    previous_network_ip_support: 3",
-                "    transport_types: 1",
-                "    transport_types: 2",
-                "    transport_types: 3",
+                "    previous_default_network_link_layer: 1",
+                "    previous_network_ip_support: 0",
+                "    validation_duration_ms: 27",
                 "  >",
                 ">",
                 "version: 2\n");
@@ -341,7 +337,6 @@
     public void testNetworkEventSerialization() {
         ConnectivityMetricsEvent ev = describeIpEvent(
                 aType(NetworkEvent.class),
-                anInt(100),
                 anInt(5),
                 aLong(20410));
 
@@ -356,9 +351,6 @@
                 "  network_event <",
                 "    event_type: 5",
                 "    latency_ms: 20410",
-                "    network_id <",
-                "      network_id: 100",
-                "    >",
                 "  >",
                 ">",
                 "version: 2\n");
@@ -512,6 +504,13 @@
         stats.rootWakeups = 2;
         stats.systemWakeups = 3;
         stats.noUidWakeups = 3;
+        stats.l2UnicastCount = 5;
+        stats.l2MulticastCount = 1;
+        stats.l2BroadcastCount = 2;
+        stats.ethertypes.put(0x800, 3);
+        stats.ethertypes.put(0x86dd, 3);
+        stats.ipNextHeaders.put(6, 5);
+
 
         IpConnectivityEvent got = IpConnectivityEventBuilder.toProto(stats);
         String want = String.join("\n",
@@ -525,6 +524,21 @@
                 "  wakeup_stats <",
                 "    application_wakeups: 5",
                 "    duration_sec: 0",
+                "    ethertype_counts <",
+                "      key: 2048",
+                "      value: 3",
+                "    >",
+                "    ethertype_counts <",
+                "      key: 34525",
+                "      value: 3",
+                "    >",
+                "    ip_next_header_counts <",
+                "      key: 6",
+                "      value: 5",
+                "    >",
+                "    l2_broadcast_count: 2",
+                "    l2_multicast_count: 1",
+                "    l2_unicast_count: 5",
                 "    no_uid_wakeups: 3",
                 "    non_application_wakeups: 1",
                 "    root_wakeups: 2",
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 6c1decc..10d6deb 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -78,6 +78,9 @@
     private static final String EXAMPLE_IPV4 = "192.0.2.1";
     private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
 
+    private static final byte[] MAC_ADDR =
+            {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
+
     @Mock Context mCtx;
     @Mock IIpConnectivityMetrics mMockService;
     @Mock ConnectivityManager mCm;
@@ -188,119 +191,99 @@
             {makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
         };
 
+        long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
+        long durationMs = 1001;
         for (NetworkAgentInfo[] pair : defaultNetworks) {
-            mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(pair[1], pair[0]);
+            timeMs += durationMs;
+            durationMs += durationMs;
+            mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, pair[1], pair[0]);
         }
 
         String want = String.join("\n",
                 "dropped_events: 0",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
-                "  network_id: 100",
-                "  time_ms: 0",
-                "  transports: 0",
-                "  default_network_event <",
-                "    default_network_duration_ms: 0",
-                "    final_score: 0",
-                "    initial_score: 0",
-                "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 100",
-                "    >",
-                "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 0",
-                "    >",
-                "    previous_network_ip_support: 0",
-                "    transport_types: 0",
-                "  >",
-                ">",
-                "events <",
-                "  if_name: \"\"",
-                "  link_layer: 0",
-                "  network_id: 101",
-                "  time_ms: 0",
-                "  transports: 0",
-                "  default_network_event <",
-                "    default_network_duration_ms: 0",
-                "    final_score: 0",
-                "    initial_score: 0",
-                "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 101",
-                "    >",
-                "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 100",
-                "    >",
-                "    previous_network_ip_support: 3",
-                "    transport_types: 1",
-                "  >",
-                ">",
-                "events <",
-                "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 5",
                 "  network_id: 0",
                 "  time_ms: 0",
                 "  transports: 0",
                 "  default_network_event <",
-                "    default_network_duration_ms: 0",
+                "    default_network_duration_ms: 1001",
                 "    final_score: 0",
                 "    initial_score: 0",
                 "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 0",
-                "    >",
                 "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 101",
-                "    >",
-                "    previous_network_ip_support: 1",
+                "    previous_default_network_link_layer: 0",
+                "    previous_network_ip_support: 0",
+                "    validation_duration_ms: 0",
                 "  >",
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
+                "  link_layer: 2",
+                "  network_id: 100",
+                "  time_ms: 0",
+                "  transports: 1",
+                "  default_network_event <",
+                "    default_network_duration_ms: 2002",
+                "    final_score: 50",
+                "    initial_score: 10",
+                "    ip_support: 3",
+                "    no_default_network_duration_ms: 0",
+                "    previous_default_network_link_layer: 0",
+                "    previous_network_ip_support: 0",
+                "    validation_duration_ms: 2002",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 4",
+                "  network_id: 101",
+                "  time_ms: 0",
+                "  transports: 2",
+                "  default_network_event <",
+                "    default_network_duration_ms: 4004",
+                "    final_score: 60",
+                "    initial_score: 20",
+                "    ip_support: 1",
+                "    no_default_network_duration_ms: 0",
+                "    previous_default_network_link_layer: 2",
+                "    previous_network_ip_support: 0",
+                "    validation_duration_ms: 4004",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 5",
+                "  network_id: 0",
+                "  time_ms: 0",
+                "  transports: 0",
+                "  default_network_event <",
+                "    default_network_duration_ms: 8008",
+                "    final_score: 0",
+                "    initial_score: 0",
+                "    ip_support: 0",
+                "    no_default_network_duration_ms: 0",
+                "    previous_default_network_link_layer: 4",
+                "    previous_network_ip_support: 0",
+                "    validation_duration_ms: 0",
+                "  >",
+                ">",
+                "events <",
+                "  if_name: \"\"",
+                "  link_layer: 2",
                 "  network_id: 102",
                 "  time_ms: 0",
-                "  transports: 0",
+                "  transports: 1",
                 "  default_network_event <",
-                "    default_network_duration_ms: 0",
-                "    final_score: 0",
-                "    initial_score: 0",
-                "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 102",
-                "    >",
+                "    default_network_duration_ms: 16016",
+                "    final_score: 50",
+                "    initial_score: 10",
+                "    ip_support: 3",
                 "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 0",
-                "    >",
+                "    previous_default_network_link_layer: 4",
                 "    previous_network_ip_support: 0",
-                "    transport_types: 0",
-                "  >",
-                ">",
-                "events <",
-                "  if_name: \"\"",
-                "  link_layer: 0",
-                "  network_id: 103",
-                "  time_ms: 0",
-                "  transports: 0",
-                "  default_network_event <",
-                "    default_network_duration_ms: 0",
-                "    final_score: 0",
-                "    initial_score: 0",
-                "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 103",
-                "    >",
-                "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 102",
-                "    >",
-                "    previous_network_ip_support: 3",
-                "    transport_types: 1",
+                "    validation_duration_ms: 16016",
                 "  >",
                 ">",
                 "version: 2\n");
@@ -371,20 +354,29 @@
         dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34);
 
         // iface, uid
-        wakeupEvent("wlan0", 1000);
-        wakeupEvent("rmnet0", 10123);
-        wakeupEvent("wlan0", 1000);
-        wakeupEvent("rmnet0", 10008);
-        wakeupEvent("wlan0", -1);
-        wakeupEvent("wlan0", 10008);
-        wakeupEvent("rmnet0", 1000);
+        final byte[] mac = {0x48, 0x7c, 0x2b, 0x6a, 0x3e, 0x4b};
+        final String srcIp = "192.168.2.1";
+        final String dstIp = "192.168.2.23";
+        final int sport = 2356;
+        final int dport = 13489;
+        final long now = 1001L;
+        final int v4 = 0x800;
+        final int tcp = 6;
+        final int udp = 17;
+        wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
+        wakeupEvent("wlan0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
+        wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+        wakeupEvent("wlan0", 10008, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+        wakeupEvent("wlan0", -1, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
+        wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
 
+        long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
         final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
         final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
         NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
         NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
-        mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(cellNai, null);
-        mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(wifiNai, cellNai);
+        mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 200, cellNai, null);
+        mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 300, wifiNai, cellNai);
 
         String want = String.join("\n",
                 "dropped_events: 0",
@@ -473,46 +465,36 @@
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
-                "  network_id: 100",
+                "  link_layer: 5",
+                "  network_id: 0",
                 "  time_ms: 0",
                 "  transports: 0",
                 "  default_network_event <",
-                "    default_network_duration_ms: 0",
+                "    default_network_duration_ms: 200",
                 "    final_score: 0",
                 "    initial_score: 0",
                 "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 100",
-                "    >",
                 "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 0",
-                "    >",
+                "    previous_default_network_link_layer: 0",
                 "    previous_network_ip_support: 0",
-                "    transport_types: 0",
+                "    validation_duration_ms: 0",
                 "  >",
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 0",
-                "  network_id: 101",
+                "  link_layer: 2",
+                "  network_id: 100",
                 "  time_ms: 0",
-                "  transports: 0",
+                "  transports: 1",
                 "  default_network_event <",
-                "    default_network_duration_ms: 0",
-                "    final_score: 0",
-                "    initial_score: 0",
-                "    ip_support: 0",
-                "    network_id <",
-                "      network_id: 101",
-                "    >",
+                "    default_network_duration_ms: 100",
+                "    final_score: 50",
+                "    initial_score: 50",
+                "    ip_support: 2",
                 "    no_default_network_duration_ms: 0",
-                "    previous_network_id <",
-                "      network_id: 100",
-                "    >",
-                "    previous_network_ip_support: 2",
-                "    transport_types: 1",
+                "    previous_default_network_link_layer: 0",
+                "    previous_network_ip_support: 0",
+                "    validation_duration_ms: 100",
                 "  >",
                 ">",
                 "events <",
@@ -589,34 +571,33 @@
                 ">",
                 "events <",
                 "  if_name: \"\"",
-                "  link_layer: 2",
-                "  network_id: 0",
-                "  time_ms: 0",
-                "  transports: 0",
-                "  wakeup_stats <",
-                "    application_wakeups: 2",
-                "    duration_sec: 0",
-                "    no_uid_wakeups: 0",
-                "    non_application_wakeups: 0",
-                "    root_wakeups: 0",
-                "    system_wakeups: 1",
-                "    total_wakeups: 3",
-                "  >",
-                ">",
-                "events <",
-                "  if_name: \"\"",
                 "  link_layer: 4",
                 "  network_id: 0",
                 "  time_ms: 0",
                 "  transports: 0",
                 "  wakeup_stats <",
-                "    application_wakeups: 1",
+                "    application_wakeups: 3",
                 "    duration_sec: 0",
+                "    ethertype_counts <",
+                "      key: 2048",
+                "      value: 6",
+                "    >",
+                "    ip_next_header_counts <",
+                "      key: 6",
+                "      value: 3",
+                "    >",
+                "    ip_next_header_counts <",
+                "      key: 17",
+                "      value: 3",
+                "    >",
+                "    l2_broadcast_count: 0",
+                "    l2_multicast_count: 0",
+                "    l2_unicast_count: 6",
                 "    no_uid_wakeups: 1",
                 "    non_application_wakeups: 0",
                 "    root_wakeups: 0",
                 "    system_wakeups: 2",
-                "    total_wakeups: 4",
+                "    total_wakeups: 6",
                 "  >",
                 ">",
                 "version: 2\n");
@@ -639,9 +620,10 @@
         mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
     }
 
-    void wakeupEvent(String iface, int uid) throws Exception {
+    void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
+            String dstIp, int sport, int dport, long now) throws Exception {
         String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
-        mNetdListener.onWakeupEvent(prefix, uid, uid, 0);
+        mNetdListener.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
     }
 
     NetworkAgentInfo makeNai(int netId, int score, boolean ipv4, boolean ipv6, long transports) {
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 6723601..67805c9 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -61,7 +61,10 @@
     private static final String EXAMPLE_IPV4 = "192.0.2.1";
     private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
 
-    NetdEventListenerService mNetdEventListenerService;
+    private static final byte[] MAC_ADDR =
+            {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
+
+    NetdEventListenerService mService;
     ConnectivityManager mCm;
 
     @Before
@@ -75,29 +78,49 @@
         when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
         when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
 
-        mNetdEventListenerService = new NetdEventListenerService(mCm);
+        mService = new NetdEventListenerService(mCm);
     }
 
     @Test
     public void testWakeupEventLogging() throws Exception {
         final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
+        final long now = System.currentTimeMillis();
+        final String iface = "wlan0";
+        final byte[] mac = MAC_ADDR;
+        final String srcIp = "192.168.2.1";
+        final String dstIp = "192.168.2.23";
+        final String srcIp6 = "2001:db8:4:fd00:a585:13d1:6a23:4fb4";
+        final String dstIp6 = "2001:db8:4006:807::200a";
+        final int sport = 2356;
+        final int dport = 13489;
 
-        // Assert no events
-        String[] events1 = listNetdEvent();
-        assertEquals(new String[]{""}, events1);
+        final int v4 = 0x800;
+        final int v6 = 0x86dd;
+        final int tcp = 6;
+        final int udp = 17;
+        final int icmp6 = 58;
 
-        long now = System.currentTimeMillis();
-        String prefix = "iface:wlan0";
-        int[] uids = { 10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004 };
-        for (int uid : uids) {
-            mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
-        }
+        // Baseline without any event
+        String[] baseline = listNetdEvent();
 
-        String[] events2 = listNetdEvent();
+        int[] uids = {10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004};
+        wakeupEvent(iface, uids[0], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent(iface, uids[1], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent(iface, uids[2], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent(iface, uids[3], v4, icmp6, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent(iface, uids[4], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent(iface, uids[5], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent(iface, uids[6], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent(iface, uids[7], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent(iface, uids[8], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+
+        String[] events2 = remove(listNetdEvent(), baseline);
         int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
         assertEquals(expectedLength2, events2.length);
         assertContains(events2[0], "WakeupStats");
         assertContains(events2[0], "wlan0");
+        assertContains(events2[0], "0x800");
+        assertContains(events2[0], "0x86dd");
         for (int i = 0; i < uids.length; i++) {
             String got = events2[i+1];
             assertContains(got, "WakeupEvent");
@@ -108,10 +131,10 @@
         int uid = 20000;
         for (int i = 0; i < BUFFER_LENGTH * 2; i++) {
             long ts = now + 10;
-            mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts);
+            wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, ts);
         }
 
-        String[] events3 = listNetdEvent();
+        String[] events3 = remove(listNetdEvent(), baseline);
         int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
         assertEquals(expectedLength3, events3.length);
         assertContains(events2[0], "WakeupStats");
@@ -124,9 +147,9 @@
         }
 
         uid = 45678;
-        mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
+        wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, now);
 
-        String[] events4 = listNetdEvent();
+        String[] events4 = remove(listNetdEvent(), baseline);
         String lastEvent = events4[events4.length - 1];
         assertContains(lastEvent, "WakeupEvent");
         assertContains(lastEvent, "wlan0");
@@ -135,21 +158,36 @@
 
     @Test
     public void testWakeupStatsLogging() throws Exception {
-        wakeupEvent("wlan0", 1000);
-        wakeupEvent("rmnet0", 10123);
-        wakeupEvent("wlan0", 1000);
-        wakeupEvent("rmnet0", 10008);
-        wakeupEvent("wlan0", -1);
-        wakeupEvent("wlan0", 10008);
-        wakeupEvent("rmnet0", 1000);
-        wakeupEvent("wlan0", 10004);
-        wakeupEvent("wlan0", 1000);
-        wakeupEvent("wlan0", 0);
-        wakeupEvent("wlan0", -1);
-        wakeupEvent("rmnet0", 10052);
-        wakeupEvent("wlan0", 0);
-        wakeupEvent("rmnet0", 1000);
-        wakeupEvent("wlan0", 1010);
+        final byte[] mac = MAC_ADDR;
+        final String srcIp = "192.168.2.1";
+        final String dstIp = "192.168.2.23";
+        final String srcIp6 = "2401:fa00:4:fd00:a585:13d1:6a23:4fb4";
+        final String dstIp6 = "2404:6800:4006:807::200a";
+        final int sport = 2356;
+        final int dport = 13489;
+        final long now = 1001L;
+
+        final int v4 = 0x800;
+        final int v6 = 0x86dd;
+        final int tcp = 6;
+        final int udp = 17;
+        final int icmp6 = 58;
+
+        wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent("rmnet0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent("rmnet0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent("rmnet0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent("wlan0", 10004, v4, udp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent("wlan0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent("rmnet0", 10052, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
+        wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent("rmnet0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
+        wakeupEvent("wlan0", 1010, v4, udp, mac, srcIp, dstIp, sport, dport, now);
 
         String got = flushStatistics();
         String want = String.join("\n",
@@ -163,6 +201,21 @@
                 "  wakeup_stats <",
                 "    application_wakeups: 3",
                 "    duration_sec: 0",
+                "    ethertype_counts <",
+                "      key: 2048",
+                "      value: 4",
+                "    >",
+                "    ethertype_counts <",
+                "      key: 34525",
+                "      value: 1",
+                "    >",
+                "    ip_next_header_counts <",
+                "      key: 6",
+                "      value: 5",
+                "    >",
+                "    l2_broadcast_count: 0",
+                "    l2_multicast_count: 0",
+                "    l2_unicast_count: 5",
                 "    no_uid_wakeups: 0",
                 "    non_application_wakeups: 0",
                 "    root_wakeups: 0",
@@ -179,6 +232,29 @@
                 "  wakeup_stats <",
                 "    application_wakeups: 2",
                 "    duration_sec: 0",
+                "    ethertype_counts <",
+                "      key: 2048",
+                "      value: 5",
+                "    >",
+                "    ethertype_counts <",
+                "      key: 34525",
+                "      value: 5",
+                "    >",
+                "    ip_next_header_counts <",
+                "      key: 6",
+                "      value: 3",
+                "    >",
+                "    ip_next_header_counts <",
+                "      key: 17",
+                "      value: 5",
+                "    >",
+                "    ip_next_header_counts <",
+                "      key: 58",
+                "      value: 2",
+                "    >",
+                "    l2_broadcast_count: 0",
+                "    l2_multicast_count: 0",
+                "    l2_unicast_count: 10",
                 "    no_uid_wakeups: 2",
                 "    non_application_wakeups: 1",
                 "    root_wakeups: 2",
@@ -402,7 +478,7 @@
     Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
         return new Thread(() -> {
             try {
-                mNetdEventListenerService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
+                mService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
             } catch (Exception e) {
                 fail(e.toString());
             }
@@ -410,12 +486,13 @@
     }
 
     void dnsEvent(int netId, int type, int result, int latency) throws Exception {
-        mNetdEventListenerService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
+        mService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
     }
 
-    void wakeupEvent(String iface, int uid) throws Exception {
+    void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
+            String dstIp, int sport, int dport, long now) throws Exception {
         String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
-        mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, 0);
+        mService.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
     }
 
     void asyncDump(long durationMs) throws Exception {
@@ -423,7 +500,7 @@
         final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
         new Thread(() -> {
             while (System.currentTimeMillis() < stop) {
-                mNetdEventListenerService.dump(pw);
+                mService.list(pw);
             }
         }).start();
     }
@@ -432,7 +509,7 @@
     String flushStatistics() throws Exception {
         IpConnectivityMetrics metricsService =
                 new IpConnectivityMetrics(mock(Context.class), (ctx) -> 2000);
-        metricsService.mNetdListener = mNetdEventListenerService;
+        metricsService.mNetdListener = mService;
 
         StringWriter buffer = new StringWriter();
         PrintWriter writer = new PrintWriter(buffer);
@@ -454,11 +531,23 @@
     String[] listNetdEvent() throws Exception {
         StringWriter buffer = new StringWriter();
         PrintWriter writer = new PrintWriter(buffer);
-        mNetdEventListenerService.list(writer);
+        mService.list(writer);
         return buffer.toString().split("\\n");
     }
 
     static void assertContains(String got, String want) {
         assertTrue(got + " did not contain \"" + want + "\"", got.contains(want));
     }
+
+    static <T> T[] remove(T[] array, T[] filtered) {
+        List<T> c = Arrays.asList(filtered);
+        int next = 0;
+        for (int i = 0; i < array.length; i++) {
+            if (c.contains(array[i])) {
+                continue;
+            }
+            array[next++] = array[i];
+        }
+        return Arrays.copyOf(array, next);
+    }
 }
diff --git a/tools/aapt2/link/ProductFilter_test.cpp b/tools/aapt2/link/ProductFilter_test.cpp
index 379ad26..86dd56a 100644
--- a/tools/aapt2/link/ProductFilter_test.cpp
+++ b/tools/aapt2/link/ProductFilter_test.cpp
@@ -73,7 +73,7 @@
       test::ValueBuilder<Id>().SetSource(Source("tablet.xml")).Build(),
       context->GetDiagnostics()));
 
-  ProductFilter filter({});
+  ProductFilter filter(std::unordered_set<std::string>{});
   ASSERT_TRUE(filter.Consume(context.get(), &table));
 
   EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<Id>(
@@ -123,7 +123,7 @@
       test::ValueBuilder<Id>().SetSource(Source("default.xml")).Build(),
       context->GetDiagnostics()));
 
-  ProductFilter filter({});
+  ProductFilter filter(std::unordered_set<std::string>{});
   ASSERT_FALSE(filter.Consume(context.get(), &table));
 }
 
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_linter.py
similarity index 100%
rename from tools/fonts/fontchain_lint.py
rename to tools/fonts/fontchain_linter.py
diff --git a/vr/Android.mk b/vr/Android.mk
index 5b65d3f..73e9f23 100644
--- a/vr/Android.mk
+++ b/vr/Android.mk
@@ -18,6 +18,7 @@
 LOCAL_MODULE := libdvr_loader
 LOCAL_MODULE_OWNER := google
 LOCAL_SRC_FILES := dvr_library_loader.cpp
+LOCAL_CFLAGS := -Wall -Werror
 include $(BUILD_SHARED_LIBRARY)
 
 # Java platform library for vr stuff.