Merge "Introduce Authentication Failure reason codes"
diff --git a/Android.mk b/Android.mk
index 7f338f9..92098eb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -210,6 +210,7 @@
 	core/java/android/net/IIpConnectivityMetrics.aidl \
 	core/java/android/net/IEthernetManager.aidl \
 	core/java/android/net/IEthernetServiceListener.aidl \
+	core/java/android/net/IIpSecService.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
 	core/java/android/net/INetworkPolicyListener.aidl \
 	core/java/android/net/INetworkPolicyManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 873f5fa..42aa2cd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6696,7 +6696,6 @@
     method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
     method public int getLeMaximumAdvertisingDataLength();
     method public java.lang.String getName();
-    method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
     method public int getProfileConnectionState(int);
     method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
     method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
@@ -7585,21 +7584,6 @@
     method public void stopScan(android.bluetooth.le.ScanCallback);
   }
 
-  public abstract class PeriodicAdvertisingCallback {
-    ctor public PeriodicAdvertisingCallback();
-    method public void onPeriodicAdvertisingReport(android.bluetooth.le.PeriodicAdvertisingReport);
-    method public void onSyncEstablished(int, android.bluetooth.BluetoothDevice, int, int, int, int);
-    method public void onSyncLost(int);
-    field public static final int SYNC_NO_RESOURCES = 2; // 0x2
-    field public static final int SYNC_NO_RESPONSE = 1; // 0x1
-  }
-
-  public final class PeriodicAdvertisingManager {
-    method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback);
-    method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback, android.os.Handler);
-    method public void unregisterSync(android.bluetooth.le.PeriodicAdvertisingCallback);
-  }
-
   public final class PeriodicAdvertisingParameters implements android.os.Parcelable {
     method public int describeContents();
     method public boolean getEnable();
@@ -7617,21 +7601,6 @@
     method public android.bluetooth.le.PeriodicAdvertisingParameters.Builder setInterval(int);
   }
 
-  public final class PeriodicAdvertisingReport implements android.os.Parcelable {
-    ctor public PeriodicAdvertisingReport(int, int, int, int, android.bluetooth.le.ScanRecord);
-    method public int describeContents();
-    method public android.bluetooth.le.ScanRecord getData();
-    method public int getDataStatus();
-    method public int getRssi();
-    method public int getSyncHandle();
-    method public long getTimestampNanos();
-    method public int getTxPower();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.le.PeriodicAdvertisingReport> CREATOR;
-    field public static final int DATA_COMPLETE = 0; // 0x0
-    field public static final int DATA_INCOMPLETE_TRUNCATED = 2; // 0x2
-  }
-
   public abstract class ScanCallback {
     ctor public ScanCallback();
     method public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult>);
@@ -23815,8 +23784,8 @@
     method public void reportNetworkConnectivity(android.net.Network, boolean);
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
     method public deprecated boolean requestRouteToHost(int, int);
@@ -23926,7 +23895,7 @@
     method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
     method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    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
   }
 
@@ -25189,7 +25158,6 @@
     ctor public PublishConfig.Builder();
     method public android.net.wifi.aware.PublishConfig build();
     method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(java.util.List<byte[]>);
-    method public android.net.wifi.aware.PublishConfig.Builder setPublishCount(int);
     method public android.net.wifi.aware.PublishConfig.Builder setPublishType(int);
     method public android.net.wifi.aware.PublishConfig.Builder setServiceName(java.lang.String);
     method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(byte[]);
@@ -25218,7 +25186,6 @@
     method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
     method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
-    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeCount(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setTerminateNotificationEnabled(boolean);
     method public android.net.wifi.aware.SubscribeConfig.Builder setTtlSec(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index eb6a3fb..2190a9d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6995,7 +6995,6 @@
     method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
     method public int getLeMaximumAdvertisingDataLength();
     method public java.lang.String getName();
-    method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
     method public int getProfileConnectionState(int);
     method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
     method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
@@ -7893,21 +7892,6 @@
     method public void stopScan(android.bluetooth.le.ScanCallback);
   }
 
-  public abstract class PeriodicAdvertisingCallback {
-    ctor public PeriodicAdvertisingCallback();
-    method public void onPeriodicAdvertisingReport(android.bluetooth.le.PeriodicAdvertisingReport);
-    method public void onSyncEstablished(int, android.bluetooth.BluetoothDevice, int, int, int, int);
-    method public void onSyncLost(int);
-    field public static final int SYNC_NO_RESOURCES = 2; // 0x2
-    field public static final int SYNC_NO_RESPONSE = 1; // 0x1
-  }
-
-  public final class PeriodicAdvertisingManager {
-    method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback);
-    method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback, android.os.Handler);
-    method public void unregisterSync(android.bluetooth.le.PeriodicAdvertisingCallback);
-  }
-
   public final class PeriodicAdvertisingParameters implements android.os.Parcelable {
     method public int describeContents();
     method public boolean getEnable();
@@ -7925,21 +7909,6 @@
     method public android.bluetooth.le.PeriodicAdvertisingParameters.Builder setInterval(int);
   }
 
-  public final class PeriodicAdvertisingReport implements android.os.Parcelable {
-    ctor public PeriodicAdvertisingReport(int, int, int, int, android.bluetooth.le.ScanRecord);
-    method public int describeContents();
-    method public android.bluetooth.le.ScanRecord getData();
-    method public int getDataStatus();
-    method public int getRssi();
-    method public int getSyncHandle();
-    method public long getTimestampNanos();
-    method public int getTxPower();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.le.PeriodicAdvertisingReport> CREATOR;
-    field public static final int DATA_COMPLETE = 0; // 0x0
-    field public static final int DATA_INCOMPLETE_TRUNCATED = 2; // 0x2
-  }
-
   public final class ResultStorageDescriptor implements android.os.Parcelable {
     ctor public ResultStorageDescriptor(int, int, int);
     method public int describeContents();
@@ -25603,8 +25572,8 @@
     method public void reportNetworkConnectivity(android.net.Network, boolean);
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
     method public deprecated boolean requestRouteToHost(int, int);
@@ -25766,7 +25735,7 @@
     method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
     method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
     method public void removeTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    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
   }
 
@@ -27749,7 +27718,6 @@
     ctor public PublishConfig.Builder();
     method public android.net.wifi.aware.PublishConfig build();
     method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(java.util.List<byte[]>);
-    method public android.net.wifi.aware.PublishConfig.Builder setPublishCount(int);
     method public android.net.wifi.aware.PublishConfig.Builder setPublishType(int);
     method public android.net.wifi.aware.PublishConfig.Builder setServiceName(java.lang.String);
     method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(byte[]);
@@ -27778,7 +27746,6 @@
     method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
     method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
-    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeCount(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setTerminateNotificationEnabled(boolean);
     method public android.net.wifi.aware.SubscribeConfig.Builder setTtlSec(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index ff93448..9f58603 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6705,7 +6705,6 @@
     method public static synchronized android.bluetooth.BluetoothAdapter getDefaultAdapter();
     method public int getLeMaximumAdvertisingDataLength();
     method public java.lang.String getName();
-    method public android.bluetooth.le.PeriodicAdvertisingManager getPeriodicAdvertisingManager();
     method public int getProfileConnectionState(int);
     method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
     method public android.bluetooth.BluetoothDevice getRemoteDevice(java.lang.String);
@@ -7594,21 +7593,6 @@
     method public void stopScan(android.bluetooth.le.ScanCallback);
   }
 
-  public abstract class PeriodicAdvertisingCallback {
-    ctor public PeriodicAdvertisingCallback();
-    method public void onPeriodicAdvertisingReport(android.bluetooth.le.PeriodicAdvertisingReport);
-    method public void onSyncEstablished(int, android.bluetooth.BluetoothDevice, int, int, int, int);
-    method public void onSyncLost(int);
-    field public static final int SYNC_NO_RESOURCES = 2; // 0x2
-    field public static final int SYNC_NO_RESPONSE = 1; // 0x1
-  }
-
-  public final class PeriodicAdvertisingManager {
-    method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback);
-    method public void registerSync(android.bluetooth.le.ScanResult, int, int, android.bluetooth.le.PeriodicAdvertisingCallback, android.os.Handler);
-    method public void unregisterSync(android.bluetooth.le.PeriodicAdvertisingCallback);
-  }
-
   public final class PeriodicAdvertisingParameters implements android.os.Parcelable {
     method public int describeContents();
     method public boolean getEnable();
@@ -7626,21 +7610,6 @@
     method public android.bluetooth.le.PeriodicAdvertisingParameters.Builder setInterval(int);
   }
 
-  public final class PeriodicAdvertisingReport implements android.os.Parcelable {
-    ctor public PeriodicAdvertisingReport(int, int, int, int, android.bluetooth.le.ScanRecord);
-    method public int describeContents();
-    method public android.bluetooth.le.ScanRecord getData();
-    method public int getDataStatus();
-    method public int getRssi();
-    method public int getSyncHandle();
-    method public long getTimestampNanos();
-    method public int getTxPower();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.le.PeriodicAdvertisingReport> CREATOR;
-    field public static final int DATA_COMPLETE = 0; // 0x0
-    field public static final int DATA_INCOMPLETE_TRUNCATED = 2; // 0x2
-  }
-
   public abstract class ScanCallback {
     ctor public ScanCallback();
     method public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult>);
@@ -23888,8 +23857,8 @@
     method public void reportNetworkConnectivity(android.net.Network, boolean);
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
     method public deprecated boolean requestRouteToHost(int, int);
@@ -23999,7 +23968,7 @@
     method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
     method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
     method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
-    method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    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
   }
 
@@ -25262,7 +25231,6 @@
     ctor public PublishConfig.Builder();
     method public android.net.wifi.aware.PublishConfig build();
     method public android.net.wifi.aware.PublishConfig.Builder setMatchFilter(java.util.List<byte[]>);
-    method public android.net.wifi.aware.PublishConfig.Builder setPublishCount(int);
     method public android.net.wifi.aware.PublishConfig.Builder setPublishType(int);
     method public android.net.wifi.aware.PublishConfig.Builder setServiceName(java.lang.String);
     method public android.net.wifi.aware.PublishConfig.Builder setServiceSpecificInfo(byte[]);
@@ -25291,7 +25259,6 @@
     method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
     method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
-    method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeCount(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
     method public android.net.wifi.aware.SubscribeConfig.Builder setTerminateNotificationEnabled(boolean);
     method public android.net.wifi.aware.SubscribeConfig.Builder setTtlSec(int);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c7fc860..f272105 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -143,6 +143,7 @@
 import libcore.io.EventLogger;
 import libcore.io.IoUtils;
 import libcore.net.event.NetworkEventDispatcher;
+import dalvik.system.BaseDexClassLoader;
 import dalvik.system.CloseGuard;
 import dalvik.system.VMDebug;
 import dalvik.system.VMRuntime;
@@ -5346,6 +5347,16 @@
             }
         }
 
+        // If we use profiles, setup the dex reporter to notify package manager
+        // of any relevant dex loads. The idle maintenance job will use the information
+        // reported to optimize the loaded dex files.
+        // Note that we only need one global reporter per app.
+        // Make sure we do this before calling onCreate so that we can capture the
+        // complete application startup.
+        if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
+            BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
+        }
+
         // Install the Network Security Config Provider. This must happen before the application
         // code is loaded to prevent issues with instances of TLS objects being created before
         // the provider is installed.
diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java
new file mode 100644
index 0000000..13f288a
--- /dev/null
+++ b/core/java/android/app/DexLoadReporter.java
@@ -0,0 +1,168 @@
+/*
+ * 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.app;
+
+import android.os.FileUtils;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import dalvik.system.BaseDexClassLoader;
+import dalvik.system.VMRuntime;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A dex load reporter which will notify package manager of any dex file loaded
+ * with {@code BaseDexClassLoader}.
+ * The goals are:
+ *     1) discover secondary dex files so that they can be optimized during the
+ *        idle maintenance job.
+ *     2) determine whether or not a dex file is used by an app which does not
+ *        own it (in order to select the optimal compilation method).
+ * @hide
+ */
+/*package*/ class DexLoadReporter implements BaseDexClassLoader.Reporter {
+    private static final String TAG = "DexLoadReporter";
+
+    private static final DexLoadReporter INSTANCE = new DexLoadReporter();
+
+    private static final boolean DEBUG = false;
+
+    // We must guard the access to the list of data directories because
+    // we might have concurrent accesses. Apps might load dex files while
+    // new data dirs are registered (due to creation of LoadedApks via
+    // create createApplicationContext).
+    @GuardedBy("mDataDirs")
+    private final Set<String> mDataDirs;
+
+    private DexLoadReporter() {
+        mDataDirs = new HashSet<>();
+    }
+
+    /*package*/ static DexLoadReporter getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Register an application data directory with the reporter.
+     * The data directories are used to determine if a dex file is secondary dex or not.
+     * Note that this method may be called multiple times for the same app, registering
+     * different data directories. This may happen when apps share the same user id
+     * ({@code android:sharedUserId}). For example, if app1 and app2 share the same user
+     * id, and app1 loads app2 apk, then both data directories will be registered.
+     */
+    /*package*/ void registerAppDataDir(String packageName, String dataDir) {
+        if (DEBUG) {
+            Slog.i(TAG, "Package " + packageName + " registering data dir: " + dataDir);
+        }
+        // TODO(calin): A few code paths imply that the data dir
+        // might be null. Investigate when that can happen.
+        if (dataDir != null) {
+            synchronized (mDataDirs) {
+                mDataDirs.add(dataDir);
+            }
+        }
+    }
+
+    @Override
+    public void report(List<String> dexPaths) {
+        if (dexPaths.isEmpty()) {
+            return;
+        }
+        // Notify the package manager about the dex loads unconditionally.
+        // The load might be for either a primary or secondary dex file.
+        notifyPackageManager(dexPaths);
+        // Check for secondary dex files and register them for profiling if
+        // possible.
+        registerSecondaryDexForProfiling(dexPaths);
+    }
+
+    private void notifyPackageManager(List<String> dexPaths) {
+        String packageName = ActivityThread.currentPackageName();
+        try {
+            ActivityThread.getPackageManager().notifyDexLoad(
+                    packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet());
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
+        }
+    }
+
+    private void registerSecondaryDexForProfiling(List<String> dexPaths) {
+        if (!SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
+            return;
+        }
+        // Make a copy of the current data directories so that we don't keep the lock
+        // while registering for profiling. The registration will perform I/O to
+        // check for or create the profile.
+        String[] dataDirs;
+        synchronized (mDataDirs) {
+            dataDirs = mDataDirs.toArray(new String[0]);
+        }
+        for (String dexPath : dexPaths) {
+            registerSecondaryDexForProfiling(dexPath, dataDirs);
+        }
+    }
+
+    private void registerSecondaryDexForProfiling(String dexPath, String[] dataDirs) {
+        if (!isSecondaryDexFile(dexPath, dataDirs)) {
+            // The dex path is not a secondary dex file. Nothing to do.
+            return;
+        }
+        File secondaryProfile = getSecondaryProfileFile(dexPath);
+        try {
+            // Create the profile if not already there.
+            // Returns true if the file was created, false if the file already exists.
+            // or throws exceptions in case of errors.
+            boolean created = secondaryProfile.createNewFile();
+            if (DEBUG && created) {
+                Slog.i(TAG, "Created profile for secondary dex: " + secondaryProfile);
+            }
+        } catch (IOException ex) {
+            Slog.e(TAG, "Failed to create profile for secondary dex " + secondaryProfile +
+                    ":" + ex.getMessage());
+            // Don't move forward with the registration if we failed to create the profile.
+            return;
+        }
+
+        VMRuntime.registerAppInfo(secondaryProfile.getPath(), new String[] { dexPath });
+    }
+
+    // A dex file is a secondary dex file if it is in any of the registered app
+    // data directories.
+    private boolean isSecondaryDexFile(String dexPath, String[] dataDirs) {
+        for (String dataDir : dataDirs) {
+            if (FileUtils.contains(dataDir, dexPath)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Secondary dex profiles are stored next to the dex file and have the same
+    // name with '.prof' appended.
+    // NOTE: Keep in sync with installd.
+    private File getSecondaryProfileFile(String dexPath) {
+        return new File(dexPath + ".prof");
+    }
+}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index c625756..404b7db 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -51,7 +51,6 @@
 import android.view.Display;
 import android.view.DisplayAdjustments;
 
-import dalvik.system.BaseDexClassLoader;
 import dalvik.system.VMRuntime;
 
 import java.io.File;
@@ -610,39 +609,10 @@
         VMRuntime.registerAppInfo(profileFile.getPath(),
                 codePaths.toArray(new String[codePaths.size()]));
 
-        // Setup the reporter to notify package manager of any relevant dex loads.
-        // At this point the primary apk is loaded and will not be reported.
-        // Anything loaded from now on will be tracked as a potential secondary
-        // or foreign dex file. The goal is to enable:
-        //    1) monitoring and compilation of secondary dex file
-        //    2) track whether or not a dex file is used by other apps (used to
-        //       determined the compilation filter of apks).
-        if (BaseDexClassLoader.getReporter() != DexLoadReporter.INSTANCE) {
-            // Set the dex load reporter if not already set.
-            // Note that during the app's life cycle different LoadedApks may be
-            // created and loaded (e.g. if two different apps share the same runtime).
-            BaseDexClassLoader.setReporter(DexLoadReporter.INSTANCE);
-        }
-    }
-
-    private static class DexLoadReporter implements BaseDexClassLoader.Reporter {
-        private static final DexLoadReporter INSTANCE = new DexLoadReporter();
-
-        private DexLoadReporter() {}
-
-        @Override
-        public void report(List<String> dexPaths) {
-            if (dexPaths.isEmpty()) {
-                return;
-            }
-            String packageName = ActivityThread.currentPackageName();
-            try {
-                ActivityThread.getPackageManager().notifyDexLoad(
-                        packageName, dexPaths, VMRuntime.getRuntime().vmInstructionSet());
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Failed to notify PM about dex load for package " + packageName, re);
-            }
-        }
+        // Register the app data directory with the reporter. It will
+        // help deciding whether or not a dex file is the primary apk or a
+        // secondary dex.
+        DexLoadReporter.getInstance().registerAppDataDir(mPackageName, mDataDir);
     }
 
     /**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 4c5fb13..c933678 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -73,7 +73,9 @@
 import android.net.EthernetManager;
 import android.net.IConnectivityManager;
 import android.net.IEthernetManager;
+import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
+import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
 import android.net.nsd.INsdManager;
@@ -239,6 +241,15 @@
                 return new ConnectivityManager(context, service);
             }});
 
+        registerService(Context.IPSEC_SERVICE, IpSecManager.class,
+                new StaticServiceFetcher<IpSecManager>() {
+            @Override
+            public IpSecManager createService() {
+                IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE);
+                IIpSecService service = IIpSecService.Stub.asInterface(b);
+                return new IpSecManager(service);
+            }});
+
         registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
                 new StaticServiceFetcher<CountryDetector>() {
             @Override
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 4960159..08e5a6e 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -611,6 +611,51 @@
     }
 
     /**
+     * Enables the optional codecs.
+     *
+     * @hide
+     */
+    public void enableOptionalCodecs() {
+        if (DBG) Log.d(TAG, "enableOptionalCodecs");
+        enableDisableOptionalCodecs(true);
+    }
+
+    /**
+     * Disables the optional codecs.
+     *
+     * @hide
+     */
+    public void disableOptionalCodecs() {
+        if (DBG) Log.d(TAG, "disableOptionalCodecs");
+        enableDisableOptionalCodecs(false);
+    }
+
+    /**
+     * Enables or disables the optional codecs.
+     *
+     * @param enable if true, enable the optional codecs, other disable them
+     */
+    private void enableDisableOptionalCodecs(boolean enable) {
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null && isEnabled()) {
+                if (enable) {
+                    mService.enableOptionalCodecs();
+                } else {
+                    mService.disableOptionalCodecs();
+                }
+            }
+            if (mService == null) Log.w(TAG, "Proxy not attached to service");
+            return;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e);
+            return;
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+    }
+
+    /**
      * Helper for converting a state to a string.
      *
      * For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 27640e7..2c4520d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -638,6 +638,7 @@
      * <p>
      * Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is
      * supported on this device before calling this method.
+     * @hide
      */
     public PeriodicAdvertisingManager getPeriodicAdvertisingManager() {
       if (!getLeAccess())
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index 176e48f..d5e1429 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -63,7 +63,7 @@
     public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
 
     private final int mCodecType;
-    private final int mCodecPriority;
+    private int mCodecPriority;
     private final int mSampleRate;
     private final int mBitsPerSample;
     private final int mChannelMode;
@@ -280,6 +280,15 @@
     }
 
     /**
+     * Checks whether the codec is mandatory.
+     *
+     * @return true if the codec is mandatory, otherwise false.
+     */
+    public boolean isMandatoryCodec() {
+        return mCodecType == SOURCE_CODEC_TYPE_SBC;
+    }
+
+    /**
      * Gets the codec selection priority.
      * The codec selection priority is relative to other codecs: larger value
      * means higher priority. If 0, reset to default.
@@ -291,6 +300,17 @@
     }
 
     /**
+     * Sets the codec selection priority.
+     * The codec selection priority is relative to other codecs: larger value
+     * means higher priority. If 0, reset to default.
+     *
+     * @param codecPriority the codec priority
+     */
+    public void setCodecPriority(int codecPriority) {
+        mCodecPriority = codecPriority;
+    }
+
+    /**
      * Gets the codec sample rate. The value can be a bitmask with all
      * supported sample rates:
      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 99ca11e..02ba403 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -778,7 +778,7 @@
 
     /**
      * Set the preferred connection PHY for this app. Please note that this is just a
-     * recommendation, wether the PHY change will happen depends on other applications peferences,
+     * recommendation, whether the PHY change will happen depends on other applications peferences,
      * local and remote controller capabilities. Controller can override these settings.
      * <p>
      * {@link BluetoothGattCallback#onPhyUpdate} will be triggered as a result of this call, even
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index b35a593..2df2ed8 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -550,7 +550,7 @@
 
     /**
      * Set the preferred connection PHY for this app. Please note that this is just a
-     * recommendation, wether the PHY change will happen depends on other applications peferences,
+     * recommendation, whether the PHY change will happen depends on other applications peferences,
      * local and remote controller capabilities. Controller can override these settings.
      * <p>
      * {@link BluetoothGattServerCallback#onPhyUpdate} will be triggered as a result of this call, even
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index dbb5b7d..a775a1f 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -40,4 +40,6 @@
     boolean isA2dpPlaying(in BluetoothDevice device);
     BluetoothCodecStatus getCodecStatus();
     oneway void setCodecConfigPreference(in BluetoothCodecConfig codecConfig);
+    oneway void enableOptionalCodecs();
+    oneway void disableOptionalCodecs();
 }
diff --git a/core/java/android/bluetooth/le/AdvertisingSetParameters.java b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
index fe1f425..3e13ad3 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetParameters.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
@@ -253,10 +253,10 @@
         /**
          * Set whether the advertisement type should be connectable or
          * non-connectable.
-         * Legacy advertisements can be both connectable and scannable. Other
-         * advertisements can be connectable only if not scannable.
+         * Legacy advertisements must be both connectable and scannable. Nonlegacy
+         * advertisements can be only scannable or only connectable.
          * @param connectable Controls whether the advertisment type will be
-         * connectable (true) or non-connectable (false).
+         * connectable (true) or nonconnectable (false).
          */
         public Builder setConnectable(boolean connectable) {
             this.connectable = connectable;
@@ -264,11 +264,11 @@
         }
 
         /**
-         * Set whether the advertisement type should be scannable
-         * Legacy advertisements can be both connectable and scannable. Other
-         * advertisements can be scannable only if not connectable.
+         * Set whether the advertisement type should be scannable.
+         * Legacy advertisements must be both connectable and scannable. Nonlegacy
+         * advertisements can be only scannable or only connectable.
          * @param scannable Controls whether the advertisment type will be
-         * scannable (true) or non-scannable (false).
+         * scannable (true) or nonscannable (false).
          */
         public Builder setScannable(boolean scannable) {
             this.scannable = scannable;
@@ -279,7 +279,7 @@
          * When set to true, advertising set will advertise 4.x Spec compliant
          * advertisements.
          *
-         * @param isLegacy wether legacy advertising mode should be used.
+         * @param isLegacy whether legacy advertising mode should be used.
          */
         public Builder setLegacyMode(boolean isLegacy) {
             this.isLegacy = isLegacy;
@@ -287,12 +287,12 @@
         }
 
         /**
-         * Set wether advertiser address should be ommited from all packets. If this
+         * Set whether advertiser address should be ommited from all packets. If this
          * mode is used, periodic advertising can't be enabled for this set.
          *
          * This is used only if legacy mode is not used.
          *
-         * @param isAnonymous wether anonymous advertising should be used.
+         * @param isAnonymous whether anonymous advertising should be used.
          */
         public Builder setAnonymous(boolean isAnonymous) {
             this.isAnonymous = isAnonymous;
@@ -300,11 +300,11 @@
         }
 
         /**
-         * Set wether TX power should be included in the extended header.
+         * Set whether TX power should be included in the extended header.
          *
          * This is used only if legacy mode is not used.
          *
-         * @param includeTxPower wether TX power should be included in extended
+         * @param includeTxPower whether TX power should be included in extended
          * header
          */
         public Builder setIncludeTxPower(boolean includeTxPower) {
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java b/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java
index 6616231..364b575 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java
@@ -23,6 +23,7 @@
  * advertising operation status.
  *
  * @see PeriodicAdvertisingManager#createSync
+ * @hide
  */
 public abstract class PeriodicAdvertisingCallback {
 
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
index 12c8a8c..d9c2d88 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
@@ -37,6 +37,7 @@
  * <p>
  * <b>Note:</b> Most of the methods here require
  * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ * @hide
  */
 public final class PeriodicAdvertisingManager {
 
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
index ebc92bd..149540c 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
@@ -93,7 +93,7 @@
         private int interval = INTERVAL_MAX;
 
         /**
-         * Set wether the Periodic Advertising should be enabled for this set.
+         * Set whether the Periodic Advertising should be enabled for this set.
          */
         public Builder setEnable(boolean enable) {
             this.enable = enable;
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java b/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
index 3ff4ca5..51b93cb 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
@@ -24,6 +24,7 @@
 
 /**
  * PeriodicAdvertisingReport for Bluetooth LE synchronized advertising.
+ * @hide
  */
 public final class PeriodicAdvertisingReport implements Parcelable {
 
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
new file mode 100644
index 0000000..b8737fe
--- /dev/null
+++ b/core/java/android/net/IIpSecService.aidl
@@ -0,0 +1,24 @@
+/*
+** 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;
+
+/**
+ * @hide
+ */
+interface IIpSecService
+{
+}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 2c544e9..83f4cc9 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -18,8 +18,6 @@
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.SystemApi;
-import android.content.Context;
-import android.os.INetworkManagementService;
 import android.os.ParcelFileDescriptor;
 import android.util.AndroidException;
 import dalvik.system.CloseGuard;
@@ -79,12 +77,11 @@
         }
     }
 
-    private final Context mContext;
-    private final INetworkManagementService mService;
+    private final IIpSecService mService;
 
     public static final class SecurityParameterIndex implements AutoCloseable {
-        private final Context mContext;
-        private final InetAddress mDestinationAddress;
+        private final IIpSecService mService;
+        private final InetAddress mRemoteAddress;
         private final CloseGuard mCloseGuard = CloseGuard.get();
         private int mSpi;
 
@@ -93,10 +90,11 @@
             return mSpi;
         }
 
-        private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi)
+        private SecurityParameterIndex(
+                IIpSecService service, int direction, InetAddress remoteAddress, int spi)
                 throws ResourceUnavailableException, SpiUnavailableException {
-            mContext = context;
-            mDestinationAddress = destinationAddress;
+            mService = service;
+            mRemoteAddress = remoteAddress;
             mSpi = spi;
             mCloseGuard.open("open");
         }
@@ -104,13 +102,9 @@
         /**
          * Release an SPI that was previously reserved.
          *
-         * <p>Release an SPI for use by other users in the system. This will fail if the SPI is
-         * currently in use by an IpSecTransform.
-         *
-         * @param destinationAddress SPIs must be unique for each combination of SPI and destination
-         *     address. Thus, the destinationAddress to which the SPI will communicate must be
-         *     supplied.
-         * @param spi the previously reserved SPI to be freed.
+         * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is
+         * applied to an IpSecTransform, it will become unusable for future transforms but should
+         * still be closed to ensure system resources are released.
          */
         @Override
         public void close() {
@@ -136,13 +130,13 @@
     public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
 
     /**
-     * Reserve an SPI for traffic bound towards the specified destination address.
+     * Reserve an SPI for traffic bound towards the specified remote address.
      *
      * <p>If successful, this SPI is guaranteed available until released by a call to {@link
      * SecurityParameterIndex#close()}.
      *
-     * @param destinationAddress SPIs must be unique for each combination of SPI and destination
-     *     address.
+     * @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.
      * @return the reserved SecurityParameterIndex
      * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
@@ -150,9 +144,9 @@
      * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
      */
     public SecurityParameterIndex reserveSecurityParameterIndex(
-            InetAddress destinationAddress, int requestedSpi)
+            int direction, InetAddress remoteAddress, int requestedSpi)
             throws SpiUnavailableException, ResourceUnavailableException {
-        return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi);
+        return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi);
     }
 
     /**
@@ -260,19 +254,19 @@
      */
     public static final class UdpEncapsulationSocket implements AutoCloseable {
         private final FileDescriptor mFd;
-        private final Context mContext;
+        private final IIpSecService mService;
         private final CloseGuard mCloseGuard = CloseGuard.get();
 
-        private UdpEncapsulationSocket(Context context, int port)
+        private UdpEncapsulationSocket(IIpSecService service, int port)
                 throws ResourceUnavailableException {
-            mContext = context;
+            mService = service;
             mCloseGuard.open("constructor");
             // TODO: go down to the kernel and get a socket on the specified
             mFd = new FileDescriptor();
         }
 
-        private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException {
-            mContext = context;
+        private UdpEncapsulationSocket(IIpSecService service) throws ResourceUnavailableException {
+            mService = service;
             mCloseGuard.open("constructor");
             // TODO: go get a random socket on a random port
             mFd = new FileDescriptor();
@@ -339,7 +333,7 @@
     public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
             throws IOException, ResourceUnavailableException {
         // Temporary code
-        return new UdpEncapsulationSocket(mContext, port);
+        return new UdpEncapsulationSocket(mService, port);
     }
 
     /**
@@ -363,7 +357,7 @@
     public UdpEncapsulationSocket openUdpEncapsulationSocket()
             throws IOException, ResourceUnavailableException {
         // Temporary code
-        return new UdpEncapsulationSocket(mContext);
+        return new UdpEncapsulationSocket(mService);
     }
 
     /**
@@ -372,8 +366,7 @@
      * @param context the application context for this manager
      * @hide
      */
-    public IpSecManager(Context context, INetworkManagementService service) {
-        mContext = checkNotNull(context, "missing context");
+    public IpSecManager(IIpSecService service) {
         mService = checkNotNull(service, "missing service");
     }
 }
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index d6dd28b..5c0bbe6 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -307,7 +307,7 @@
          * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
          * possible. Random number generation is a reasonable approach to selecting an SPI. For
          * outbound SPIs, they must be reserved by calling {@link
-         * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+         * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will
          * fail to build.
          *
          * <p>Unless an SPI is set for a given direction, traffic in that direction will be
@@ -329,7 +329,7 @@
          * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
          * possible. Random number generation is a reasonable approach to selecting an SPI. For
          * outbound SPIs, they must be reserved by calling {@link
-         * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+         * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will
          * fail to activate.
          *
          * <p>Unless an SPI is set for a given direction, traffic in that direction will be
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 8e24caf..bd8af4d 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -428,14 +428,13 @@
      */
     public static boolean contains(File dir, File file) {
         if (dir == null || file == null) return false;
+        return contains(dir.getAbsolutePath(), file.getAbsolutePath());
+    }
 
-        String dirPath = dir.getAbsolutePath();
-        String filePath = file.getAbsolutePath();
-
+    public static boolean contains(String dirPath, String filePath) {
         if (dirPath.equals(filePath)) {
             return true;
         }
-
         if (!dirPath.endsWith("/")) {
             dirPath += "/";
         }
diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java
new file mode 100644
index 0000000..7dec4d7
--- /dev/null
+++ b/core/java/android/os/HidlSupport.java
@@ -0,0 +1,159 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+/** @hide */
+public class HidlSupport {
+    /**
+     * Similar to Objects.deepEquals, but also take care of lists.
+     * Two objects of HIDL types are considered equal if:
+     * 1. Both null
+     * 2. Both non-null, and of the same class, and:
+     * 2.1 Both are primitive arrays / enum arrays, elements are equal using == check
+     * 2.2 Both are object arrays, elements are checked recursively
+     * 2.3 Both are Lists, elements are checked recursively
+     * 2.4 (If both are collections other than lists or maps, throw an error)
+     * 2.5 lft.equals(rgt) returns true
+     */
+    public static boolean deepEquals(Object lft, Object rgt) {
+        if (lft == rgt) {
+            return true;
+        }
+        if (lft == null || rgt == null) {
+            return false;
+        }
+
+        Class<?> lftClazz = lft.getClass();
+        Class<?> rgtClazz = rgt.getClass();
+        if (lftClazz != rgtClazz) {
+            return false;
+        }
+
+        if (lftClazz.isArray()) {
+            Class<?> lftElementType = lftClazz.getComponentType();
+            if (lftElementType != rgtClazz.getComponentType()) {
+                return false;
+            }
+
+            if (lftElementType.isPrimitive()) {
+                return Objects.deepEquals(lft, rgt);
+            }
+
+            Object[] lftArray = (Object[])lft;
+            Object[] rgtArray = (Object[])rgt;
+            return (lftArray.length == rgtArray.length) &&
+                   IntStream.range(0, lftArray.length).allMatch(
+                        i -> deepEquals(lftArray[i], rgtArray[i]));
+        }
+
+        if (lft instanceof List<?>) {
+            List<Object> lftList = (List<Object>)lft;
+            List<Object> rgtList = (List<Object>)rgt;
+            if (lftList.size() != rgtList.size()) {
+                return false;
+            }
+
+            Iterator<Object> lftIter = lftList.iterator();
+            return rgtList.stream()
+                    .allMatch(rgtElement -> deepEquals(lftIter.next(), rgtElement));
+        }
+
+        throwErrorIfUnsupportedType(lft);
+
+        return lft.equals(rgt);
+    }
+
+    /**
+     * Similar to Arrays.deepHashCode, but also take care of lists.
+     */
+    public static int deepHashCode(Object o) {
+        if (o == null) {
+            return 0;
+        }
+        Class<?> clazz = o.getClass();
+        if (clazz.isArray()) {
+            Class<?> elementType = clazz.getComponentType();
+            if (elementType.isPrimitive()) {
+                return primitiveArrayHashCode(o);
+            }
+            return Arrays.hashCode(Arrays.stream((Object[])o)
+                    .mapToInt(element -> deepHashCode(element))
+                    .toArray());
+        }
+
+        if (o instanceof List<?>) {
+            return Arrays.hashCode(((List<Object>)o).stream()
+                    .mapToInt(element -> deepHashCode(element))
+                    .toArray());
+        }
+
+        throwErrorIfUnsupportedType(o);
+
+        return o.hashCode();
+    }
+
+    private static void throwErrorIfUnsupportedType(Object o) {
+        if (o instanceof Collection<?> && !(o instanceof List<?>)) {
+            throw new UnsupportedOperationException(
+                    "Cannot check equality on collections other than lists: " +
+                    o.getClass().getName());
+        }
+
+        if (o instanceof Map<?, ?>) {
+            throw new UnsupportedOperationException(
+                    "Cannot check equality on maps");
+        }
+    }
+
+    private static int primitiveArrayHashCode(Object o) {
+        Class<?> elementType = o.getClass().getComponentType();
+        if (elementType == boolean.class) {
+            return Arrays.hashCode(((boolean[])o));
+        }
+        if (elementType == byte.class) {
+            return Arrays.hashCode(((byte[])o));
+        }
+        if (elementType == char.class) {
+            return Arrays.hashCode(((char[])o));
+        }
+        if (elementType == double.class) {
+            return Arrays.hashCode(((double[])o));
+        }
+        if (elementType == float.class) {
+            return Arrays.hashCode(((float[])o));
+        }
+        if (elementType == int.class) {
+            return Arrays.hashCode(((int[])o));
+        }
+        if (elementType == long.class) {
+            return Arrays.hashCode(((long[])o));
+        }
+        if (elementType == short.class) {
+            return Arrays.hashCode(((short[])o));
+        }
+        // Should not reach here.
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index d48431a..4f4152c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -483,7 +483,7 @@
             }
 
             final String filenameArg = "--update_package=" + filename + "\n";
-            final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
+            final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() + "\n";
             final String securityArg = "--security\n";
 
             String command = filenameArg + localeArg;
@@ -531,7 +531,7 @@
         }
 
         final String filenameArg = "--update_package=" + filename + "\n";
-        final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
+        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() + "\n";
         final String securityArg = "--security\n";
 
         String command = filenameArg + localeArg;
@@ -646,7 +646,7 @@
             reasonArg = "--reason=" + sanitizeArg(reason);
         }
 
-        final String localeArg = "--locale=" + Locale.getDefault().toString();
+        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;
         bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
     }
 
@@ -665,7 +665,7 @@
             reasonArg = "--reason=" + sanitizeArg(reason);
         }
 
-        final String localeArg = "--locale=" + Locale.getDefault().toString();
+        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;
         bootCommand(context, "--wipe_cache", reasonArg, localeArg);
     }
 
@@ -690,7 +690,7 @@
 
         final String filename = packageFile.getCanonicalPath();
         final String filenameArg = "--wipe_package=" + filename;
-        final String localeArg = "--locale=" + Locale.getDefault().toString();
+        final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;
         bootCommand(context, "--wipe_ab", filenameArg, reasonArg, localeArg);
     }
 
@@ -728,6 +728,10 @@
             int timeTotal = -1;
             int uncryptTime = -1;
             int sourceVersion = -1;
+            int temperature_start = -1;
+            int temperature_end = -1;
+            int temperature_max = -1;
+
             while ((line = in.readLine()) != null) {
                 // Here is an example of lines in last_install:
                 // ...
@@ -772,6 +776,12 @@
                 } else if (line.startsWith("bytes_stashed")) {
                     bytesStashedInMiB = (bytesStashedInMiB == -1) ? scaled :
                             bytesStashedInMiB + scaled;
+                } else if (line.startsWith("temperature_start")) {
+                    temperature_start = scaled;
+                } else if (line.startsWith("temperature_end")) {
+                    temperature_end = scaled;
+                } else if (line.startsWith("temperature_max")) {
+                    temperature_max = scaled;
                 }
             }
 
@@ -791,6 +801,15 @@
             if (bytesStashedInMiB != -1) {
                 MetricsLogger.histogram(context, "ota_stashed_in_MiBs", bytesStashedInMiB);
             }
+            if (temperature_start != -1) {
+                MetricsLogger.histogram(context, "ota_temperature_start", temperature_start);
+            }
+            if (temperature_end != -1) {
+                MetricsLogger.histogram(context, "ota_temperature_end", temperature_end);
+            }
+            if (temperature_max != -1) {
+                MetricsLogger.histogram(context, "ota_temperature_max", temperature_max);
+            }
 
         } catch (IOException e) {
             Log.e(TAG, "Failed to read lines in last_install", e);
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index d67cef3..8d9630f 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -2070,8 +2070,6 @@
      * @param args
      */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        // Cannot just invoke pw.println(this.toString()) because if the
-        // resulting string is to long it won't be displayed.
         pw.println(getName() + ":");
         pw.println(" total records=" + getLogRecCount());
         for (int i = 0; i < getLogRecSize(); i++) {
@@ -2083,12 +2081,15 @@
 
     @Override
     public String toString() {
-        StringWriter sr = new StringWriter();
-        PrintWriter pr = new PrintWriter(sr);
-        dump(null, pr, null);
-        pr.flush();
-        pr.close();
-        return sr.toString();
+        String name = "(null)";
+        String state = "(null)";
+        try {
+            name = mName.toString();
+            state = mSmHandler.getCurrentState().getName().toString();
+        } catch (NullPointerException npe) {
+            // Will use default(s) initialized above.
+        }
+        return "name=" + name + " state=" + state;
     }
 
     /**
diff --git a/core/tests/utiltests/runtests.sh b/core/tests/utiltests/runtests.sh
new file mode 100755
index 0000000..853119f
--- /dev/null
+++ b/core/tests/utiltests/runtests.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+
+echo "Running tests"
+
+set -e # fail early
+
+echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/core/tests/utiltests"
+# NOTE Don't actually run the command above since this shell doesn't inherit functions from the
+#      caller.
+make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-base-core-tests-utiltests
+
+set -x # print commands
+
+adb root
+adb wait-for-device
+
+adb install -r -g "$OUT/data/app/FrameworksUtilTests/FrameworksUtilTests.apk"
+
+adb shell am instrument -w "$@" 'com.android.frameworks.utiltests/android.support.test.runner.AndroidJUnitRunner'
diff --git a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
index d29b572..eb2a516 100644
--- a/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
@@ -80,6 +80,66 @@
     }
 
     /**
+     * Tests {@link StateMachine#toString()}.
+     */
+    class StateMachineToStringTest extends StateMachine {
+        StateMachineToStringTest(String name) {
+            super(name);
+        }
+    }
+
+    class ExampleState extends State {
+        String mName;
+
+        ExampleState(String name) {
+            mName = name;
+        }
+
+        @Override
+        public String getName() {
+            return mName;
+        }
+    }
+
+    @SmallTest
+    public void testToStringSucceedsEvenIfMachineHasNoStates() throws Exception {
+        StateMachine stateMachine = new StateMachineToStringTest("TestStateMachine");
+        assertTrue(stateMachine.toString().contains("TestStateMachine"));
+    }
+
+    @SmallTest
+    public void testToStringSucceedsEvenIfStateHasNoName() throws Exception {
+        StateMachine stateMachine = new StateMachineToStringTest("TestStateMachine");
+        State exampleState = new ExampleState(null);
+        stateMachine.addState(exampleState);
+        stateMachine.setInitialState(exampleState);
+        stateMachine.start();
+        assertTrue(stateMachine.toString().contains("TestStateMachine"));
+        assertTrue(stateMachine.toString().contains("(null)"));
+    }
+
+    @SmallTest
+    public void testToStringIncludesMachineAndStateNames() throws Exception {
+        StateMachine stateMachine = new StateMachineToStringTest("TestStateMachine");
+        State exampleState = new ExampleState("exampleState");
+        stateMachine.addState(exampleState);
+        stateMachine.setInitialState(exampleState);
+        stateMachine.start();
+        assertTrue(stateMachine.toString().contains("TestStateMachine"));
+        assertTrue(stateMachine.toString().contains("exampleState"));
+    }
+
+    @SmallTest
+    public void testToStringDoesNotContainMultipleLines() throws Exception {
+        StateMachine stateMachine = new StateMachineToStringTest("TestStateMachine");
+        State exampleState = new ExampleState("exampleState");
+        stateMachine.addState(exampleState);
+        stateMachine.setInitialState(exampleState);
+        stateMachine.start();
+        assertFalse(stateMachine.toString().contains("\n"));
+    }
+
+    /**
      * Tests {@link StateMachine#quit()}.
      */
     class StateMachineQuitTest extends StateMachine {
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 950ed3e..13ec722 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -124,6 +124,8 @@
         <item>aptX</item>
         <item>aptX HD</item>
         <item>LDAC</item>
+        <item>Enable Optional Codecs</item>
+        <item>Disable Optional Codecs</item>
     </string-array>
 
     <!-- Values for Bluetooth Audio Codec selection preference. -->
@@ -134,6 +136,8 @@
         <item>2</item>
         <item>3</item>
         <item>4</item>
+        <item>5</item>
+        <item>6</item>
     </string-array>
 
     <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50]-->
@@ -144,6 +148,8 @@
         <item>aptX</item>
         <item>aptX HD</item>
         <item>LDAC</item>
+        <item>Enable Optional Codecs</item>
+        <item>Disable Optional Codecs</item>
     </string-array>
 
     <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=50] -->
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ff079ad..1e3ae2a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3737,8 +3737,6 @@
                 vpn.setAlwaysOnPackage(null, false);
                 return false;
             }
