Merge "Move NetworkMonitor to NetworkStack"
diff --git a/api/current.txt b/api/current.txt
index 1d60e8f..62ae1aa 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -8339,42 +8339,44 @@
     field public static final java.lang.String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = "android.bluetooth.headset.intent.category.companyid";
   }
 
-  public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
-    method public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
-    method public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
+  public final deprecated class BluetoothHealth implements android.bluetooth.BluetoothProfile {
+    ctor public BluetoothHealth();
+    method public deprecated boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+    method public deprecated boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
     method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
-    method public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
-    method public boolean registerSinkAppConfiguration(java.lang.String, int, android.bluetooth.BluetoothHealthCallback);
-    method public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
-    field public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
-    field public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
-    field public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
-    field public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2
-    field public static final int CHANNEL_TYPE_RELIABLE = 10; // 0xa
-    field public static final int CHANNEL_TYPE_STREAMING = 11; // 0xb
-    field public static final int SINK_ROLE = 2; // 0x2
-    field public static final int SOURCE_ROLE = 1; // 0x1
-    field public static final int STATE_CHANNEL_CONNECTED = 2; // 0x2
-    field public static final int STATE_CHANNEL_CONNECTING = 1; // 0x1
-    field public static final int STATE_CHANNEL_DISCONNECTED = 0; // 0x0
-    field public static final int STATE_CHANNEL_DISCONNECTING = 3; // 0x3
+    method public deprecated android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+    method public deprecated boolean registerSinkAppConfiguration(java.lang.String, int, android.bluetooth.BluetoothHealthCallback);
+    method public deprecated boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
+    field public static final deprecated int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
+    field public static final deprecated int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
+    field public static final deprecated int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
+    field public static final deprecated int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2
+    field public static final deprecated int CHANNEL_TYPE_RELIABLE = 10; // 0xa
+    field public static final deprecated int CHANNEL_TYPE_STREAMING = 11; // 0xb
+    field public static final deprecated int SINK_ROLE = 2; // 0x2
+    field public static final deprecated int SOURCE_ROLE = 1; // 0x1
+    field public static final deprecated int STATE_CHANNEL_CONNECTED = 2; // 0x2
+    field public static final deprecated int STATE_CHANNEL_CONNECTING = 1; // 0x1
+    field public static final deprecated int STATE_CHANNEL_DISCONNECTED = 0; // 0x0
+    field public static final deprecated int STATE_CHANNEL_DISCONNECTING = 3; // 0x3
   }
 
-  public final class BluetoothHealthAppConfiguration implements android.os.Parcelable {
+  public final deprecated class BluetoothHealthAppConfiguration implements android.os.Parcelable {
+    ctor public BluetoothHealthAppConfiguration();
     method public int describeContents();
-    method public int getDataType();
-    method public java.lang.String getName();
-    method public int getRole();
+    method public deprecated int getDataType();
+    method public deprecated java.lang.String getName();
+    method public deprecated int getRole();
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHealthAppConfiguration> CREATOR;
+    field public static final deprecated android.os.Parcelable.Creator<android.bluetooth.BluetoothHealthAppConfiguration> CREATOR;
   }
 
-  public abstract class BluetoothHealthCallback {
+  public abstract deprecated class BluetoothHealthCallback {
     ctor public BluetoothHealthCallback();
-    method public void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int);
-    method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
+    method public deprecated void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int);
+    method public deprecated void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
   }
 
   public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
@@ -8471,7 +8473,7 @@
     field public static final int GATT = 7; // 0x7
     field public static final int GATT_SERVER = 8; // 0x8
     field public static final int HEADSET = 1; // 0x1
-    field public static final int HEALTH = 3; // 0x3
+    field public static final deprecated int HEALTH = 3; // 0x3
     field public static final int HID_DEVICE = 19; // 0x13
     field public static final int SAP = 10; // 0xa
     field public static final int STATE_CONNECTED = 2; // 0x2
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index e305b54..80e6b9b 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -82,6 +82,7 @@
                         Status::EX_SECURITY,
                         "Calling process does not have permission to get local data.");
             }
+            break;
         case DEST_EXPLICIT:
             if (callingUid != AID_SHELL && callingUid != AID_ROOT && callingUid != AID_STATSD &&
                 callingUid != AID_SYSTEM) {
@@ -91,6 +92,7 @@
                         Status::EX_SECURITY,
                         "Calling process does not have permission to get explicit data.");
             }
+            break;
     }
     return Status::ok();
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 10c8b15..38245fb 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2066,8 +2066,7 @@
      * Get the current connection state of a profile.
      * This function can be used to check whether the local Bluetooth adapter
      * is connected to any remote device for a specific profile.