-
-            vpn.saveAlwaysOnPackage();
         }
         return true;
     }
@@ -3899,15 +3897,6 @@
             }
             userVpn = new Vpn(mHandler.getLooper(), mContext, mNetd, userId);
             mVpns.put(userId, userVpn);
-
-            final ContentResolver cr = mContext.getContentResolver();
-            String alwaysOnPackage = Settings.Secure.getStringForUser(cr,
-                    Settings.Secure.ALWAYS_ON_VPN_APP, userId);
-            final boolean alwaysOnLockdown = Settings.Secure.getIntForUser(cr,
-                    Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, /* default */ 0, userId) != 0;
-            if (alwaysOnPackage != null) {
-                userVpn.setAlwaysOnPackage(alwaysOnPackage, alwaysOnLockdown);
-            }
         }
         if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
             updateLockdownVpn();
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
new file mode 100644
index 0000000..994adc4
--- /dev/null
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -0,0 +1,114 @@
+/*
+ * 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.server;
+
+import static android.Manifest.permission.DUMP;
+
+import android.content.Context;
+import android.net.IIpSecService;
+import android.net.INetd;
+import android.net.util.NetdService;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/** @hide */
+public class IpSecService extends IIpSecService.Stub {
+    private static final String TAG = "IpSecService";
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final String NETD_SERVICE_NAME = "netd";
+
+    /** Binder context for this service */
+    private final Context mContext;
+
+    private Object mLock = new Object();
+
+    private static final int NETD_FETCH_TIMEOUT = 5000; //ms
+
+    /**
+     * Constructs a new IpSecService instance
+     *
+     * @param context Binder context for this service
+     */
+    private IpSecService(Context context) {
+        mContext = context;
+    }
+
+    static IpSecService create(Context context) throws InterruptedException {
+        final IpSecService service = new IpSecService(context);
+        service.connectNativeNetdService();
+        return service;
+    }
+
+    public void systemReady() {
+        if (isNetdAlive()) {
+            Slog.d(TAG, "IpSecService is ready");
+        } else {
+            Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
+        }
+    }
+
+    private void connectNativeNetdService() {
+        // Avoid blocking the system server to do this
+        Thread t =
+                new Thread(
+                        new Runnable() {
+                            @Override
+                            public void run() {
+                                synchronized (mLock) {
+                                    NetdService.get(NETD_FETCH_TIMEOUT);
+                                }
+                            }
+                        });
+        t.run();
+    }
+
+    INetd getNetdInstance() {
+        final INetd netd = NetdService.getInstance();
+        if (netd == null) {
+            throw new RemoteException("Failed to Get Netd Instance").rethrowFromSystemServer();
+        }
+        return netd;
+    }
+
+    boolean isNetdAlive() {
+        synchronized (mLock) {
+            final INetd netd = getNetdInstance();
+            if (netd == null) {
+                return false;
+            }
+
+            try {
+                return netd.isAlive();
+            } catch (RemoteException re) {
+                return false;
+            }
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
+
+        pw.println("IpSecService Log:");
+        pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1feaa72..9a12aeb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3790,8 +3790,13 @@
             if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
                 // Debuggable apps may include a wrapper script with their library directory.
                 String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
-                if (new File(wrapperFileName).exists()) {
-                    invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+                try {
+                    if (new File(wrapperFileName).exists()) {
+                        invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+                    }
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
                 }
             }
 
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index 8c18c46..0412db5 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -20,6 +20,8 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemClock;
+import android.util.Slog;
 import android.view.WindowManager;
 import android.widget.Toast;
 
@@ -31,10 +33,12 @@
  */
 public class LockTaskNotify {
     private static final String TAG = "LockTaskNotify";
+    private static final long SHOW_TOAST_MINIMUM_INTERVAL = 1000;
 
     private final Context mContext;
     private final H mHandler;
     private Toast mLastToast;
+    private long mLastShowToastTime;
 
     public LockTaskNotify(Context context) {
         mContext = context;
@@ -55,10 +59,16 @@
         if (text == null) {
             return;
         }
+        long showToastTime = SystemClock.elapsedRealtime();
+        if ((showToastTime - mLastShowToastTime) < SHOW_TOAST_MINIMUM_INTERVAL) {
+            Slog.i(TAG, "Ignore toast since it is requested in very short interval.");
+            return;
+        }
         if (mLastToast != null) {
             mLastToast.cancel();
         }
         mLastToast = makeAllUserToastAndShow(text);
+        mLastShowToastTime = showToastTime;
     }
 
     public void show(boolean starting) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a5876dd..584994a 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -32,7 +32,6 @@
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -132,6 +131,7 @@
     private NetworkAgent mNetworkAgent;
     private final Looper mLooper;
     private final NetworkCapabilities mNetworkCapabilities;
+    private final SystemServices mSystemServices;
 
     /**
      * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This
@@ -199,7 +199,7 @@
                         final boolean isPackageRemoved = !intent.getBooleanExtra(
                                 Intent.EXTRA_REPLACING, false);
                         if (isPackageRemoved) {
-                            setAndSaveAlwaysOnPackage(null, false);
+                            setAlwaysOnPackage(null, false);
                         }
                         break;
                 }
@@ -210,11 +210,18 @@
     private boolean mIsPackageIntentReceiverRegistered = false;
 
     public Vpn(Looper looper, Context context, INetworkManagementService netService,
-            int userHandle) {
+            @UserIdInt int userHandle) {
+        this(looper, context, netService, userHandle, new SystemServices(context));
+    }
+
+    @VisibleForTesting
+    protected Vpn(Looper looper, Context context, INetworkManagementService netService,
+            int userHandle, SystemServices systemServices) {
         mContext = context;
         mNetd = netService;
         mUserHandle = userHandle;
         mLooper = looper;
+        mSystemServices = systemServices;
 
         mPackage = VpnConfig.LEGACY_VPN;
         mOwnerUID = getAppUid(mPackage, mUserHandle);
@@ -230,6 +237,8 @@
         mNetworkCapabilities = new NetworkCapabilities();
         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
         mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
+
+        loadAlwaysOnPackage();
     }
 
     /**
@@ -268,6 +277,26 @@
      */
     public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
         enforceControlPermissionOrInternalCaller();
+
+        if (setAlwaysOnPackageInternal(packageName, lockdown)) {
+            saveAlwaysOnPackage();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Configures an always-on VPN connection through a specific application, the same as
+     * {@link #setAlwaysOnPackage}.
+     *
+     * Does not perform permission checks. Does not persist any of the changes to storage.
+     *
+     * @param packageName the package to designate as always-on VPN supplier.
+     * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
+     * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
+     */
+    @GuardedBy("this")
+    private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) {
         if (VpnConfig.LEGACY_VPN.equals(packageName)) {
             Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
             return false;
@@ -340,13 +369,13 @@
     /**
      * Save the always-on package and lockdown config into Settings.Secure
      */
-    public synchronized void saveAlwaysOnPackage() {
+    @GuardedBy("this")
+    private void saveAlwaysOnPackage() {
         final long token = Binder.clearCallingIdentity();
         try {
-            final ContentResolver cr = mContext.getContentResolver();
-            Settings.Secure.putStringForUser(cr, Settings.Secure.ALWAYS_ON_VPN_APP,
+            mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP,
                     getAlwaysOnPackage(), mUserHandle);
-            Settings.Secure.putIntForUser(cr, Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
+            mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
                     (mLockdown ? 1 : 0), mUserHandle);
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -354,18 +383,19 @@
     }
 
     /**
-     * Set and save always-on package and lockdown config
-     * @see Vpn#setAlwaysOnPackage(String, boolean)
-     * @see Vpn#saveAlwaysOnPackage()
-     *
-     * @return result of Vpn#setAndSaveAlwaysOnPackage(String, boolean)
+     * Load the always-on package and lockdown config from Settings.Secure
      */
-    private synchronized boolean setAndSaveAlwaysOnPackage(String packageName, boolean lockdown) {
-        if (setAlwaysOnPackage(packageName, lockdown)) {
-            saveAlwaysOnPackage();
-            return true;
-        } else {
-            return false;
+    @GuardedBy("this")
+    private void loadAlwaysOnPackage() {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser(
+                    Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
+            final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
+                    Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
+            setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown);
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
     }
 
@@ -1257,11 +1287,7 @@
 
     private void updateAlwaysOnNotification(DetailedState networkState) {
         final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
-        updateAlwaysOnNotificationInternal(visible);
-    }
 
-    @VisibleForTesting
-    protected void updateAlwaysOnNotificationInternal(boolean visible) {
         final UserHandle user = UserHandle.of(mUserHandle);
         final long token = Binder.clearCallingIdentity();
         try {
@@ -1271,10 +1297,8 @@
                 return;
             }
             final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
-            final PendingIntent configIntent = PendingIntent.getActivityAsUser(
-                    mContext, /* request */ 0, intent,
-                    PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
-                    null, user);
+            final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser(
+                    intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user);
             final Notification.Builder builder = new Notification.Builder(mContext)
                     .setDefaults(0)
                     .setSmallIcon(R.drawable.vpn_connected)
@@ -1292,6 +1316,58 @@
         }
     }
 
+    /**
+     * Facade for system service calls that change, or depend on, state outside of
+     * {@link ConnectivityService} and have hard-to-mock interfaces.
+     *
+     * @see com.android.server.connectivity.VpnTest
+     */
+    @VisibleForTesting
+    public static class SystemServices {
+        private final Context mContext;
+
+        public SystemServices(@NonNull Context context) {
+            mContext = context;
+        }
+
+        /**
+         * @see PendingIntent#getActivityAsUser()
+         */
+        public PendingIntent pendingIntentGetActivityAsUser(
+                Intent intent, int flags, UserHandle user) {
+            return PendingIntent.getActivityAsUser(mContext, 0 /*request*/, intent, flags,
+                    null /*options*/, user);
+        }
+
+        /**
+         * @see Settings.Secure#putStringForUser
+         */
+        public void settingsSecurePutStringForUser(String key, String value, int userId) {
+            Settings.Secure.putStringForUser(mContext.getContentResolver(), key, value, userId);
+        }
+
+        /**
+         * @see Settings.Secure#putIntForUser
+         */
+        public void settingsSecurePutIntForUser(String key, int value, int userId) {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userId);
+        }
+
+        /**
+         * @see Settings.Secure#getStringForUser
+         */
+        public String settingsSecureGetStringForUser(String key, int userId) {
+            return Settings.Secure.getStringForUser(mContext.getContentResolver(), key, userId);
+        }
+
+        /**
+         * @see Settings.Secure#getIntForUser
+         */
+        public int settingsSecureGetIntForUser(String key, int def, int userId) {
+            return Settings.Secure.getIntForUser(mContext.getContentResolver(), key, def, userId);
+        }
+    }
+
     private native int jniCreate(int mtu);
     private native String jniGetName(int tun);
     private native int jniSetAddresses(String interfaze, String addresses);
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 7aa96cf..d364d17 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -49,8 +49,6 @@
 
     private static final boolean DEBUG = false;
 
-    private static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;
-
     private static final int JOB_IDLE_OPTIMIZE = 800;
     private static final int JOB_POST_BOOT_UPDATE = 801;
 
@@ -292,8 +290,8 @@
                             PackageManagerService.REASON_BACKGROUND_DEXOPT,
                             /* force */ false)
                     : pm.performDexOptSecondary(pkg,
-                            PackageManagerServiceCompilerMapping.getFullCompilerFilter(),
-                            /* force */ true);
+                            PackageManagerService.REASON_BACKGROUND_DEXOPT,
+                            /* force */ false);
             if (success) {
                 // Dexopt succeeded, remove package from the list of failing ones.
                 synchronized (failedPackageNames) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 42f6502..2b7e9b9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7516,6 +7516,11 @@
         return mDexManager.dexoptSecondaryDex(packageName, compilerFilter, force);
     }
 
+    public boolean performDexOptSecondary(String packageName, int compileReason,
+            boolean force) {
+        return mDexManager.dexoptSecondaryDex(packageName, compileReason, force);
+    }
+
     /**
      * Reconcile the information we have about the secondary dex files belonging to
      * {@code packagName} and the actual dex files. For all dex files that were
@@ -7738,6 +7743,7 @@
             } catch (InstallerException e) {
                 Slog.w(TAG, String.valueOf(e));
             }
+            mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
         }
     }
 
@@ -14449,6 +14455,8 @@
                 }
                 prepareAppDataAfterInstallLIF(newPackage);
                 addedPkg = true;
+                mDexManager.notifyPackageUpdated(newPackage.packageName,
+                        newPackage.baseCodePath, newPackage.splitCodePaths);
             } catch (PackageManagerException e) {
                 res.setError("Package couldn't be installed in " + pkg.codePath, e);
             }
@@ -14596,6 +14604,9 @@
 
                 updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
                 prepareAppDataAfterInstallLIF(newPackage);
+
+                mDexManager.notifyPackageUpdated(newPackage.packageName,
+                            newPackage.baseCodePath, newPackage.splitCodePaths);
             }
         } catch (PackageManagerException e) {
             res.setReturnCode(INSTALL_FAILED_INTERNAL_ERROR);
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 01124e2..a904d17 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageParser;
 import android.os.RemoteException;
 import android.os.storage.StorageManager;
+import android.os.UserHandle;
 
 import android.util.Slog;
 
@@ -179,17 +180,64 @@
         }
     }
 
-    public void notifyPackageInstalled(PackageInfo info, int userId) {
-        cachePackageCodeLocation(info, userId);
+    /**
+     * Notifies that a new package was installed for {@code userId}.
+     * {@code userId} must not be {@code UserHandle.USER_ALL}.
+     *
+     * @throws IllegalArgumentException if {@code userId} is {@code UserHandle.USER_ALL}.
+     */
+    public void notifyPackageInstalled(PackageInfo pi, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            throw new IllegalArgumentException(
+                "notifyPackageInstalled called with USER_ALL");
+        }
+        cachePackageCodeLocation(pi.packageName, pi.applicationInfo.sourceDir,
+                pi.applicationInfo.splitSourceDirs, pi.applicationInfo.dataDir, userId);
     }
 
-    private void cachePackageCodeLocation(PackageInfo info, int userId) {
-        PackageCodeLocations pcl = mPackageCodeLocationsCache.get(info.packageName);
-        if (pcl != null) {
-            pcl.mergeAppDataDirs(info.applicationInfo, userId);
-        } else {
-            mPackageCodeLocationsCache.put(info.packageName,
-                new PackageCodeLocations(info.applicationInfo, userId));
+    /**
+     * Notifies that package {@code packageName} was updated.
+     * This will clear the UsedByOtherApps mark if it exists.
+     */
+    public void notifyPackageUpdated(String packageName, String baseCodePath,
+            String[] splitCodePaths) {
+        cachePackageCodeLocation(packageName, baseCodePath, splitCodePaths, null, /*userId*/ -1);
+        // In case there was an update, write the package use info to disk async.
+        // Note that we do the writing here and not in PackageDexUsage in order to be
+        // consistent with other methods in DexManager (e.g. reconcileSecondaryDexFiles performs
+        // multiple updates in PackaeDexUsage before writing it).
+        if (mPackageDexUsage.clearUsedByOtherApps(packageName)) {
+            mPackageDexUsage.maybeWriteAsync();
+        }
+    }
+
+    /**
+     * Notifies that the user {@code userId} data for package {@code packageName}
+     * was destroyed. This will remove all usage info associated with the package
+     * for the given user.
+     * {@code userId} is allowed to be {@code UserHandle.USER_ALL} in which case
+     * all usage information for the package will be removed.
+     */
+    public void notifyPackageDataDestroyed(String packageName, int userId) {
+        boolean updated = userId == UserHandle.USER_ALL
+            ? mPackageDexUsage.removePackage(packageName)
+            : mPackageDexUsage.removeUserPackage(packageName, userId);
+        // In case there was an update, write the package use info to disk async.
+        // Note that we do the writing here and not in PackageDexUsage in order to be
+        // consistent with other methods in DexManager (e.g. reconcileSecondaryDexFiles performs
+        // multiple updates in PackaeDexUsage before writing it).
+        if (updated) {
+            mPackageDexUsage.maybeWriteAsync();
+        }
+    }
+
+    public void cachePackageCodeLocation(String packageName, String baseCodePath,
+            String[] splitCodePaths, String dataDir, int userId) {
+        PackageCodeLocations pcl = putIfAbsent(mPackageCodeLocationsCache, packageName,
+                new PackageCodeLocations(packageName, baseCodePath, splitCodePaths));
+        pcl.updateCodeLocation(baseCodePath, splitCodePaths);
+        if (dataDir != null) {
+            pcl.mergeAppDataDirs(dataDir, userId);
         }
     }
 
@@ -202,7 +250,8 @@
             int userId = entry.getKey();
             for (PackageInfo pi : packageInfoList) {
                 // Cache the code locations.
-                cachePackageCodeLocation(pi, userId);
+                cachePackageCodeLocation(pi.packageName, pi.applicationInfo.sourceDir,
+                        pi.applicationInfo.splitSourceDirs, pi.applicationInfo.dataDir, userId);
 
                 // Cache a map from package name to the set of user ids who installed the package.
                 // We will use it to sync the data and remove obsolete entries from
@@ -230,6 +279,17 @@
      * @return true if all secondary dex files were processed successfully (compiled or skipped
      *         because they don't need to be compiled)..
      */
+    public boolean dexoptSecondaryDex(String packageName, int compilerReason, boolean force) {
+        return dexoptSecondaryDex(packageName,
+                PackageManagerServiceCompilerMapping.getCompilerFilterForReason(compilerReason),
+                force);
+    }
+
+    /**
+     * Perform dexopt on the package {@code packageName} secondary dex files.
+     * @return true if all secondary dex files were processed successfully (compiled or skipped
+     *         because they don't need to be compiled)..
+     */
     public boolean dexoptSecondaryDex(String packageName, String compilerFilter, boolean force) {
         // Select the dex optimizer based on the force parameter.
         // Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust
@@ -383,7 +443,7 @@
         // Ignore framework code.
         // TODO(calin): is there a better way to detect it?
         if (dexPath.startsWith("/system/framework/")) {
-            new DexSearchResult("framework", DEX_SEARCH_NOT_FOUND);
+            return new DexSearchResult("framework", DEX_SEARCH_NOT_FOUND);
         }
 
         // First, check if the package which loads the dex file actually owns it.
@@ -425,27 +485,36 @@
      */
     private static class PackageCodeLocations {
         private final String mPackageName;
-        private final String mBaseCodePath;
+        private String mBaseCodePath;
         private final Set<String> mSplitCodePaths;
         // Maps user id to the application private directory.
         private final Map<Integer, Set<String>> mAppDataDirs;
 
         public PackageCodeLocations(ApplicationInfo ai, int userId) {
-            mPackageName = ai.packageName;
-            mBaseCodePath = ai.sourceDir;
+            this(ai.packageName, ai.sourceDir, ai.splitSourceDirs);
+            mergeAppDataDirs(ai.dataDir, userId);
+        }
+        public PackageCodeLocations(String packageName, String baseCodePath,
+                String[] splitCodePaths) {
+            mPackageName = packageName;
             mSplitCodePaths = new HashSet<>();
-            if (ai.splitSourceDirs != null) {
-                for (String split : ai.splitSourceDirs) {
+            mAppDataDirs = new HashMap<>();
+            updateCodeLocation(baseCodePath, splitCodePaths);
+        }
+
+        public void updateCodeLocation(String baseCodePath, String[] splitCodePaths) {
+            mBaseCodePath = baseCodePath;
+            mSplitCodePaths.clear();
+            if (splitCodePaths != null) {
+                for (String split : splitCodePaths) {
                     mSplitCodePaths.add(split);
                 }
             }
-            mAppDataDirs = new HashMap<>();
-            mergeAppDataDirs(ai, userId);
         }
 
-        public void mergeAppDataDirs(ApplicationInfo ai, int userId) {
+        public void mergeAppDataDirs(String dataDir, int userId) {
             Set<String> dataDirs = putIfAbsent(mAppDataDirs, userId, new HashSet<>());
-            dataDirs.add(ai.dataDir);
+            dataDirs.add(dataDir);
         }
 
         public int searchDex(String dexPath, int userId) {
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 3693bce0..8a66f12 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -377,7 +377,34 @@
     }
 
     /**
+     * Clears the {@code usesByOtherApps} marker for the package {@code packageName}.
+     * @return true if the package usage info was updated.
+     */
+    public boolean clearUsedByOtherApps(String packageName) {
+        synchronized (mPackageUseInfoMap) {
+            PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName);
+            if (packageUseInfo == null || !packageUseInfo.mIsUsedByOtherApps) {
+                return false;
+            }
+            packageUseInfo.mIsUsedByOtherApps = false;
+            return true;
+        }
+    }
+
+    /**
+     * Remove the usage data associated with package {@code packageName}.
+     * @return true if the package usage was found and removed successfully.
+     */
+    public boolean removePackage(String packageName) {
+        synchronized (mPackageUseInfoMap) {
+            return mPackageUseInfoMap.remove(packageName) != null;
+        }
+    }
+
+    /**
      * Remove all the records about package {@code packageName} belonging to user {@code userId}.
+     * If the package is left with no records of secondary dex usage and is not used by other
+     * apps it will be removed as well.
      * @return true if the record was found and actually deleted,
      *         false if the record doesn't exist
      */
@@ -397,6 +424,12 @@
                     updated = true;
                 }
             }
+            // If no secondary dex info is left and the package is not used by other apps
+            // remove the data since it is now useless.
+            if (packageUseInfo.mDexUseInfoMap.isEmpty() && !packageUseInfo.mIsUsedByOtherApps) {
+                mPackageUseInfoMap.remove(packageName);
+                updated = true;
+            }
             return updated;
         }
     }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c907cf3..1fca41c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -527,6 +527,7 @@
         VibratorService vibrator = null;
         IMountService mountService = null;
         NetworkManagementService networkManagement = null;
+        IpSecService ipSecService = null;
         NetworkStatsService networkStats = null;
         NetworkPolicyManagerService networkPolicy = null;
         ConnectivityService connectivity = null;
@@ -803,6 +804,15 @@
                     reportWtf("starting NetworkManagement Service", e);
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
+                traceBeginAndSlog("StartIpSecService");
+                try {
+                    ipSecService = IpSecService.create(context);
+                    ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
+                } catch (Throwable e) {
+                    reportWtf("starting IpSec Service", e);
+                }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNonCoreServices && !disableTextServices) {
@@ -1318,6 +1328,7 @@
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final MediaRouterService mediaRouterF = mediaRouter;
         final MmsServiceBroker mmsServiceF = mmsService;
+        final IpSecService ipSecServiceF = ipSecService;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -1368,6 +1379,13 @@
                     reportWtf("making Network Managment Service ready", e);
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeIpSecServiceReady");
+                try {
+                    if (ipSecServiceF != null) ipSecServiceF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making IpSec Service ready", e);
+                }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkStatsServiceReady");
                 try {
                     if (networkStatsF != null) networkStatsF.systemReady();
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 4addbfc..745764b 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -23,7 +23,6 @@
 import android.net.apf.ApfCapabilities;
 import android.net.apf.ApfFilter;
 import android.net.DhcpResults;
-import android.net.INetd;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -35,12 +34,10 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpManagerEvent;
 import android.net.util.MultinetworkPolicyTracker;
-import android.net.util.NetdService;
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.LocalLog;
@@ -1030,16 +1027,14 @@
 
     private boolean startIPv6() {
         // Set privacy extensions.
-        final String PREFER_TEMPADDRS = "2";
         try {
-            NetdService.run((INetd netd) -> {
-                netd.setProcSysNet(
-                        INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr",
-                        PREFER_TEMPADDRS);
-            });
+            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
             mNwService.enableIpv6(mInterfaceName);
-        } catch (IllegalStateException|RemoteException|ServiceSpecificException e) {
-            logError("Unable to change interface settings: %s", e);
+        } catch (RemoteException re) {
+            logError("Unable to change interface settings: %s", re);
+            return false;
+        } catch (IllegalStateException ie) {
+            logError("Unable to change interface settings: %s", ie);
             return false;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 90a2ec0..72fb78e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -16,9 +16,10 @@
 
 package com.android.server.pm.dex;
 
-import android.os.Build;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.os.Build;
+import android.os.UserHandle;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -57,9 +58,9 @@
 
     private int mUser0;
     private int mUser1;
+
     @Before
     public void setup() {
-
         mUser0 = 0;
         mUser1 = 1;
 
@@ -243,6 +244,122 @@
         assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0);
     }
 
+    @Test
+    public void testNotifyPackageUpdated() {
+        // Foo loads Bar main apks.
+        notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
+
+        // Bar is used by others now and should be in our records.
+        PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+        assertNotNull(pui);
+        assertTrue(pui.isUsedByOtherApps());
+        assertTrue(pui.getDexUseInfoMap().isEmpty());
+
+        // Notify that bar is updated.
+        mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(),
+                mBarUser0.mPackageInfo.applicationInfo.sourceDir,
+                mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs);
+
+        // The usedByOtherApps flag should be clear now.
+        pui = getPackageUseInfo(mBarUser0);
+        assertNotNull(pui);
+        assertFalse(pui.isUsedByOtherApps());
+    }
+
+    @Test
+    public void testNotifyPackageUpdatedCodeLocations() {
+        // Simulate a split update.
+        String newSplit = mBarUser0.replaceLastSplit();
+        List<String> newSplits = new ArrayList<>();
+        newSplits.add(newSplit);
+
+        // We shouldn't find yet the new split as we didn't notify the package update.
+        notifyDexLoad(mFooUser0, newSplits, mUser0);
+        PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+        assertNull(pui);
+
+        // Notify that bar is updated. splitSourceDirs will contain the updated path.
+        mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(),
+                mBarUser0.mPackageInfo.applicationInfo.sourceDir,
+                mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs);
+
+        // Now, when the split is loaded we will find it and we should mark Bar as usedByOthers.
+        notifyDexLoad(mFooUser0, newSplits, mUser0);
+        pui = getPackageUseInfo(mBarUser0);
+        assertNotNull(pui);
+        assertTrue(pui.isUsedByOtherApps());
+    }
+
+    @Test
+    public void testNotifyPackageDataDestroyForOne() {
+        // Bar loads its own secondary files.
+        notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0);
+        notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
+
+        mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0);
+
+        // Bar should not be around since it was removed for all users.
+        PackageUseInfo pui = getPackageUseInfo(mBarUser1);
+        assertNotNull(pui);
+        assertSecondaryUse(mBarUser1, pui, mBarUser1.getSecondaryDexPaths(),
+                /*isUsedByOtherApps*/false, mUser1);
+    }
+
+    @Test
+    public void testNotifyPackageDataDestroyForeignUse() {
+        // Foo loads its own secondary files.
+        List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+        notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
+
+        // Bar loads Foo main apks.
+        notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0);
+
+        mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
+
+        // Foo should still be around since it's used by other apps but with no
+        // secondary dex info.
+        PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+        assertNotNull(pui);
+        assertTrue(pui.isUsedByOtherApps());
+        assertTrue(pui.getDexUseInfoMap().isEmpty());
+    }
+
+    @Test
+    public void testNotifyPackageDataDestroyComplete() {
+        // Foo loads its own secondary files.
+        List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
+        notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
+
+        mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
+
+        // Foo should not be around since all its secondary dex info were deleted
+        // and it is not used by other apps.
+        PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+        assertNull(pui);
+    }
+
+    @Test
+    public void testNotifyPackageDataDestroyForAll() {
+        // Foo loads its own secondary files.
+        notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0);
+        notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
+
+        mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL);
+
+        // Bar should not be around since it was removed for all users.
+        PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+        assertNull(pui);
+    }
+
+    @Test
+    public void testNotifyFrameworkLoad() {
+        String frameworkDex = "/system/framework/com.android.location.provider.jar";
+        // Load a dex file from framework.
+        notifyDexLoad(mFooUser0, Arrays.asList(frameworkDex), mUser0);
+        // The dex file should not be recognized as a package.
+        assertNull(mDexManager.getPackageUseInfo(frameworkDex));
+    }
+
     private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
             List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) {
         for (String dex : secondaries) {
@@ -317,5 +434,12 @@
             }
             return paths;
         }
+
+        String replaceLastSplit() {
+            int length = mPackageInfo.applicationInfo.splitSourceDirs.length;
+            // Add an extra bogus dex extension to simulate a new split name.
+            mPackageInfo.applicationInfo.splitSourceDirs[length - 1] += ".dex";
+            return mPackageInfo.applicationInfo.splitSourceDirs[length - 1];
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
index 19e0bcf..2e99433 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -257,6 +257,30 @@
     }
 
     @Test
+    public void testRemovePackage() {
+        // Record Bar secondaries for two different users.
+        assertTrue(record(mBarSecondary1User0));
+        assertTrue(record(mBarSecondary2User1));
+
+        // Remove the package.
+        assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
+        // Assert that we can't find the package anymore.
+        assertNull(mPackageDexUsage.getPackageUseInfo(mBarSecondary1User0.mPackageName));
+    }
+
+    @Test
+    public void testRemoveNonexistentPackage() {
+        // Record Bar secondaries for two different users.
+        assertTrue(record(mBarSecondary1User0));
+
+        // Remove the package.
+        assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
+        // Remove the package again. It should return false because the package no longer
+        // has a record in the use info.
+        assertFalse(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
+    }
+
+    @Test
     public void testRemoveUserPackage() {
         // Record Bar secondaries for two different users.
         assertTrue(record(mBarSecondary1User0));
@@ -282,6 +306,32 @@
         assertPackageDexUsage(null, mBarSecondary2User1);
     }
 
+    @Test
+    public void testClearUsedByOtherApps() {
+        // Write a package which is used by other apps.
+        assertTrue(record(mFooSplit2UsedByOtherApps0));
+        assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
+
+        // Check that the package is no longer used by other apps.
+        TestData noLongerUsedByOtherApps = new TestData(
+            mFooSplit2UsedByOtherApps0.mPackageName,
+            mFooSplit2UsedByOtherApps0.mDexFile,
+            mFooSplit2UsedByOtherApps0.mOwnerUserId,
+            mFooSplit2UsedByOtherApps0.mLoaderIsa,
+            /*mIsUsedByOtherApps*/false,
+            mFooSplit2UsedByOtherApps0.mPrimaryOrSplit);
+        assertPackageDexUsage(noLongerUsedByOtherApps);
+    }
+
+    @Test
+    public void testClearUsedByOtherAppsNonexistent() {
+        // Write a package which is used by other apps.
+        assertTrue(record(mFooSplit2UsedByOtherApps0));
+        assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
+        // Clearing again should return false as there should be no update on the use info.
+        assertFalse(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
+    }
+
     private void assertPackageDexUsage(TestData primary, TestData... secondaries) {
         String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName;
         boolean primaryUsedByOtherApps = primary == null ? false : primary.mUsedByOtherApps;
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 39da224..de5cafb 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -570,8 +570,11 @@
                 // Set the new USB configuration.
                 setUsbConfig(functions);
 
-                // Start up dependent services.
-                updateUsbStateBroadcastIfNeeded(true);
+                if (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
+                        || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP)) {
+                    // Start up dependent services.
+                    updateUsbStateBroadcastIfNeeded(true);
+                }
 
                 if (!waitForState(functions)) {
                     Slog.e(TAG, "Failed to switch USB config to " + functions);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 80333a4..264869e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1166,6 +1166,13 @@
     public static final String KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY =
             "boosted_lte_earfcns_string_array";
 
+    /**
+     * Key identifying if voice call barring notification is required to be shown to the user.
+     * @hide
+     */
+    public static final String KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL =
+            "disable_voice_barring_notification_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -1376,6 +1383,7 @@
         sDefaults.putBoolean(KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL, false);
         sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
         sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/com/android/ims/ImsException.java b/telephony/java/com/android/ims/ImsException.java
index 74b20f4..0e8bad7 100644
--- a/telephony/java/com/android/ims/ImsException.java
+++ b/telephony/java/com/android/ims/ImsException.java
@@ -32,7 +32,7 @@
     }
 
     public ImsException(String message, int code) {
-        super(message + ", code = " + code);
+        super(message + "(" + code + ")");
         mCode = code;
     }
 
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index b51b277..efe6fec 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -27,10 +27,12 @@
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.UidRange;
+import android.os.Build;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -45,6 +47,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.mockito.Answers;
 import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
@@ -87,12 +90,13 @@
         }
     }
 
-    @Mock private Context mContext;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
     @Mock private UserManager mUserManager;
     @Mock private PackageManager mPackageManager;
     @Mock private INetworkManagementService mNetService;
     @Mock private AppOpsManager mAppOps;
     @Mock private NotificationManager mNotificationManager;
+    @Mock private Vpn.SystemServices mSystemServices;
 
     @Override
     public void setUp() throws Exception {
@@ -104,6 +108,12 @@
         when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
         when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
                 .thenReturn(mNotificationManager);
+
+        // Used by {@link Notification.Builder}
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+        when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
+
         doNothing().when(mNetService).registerObserver(any());
     }
 
@@ -111,7 +121,7 @@
     public void testRestrictedProfilesAreAddedToVpn() {
         setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
 
-        final Vpn vpn = spyVpn(primaryUser.id);
+        final Vpn vpn = createVpn(primaryUser.id);
         final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
                 null, null);
 
@@ -125,7 +135,7 @@
     public void testManagedProfilesAreNotAddedToVpn() {
         setMockedUsers(primaryUser, managedProfileA);
 
-        final Vpn vpn = spyVpn(primaryUser.id);
+        final Vpn vpn = createVpn(primaryUser.id);
         final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
                 null, null);
 
@@ -138,7 +148,7 @@
     public void testAddUserToVpnOnlyAddsOneUser() {
         setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
 
-        final Vpn vpn = spyVpn(primaryUser.id);
+        final Vpn vpn = createVpn(primaryUser.id);
         final Set<UidRange> ranges = new ArraySet<>();
         vpn.addUserToRanges(ranges, primaryUser.id, null, null);
 
@@ -149,7 +159,7 @@
 
     @SmallTest
     public void testUidWhiteAndBlacklist() throws Exception {
-        final Vpn vpn = spyVpn(primaryUser.id);
+        final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = UidRange.createForUser(primaryUser.id);
         final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
 
@@ -174,7 +184,7 @@
 
     @SmallTest
     public void testLockdownChangingPackage() throws Exception {
-        final Vpn vpn = spyVpn(primaryUser.id);
+        final Vpn vpn = createVpn(primaryUser.id);
         final UidRange user = UidRange.createForUser(primaryUser.id);
 
         // Default state.
@@ -209,7 +219,7 @@
 
     @SmallTest
     public void testLockdownAddingAProfile() throws Exception {
-        final Vpn vpn = spyVpn(primaryUser.id);
+        final Vpn vpn = createVpn(primaryUser.id);
         setMockedUsers(primaryUser);
 
         // Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
@@ -249,40 +259,41 @@
 
     @SmallTest
     public void testNotificationShownForAlwaysOnApp() {
-        final Vpn vpn = spyVpn(primaryUser.id);
-        final InOrder order = inOrder(vpn);
+        final UserHandle userHandle = UserHandle.of(primaryUser.id);
+        final Vpn vpn = createVpn(primaryUser.id);
         setMockedUsers(primaryUser);
 
+        final InOrder order = inOrder(mNotificationManager);
+
         // Don't show a notification for regular disconnected states.
         vpn.updateState(DetailedState.DISCONNECTED, TAG);
-        order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+        order.verify(mNotificationManager, atLeastOnce())
+                .cancelAsUser(anyString(), anyInt(), eq(userHandle));
 
         // Start showing a notification for disconnected once always-on.
         vpn.setAlwaysOnPackage(PKGS[0], false);
-        order.verify(vpn).updateAlwaysOnNotificationInternal(true);
+        order.verify(mNotificationManager)
+                .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
 
         // Stop showing the notification once connected.
         vpn.updateState(DetailedState.CONNECTED, TAG);
-        order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+        order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
 
         // Show the notification if we disconnect again.
         vpn.updateState(DetailedState.DISCONNECTED, TAG);
-        order.verify(vpn).updateAlwaysOnNotificationInternal(true);
+        order.verify(mNotificationManager)
+                .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
 
         // Notification should be cleared after unsetting always-on package.
         vpn.setAlwaysOnPackage(null, false);
-        order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+        order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
     }
 
     /**
      * Mock some methods of vpn object.
      */
-    private Vpn spyVpn(@UserIdInt int userId) {
-        final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId));
-
-        // Block calls to the NotificationManager or PendingIntent#getActivity.
-        doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean());
-        return vpn;
+    private Vpn createVpn(@UserIdInt int userId) {
+        return new Vpn(Looper.myLooper(), mContext, mNetService, userId, mSystemServices);
     }
 
     private static void assertBlocked(Vpn vpn, int... uids) {
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 5847f79..40e34b1 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -934,46 +934,13 @@
 
         /** Implement the Parcelable interface {@hide} */
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(rssiSampleSize);
-            dest.writeInt(lostApSampleSize);
-            dest.writeInt(unchangedSampleSize);
-            dest.writeInt(minApsBreachingThreshold);
-            dest.writeInt(periodInMs);
-            if (bssidInfos != null) {
-                dest.writeInt(bssidInfos.length);
-                for (int i = 0; i < bssidInfos.length; i++) {
-                    BssidInfo info = bssidInfos[i];
-                    dest.writeString(info.bssid);
-                    dest.writeInt(info.low);
-                    dest.writeInt(info.high);
-                    dest.writeInt(info.frequencyHint);
-                }
-            } else {
-                dest.writeInt(0);
-            }
         }
 
         /** Implement the Parcelable interface {@hide} */
         public static final Creator<WifiChangeSettings> CREATOR =
                 new Creator<WifiChangeSettings>() {
                     public WifiChangeSettings createFromParcel(Parcel in) {
-                        WifiChangeSettings settings = new WifiChangeSettings();
-                        settings.rssiSampleSize = in.readInt();
-                        settings.lostApSampleSize = in.readInt();
-                        settings.unchangedSampleSize = in.readInt();
-                        settings.minApsBreachingThreshold = in.readInt();
-                        settings.periodInMs = in.readInt();
-                        int len = in.readInt();
-                        settings.bssidInfos = new BssidInfo[len];
-                        for (int i = 0; i < len; i++) {
-                            BssidInfo info = new BssidInfo();
-                            info.bssid = in.readString();
-                            info.low = in.readInt();
-                            info.high = in.readInt();
-                            info.frequencyHint = in.readInt();
-                            settings.bssidInfos[i] = info;
-                        }
-                        return settings;
+                        return new WifiChangeSettings();
                     }
 
                     public WifiChangeSettings[] newArray(int size) {
@@ -998,20 +965,10 @@
             int unchangedSampleSize,                        /* samples to confirm no change */
             int minApsBreachingThreshold,                   /* change threshold to trigger event */
             int periodInMs,                                 /* period of scan */
-            BssidInfo[] bssidInfos                          /* signal thresholds to crosss */
+            BssidInfo[] bssidInfos                          /* signal thresholds to cross */
             )
     {
-        validateChannel();
-
-        WifiChangeSettings settings = new WifiChangeSettings();
-        settings.rssiSampleSize = rssiSampleSize;
-        settings.lostApSampleSize = lostApSampleSize;
-        settings.unchangedSampleSize = unchangedSampleSize;
-        settings.minApsBreachingThreshold = minApsBreachingThreshold;
-        settings.periodInMs = periodInMs;
-        settings.bssidInfos = bssidInfos;
-
-        configureWifiChange(settings);
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -1034,11 +991,7 @@
      *                 provided on {@link #stopTrackingWifiChange}
      */
     public void startTrackingWifiChange(WifiChangeListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        int key = addListener(listener);
-        if (key == INVALID_KEY) return;
-        validateChannel();
-        mAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -1047,17 +1000,13 @@
      * #stopTrackingWifiChange}
      */
     public void stopTrackingWifiChange(WifiChangeListener listener) {
-        int key = removeListener(listener);
-        if (key == INVALID_KEY) return;
-        validateChannel();
-        mAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
+        throw new UnsupportedOperationException();
     }
 
     /** @hide */
     @SystemApi
     public void configureWifiChange(WifiChangeSettings settings) {
-        validateChannel();
-        mAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+        throw new UnsupportedOperationException();
     }
 
     /** interface to receive hotlist events on; use this on {@link #setHotlist} */
@@ -1085,20 +1034,6 @@
 
         /** Implement the Parcelable interface {@hide} */
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(apLostThreshold);
-
-            if (bssidInfos != null) {
-                dest.writeInt(bssidInfos.length);
-                for (int i = 0; i < bssidInfos.length; i++) {
-                    BssidInfo info = bssidInfos[i];
-                    dest.writeString(info.bssid);
-                    dest.writeInt(info.low);
-                    dest.writeInt(info.high);
-                    dest.writeInt(info.frequencyHint);
-                }
-            } else {
-                dest.writeInt(0);
-            }
         }
 
         /** Implement the Parcelable interface {@hide} */
@@ -1106,17 +1041,6 @@
                 new Creator<HotlistSettings>() {
                     public HotlistSettings createFromParcel(Parcel in) {
                         HotlistSettings settings = new HotlistSettings();
-                        settings.apLostThreshold = in.readInt();
-                        int n = in.readInt();
-                        settings.bssidInfos = new BssidInfo[n];
-                        for (int i = 0; i < n; i++) {
-                            BssidInfo info = new BssidInfo();
-                            info.bssid = in.readString();
-                            info.low = in.readInt();
-                            info.high = in.readInt();
-                            info.frequencyHint = in.readInt();
-                            settings.bssidInfos[i] = info;
-                        }
                         return settings;
                     }
 
@@ -1135,14 +1059,7 @@
      */
     public void startTrackingBssids(BssidInfo[] bssidInfos,
                                     int apLostThreshold, BssidListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        int key = addListener(listener);
-        if (key == INVALID_KEY) return;
-        validateChannel();
-        HotlistSettings settings = new HotlistSettings();
-        settings.bssidInfos = bssidInfos;
-        settings.apLostThreshold = apLostThreshold;
-        mAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -1150,11 +1067,7 @@
      * @param listener same object provided in {@link #startTrackingBssids}
      */
     public void stopTrackingBssids(BssidListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        int key = removeListener(listener);
-        if (key == INVALID_KEY) return;
-        validateChannel();
-        mAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
+        throw new UnsupportedOperationException();
     }
 
 
@@ -1177,20 +1090,10 @@
     /** @hide */
     public static final int CMD_SCAN_RESULT                 = BASE + 5;
     /** @hide */
-    public static final int CMD_SET_HOTLIST                 = BASE + 6;
-    /** @hide */
-    public static final int CMD_RESET_HOTLIST               = BASE + 7;
-    /** @hide */
     public static final int CMD_AP_FOUND                    = BASE + 9;
     /** @hide */
     public static final int CMD_AP_LOST                     = BASE + 10;
     /** @hide */
-    public static final int CMD_START_TRACKING_CHANGE       = BASE + 11;
-    /** @hide */
-    public static final int CMD_STOP_TRACKING_CHANGE        = BASE + 12;
-    /** @hide */
-    public static final int CMD_CONFIGURE_WIFI_CHANGE       = BASE + 13;
-    /** @hide */
     public static final int CMD_WIFI_CHANGE_DETECTED        = BASE + 15;
     /** @hide */
     public static final int CMD_WIFI_CHANGES_STABILIZED     = BASE + 16;
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index 9645b1d..334205b 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -85,7 +85,7 @@
     /**
      * Called when a discovery session (publish or subscribe) terminates. Termination may be due
      * to user-request (either directly through {@link DiscoverySession#destroy()} or
-     * application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
+     * application-specified expiration, e.g. {@link PublishConfig.Builder#setTtlSec(int)}
      * or {@link SubscribeConfig.Builder#setTtlSec(int)}).
      */
     public void onSessionTerminated() {
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index a996844..1ce12f3 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -75,9 +75,6 @@
     public final int mPublishType;
 
     /** @hide */
-    public final int mPublishCount;
-
-    /** @hide */
     public final int mTtlSec;
 
     /** @hide */
@@ -85,12 +82,11 @@
 
     /** @hide */
     public PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
-            int publishType, int publichCount, int ttlSec, boolean enableTerminateNotification) {
+            int publishType, int ttlSec, boolean enableTerminateNotification) {
         mServiceName = serviceName;
         mServiceSpecificInfo = serviceSpecificInfo;
         mMatchFilter = matchFilter;
         mPublishType = publishType;
-        mPublishCount = publichCount;
         mTtlSec = ttlSec;
         mEnableTerminateNotification = enableTerminateNotification;
     }
@@ -100,8 +96,8 @@
         return "PublishConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + (
                 (mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
                 + ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1,
-                mMatchFilter)).toString() + ", mPublishType=" + mPublishType + ", mPublishCount="
-                + mPublishCount + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification="
+                mMatchFilter)).toString() + ", mPublishType=" + mPublishType
+                + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification="
                 + mEnableTerminateNotification + "]";
     }
 
@@ -116,7 +112,6 @@
         dest.writeByteArray(mServiceSpecificInfo);
         dest.writeByteArray(mMatchFilter);
         dest.writeInt(mPublishType);
-        dest.writeInt(mPublishCount);
         dest.writeInt(mTtlSec);
         dest.writeInt(mEnableTerminateNotification ? 1 : 0);
     }
@@ -133,11 +128,10 @@
             byte[] ssi = in.createByteArray();
             byte[] matchFilter = in.createByteArray();
             int publishType = in.readInt();
-            int publishCount = in.readInt();
             int ttlSec = in.readInt();
             boolean enableTerminateNotification = in.readInt() != 0;
 
-            return new PublishConfig(serviceName, ssi, matchFilter, publishType, publishCount,
+            return new PublishConfig(serviceName, ssi, matchFilter, publishType,
                     ttlSec, enableTerminateNotification);
         }
     };
@@ -156,7 +150,7 @@
 
         return Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals(mServiceSpecificInfo,
                 lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter)
-                && mPublishType == lhs.mPublishType && mPublishCount == lhs.mPublishCount
+                && mPublishType == lhs.mPublishType
                 && mTtlSec == lhs.mTtlSec
                 && mEnableTerminateNotification == lhs.mEnableTerminateNotification;
     }
@@ -169,7 +163,6 @@
         result = 31 * result + Arrays.hashCode(mServiceSpecificInfo);
         result = 31 * result + Arrays.hashCode(mMatchFilter);
         result = 31 * result + mPublishType;
-        result = 31 * result + mPublishCount;
         result = 31 * result + mTtlSec;
         result = 31 * result + (mEnableTerminateNotification ? 1 : 0);
 
@@ -193,9 +186,6 @@
         if (mPublishType < PUBLISH_TYPE_UNSOLICITED || mPublishType > PUBLISH_TYPE_SOLICITED) {
             throw new IllegalArgumentException("Invalid publishType - " + mPublishType);
         }
-        if (mPublishCount < 0) {
-            throw new IllegalArgumentException("Invalid publishCount - must be non-negative");
-        }
         if (mTtlSec < 0) {
             throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
         }
@@ -229,7 +219,6 @@
         private byte[] mServiceSpecificInfo;
         private byte[] mMatchFilter;
         private int mPublishType = PUBLISH_TYPE_UNSOLICITED;
-        private int mPublishCount = 0;
         private int mTtlSec = 0;
         private boolean mEnableTerminateNotification = true;
 
@@ -317,30 +306,6 @@
         }
 
         /**
-         * Sets the number of times an unsolicited (configured using
-         * {@link PublishConfig.Builder#setPublishType(int)}) publish session
-         * will be broadcast. When the count is reached an event will be
-         * generated for {@link DiscoverySessionCallback#onSessionTerminated()}
-         * [unless {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
-         * <p>
-         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link DiscoverySession#destroy()} is
-         *     called.
-         *
-         * @param publishCount Number of publish packets to broadcast.
-         *
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setPublishCount(int publishCount) {
-            if (publishCount < 0) {
-                throw new IllegalArgumentException("Invalid publishCount - must be non-negative");
-            }
-            mPublishCount = publishCount;
-            return this;
-        }
-
-        /**
          * Sets the time interval (in seconds) an unsolicited (
          * {@link PublishConfig.Builder#setPublishType(int)}) publish session
          * will be alive - broadcasting a packet. When the TTL is reached
@@ -387,7 +352,7 @@
          */
         public PublishConfig build() {
             return new PublishConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, mPublishType,
-                    mPublishCount, mTtlSec, mEnableTerminateNotification);
+                    mTtlSec, mEnableTerminateNotification);
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index 3397c4b..97a6a3f 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -94,9 +94,6 @@
     public final int mSubscribeType;
 
     /** @hide */
-    public final int mSubscribeCount;
-
-    /** @hide */
     public final int mTtlSec;
 
     /** @hide */
@@ -107,13 +104,12 @@
 
     /** @hide */
     public SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
-            int subscribeType, int publichCount, int ttlSec, int matchStyle,
+            int subscribeType, int ttlSec, int matchStyle,
             boolean enableTerminateNotification) {
         mServiceName = serviceName;
         mServiceSpecificInfo = serviceSpecificInfo;
         mMatchFilter = matchFilter;
         mSubscribeType = subscribeType;
-        mSubscribeCount = publichCount;
         mTtlSec = ttlSec;
         mMatchStyle = matchStyle;
         mEnableTerminateNotification = enableTerminateNotification;
@@ -125,7 +121,7 @@
                 (mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
                 + ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1,
                 mMatchFilter)).toString() + ", mSubscribeType=" + mSubscribeType
-                + ", mSubscribeCount=" + mSubscribeCount + ", mTtlSec=" + mTtlSec + ", mMatchType="
+                + ", mTtlSec=" + mTtlSec + ", mMatchType="
                 + mMatchStyle + ", mEnableTerminateNotification=" + mEnableTerminateNotification
                 + "]";
     }
@@ -141,7 +137,6 @@
         dest.writeByteArray(mServiceSpecificInfo);
         dest.writeByteArray(mMatchFilter);
         dest.writeInt(mSubscribeType);
-        dest.writeInt(mSubscribeCount);
         dest.writeInt(mTtlSec);
         dest.writeInt(mMatchStyle);
         dest.writeInt(mEnableTerminateNotification ? 1 : 0);
@@ -159,12 +154,11 @@
             byte[] ssi = in.createByteArray();
             byte[] matchFilter = in.createByteArray();
             int subscribeType = in.readInt();
-            int subscribeCount = in.readInt();
             int ttlSec = in.readInt();
             int matchStyle = in.readInt();
             boolean enableTerminateNotification = in.readInt() != 0;
 
-            return new SubscribeConfig(serviceName, ssi, matchFilter, subscribeType, subscribeCount,
+            return new SubscribeConfig(serviceName, ssi, matchFilter, subscribeType,
                     ttlSec, matchStyle, enableTerminateNotification);
         }
     };
@@ -183,7 +177,7 @@
 
         return Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals(mServiceSpecificInfo,
                 lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter)
-                && mSubscribeType == lhs.mSubscribeType && mSubscribeCount == lhs.mSubscribeCount
+                && mSubscribeType == lhs.mSubscribeType
                 && mTtlSec == lhs.mTtlSec && mMatchStyle == lhs.mMatchStyle
                 && mEnableTerminateNotification == lhs.mEnableTerminateNotification;
     }
@@ -196,7 +190,6 @@
         result = 31 * result + Arrays.hashCode(mServiceSpecificInfo);
         result = 31 * result + Arrays.hashCode(mMatchFilter);
         result = 31 * result + mSubscribeType;
-        result = 31 * result + mSubscribeCount;
         result = 31 * result + mTtlSec;
         result = 31 * result + mMatchStyle;
         result = 31 * result + (mEnableTerminateNotification ? 1 : 0);
@@ -221,9 +214,6 @@
         if (mSubscribeType < SUBSCRIBE_TYPE_PASSIVE || mSubscribeType > SUBSCRIBE_TYPE_ACTIVE) {
             throw new IllegalArgumentException("Invalid subscribeType - " + mSubscribeType);
         }
-        if (mSubscribeCount < 0) {
-            throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative");
-        }
         if (mTtlSec < 0) {
             throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
         }