-     * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
-     * {@link BluetoothProfile#A2DP}.
+     * Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}.
      *
      * <p> Return value can be one of
      * {@link BluetoothProfile#STATE_DISCONNECTED},
@@ -2441,16 +2440,15 @@
     /**
      * Get the profile proxy object associated with the profile.
      *
-     * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
-     * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
-     * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
-     * {@link BluetoothProfile.ServiceListener} to get notified of
-     * the connection status and to get the proxy object.
+     * <p>Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP},
+     * {@link BluetoothProfile#GATT}, or {@link BluetoothProfile#GATT_SERVER}. Clients must
+     * implement {@link BluetoothProfile.ServiceListener} to get notified of the connection status
+     * and to get the proxy object.
      *
      * @param context Context of the application
      * @param listener The service Listener for connection callbacks.
-     * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, {@link
-     * BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or
+     * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET},
+     * {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or
      * {@link BluetoothProfile#GATT_SERVER}.
      * @return true on success, false on error
      */
@@ -2479,8 +2477,8 @@
             BluetoothPan pan = new BluetoothPan(context, listener);
             return true;
         } else if (profile == BluetoothProfile.HEALTH) {
-            BluetoothHealth health = new BluetoothHealth(context, listener);
-            return true;
+            Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated");
+            return false;
         } else if (profile == BluetoothProfile.MAP) {
             BluetoothMap map = new BluetoothMap(context, listener);
             return true;
@@ -2512,8 +2510,7 @@
      *
      * <p> Clients should call this when they are no longer using
      * the proxy obtained from {@link #getProfileProxy}.
-     * Profile can be one of  {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
-     * {@link BluetoothProfile#A2DP}
+     * Profile can be one of  {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}
      *
      * @param profile
      * @param proxy Profile proxy object
@@ -2548,10 +2545,6 @@
                 BluetoothPan pan = (BluetoothPan) proxy;
                 pan.close();
                 break;
-            case BluetoothProfile.HEALTH:
-                BluetoothHealth health = (BluetoothHealth) proxy;
-                health.close();
-                break;
             case BluetoothProfile.GATT:
                 BluetoothGatt gatt = (BluetoothGatt) proxy;
                 gatt.close();
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index b967fb2..e2e56fd 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -16,14 +16,7 @@
 
 package android.bluetooth;
 
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Binder;
-import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -53,79 +46,59 @@
  * <li> When done, close the health channel by calling {@link #disconnectChannel}
  * and unregister the application configuration calling
  * {@link #unregisterAppConfiguration}
+ *
+ * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New apps
+ * should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+ * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+ * {@link BluetoothDevice#createL2capChannel(int)}
  */
+@Deprecated
 public final class BluetoothHealth implements BluetoothProfile {
     private static final String TAG = "BluetoothHealth";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
-
     /**
      * Health Profile Source Role - the health device.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public static final int SOURCE_ROLE = 1 << 0;
 
     /**
      * Health Profile Sink Role the device talking to the health device.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public static final int SINK_ROLE = 1 << 1;
 
     /**
      * Health Profile - Channel Type used - Reliable
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public static final int CHANNEL_TYPE_RELIABLE = 10;
 
     /**
      * Health Profile - Channel Type used - Streaming
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public static final int CHANNEL_TYPE_STREAMING = 11;
 
-    /**
-     * @hide
-     */
-    public static final int CHANNEL_TYPE_ANY = 12;
-
-    /** @hide */
-    public static final int HEALTH_OPERATION_SUCCESS = 6000;
-    /** @hide */
-    public static final int HEALTH_OPERATION_ERROR = 6001;
-    /** @hide */
-    public static final int HEALTH_OPERATION_INVALID_ARGS = 6002;
-    /** @hide */
-    public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003;
-    /** @hide */
-    public static final int HEALTH_OPERATION_NOT_FOUND = 6004;
-    /** @hide */
-    public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
-
-    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
-            new IBluetoothStateChangeCallback.Stub() {
-                public void onBluetoothStateChange(boolean up) {
-                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
-                    if (!up) {
-                        if (VDBG) Log.d(TAG, "Unbinding service...");
-                        synchronized (mConnection) {
-                            try {
-                                mService = null;
-                                mContext.unbindService(mConnection);
-                            } catch (Exception re) {
-                                Log.e(TAG, "", re);
-                            }
-                        }
-                    } else {
-                        synchronized (mConnection) {
-                            try {
-                                if (mService == null) {
-                                    if (VDBG) Log.d(TAG, "Binding service...");
-                                    doBind();
-                                }
-                            } catch (Exception re) {
-                                Log.e(TAG, "", re);
-                            }
-                        }
-                    }
-                }
-            };
-
 
     /**
      * Register an application configuration that acts as a Health SINK.
@@ -141,53 +114,17 @@
      * @param callback A callback to indicate success or failure of the registration and all
      * operations done on this application configuration.
      * @return If true, callback will be called.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public boolean registerSinkAppConfiguration(String name, int dataType,
             BluetoothHealthCallback callback) {
-        if (!isEnabled() || name == null) return false;
-
-        if (VDBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
-        return registerAppConfiguration(name, dataType, SINK_ROLE,
-                CHANNEL_TYPE_ANY, callback);
-    }
-
-    /**
-     * Register an application configuration that acts as a Health SINK or in a Health
-     * SOURCE role.This is an asynchronous call and so
-     * the callback is used to notify success or failure if the function returns true.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param name The friendly name associated with the application or configuration.
-     * @param dataType The dataType of the Source role of Health Profile.
-     * @param channelType The channel type. Will be one of {@link #CHANNEL_TYPE_RELIABLE}  or {@link
-     * #CHANNEL_TYPE_STREAMING}
-     * @param callback - A callback to indicate success or failure.
-     * @return If true, callback will be called.
-     * @hide
-     */
-    public boolean registerAppConfiguration(String name, int dataType, int role,
-            int channelType, BluetoothHealthCallback callback) {
-        boolean result = false;
-        if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
-
-        if (VDBG) log("registerApplication(" + name + ":" + dataType + ")");
-        BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
-        BluetoothHealthAppConfiguration config =
-                new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
-
-        final IBluetoothHealth service = mService;
-        if (service != null) {
-            try {
-                result = service.registerAppConfiguration(config, wrapper);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
-        return result;
+        Log.e(TAG, "registerSinkAppConfiguration(): BluetoothHealth is deprecated");
+        return false;
     }
 
     /**
@@ -198,22 +135,16 @@
      *
      * @param config The health app configuration
      * @return Success or failure.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
-        boolean result = false;
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && config != null) {
-            try {
-                result = service.unregisterAppConfiguration(config);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
-
-        return result;
+        Log.e(TAG, "unregisterAppConfiguration(): BluetoothHealth is deprecated");
+        return false;
     }
 
     /**
@@ -227,49 +158,16 @@
      * @param config The application configuration which has been registered using {@link
      * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
      * @return If true, the callback associated with the application config will be called.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public boolean connectChannelToSource(BluetoothDevice device,
             BluetoothHealthAppConfiguration config) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device) && config != null) {
-            try {
-                return service.connectChannelToSource(device, config);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
-        return false;
-    }
-
-    /**
-     * Connect to a health device which has the {@link #SINK_ROLE}.
-     * This is an asynchronous call. If this function returns true, the callback
-     * associated with the application configuration will be called.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device The remote Bluetooth device.
-     * @param config The application configuration which has been registered using {@link
-     * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
-     * @return If true, the callback associated with the application config will be called.
-     * @hide
-     */
-    public boolean connectChannelToSink(BluetoothDevice device,
-            BluetoothHealthAppConfiguration config, int channelType) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device) && config != null) {
-            try {
-                return service.connectChannelToSink(device, config, channelType);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
+        Log.e(TAG, "connectChannelToSource(): BluetoothHealth is deprecated");
         return false;
     }
 
@@ -285,20 +183,16 @@
      * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
      * @param channelId The channel id associated with the channel
      * @return If true, the callback associated with the application config will be called.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public boolean disconnectChannel(BluetoothDevice device,
             BluetoothHealthAppConfiguration config, int channelId) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device) && config != null) {
-            try {
-                return service.disconnectChannel(device, config, channelId);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
+        Log.e(TAG, "disconnectChannel(): BluetoothHealth is deprecated");
         return false;
     }
 
@@ -314,20 +208,16 @@
      * @param device The remote Bluetooth health device
      * @param config The application configuration
      * @return null on failure, ParcelFileDescriptor on success.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
             BluetoothHealthAppConfiguration config) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device) && config != null) {
-            try {
-                return service.getMainChannelFd(device, config);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
+        Log.e(TAG, "getMainChannelFd(): BluetoothHealth is deprecated");
         return null;
     }
 
@@ -347,17 +237,7 @@
      */
     @Override
     public int getConnectionState(BluetoothDevice device) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled() && isValidDevice(device)) {
-            try {
-                return service.getHealthDeviceConnectionState(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
+        Log.e(TAG, "getConnectionState(): BluetoothHealth is deprecated");
         return STATE_DISCONNECTED;
     }
 
@@ -377,17 +257,8 @@
      */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled()) {
-            try {
-                return service.getConnectedHealthDevices();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return new ArrayList<BluetoothDevice>();
-            }
-        }
-        if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return new ArrayList<BluetoothDevice>();
+        Log.e(TAG, "getConnectedDevices(): BluetoothHealth is deprecated");
+        return new ArrayList<>();
     }
 
     /**
@@ -409,163 +280,81 @@
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        final IBluetoothHealth service = mService;
-        if (service != null && isEnabled()) {
-            try {
-                return service.getHealthDevicesMatchingConnectionStates(states);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
-                return new ArrayList<BluetoothDevice>();
-            }
-        }
-        if (service == null) Log.w(TAG, "Proxy not attached to service");
-        return new ArrayList<BluetoothDevice>();
+        Log.e(TAG, "getDevicesMatchingConnectionStates(): BluetoothHealth is deprecated");
+        return new ArrayList<>();
     }
 
-    private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
-        private BluetoothHealthCallback mCallback;
-
-        public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
-                int status) {
-            mCallback.onHealthAppConfigurationStatusChange(config, status);
-        }
-
-        @Override
-        public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
-                BluetoothDevice device, int prevState, int newState,
-                ParcelFileDescriptor fd, int channelId) {
-            mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
-                    channelId);
-        }
-    }
-
-    /** Health Channel Connection State - Disconnected */
+    /** Health Channel Connection State - Disconnected
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
     public static final int STATE_CHANNEL_DISCONNECTED = 0;
-    /** Health Channel Connection State - Connecting */
+    /** Health Channel Connection State - Connecting
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
     public static final int STATE_CHANNEL_CONNECTING = 1;
-    /** Health Channel Connection State - Connected */
+    /** Health Channel Connection State - Connected
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
     public static final int STATE_CHANNEL_CONNECTED = 2;
-    /** Health Channel Connection State - Disconnecting */
+    /** Health Channel Connection State - Disconnecting
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
     public static final int STATE_CHANNEL_DISCONNECTING = 3;
 
-    /** Health App Configuration registration success */
-    public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
-    /** Health App Configuration registration failure */
-    public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
-    /** Health App Configuration un-registration success */
-    public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
-    /** Health App Configuration un-registration failure */
-    public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
-
-    private Context mContext;
-    private ServiceListener mServiceListener;
-    private volatile IBluetoothHealth mService;
-    BluetoothAdapter mAdapter;
-
-    /**
-     * Create a BluetoothHealth proxy object.
+    /** Health App Configuration registration success
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
-    /*package*/ BluetoothHealth(Context context, ServiceListener l) {
-        mContext = context;
-        mServiceListener = l;
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
-        IBluetoothManager mgr = mAdapter.getBluetoothManager();
-        if (mgr != null) {
-            try {
-                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException e) {
-                Log.e(TAG, "", e);
-            }
-        }
-
-        doBind();
-    }
-
-    boolean doBind() {
-        Intent intent = new Intent(IBluetoothHealth.class.getName());
-        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
-        intent.setComponent(comp);
-        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
-                mContext.getUser())) {
-            Log.e(TAG, "Could not bind to Bluetooth Health Service with " + intent);
-            return false;
-        }
-        return true;
-    }
-
-    /*package*/ void close() {
-        if (VDBG) log("close()");
-        IBluetoothManager mgr = mAdapter.getBluetoothManager();
-        if (mgr != null) {
-            try {
-                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (Exception e) {
-                Log.e(TAG, "", e);
-            }
-        }
-
-        synchronized (mConnection) {
-            if (mService != null) {
-                try {
-                    mService = null;
-                    mContext.unbindService(mConnection);
-                } catch (Exception re) {
-                    Log.e(TAG, "", re);
-                }
-            }
-        }
-        mServiceListener = null;
-    }
-
-    private final ServiceConnection mConnection = new ServiceConnection() {
-        public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) Log.d(TAG, "Proxy object connected");
-            mService = IBluetoothHealth.Stub.asInterface(Binder.allowBlocking(service));
-
-            if (mServiceListener != null) {
-                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
-            }
-        }
-
-        public void onServiceDisconnected(ComponentName className) {
-            if (DBG) Log.d(TAG, "Proxy object disconnected");
-            mService = null;
-            if (mServiceListener != null) {
-                mServiceListener.onServiceDisconnected(BluetoothProfile.HEALTH);
-            }
-        }
-    };
-
-    private boolean isEnabled() {
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
-        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
-        log("Bluetooth is Not enabled");
-        return false;
-    }
-
-    private static boolean isValidDevice(BluetoothDevice device) {
-        return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
-    }
-
-    private boolean checkAppParam(String name, int role, int channelType,
-            BluetoothHealthCallback callback) {
-        if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE)
-                || (channelType != CHANNEL_TYPE_RELIABLE && channelType != CHANNEL_TYPE_STREAMING
-                    && channelType != CHANNEL_TYPE_ANY)
-                || callback == null) {
-            return false;
-        }
-        if (role == SOURCE_ROLE && channelType == CHANNEL_TYPE_ANY) return false;
-        return true;
-    }
-
-    private static void log(String msg) {
-        Log.d(TAG, msg);
-    }
+    @Deprecated
+    public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
+    /** Health App Configuration registration failure
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
+    public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
+    /** Health App Configuration un-registration success
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
+    public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
+    /** Health App Configuration un-registration failure
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
+     */
+    @Deprecated
+    public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
 }
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index 7c9db6f..9788bbf 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -25,72 +25,14 @@
  * the {@link BluetoothHealth} class. This class represents an application configuration
  * that the Bluetooth Health third party application will register to communicate with the
  * remote Bluetooth health device.