@@ -261,7 +251,6 @@
         private byte[] mServiceSpecificInfo;
         private byte[] mMatchFilter;
         private int mSubscribeType = SUBSCRIBE_TYPE_PASSIVE;
-        private int mSubscribeCount = 0;
         private int mTtlSec = 0;
         private int mMatchStyle = MATCH_STYLE_ALL;
         private boolean mEnableTerminateNotification = true;
@@ -350,29 +339,6 @@
         }
 
         /**
-         * Sets the number of times an active (
-         * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
-         * will broadcast. When the count is reached an event will be
-         * generated for {@link DiscoverySessionCallback#onSessionTerminated()}.
-         * <p>
-         *     Optional. 0 by default - indicating the session doesn't terminate on its own.
-         *     Session will be terminated when {@link DiscoverySession#destroy()} is
-         *     called.
-         *
-         * @param subscribeCount Number of subscribe packets to broadcast.
-         *
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setSubscribeCount(int subscribeCount) {
-            if (subscribeCount < 0) {
-                throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative");
-            }
-            mSubscribeCount = subscribeCount;
-            return this;
-        }
-
-        /**
          * Sets the time interval (in seconds) an active (
          * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
          * will be alive - i.e. broadcasting a packet. When the TTL is reached
@@ -440,7 +406,7 @@
          */
         public SubscribeConfig build() {
             return new SubscribeConfig(mServiceName, mServiceSpecificInfo, mMatchFilter,
-                    mSubscribeType, mSubscribeCount, mTtlSec, mMatchStyle,
+                    mSubscribeType, mTtlSec, mMatchStyle,
                     mEnableTerminateNotification);
         }
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index a829eb9..e542789 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -16,20 +16,12 @@
 
 package android.net.wifi;
 
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.validateMockitoUsage;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.net.wifi.WifiScanner.BssidInfo;
-import android.net.wifi.WifiScanner.BssidListener;
 import android.os.Handler;
-import android.os.Message;
 import android.os.test.TestLooper;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -37,11 +29,10 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+
 /**
  * Unit tests for {@link android.net.wifi.WifiScanner}.
  */
@@ -51,8 +42,6 @@
     private Context mContext;
     @Mock
     private IWifiScanner mService;
-    @Mock
-    private BssidListener mBssidListener;
 
     private WifiScanner mWifiScanner;
     private TestLooper mLooper;
@@ -81,31 +70,4 @@
         validateMockitoUsage();
     }
 
-    private void verifySetHotlistMessage(Handler handler) {
-        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
-        verify(handler, atLeastOnce()).handleMessage(messageCaptor.capture());
-        assertEquals("message.what is not CMD_SET_HOTLIST",
-                WifiScanner.CMD_SET_HOTLIST,
-                messageCaptor.getValue().what);
-    }
-
-    /**
-     * Test duplicate listeners for bssid tracking.
-     */
-    @Test
-    public void testStartTrackingBssidsDuplicateListeners() throws Exception {
-        BssidInfo[] bssids = new BssidInfo[] {
-                new BssidInfo()
-        };
-
-        // First start tracking succeeds.
-        mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener);
-        mLooper.dispatchAll();
-        verifySetHotlistMessage(mHandler);
-
-        // Second start tracking should fail.
-        mWifiScanner.startTrackingBssids(bssids, -100, mBssidListener);
-        mLooper.dispatchAll();
-        verify(mBssidListener).onFailure(eq(WifiScanner.REASON_DUPLICATE_REQEUST), anyString());
-    }
 }
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index eceb365..830db22 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -18,11 +18,10 @@
 
 import static org.hamcrest.core.IsEqual.equalTo;
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -140,8 +139,8 @@
 
         // (1) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(binder.capture(), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(binder.capture(), any(),