+ *
+ * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+ * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+ * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+ * {@link BluetoothDevice#createL2capChannel(int)}
  */
+@Deprecated
 public final class BluetoothHealthAppConfiguration implements Parcelable {
-    private final String mName;
-    private final int mDataType;
-    private final int mRole;
-    private final int mChannelType;
-
-    /**
-     * Constructor to register the SINK role
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = BluetoothHealth.SINK_ROLE;
-        mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY;
-    }
-
-    /**
-     * Constructor to register the application configuration.
-     *
-     * @param name Friendly name associated with the application configuration
-     * @param dataType Data Type of the remote Bluetooth Health device
-     * @param role {@link BluetoothHealth#SOURCE_ROLE} or {@link BluetoothHealth#SINK_ROLE}
-     * @hide
-     */
-    BluetoothHealthAppConfiguration(String name, int dataType, int role, int
-            channelType) {
-        mName = name;
-        mDataType = dataType;
-        mRole = role;
-        mChannelType = channelType;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof BluetoothHealthAppConfiguration) {
-            BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
-
-            if (mName == null) return false;
-
-            return mName.equals(config.getName()) && mDataType == config.getDataType()
-                    && mRole == config.getRole() && mChannelType == config.getChannelType();
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-        result = 31 * result + (mName != null ? mName.hashCode() : 0);
-        result = 31 * result + mDataType;
-        result = 31 * result + mRole;
-        result = 31 * result + mChannelType;
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "BluetoothHealthAppConfiguration [mName = " + mName + ",mDataType = " + mDataType
-                + ", mRole = " + mRole + ",mChannelType = " + mChannelType + "]";
-    }
-
     @Override
     public int describeContents() {
         return 0;
@@ -100,50 +42,59 @@
      * Return the data type associated with this application configuration.
      *
      * @return dataType
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public int getDataType() {
-        return mDataType;
+        return 0;
     }
 
     /**
      * Return the name of the application configuration.
      *
      * @return String name
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public String getName() {
-        return mName;
+        return null;
     }
 
     /**
      * Return the role associated with this application configuration.
      *
      * @return One of {@link BluetoothHealth#SOURCE_ROLE} or {@link BluetoothHealth#SINK_ROLE}
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     public int getRole() {
-        return mRole;
+        return 0;
     }
 
     /**
-     * Return the channel type associated with this application configuration.
-     *
-     * @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or {@link
-     * BluetoothHealth#CHANNEL_TYPE_STREAMING} or {@link BluetoothHealth#CHANNEL_TYPE_ANY}.
-     * @hide
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
-    public int getChannelType() {
-        return mChannelType;
-    }
-
+    @Deprecated
     public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
             new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
                 @Override
                 public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
-                    String name = in.readString();
-                    int type = in.readInt();
-                    int role = in.readInt();
-                    int channelType = in.readInt();
-                    return new BluetoothHealthAppConfiguration(name, type, role,
-                            channelType);
+                    return new BluetoothHealthAppConfiguration();
                 }
 
                 @Override
@@ -153,10 +104,5 @@
             };
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mName);
-        out.writeInt(mDataType);
-        out.writeInt(mRole);
-        out.writeInt(mChannelType);
-    }
+    public void writeToParcel(Parcel out, int flags) {}
 }
diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java
index 4023485..4769212 100644
--- a/core/java/android/bluetooth/BluetoothHealthCallback.java
+++ b/core/java/android/bluetooth/BluetoothHealthCallback.java
@@ -23,7 +23,13 @@
 
 /**
  * This abstract class is used to implement {@link BluetoothHealth} callbacks.
+ *
+ * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+ * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+ * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+ * {@link BluetoothDevice#createL2capChannel(int)}
  */
+@Deprecated
 public abstract class BluetoothHealthCallback {
     private static final String TAG = "BluetoothHealthCallback";
 
@@ -38,8 +44,14 @@
      * BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or
      * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS}
      * or {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE}
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
     @BinderThread
+    @Deprecated
     public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
             int status) {
         Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status);
@@ -58,8 +70,14 @@
      * @param fd The Parcel File Descriptor when the channel state is connected.
      * @param channelId The id associated with the channel. This id will be used in future calls
      * like when disconnecting the channel.
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
     @BinderThread
+    @Deprecated
     public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
             BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd,
             int channelId) {
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 3c3a01b..3c87c73 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -72,7 +72,13 @@
 
     /**
      * Health Profile
+     *
+     * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
+     * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
+     * {@link BluetoothAdapter#listenUsingL2capChannel()}, or
+     * {@link BluetoothDevice#createL2capChannel(int)}
      */
+    @Deprecated
     int HEALTH = 3;
 
     /**
@@ -269,9 +275,8 @@
          * Called to notify the client when the proxy object has been
          * connected to the service.
          *
-         * @param profile - One of {@link #HEALTH}, {@link #HEADSET} or {@link #A2DP}
-         * @param proxy - One of {@link BluetoothHealth}, {@link BluetoothHeadset} or {@link
-         * BluetoothA2dp}
+         * @param profile - One of {@link #HEADSET} or {@link #A2DP}
+         * @param proxy - One of {@link BluetoothHeadset} or {@link BluetoothA2dp}
          */
         public void onServiceConnected(int profile, BluetoothProfile proxy);
 
@@ -279,7 +284,7 @@
          * Called to notify the client that this proxy object has been
          * disconnected from the service.
          *
-         * @param profile - One of {@link #HEALTH}, {@link #HEADSET} or {@link #A2DP}
+         * @param profile - One of {@link #HEADSET} or {@link #A2DP}
          */
         public void onServiceDisconnected(int profile);
     }
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 3a79206..4a466f3 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -55,6 +55,8 @@
     private String mIfaceName;
     private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
     private ArrayList<InetAddress> mDnses = new ArrayList<>();
+    // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
+    private ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
     private ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
     private boolean mUsePrivateDns;
     private String mPrivateDnsServerName;
@@ -179,6 +181,7 @@
             mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
             mUsePrivateDns = source.mUsePrivateDns;
             mPrivateDnsServerName = source.mPrivateDnsServerName;
+            mPcscfs.addAll(source.mPcscfs);
             mDomains = source.mDomains;
             mRoutes.addAll(source.mRoutes);
             mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
@@ -525,6 +528,60 @@
     }
 
     /**
+     * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present.
+     *
+     * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers.
+     * @return true if the PCSCF server was added, false otherwise.
+     * @hide
+     */
+    public boolean addPcscfServer(InetAddress pcscfServer) {
+        if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
+            mPcscfs.add(pcscfServer);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Removes the given {@link InetAddress} from the list of PCSCF servers.
+     *
+     * @param pcscf Server The {@link InetAddress} to remove from the list of PCSCF servers.
+     * @return true if the PCSCF server was removed, false otherwise.
+     * @hide
+     */
+    public boolean removePcscfServer(InetAddress pcscfServer) {
+        if (pcscfServer != null) {
+            return mPcscfs.remove(pcscfServer);
+        }
+        return false;
+    }
+
+    /**
+     * Replaces the PCSCF servers in this {@code LinkProperties} with
+     * the given {@link Collection} of {@link InetAddress} objects.
+     *
+     * @param addresses The {@link Collection} of PCSCF servers to set in this object.
+     * @hide
+     */
+    public void setPcscfServers(Collection<InetAddress> pcscfServers) {
+        mPcscfs.clear();
+        for (InetAddress pcscfServer: pcscfServers) {
+            addPcscfServer(pcscfServer);
+        }
+    }
+
+    /**
+     * Returns all the {@link InetAddress} for PCSCF servers on this link.
+     *
+     * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on
+     *         this link.
+     * @hide
+     */
+    public List<InetAddress> getPcscfServers() {
+        return Collections.unmodifiableList(mPcscfs);
+    }
+
+    /**
      * Sets the DNS domain search path used on this link.
      *
      * @param domains A {@link String} listing in priority order the comma separated
@@ -767,6 +824,7 @@
         mDnses.clear();
         mUsePrivateDns = false;
         mPrivateDnsServerName = null;
+        mPcscfs.clear();
         mDomains = null;
         mRoutes.clear();
         mHttpProxy = null;
@@ -813,6 +871,12 @@
             resultJoiner.add(mPrivateDnsServerName);
         }
 
+        if (!mPcscfs.isEmpty()) {
+            resultJoiner.add("PcscfAddresses: [");
+            resultJoiner.add(TextUtils.join(",", mPcscfs));
+            resultJoiner.add("]");
+        }
+
         if (!mValidatedPrivateDnses.isEmpty()) {
             final StringJoiner validatedPrivateDnsesJoiner =
                     new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
@@ -965,6 +1029,36 @@
     }
 
     /**
+     * Returns true if this link has an IPv4 PCSCF server.
+     *
+     * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise.
+     * @hide
+     */
+    public boolean hasIPv4PcscfServer() {
+        for (InetAddress ia : mPcscfs) {
+          if (ia instanceof Inet4Address) {
+            return true;
+          }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if this link has an IPv6 PCSCF server.
+     *
+     * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise.
+     * @hide
+     */
+    public boolean hasIPv6PcscfServer() {
+        for (InetAddress ia : mPcscfs) {
+          if (ia instanceof Inet6Address) {
+            return true;
+          }
+        }
+        return false;
+    }
+
+    /**
      * Returns true if this link is provisioned for global IPv4 connectivity.
      * This requires an IP address, default route, and DNS server.
      *
@@ -1117,6 +1211,19 @@
     }
 
     /**
+     * Compares this {@code LinkProperties} PCSCF addresses against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     * @hide
+     */
+    public boolean isIdenticalPcscfs(LinkProperties target) {
+        Collection<InetAddress> targetPcscfs = target.getPcscfServers();
+        return (mPcscfs.size() == targetPcscfs.size()) ?
+                    mPcscfs.containsAll(targetPcscfs) : false;
+    }
+
+    /**
      * Compares this {@code LinkProperties} Routes against the target
      *
      * @param target LinkProperties to compare.
@@ -1218,6 +1325,7 @@
                 && isIdenticalDnses(target)
                 && isIdenticalPrivateDns(target)
                 && isIdenticalValidatedPrivateDnses(target)
+                && isIdenticalPcscfs(target)
                 && isIdenticalRoutes(target)
                 && isIdenticalHttpProxy(target)
                 && isIdenticalStackedLinks(target)
@@ -1334,6 +1442,7 @@
                 + mMtu * 51
                 + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
                 + (mUsePrivateDns ? 57 : 0)
+                + mPcscfs.size() * 67
                 + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode());
     }
 
@@ -1357,6 +1466,10 @@
         }
         dest.writeBoolean(mUsePrivateDns);
         dest.writeString(mPrivateDnsServerName);
+        dest.writeInt(mPcscfs.size());
+        for (InetAddress d : mPcscfs) {
+            dest.writeByteArray(d.getAddress());
+        }
         dest.writeString(mDomains);
         dest.writeInt(mMtu);
         dest.writeString(mTcpBufferSizes);
@@ -1406,6 +1519,12 @@
                 }
                 netProp.setUsePrivateDns(in.readBoolean());
                 netProp.setPrivateDnsServerName(in.readString());
+                addressCount = in.readInt();
+                for (int i = 0; i < addressCount; i++) {
+                    try {
+                        netProp.addPcscfServer(InetAddress.getByAddress(in.createByteArray()));
+                    } catch (UnknownHostException e) { }
+                }
                 netProp.setDomains(in.readString());
                 netProp.setMtu(in.readInt());
                 netProp.setTcpBufferSizes(in.readString());
diff --git a/native/android/Android.bp b/native/android/Android.bp
index c26d980..40290ab 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -78,6 +78,10 @@
     include_dirs: ["bionic/libc/dns/include"],
 
     version_script: "libandroid.map.txt",
+    stubs: {
+        symbol_file: "libandroid.map.txt",
+        versions: ["29"],
+    },
 }
 
 // Network library.
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
index a40cf1c..d969c69 100644
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -16,6 +16,9 @@
 
 #define LOG_TAG "PacProcessor"
 
+#include <stdlib.h>
+#include <string>
+
 #include <utils/Log.h>
 #include <utils/Mutex.h>
 #include "android_runtime/AndroidRuntime.h"
@@ -23,24 +26,24 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
-#include "proxy_resolver_v8.h"
+#include "proxy_resolver_v8_wrapper.h"
 
 namespace android {
 
-net::ProxyResolverV8* proxyResolver = NULL;
+ProxyResolverV8Handle* proxyResolver = NULL;
 bool pacSet = false;
 
-String16 jstringToString16(JNIEnv* env, jstring jstr) {
+std::u16string jstringToString16(JNIEnv* env, jstring jstr) {
     const jchar* str = env->GetStringCritical(jstr, 0);
-    String16 str16(reinterpret_cast<const char16_t*>(str),
+    std::u16string str16(reinterpret_cast<const char16_t*>(str),
                    env->GetStringLength(jstr));
     env->ReleaseStringCritical(jstr, str);
     return str16;
 }
 
-jstring string16ToJstring(JNIEnv* env, String16 string) {
-    const char16_t* str = string.string();
-    size_t len = string.size();
+jstring string16ToJstring(JNIEnv* env, std::u16string string) {
+    const char16_t* str = string.data();
+    size_t len = string.length();
 
     return env->NewString(reinterpret_cast<const jchar*>(str), len);
 }
@@ -48,7 +51,7 @@
 static jboolean com_android_pacprocessor_PacNative_createV8ParserNativeLocked(JNIEnv* /* env */,
         jobject) {
     if (proxyResolver == NULL) {
-        proxyResolver = new net::ProxyResolverV8(net::ProxyResolverJSBindings::CreateDefault());
+        proxyResolver = ProxyResolverV8Handle_new();
         pacSet = false;
         return JNI_FALSE;
     }
@@ -58,7 +61,7 @@
 static jboolean com_android_pacprocessor_PacNative_destroyV8ParserNativeLocked(JNIEnv* /* env */,
         jobject) {
     if (proxyResolver != NULL) {
-        delete proxyResolver;
+        ProxyResolverV8Handle_delete(proxyResolver);
         proxyResolver = NULL;
         return JNI_FALSE;
     }
@@ -67,14 +70,14 @@
 
 static jboolean com_android_pacprocessor_PacNative_setProxyScriptNativeLocked(JNIEnv* env, jobject,
         jstring script) {
-    String16 script16 = jstringToString16(env, script);
+    std::u16string script16 = jstringToString16(env, script);
 
     if (proxyResolver == NULL) {
         ALOGE("V8 Parser not started when setting PAC script");
         return JNI_TRUE;
     }
 
-    if (proxyResolver->SetPacScript(script16) != OK) {
+    if (ProxyResolverV8Handle_SetPacScript(proxyResolver, script16.data()) != OK) {
         ALOGE("Unable to set PAC script");
         return JNI_TRUE;
     }
@@ -85,9 +88,8 @@
 
 static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(JNIEnv* env, jobject,
         jstring url, jstring host) {
-    String16 url16 = jstringToString16(env, url);
-    String16 host16 = jstringToString16(env, host);
-    String16 ret;
+    std::u16string url16 = jstringToString16(env, url);
+    std::u16string host16 = jstringToString16(env, host);
 
     if (proxyResolver == NULL) {
         ALOGE("V8 Parser not initialized when running PAC script");
@@ -99,12 +101,14 @@
         return NULL;
     }
 
-    if (proxyResolver->GetProxyForURL(url16, host16, &ret) != OK) {
-        String8 ret8(ret);
-        ALOGE("Error Running PAC: %s", ret8.string());
+    std::unique_ptr<char16_t, decltype(&free)> result = std::unique_ptr<char16_t, decltype(&free)>(
+        ProxyResolverV8Handle_GetProxyForURL(proxyResolver, url16.data(), host16.data()), &free);
+    if (result.get() == NULL) {
+        ALOGE("Error Running PAC");
         return NULL;
     }
 
+    std::u16string ret(result.get());
     jstring jret = string16ToJstring(env, ret);
 
     return jret;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 514c9f6..ec7947e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -75,6 +75,7 @@
 import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.FIRST_ISOLATED_UID;
 import static android.os.Process.LAST_ISOLATED_UID;
+import static android.os.Process.NETWORK_STACK_UID;
 import static android.os.Process.NFC_UID;
 import static android.os.Process.PHONE_UID;
 import static android.os.Process.PROC_CHAR;
@@ -21202,6 +21203,7 @@
             case BLUETOOTH_UID:
             case NFC_UID:
             case SE_UID:
+            case NETWORK_STACK_UID:
                 isCallerSystem = true;
                 break;
             default:
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 5e1ed03..51575a4 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -87,9 +87,6 @@
     // One minute over PM WATCHDOG_TIMEOUT
     private static final long WAKELOCK_TIMEOUT_MS = WATCHDOG_TIMEOUT + 1000 * 60;
 
-    /** Special library name that skips shared libraries check during compilation. */
-    public static final String SKIP_SHARED_LIBRARY_CHECK = "&";
-
     @GuardedBy("mInstallLock")
     private final Installer mInstaller;
     private final Object mInstallLock;
@@ -399,23 +396,23 @@
             Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName);
             return DEX_OPT_FAILED;
         }
-        Log.d(TAG, "Running dexopt on: " + path
-                + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas()
-                + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
-                + " target-filter=" + compilerFilter);
-
-        String classLoaderContext;
+        String classLoaderContext = null;
         if (dexUseInfo.isUnknownClassLoaderContext() || dexUseInfo.isVariableClassLoaderContext()) {
-            // If we have an unknown (not yet set), or a variable class loader chain, compile
-            // without a context and mark the oat file with SKIP_SHARED_LIBRARY_CHECK. Note that
-            // this might lead to a incorrect compilation.
-            // TODO(calin): We should just extract in this case.
-            classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
+            // If we have an unknown (not yet set), or a variable class loader chain. Just extract
+            // the dex file.
+            compilerFilter = "extract";
         } else {
             classLoaderContext = dexUseInfo.getClassLoaderContext();
         }
 
         int reason = options.getCompilationReason();
+        Log.d(TAG, "Running dexopt on: " + path
+                + " pkg=" + info.packageName + " isa=" + dexUseInfo.getLoaderIsas()
+                + " reason=" + getReasonName(reason)
+                + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
+                + " target-filter=" + compilerFilter
+                + " class-loader-context=" + classLoaderContext);
+
         try {
             for (String isa : dexUseInfo.getLoaderIsas()) {
                 // Reuse the same dexopt path as for the primary apks. We don't need all the
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 93ee44c..91ad11e 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -22,7 +22,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.os.ClassLoaderFactory;
-import com.android.server.pm.PackageDexOptimizer;
 
 import java.io.File;
 import java.util.List;
@@ -275,15 +274,11 @@
     /**
      * Encodes a single class loader dependency starting from {@param path} and
      * {@param classLoaderName}.
-     * When classpath is {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns
-     * the same. This special property is used only during OTA.
      * NOTE: Keep this in sync with the dexopt expectations! Right now that is either "PCL[path]"
      * for a PathClassLoader or "DLC[path]" for a DelegateLastClassLoader.
      */
     /*package*/ static String encodeClassLoader(String classpath, String classLoaderName) {
-        if (classpath.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK)) {
-            return classpath;
-        }
+        classpath.getClass();  // Throw NPE if classpath is null
         String classLoaderDexoptEncoding = classLoaderName;
         if (ClassLoaderFactory.isPathClassLoaderName(classLoaderName)) {
             classLoaderDexoptEncoding = "PCL";
@@ -306,16 +301,10 @@
     /**
      * Links to dependencies together in a format accepted by dexopt.
      * For the special case when either of cl1 or cl2 equals
-     * {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns the same. This
-     * property is used only during OTA.
      * NOTE: Keep this in sync with the dexopt expectations! Right now that is a list of split
      * dependencies {@see encodeClassLoader} separated by ';'.
      */
     /*package*/ static String encodeClassLoaderChain(String cl1, String cl2) {
-        if (cl1.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK) ||
-                cl2.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK)) {
-            return PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK;
-        }
         if (cl1.isEmpty()) return cl2;
         if (cl2.isEmpty()) return cl1;
         return cl1 + ";" + cl2;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 1542120..aa51ecd 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -16,9 +16,6 @@
 
 package com.android.server.pm.dex;
 
-import com.android.server.pm.PackageDexOptimizer;
-
-import static com.android.server.pm.PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -412,12 +409,6 @@
 
     @Test
     public void testEncodeClassLoader() {
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
-                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.PathClassLoader"));
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
-                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.DexClassLoader"));
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
-                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.DelegateLastClassLoader"));
         assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz",
                 "dalvik.system.PathClassLoader"));
         assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz",
@@ -435,15 +426,8 @@
 
     @Test
     public void testEncodeClassLoaderChain() {
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain(
-                SKIP_SHARED_LIBRARY_CHECK, "PCL[a]"));
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain("PCL[a]",
-                SKIP_SHARED_LIBRARY_CHECK));
         assertEquals("PCL[a];DLC[b]", DexoptUtils.encodeClassLoaderChain("PCL[a]",
                 "DLC[b]"));
-        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain("PCL[a]",
-                SKIP_SHARED_LIBRARY_CHECK));
-
         try {
             DexoptUtils.encodeClassLoaderChain("a", null);
             fail(); // exception is expected
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index 9695e9a..f82b380 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -53,6 +53,8 @@
     private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
     private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
     private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
+    private static InetAddress PCSCFV6 =  NetworkUtils.numericToInetAddress(
+            "2001:0db8:85a3:0000:0000:8a2e:0370:1");
     private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
     private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
     private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
@@ -86,6 +88,9 @@
         assertTrue(source.isIdenticalValidatedPrivateDnses(target));
         assertTrue(target.isIdenticalValidatedPrivateDnses(source));
 
+        assertTrue(source.isIdenticalPcscfs(target));
+        assertTrue(target.isIdenticalPcscfs(source));
+
         assertTrue(source.isIdenticalRoutes(target));
         assertTrue(target.isIdenticalRoutes(source));
 
@@ -128,6 +133,8 @@
         // set 2 dnses
         source.addDnsServer(DNS1);
         source.addDnsServer(DNS2);
+        // set 1 pcscf
+        source.addPcscfServer(PCSCFV6);
         // set 2 gateways
         source.addRoute(new RouteInfo(GATEWAY1));
         source.addRoute(new RouteInfo(GATEWAY2));
@@ -141,6 +148,7 @@
         target.addLinkAddress(LINKADDRV6);
         target.addDnsServer(DNS1);
         target.addDnsServer(DNS2);
+        target.addPcscfServer(PCSCFV6);
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);
@@ -154,6 +162,7 @@
         target.addLinkAddress(LINKADDRV6);
         target.addDnsServer(DNS1);
         target.addDnsServer(DNS2);
+        target.addPcscfServer(PCSCFV6);
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);
@@ -167,6 +176,7 @@
         target.addLinkAddress(LINKADDRV6);
         target.addDnsServer(DNS1);
         target.addDnsServer(DNS2);
+        target.addPcscfServer(PCSCFV6);
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);
@@ -179,6 +189,21 @@
         // change dnses
         target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
         target.addDnsServer(DNS2);
+        target.addPcscfServer(PCSCFV6);
+        target.addRoute(new RouteInfo(GATEWAY1));
+        target.addRoute(new RouteInfo(GATEWAY2));
+        target.setMtu(MTU);
+        assertFalse(source.equals(target));
+
+        target.clear();
+        target.setInterfaceName(NAME);
+        target.addLinkAddress(LINKADDRV4);
+        target.addLinkAddress(LINKADDRV6);
+        target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
+        target.addDnsServer(DNS2);
+        // change pcscf
+        target.addPcscfServer(NetworkUtils.numericToInetAddress(
+            "2001::1"));
         target.addRoute(new RouteInfo(GATEWAY1));
         target.addRoute(new RouteInfo(GATEWAY2));
         target.setMtu(MTU);