+                clientProxyCallback.capture(), isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -150,8 +149,7 @@
         // (2) publish - should succeed
         PublishConfig publishConfig = new PublishConfig.Builder().build();
         session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
-                any(IWifiAwareDiscoverySessionCallback.class));
+        inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig), any());
 
         // (3) disconnect
         session.destroy();
@@ -163,8 +161,8 @@
 
         // (5) connect
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(binder.capture(), anyString(),
-                any(IWifiAwareEventCallback.class), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(binder.capture(), any(), any(), isNull(),
+                eq(false));
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
     }
@@ -185,16 +183,16 @@
 
         // (1) connect + failure
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                isNull(), eq(false));
         clientProxyCallback.getValue().onConnectFail(reason);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttachFailed();
 
         // (2) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -203,8 +201,7 @@
         // (4) subscribe: should succeed
         SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
         session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
-                any(IWifiAwareDiscoverySessionCallback.class));
+        inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig), any());
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
     }
@@ -223,19 +220,19 @@
 
         // (1) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
-        inOrder.verify(mockCallback).onAttached(any(WifiAwareSession.class));
+        inOrder.verify(mockCallback).onAttached(any());
 
         // (2) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), (ConfigRequest) isNull(), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId + 1);
         mMockLooper.dispatchAll();
-        inOrder.verify(mockCallback).onAttached(any(WifiAwareSession.class));
+        inOrder.verify(mockCallback).onAttached(any());
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
     }
@@ -278,8 +275,8 @@
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -370,8 +367,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -426,8 +423,8 @@
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -507,8 +504,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -691,7 +688,6 @@
         collector.checkThat("mServiceName", subscribeConfig.mServiceName, equalTo(null));
         collector.checkThat("mSubscribeType", subscribeConfig.mSubscribeType,
                 equalTo(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE));
-        collector.checkThat("mSubscribeCount", subscribeConfig.mSubscribeCount, equalTo(0));
         collector.checkThat("mTtlSec", subscribeConfig.mTtlSec, equalTo(0));
         collector.checkThat("mMatchStyle", subscribeConfig.mMatchStyle,
                 equalTo(SubscribeConfig.MATCH_STYLE_ALL));
@@ -714,7 +710,7 @@
                 .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
                         new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
                 .setSubscribeType(subscribeType)
-                .setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
+                .setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
                 .setTerminateNotificationEnabled(enableTerminateNotification).build();
 
         collector.checkThat("mServiceName", serviceName.getBytes(),
@@ -724,8 +720,6 @@
         collector.checkThat("mMatchFilter", matchFilter, equalTo(subscribeConfig.mMatchFilter));
         collector.checkThat("mSubscribeType", subscribeType,
                 equalTo(subscribeConfig.mSubscribeType));
-        collector.checkThat("mSubscribeCount", subscribeCount,
-                equalTo(subscribeConfig.mSubscribeCount));
         collector.checkThat("mTtlSec", subscribeTtl, equalTo(subscribeConfig.mTtlSec));
         collector.checkThat("mMatchStyle", matchStyle, equalTo(subscribeConfig.mMatchStyle));
         collector.checkThat("mEnableTerminateNotification", enableTerminateNotification,
@@ -747,7 +741,7 @@
                 .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
                         new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
                 .setSubscribeType(subscribeType)
-                .setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
+                .setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
                 .setTerminateNotificationEnabled(enableTerminateNotification).build();
 
         Parcel parcelW = Parcel.obtain();
@@ -769,11 +763,6 @@
     }
 
     @Test(expected = IllegalArgumentException.class)
-    public void testSubscribeConfigBuilderNegativeCount() {
-        new SubscribeConfig.Builder().setSubscribeCount(-1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
     public void testSubscribeConfigBuilderNegativeTtl() {
         new SubscribeConfig.Builder().setTtlSec(-100);
     }
@@ -797,7 +786,6 @@
         collector.checkThat("mServiceName", publishConfig.mServiceName, equalTo(null));
         collector.checkThat("mPublishType", publishConfig.mPublishType,
                 equalTo(PublishConfig.PUBLISH_TYPE_UNSOLICITED));
-        collector.checkThat("mPublishCount", publishConfig.mPublishCount, equalTo(0));
         collector.checkThat("mTtlSec", publishConfig.mTtlSec, equalTo(0));
         collector.checkThat("mEnableTerminateNotification",
                 publishConfig.mEnableTerminateNotification, equalTo(true));
@@ -817,7 +805,7 @@
                 .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
                         new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
                 .setPublishType(publishType)
-                .setPublishCount(publishCount).setTtlSec(publishTtl)
+                .setTtlSec(publishTtl)
                 .setTerminateNotificationEnabled(enableTerminateNotification).build();
 
         collector.checkThat("mServiceName", serviceName.getBytes(),
@@ -826,7 +814,6 @@
                 serviceSpecificInfo.getBytes(), equalTo(publishConfig.mServiceSpecificInfo));
         collector.checkThat("mMatchFilter", matchFilter, equalTo(publishConfig.mMatchFilter));
         collector.checkThat("mPublishType", publishType, equalTo(publishConfig.mPublishType));
-        collector.checkThat("mPublishCount", publishCount, equalTo(publishConfig.mPublishCount));
         collector.checkThat("mTtlSec", publishTtl, equalTo(publishConfig.mTtlSec));
         collector.checkThat("mEnableTerminateNotification", enableTerminateNotification,
                 equalTo(publishConfig.mEnableTerminateNotification));
@@ -846,7 +833,7 @@
                 .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
                         new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
                 .setPublishType(publishType)
-                .setPublishCount(publishCount).setTtlSec(publishTtl)
+                .setTtlSec(publishTtl)
                 .setTerminateNotificationEnabled(enableTerminateNotification).build();
 
         Parcel parcelW = Parcel.obtain();
@@ -868,11 +855,6 @@
     }
 
     @Test(expected = IllegalArgumentException.class)
-    public void testPublishConfigBuilderNegativeCount() {
-        new PublishConfig.Builder().setPublishCount(-4);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
     public void testPublishConfigBuilderNegativeTtl() {
         new PublishConfig.Builder().setTtlSec(-10);
     }
@@ -899,8 +881,7 @@
         final RttManager.RttResult rttResults = new RttManager.RttResult();
         rttResults.distance = 10;
 
-        when(mockAwareService.startRanging(anyInt(), anyInt(),
-                any(RttManager.ParcelableRttParams.class))).thenReturn(rangingId);
+        when(mockAwareService.startRanging(anyInt(), anyInt(), any())).thenReturn(rangingId);
 
         InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
                 mockPublishSession, mockRttListener);
@@ -919,8 +900,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -994,8 +975,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
@@ -1085,8 +1066,8 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(IBinder.class), anyString(),
-                clientProxyCallback.capture(), eq(configRequest), eq(false));
+        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+                eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
         inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());