Merge changes from topic 'framework-net-aosp'

* changes:
  DO NOT MERGE: [CS] Remove timeout event after first available
  DO NOT MERGE: ApfTest: tag tests with @SmallTest or @MediumTest
  DO NOT MERGE: Unbreak TetherInterfaceStateMachineTest.
  DO NOT MERGE: Move the connectivity tests to frameworks/base/tests/net.
  DO NOT MERGE: De-guava BroadcastInterceptingContext and move it to testutils.
  DO NOT MERGE: Move FakeSettingsProvider to a common location.
  DO NOT MERGE: ConnectivityServiceTest: mark flaky test as such
  DO NOT MERGE: Add option to skip and avoid captive portals.
  DO NOT MERGE: ApfFilter: use elapsedRealTime for RA lifetime
  DO NOT MERGE: Do not synchronize boolean reads/writes
  DO NOT MERGE: ApfFilter: systematically use u8, u16, u32 getters
  DO NOT MERGE: Add fuzzing tests to ApfFilter RA processing
  DO NOT MERGE: Support timeouts for requestNetwork() invocations.
  DO NOT MERGE: Silence the obnoxious MTU 0 error message that occur when no MTU is specified for a given network.
diff --git a/cmds/uiautomator/library/Android.mk b/cmds/uiautomator/library/Android.mk
index d65b0833..af2e25a 100644
--- a/cmds/uiautomator/library/Android.mk
+++ b/cmds/uiautomator/library/Android.mk
@@ -18,7 +18,7 @@
 
 uiautomator.core_src_files := $(call all-java-files-under, core-src) \
 	$(call all-java-files-under, testrunner-src)
-uiautomator.core_java_libraries := android.test.runner core-junit
+uiautomator.core_java_libraries := android.test.runner junit
 
 uiautomator_internal_api_file := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/uiautomator_api.txt
 uiautomator_internal_removed_api_file := \
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 59cbf6e..542a0a7 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -56,17 +56,26 @@
     void disableScoring();
 
     /**
-     * Register a network subsystem for scoring.
+     * Register a cache to receive scoring updates.
      *
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
      * @throws SecurityException if the caller is not the system.
-     * @throws IllegalArgumentException if a score cache is already registed for this type.
      * @hide
      */
     void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
 
     /**
+     * Unregister a cache to receive scoring updates.
+     *
+     * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
+     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
+     * @throws SecurityException if the caller is not the system.
+     * @hide
+     */
+    void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
+
+    /**
      * Request a recommendation for the best network to connect to
      * taking into account the inputs from the {@link RecommendationRequest}.
      *
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index c301fe3..af21cef 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -279,6 +279,24 @@
     }
 
     /**
+     * Unregister a network score cache.
+     *
+     * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
+     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
+     * @throws SecurityException if the caller does not hold the
+     *         {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+     * @throws IllegalArgumentException if a score cache is already registered for this type.
+     * @hide
+     */
+    public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+        try {
+            mService.unregisterNetworkScoreCache(networkType, scoreCache);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Request a recommendation for which network to connect to.
      *
      * @param request a {@link RecommendationRequest} instance containing additional
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1a8ba74..db7baac 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7646,6 +7646,8 @@
 
         /**
          * Value to specify if Wi-Fi Wakeup feature is enabled.
+         *
+         * Type: int (0 for false, 1 for true)
          * @hide
          */
         @SystemApi
@@ -7654,6 +7656,8 @@
         /**
          * Value to specify if network recommendations from
          * {@link com.android.server.NetworkScoreService} are enabled.
+         *
+         * Type: int (0 for false, 1 for true)
          * @hide
          */
         @SystemApi
diff --git a/core/java/com/android/internal/os/TransferPipe.java b/core/java/com/android/internal/os/TransferPipe.java
index e76b395..f904150 100644
--- a/core/java/com/android/internal/os/TransferPipe.java
+++ b/core/java/com/android/internal/os/TransferPipe.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.os;
 
+import java.io.Closeable;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -32,13 +33,13 @@
 /**
  * Helper for transferring data through a pipe from a client app.
  */
-public final class TransferPipe implements Runnable {
+public final class TransferPipe implements Runnable, Closeable {
     static final String TAG = "TransferPipe";
     static final boolean DEBUG = false;
 
     static final long DEFAULT_TIMEOUT = 5000;  // 5 seconds
 
-    final Thread mThread;;
+    final Thread mThread;
     final ParcelFileDescriptor[] mFds;
 
     FileDescriptor mOutFd;
@@ -54,8 +55,13 @@
     }
 
     public TransferPipe() throws IOException {
+        this(null);
+    }
+
+    public TransferPipe(String bufferPrefix) throws IOException {
         mThread = new Thread(this, "TransferPipe");
         mFds = ParcelFileDescriptor.createPipe();
+        mBufferPrefix = bufferPrefix;
     }
 
     ParcelFileDescriptor getReadFd() {
@@ -70,6 +76,11 @@
         mBufferPrefix = prefix;
     }
 
+    public static void dumpAsync(IBinder binder, FileDescriptor out, String[] args)
+            throws IOException, RemoteException {
+        goDump(binder, out, args);
+    }
+
     static void go(Caller caller, IInterface iface, FileDescriptor out,
             String prefix, String[] args) throws IOException, RemoteException {
         go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT);
@@ -86,12 +97,9 @@
             return;
         }
 
-        TransferPipe tp = new TransferPipe();
-        try {
+        try (TransferPipe tp = new TransferPipe()) {
             caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args);
             tp.go(out, timeout);
-        } finally {
-            tp.kill();
         }
     }
 
@@ -111,12 +119,9 @@
             return;
         }
 
-        TransferPipe tp = new TransferPipe();
-        try {
+        try (TransferPipe tp = new TransferPipe()) {
             binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
             tp.go(out, timeout);
-        } finally {
-            tp.kill();
         }
     }
 
@@ -173,6 +178,11 @@
         }
     }
 
+    @Override
+    public void close() {
+        kill();
+    }
+
     public void kill() {
         synchronized (this) {
             closeFd(0);
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index fe5d8ca..0011002 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -27,3 +27,15 @@
 LOCAL_MODULE := legacy-test
 
 include $(BUILD_JAVA_LIBRARY)
+
+ifeq ($(HOST_OS),linux)
+# Build the legacy-performance-test-hostdex library
+# =================================================
+# This contains the android.test.PerformanceTestCase class only
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := ../core/java/android/test/PerformanceTestCase.java
+LOCAL_MODULE := legacy-performance-test-hostdex
+
+include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+endif  # HOST_OS == linux
diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl
index 8870d2a..e86ad1a 100644
--- a/location/java/android/location/IFusedProvider.aidl
+++ b/location/java/android/location/IFusedProvider.aidl
@@ -22,11 +22,11 @@
  * Interface definition for Location providers that require FLP services.
  * @hide
  */
-interface IFusedProvider {
+oneway interface IFusedProvider {
     /**
      * Provides access to a FusedLocationHardware instance needed for the provider to work.
      *
      * @param instance      The FusedLocationHardware available for the provider to use.
      */
     void onFusedLocationHardwareChange(in IFusedLocationHardware instance);
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index df1b6f5..3ad264d 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -25,6 +25,7 @@
 import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethod;
@@ -4030,9 +4031,9 @@
         if (client != null) {
             pw.flush();
             try {
-                client.client.asBinder().dump(fd, args);
-            } catch (RemoteException e) {
-                p.println("Input method client dead: " + e);
+                TransferPipe.dumpAsync(client.client.asBinder(), fd, args);
+            } catch (IOException | RemoteException e) {
+                p.println("Failed to dump input method client: " + e);
             }
         } else {
             p.println("No input method client.");
@@ -4046,9 +4047,9 @@
             p.println(" ");
             pw.flush();
             try {
-                focusedWindowClient.client.asBinder().dump(fd, args);
-            } catch (RemoteException e) {
-                p.println("Input method client in focused window dead: " + e);
+                TransferPipe.dumpAsync(focusedWindowClient.client.asBinder(), fd, args);
+            } catch (IOException | RemoteException e) {
+                p.println("Failed to dump input method client in focused window: " + e);
             }
         }
 
@@ -4056,9 +4057,9 @@
         if (method != null) {
             pw.flush();
             try {
-                method.asBinder().dump(fd, args);
-            } catch (RemoteException e) {
-                p.println("Input method service dead: " + e);
+                TransferPipe.dumpAsync(method.asBinder(), fd, args);
+            } catch (IOException | RemoteException e) {
+                p.println("Failed to dump input method service: " + e);
             }
         } else {
             p.println("No input method service.");
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 4e969be..6412e01 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -36,25 +36,29 @@
 import android.net.wifi.WifiConfiguration;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.Log;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.TransferPipe;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
+import java.util.function.Consumer;
 
 /**
  * Backing service for {@link android.net.NetworkScoreManager}.
@@ -66,7 +70,8 @@
 
     private final Context mContext;
     private final NetworkScorerAppManager mNetworkScorerAppManager;
-    private final Map<Integer, INetworkScoreCache> mScoreCaches;
+    @GuardedBy("mScoreCaches")
+    private final Map<Integer, RemoteCallbackList<INetworkScoreCache>> mScoreCaches;
     /** Lock used to update mPackageMonitor when scorer package changes occur. */
     private final Object mPackageMonitorLock = new Object[0];
 
@@ -164,7 +169,7 @@
     NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager) {
         mContext = context;
         mNetworkScorerAppManager = networkScoreAppManager;
-        mScoreCaches = new HashMap<>();
+        mScoreCaches = new ArrayMap<>();
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
         // TODO: Need to update when we support per-user scorers. http://b/23422763
         mContext.registerReceiverAsUser(
@@ -274,7 +279,7 @@
         }
 
         // Separate networks by type.
-        Map<Integer, List<ScoredNetwork>> networksByType = new HashMap<>();
+        Map<Integer, List<ScoredNetwork>> networksByType = new ArrayMap<>();
         for (ScoredNetwork network : networks) {
             List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type);
             if (networkList == null) {
@@ -285,19 +290,32 @@
         }
 
         // Pass the scores of each type down to the appropriate network scorer.
-        for (Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
-            INetworkScoreCache scoreCache = mScoreCaches.get(entry.getKey());
-            if (scoreCache != null) {
-                try {
-                    scoreCache.updateScores(entry.getValue());
-                } catch (RemoteException e) {
-                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                        Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
+        for (final Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
+            final RemoteCallbackList<INetworkScoreCache> callbackList;
+            final boolean isEmpty;
+            synchronized (mScoreCaches) {
+                callbackList = mScoreCaches.get(entry.getKey());
+                isEmpty = callbackList == null || callbackList.getRegisteredCallbackCount() == 0;
+            }
+            if (isEmpty) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
+                }
+                continue;
+            }
+
+            sendCallback(new Consumer<INetworkScoreCache>() {
+                @Override
+                public void accept(INetworkScoreCache networkScoreCache) {
+                    try {
+                        networkScoreCache.updateScores(entry.getValue());
+                    } catch (RemoteException e) {
+                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                            Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
+                        }
                     }
                 }
-            } else if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
-            }
+            }, Collections.singleton(callbackList));
         }
 
         return true;
@@ -392,28 +410,52 @@
 
     /** Clear scores. Callers are responsible for checking permissions as appropriate. */
     private void clearInternal() {
-        Set<INetworkScoreCache> cachesToClear = getScoreCaches();
-
-        for (INetworkScoreCache scoreCache : cachesToClear) {
-            try {
-                scoreCache.clearScores();
-            } catch (RemoteException e) {
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "Unable to clear scores", e);
+        sendCallback(new Consumer<INetworkScoreCache>() {
+            @Override
+            public void accept(INetworkScoreCache networkScoreCache) {
+                try {
+                    networkScoreCache.clearScores();
+                } catch (RemoteException e) {
+                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                        Log.v(TAG, "Unable to clear scores", e);
+                    }
                 }
             }
-        }
+        }, getScoreCacheLists());
     }
 
     @Override
     public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
         mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
         synchronized (mScoreCaches) {
-            if (mScoreCaches.containsKey(networkType)) {
-                throw new IllegalArgumentException(
-                        "Score cache already registered for type " + networkType);
+            RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
+            if (callbackList == null) {
+                callbackList = new RemoteCallbackList<>();
+                mScoreCaches.put(networkType, callbackList);
             }
-            mScoreCaches.put(networkType, scoreCache);
+            if (!callbackList.register(scoreCache)) {
+                if (callbackList.getRegisteredCallbackCount() == 0) {
+                    mScoreCaches.remove(networkType);
+                }
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "Unable to register NetworkScoreCache for type " + networkType);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        synchronized (mScoreCaches) {
+            RemoteCallbackList<INetworkScoreCache> callbackList = mScoreCaches.get(networkType);
+            if (callbackList == null || !callbackList.unregister(scoreCache)) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "Unable to unregister NetworkScoreCache for type " + networkType);
+                }
+            } else if (callbackList.getRegisteredCallbackCount() == 0) {
+                mScoreCaches.remove(networkType);
+            }
         }
     }
 
@@ -428,7 +470,7 @@
     }
 
     @Override
-    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+    protected void dump(final FileDescriptor fd, final PrintWriter writer, final String[] args) {
         mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
         NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
         if (currentScorer == null) {
@@ -437,16 +479,17 @@
         }
         writer.println("Current scorer: " + currentScorer.mPackageName);
 
-        for (INetworkScoreCache scoreCache : getScoreCaches()) {
-            try {
-                scoreCache.asBinder().dump(fd, args);
-            } catch (RemoteException e) {
-                writer.println("Unable to dump score cache");
-                if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    Log.v(TAG, "Unable to dump score cache", e);
+        sendCallback(new Consumer<INetworkScoreCache>() {
+            @Override
+            public void accept(INetworkScoreCache networkScoreCache) {
+                try {
+                  TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
+                } catch (IOException | RemoteException e) {
+                  writer.println("Failed to dump score cache: " + e);
                 }
             }
-        }
+        }, getScoreCacheLists());
+
         if (mServiceConnection != null) {
             mServiceConnection.dump(fd, writer, args);
         } else {
@@ -456,14 +499,30 @@
     }
 
     /**
-     * Returns a set of all score caches that are currently active.
+     * Returns a {@link Collection} of all {@link RemoteCallbackList}s that are currently active.
      *
      * <p>May be used to perform an action on all score caches without potentially strange behavior
      * if a new scorer is registered during that action's execution.
      */
-    private Set<INetworkScoreCache> getScoreCaches() {
+    private Collection<RemoteCallbackList<INetworkScoreCache>> getScoreCacheLists() {
         synchronized (mScoreCaches) {
-            return new HashSet<>(mScoreCaches.values());
+            return new ArrayList<>(mScoreCaches.values());
+        }
+    }
+
+    private void sendCallback(Consumer<INetworkScoreCache> consumer,
+            Collection<RemoteCallbackList<INetworkScoreCache>> remoteCallbackLists) {
+        for (RemoteCallbackList<INetworkScoreCache> callbackList : remoteCallbackLists) {
+            synchronized (callbackList) { // Ensure only one active broadcast per RemoteCallbackList
+                final int count = callbackList.beginBroadcast();
+                try {
+                    for (int i = 0; i < count; i++) {
+                        consumer.accept(callbackList.getBroadcastItem(i));
+                    }
+                } finally {
+                    callbackList.finishBroadcast();
+                }
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 5eb06ed..b44087c 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -17,6 +17,7 @@
 package com.android.server.location;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 
 import android.content.Context;
@@ -30,6 +31,7 @@
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ILocationProvider;
 import com.android.internal.location.ProviderRequest;
+import com.android.internal.os.TransferPipe;
 import com.android.server.LocationManagerService;
 import com.android.server.ServiceWatcher;
 
@@ -230,14 +232,9 @@
         pw.flush();
 
         try {
-            service.asBinder().dump(fd, args);
-        } catch (RemoteException e) {
-            pw.println("service down (RemoteException)");
-            Log.w(TAG, e);
-        } catch (Exception e) {
-            pw.println("service down (Exception)");
-            // never let remote service crash system server
-            Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
+            TransferPipe.dumpAsync(service.asBinder(), fd, args);
+        } catch (IOException | RemoteException e) {
+            pw.println("Failed to dump location provider: " + e);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 68b465a..07d98bc 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -32,7 +32,10 @@
 import android.os.UserHandle;
 import android.util.TimedRemoteCaller;
 
+import com.android.internal.os.TransferPipe;
+
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -85,13 +88,11 @@
                     .append((mRemoteInstance != null) ? "true" : "false").println();
 
             pw.flush();
-
             try {
-                getRemoteInstanceLazy().asBinder().dump(fd, new String[] { prefix });
-            } catch (TimeoutException te) {
-                /* ignore */
-            } catch (RemoteException re) {
-                /* ignore */
+                TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd,
+                        new String[] { prefix });
+            } catch (IOException | TimeoutException | RemoteException e) {
+                pw.println("Failed to dump remote instance: " + e);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index d8f6b80..bff68d8 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -204,35 +204,70 @@
                 outputPath, dexFlags, compilerFilter, volumeUuid, sharedLibraries);
     }
 
-    public boolean mergeProfiles(int uid, String pkgName) throws InstallerException {
-        return mInstaller.mergeProfiles(uid, pkgName);
+    public boolean mergeProfiles(int uid, String packageName) throws InstallerException {
+        checkLock();
+        try {
+            return mInstalld.mergeProfiles(uid, packageName);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
-    public boolean dumpProfiles(String gid, String packageName, String codePaths)
+    public boolean dumpProfiles(int uid, String packageName, String codePaths)
             throws InstallerException {
-        return mInstaller.dumpProfiles(gid, packageName, codePaths);
+        checkLock();
+        try {
+            return mInstalld.dumpProfiles(uid, packageName, codePaths);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void idmap(String targetApkPath, String overlayApkPath, int uid)
             throws InstallerException {
-        mInstaller.execute("idmap", targetApkPath, overlayApkPath, uid);
+        checkLock();
+        try {
+            mInstalld.idmap(targetApkPath, overlayApkPath, uid);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void rmdex(String codePath, String instructionSet) throws InstallerException {
         assertValidInstructionSet(instructionSet);
-        mInstaller.execute("rmdex", codePath, instructionSet);
+        checkLock();
+        try {
+            mInstalld.rmdex(codePath, instructionSet);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void rmPackageDir(String packageDir) throws InstallerException {
-        mInstaller.execute("rmpackagedir", packageDir);
+        checkLock();
+        try {
+            mInstalld.rmPackageDir(packageDir);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
-    public void clearAppProfiles(String pkgName) throws InstallerException {
-        mInstaller.execute("clear_app_profiles", pkgName);
+    public void clearAppProfiles(String packageName) throws InstallerException {
+        checkLock();
+        try {
+            mInstalld.clearAppProfiles(packageName);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
-    public void destroyAppProfiles(String pkgName) throws InstallerException {
-        mInstaller.execute("destroy_app_profiles", pkgName);
+    public void destroyAppProfiles(String packageName) throws InstallerException {
+        checkLock();
+        try {
+            mInstalld.destroyAppProfiles(packageName);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void createUserData(String uuid, int userId, int userSerial, int flags)
@@ -256,11 +291,21 @@
 
     public void markBootComplete(String instructionSet) throws InstallerException {
         assertValidInstructionSet(instructionSet);
-        mInstaller.execute("markbootcomplete", instructionSet);
+        checkLock();
+        try {
+            mInstalld.markBootComplete(instructionSet);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void freeCache(String uuid, long freeStorageSize) throws InstallerException {
-        mInstaller.execute("freecache", uuid, freeStorageSize);
+        checkLock();
+        try {
+            mInstalld.freeCache(uuid, freeStorageSize);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     /**
@@ -268,29 +313,54 @@
      * directory to the real location for backward compatibility. Note that no
      * such symlink is created for 64 bit shared libraries.
      */
-    public void linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
+    public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32,
             int userId) throws InstallerException {
-        mInstaller.execute("linklib", uuid, dataPath, nativeLibPath32, userId);
+        checkLock();
+        try {
+            mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void createOatDir(String oatDir, String dexInstructionSet)
             throws InstallerException {
-        mInstaller.execute("createoatdir", oatDir, dexInstructionSet);
+        checkLock();
+        try {
+            mInstalld.createOatDir(oatDir, dexInstructionSet);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void linkFile(String relativePath, String fromBase, String toBase)
             throws InstallerException {
-        mInstaller.execute("linkfile", relativePath, fromBase, toBase);
+        checkLock();
+        try {
+            mInstalld.linkFile(relativePath, fromBase, toBase);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void moveAb(String apkPath, String instructionSet, String outputPath)
             throws InstallerException {
-        mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
+        checkLock();
+        try {
+            mInstalld.moveAb(apkPath, instructionSet, outputPath);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     public void deleteOdex(String apkPath, String instructionSet, String outputPath)
             throws InstallerException {
-        mInstaller.execute("delete_odex", apkPath, instructionSet, outputPath);
+        checkLock();
+        try {
+            mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new InstallerException(e.getMessage());
+        }
     }
 
     private static void assertValidInstructionSet(String instructionSet)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 56a0173..9102fee 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7530,9 +7530,8 @@
             final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
             try {
                 List<String> allCodePaths = pkg.getAllCodePathsExcludingResourceOnly();
-                String gid = Integer.toString(sharedGid);
                 String codePaths = TextUtils.join(";", allCodePaths);
-                mInstaller.dumpProfiles(gid, packageName, codePaths);
+                mInstaller.dumpProfiles(sharedGid, packageName, codePaths);
             } catch (InstallerException e) {
                 Slog.w(TAG, "Failed to dump profiles", e);
             }
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index 07b26e8..6b919df 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -43,9 +43,12 @@
 import android.util.Slog;
 import android.util.TimedRemoteCaller;
 
+import com.android.internal.os.TransferPipe;
+
 import libcore.io.IoUtils;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.List;
@@ -572,13 +575,11 @@
                     .append((mRemoteInstance != null) ? "true" : "false").println();
 
             pw.flush();
-
             try {
-                getRemoteInstanceLazy().asBinder().dump(fd, new String[]{prefix});
-            } catch (TimeoutException te) {
-                /* ignore */
-            } catch (RemoteException re) {
-                /* ignore */
+                TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd,
+                        new String[] { prefix });
+            } catch (IOException | TimeoutException | RemoteException e) {
+                pw.println("Failed to dump remote instance: " + e);
             }
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
new file mode 100644
index 0000000..0139671
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2012 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 junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.Manifest.permission;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.INetworkScoreCache;
+import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppManager;
+import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.ScoredNetwork;
+import android.net.WifiKey;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.server.devicepolicy.MockUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link NetworkScoreService}.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class NetworkScoreServiceTest {
+    private static final ScoredNetwork SCORED_NETWORK =
+            new ScoredNetwork(new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")),
+                    null /* rssiCurve*/);
+    private static final NetworkScorerAppData PREV_SCORER = new NetworkScorerAppData(
+            "prevPackageName", 0, "prevScorerName", null /* configurationActivityClassName */,
+            "prevScoringServiceClass");
+    private static final NetworkScorerAppData NEW_SCORER = new NetworkScorerAppData(
+            "newPackageName", 1, "newScorerName", null /* configurationActivityClassName */,
+            "newScoringServiceClass");
+
+    @Mock private PackageManager mPackageManager;
+    @Mock private NetworkScorerAppManager mNetworkScorerAppManager;
+    @Mock private Context mContext;
+    @Mock private Resources mResources;
+    @Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2;
+    @Mock private IBinder mIBinder, mIBinder2;
+    @Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
+
+    private ContentResolver mContentResolver;
+    private NetworkScoreService mNetworkScoreService;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mNetworkScoreCache.asBinder()).thenReturn(mIBinder);
+        when(mNetworkScoreCache2.asBinder()).thenReturn(mIBinder2);
+        mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getResources()).thenReturn(mResources);
+        mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager);
+    }
+
+    @Test
+    public void testSystemReady_networkScorerProvisioned() throws Exception {
+        Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 1);
+
+        mNetworkScoreService.systemReady();
+
+        verify(mNetworkScorerAppManager, never()).setActiveScorer(anyString());
+    }
+
+    @Test
+    public void testSystemReady_networkScorerNotProvisioned_defaultScorer() throws Exception {
+        Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 0);
+
+        when(mResources.getString(R.string.config_defaultNetworkScorerPackageName))
+                .thenReturn(NEW_SCORER.mPackageName);
+
+        mNetworkScoreService.systemReady();
+
+        verify(mNetworkScorerAppManager).setActiveScorer(NEW_SCORER.mPackageName);
+        assertEquals(1,
+                Settings.Global.getInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED));
+
+    }
+
+    @Test
+    public void testSystemReady_networkScorerNotProvisioned_noDefaultScorer() throws Exception {
+        Settings.Global.putInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED, 0);
+
+        when(mResources.getString(R.string.config_defaultNetworkScorerPackageName))
+                .thenReturn(null);
+
+        mNetworkScoreService.systemReady();
+
+        verify(mNetworkScorerAppManager, never()).setActiveScorer(anyString());
+        assertEquals(1,
+                Settings.Global.getInt(mContentResolver, Global.NETWORK_SCORING_PROVISIONED));
+    }
+
+    @Test
+    public void testSystemRunning() {
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
+
+        mNetworkScoreService.systemRunning();
+
+        verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
+                new ComponentName(NEW_SCORER.mPackageName, NEW_SCORER.mScoringServiceClassName))),
+                any(ServiceConnection.class),
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+                eq(UserHandle.SYSTEM));
+    }
+
+    @Test
+    public void testUpdateScores_notActiveScorer() {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+
+        try {
+            mNetworkScoreService.updateScores(new ScoredNetwork[0]);
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testUpdateScores_oneRegisteredCache() throws RemoteException {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+
+        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+
+        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
+
+        verify(mNetworkScoreCache).updateScores(mScoredNetworkCaptor.capture());
+
+        assertEquals(1, mScoredNetworkCaptor.getValue().size());
+        assertEquals(SCORED_NETWORK, mScoredNetworkCaptor.getValue().get(0));
+    }
+
+    @Test
+    public void testUpdateScores_twoRegisteredCaches() throws RemoteException {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+
+        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+        mNetworkScoreService.registerNetworkScoreCache(
+                NetworkKey.TYPE_WIFI, mNetworkScoreCache2);
+
+        // updateScores should update both caches
+        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
+
+        verify(mNetworkScoreCache).updateScores(anyListOf(ScoredNetwork.class));
+        verify(mNetworkScoreCache2).updateScores(anyListOf(ScoredNetwork.class));
+
+        mNetworkScoreService.unregisterNetworkScoreCache(
+                NetworkKey.TYPE_WIFI, mNetworkScoreCache2);
+
+        // updateScores should only update the first cache since the 2nd has been unregistered
+        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
+
+        verify(mNetworkScoreCache, times(2)).updateScores(anyListOf(ScoredNetwork.class));
+
+        mNetworkScoreService.unregisterNetworkScoreCache(
+                NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+
+        // updateScores should not update any caches since they are both unregistered
+        mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
+
+        verifyNoMoreInteractions(mNetworkScoreCache, mNetworkScoreCache2);
+    }
+
+    @Test
+    public void testClearScores_notActiveScorer_noBroadcastNetworkPermission() {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+            .thenReturn(PackageManager.PERMISSION_DENIED);
+        try {
+            mNetworkScoreService.clearScores();
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testClearScores_activeScorer_noBroadcastNetworkPermission() {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+            .thenReturn(PackageManager.PERMISSION_DENIED);
+
+        mNetworkScoreService.clearScores();
+    }
+
+    @Test
+    public void testClearScores_activeScorer() throws RemoteException {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+
+        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+        mNetworkScoreService.clearScores();
+
+        verify(mNetworkScoreCache).clearScores();
+    }
+
+    @Test
+    public void testClearScores_notActiveScorer_hasBroadcastNetworkPermission()
+            throws RemoteException {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+        mNetworkScoreService.clearScores();
+
+        verify(mNetworkScoreCache).clearScores();
+    }
+
+    @Test
+    public void testSetActiveScorer_noScoreNetworksPermission() {
+        doThrow(new SecurityException()).when(mContext)
+                .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString());
+
+        try {
+            mNetworkScoreService.setActiveScorer(null);
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testSetActiveScorer_failure() throws RemoteException {
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER);
+        when(mNetworkScorerAppManager.setActiveScorer(NEW_SCORER.mPackageName)).thenReturn(false);
+        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+
+        boolean success = mNetworkScoreService.setActiveScorer(NEW_SCORER.mPackageName);
+
+        assertFalse(success);
+        verify(mNetworkScoreCache).clearScores();
+        verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
+                new ComponentName(PREV_SCORER.mPackageName, PREV_SCORER.mScoringServiceClassName))),
+                any(ServiceConnection.class),
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+                eq(UserHandle.SYSTEM));
+    }
+
+    @Test
+    public void testSetActiveScorer_success() throws RemoteException {
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, NEW_SCORER);
+        when(mNetworkScorerAppManager.setActiveScorer(NEW_SCORER.mPackageName)).thenReturn(true);
+        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+
+        boolean success = mNetworkScoreService.setActiveScorer(NEW_SCORER.mPackageName);
+
+        assertTrue(success);
+        verify(mNetworkScoreCache).clearScores();
+        verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent(
+                new ComponentName(NEW_SCORER.mPackageName, NEW_SCORER.mScoringServiceClassName))),
+                any(ServiceConnection.class),
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
+                eq(UserHandle.SYSTEM));
+        verify(mContext, times(2)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(NetworkScoreManager.ACTION_SCORER_CHANGED),
+                eq(UserHandle.SYSTEM));
+    }
+
+    @Test
+    public void testDisableScoring_notActiveScorer_noBroadcastNetworkPermission() {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+
+        try {
+            mNetworkScoreService.disableScoring();
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+
+    }
+
+    @Test
+    public void testDisableScoring_activeScorer() throws RemoteException {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, null);
+        when(mNetworkScorerAppManager.setActiveScorer(null)).thenReturn(true);
+        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+
+        mNetworkScoreService.disableScoring();
+
+        verify(mNetworkScoreCache).clearScores();
+        verify(mContext).sendBroadcastAsUser(
+                MockUtils.checkIntent(new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED)
+                        .setPackage(PREV_SCORER.mPackageName)),
+                eq(UserHandle.SYSTEM));
+        verify(mContext, never()).bindServiceAsUser(any(Intent.class),
+                any(ServiceConnection.class), anyInt(), any(UserHandle.class));
+    }
+
+    @Test
+    public void testDisableScoring_notActiveScorer_hasBroadcastNetworkPermission()
+            throws RemoteException {
+        when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
+        when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(PREV_SCORER, null);
+        when(mNetworkScorerAppManager.setActiveScorer(null)).thenReturn(true);
+        mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+
+        mNetworkScoreService.disableScoring();
+
+        verify(mNetworkScoreCache).clearScores();
+        verify(mContext).sendBroadcastAsUser(
+                MockUtils.checkIntent(new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED)
+                        .setPackage(PREV_SCORER.mPackageName)),
+                eq(UserHandle.SYSTEM));
+        verify(mContext, never()).bindServiceAsUser(any(Intent.class),
+                any(ServiceConnection.class), anyInt(), any(UserHandle.class));
+    }
+
+    @Test
+    public void testRegisterNetworkScoreCache_noBroadcastNetworkPermission() {
+        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+                eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+
+        try {
+            mNetworkScoreService.registerNetworkScoreCache(
+                NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testUnregisterNetworkScoreCache_noBroadcastNetworkPermission() {
+        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+                eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+
+        try {
+            mNetworkScoreService.unregisterNetworkScoreCache(
+                    NetworkKey.TYPE_WIFI, mNetworkScoreCache);
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testDump_noDumpPermission() {
+        doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+                eq(permission.DUMP), anyString());
+
+        try {
+            mNetworkScoreService.dump(
+                    new FileDescriptor(), new PrintWriter(new StringWriter()), new String[0]);
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testDump_doesNotCrash() {
+        when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
+        StringWriter stringWriter = new StringWriter();
+
+        mNetworkScoreService.dump(
+                new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
+
+        assertFalse(stringWriter.toString().isEmpty());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index 58db192..3806da6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -82,6 +82,21 @@
         return Mockito.argThat(m);
     }
 
+    public static Intent checkIntent(final Intent intent) {
+        final Matcher<Intent> m = new BaseMatcher<Intent>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) return false;
+                return intent.filterEquals((Intent) item);
+            }
+            @Override
+            public void describeTo(Description description) {
+                description.appendText(intent.toString());
+            }
+        };
+        return Mockito.argThat(m);
+    }
+
     public static Bundle checkUserRestrictions(String... keys) {
         final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
         final Matcher<Bundle> m = new BaseMatcher<Bundle>() {
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 68bde35..a317994 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-junit framework
+LOCAL_JAVA_LIBRARIES := core-oj core-libart junit framework
 LOCAL_STATIC_JAVA_LIBRARIES := junit-runner
 
 LOCAL_MODULE:= android.test.runner
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 69e9fcd..43e6246 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -746,50 +746,6 @@
     @SystemApi
     public int numAssociation;
 
-    /**
-     * @hide
-     * Number of time user disabled WiFi while associated to this configuration with Low RSSI.
-     */
-    public int numUserTriggeredWifiDisableLowRSSI;
-
-    /**
-     * @hide
-     * Number of time user disabled WiFi while associated to this configuration with Bad RSSI.
-     */
-    public int numUserTriggeredWifiDisableBadRSSI;
-
-    /**
-     * @hide
-     * Number of time user disabled WiFi while associated to this configuration
-     * and RSSI was not HIGH.
-     */
-    public int numUserTriggeredWifiDisableNotHighRSSI;
-
-    /**
-     * @hide
-     * Number of ticks associated to this configuration with Low RSSI.
-     */
-    public int numTicksAtLowRSSI;
-
-    /**
-     * @hide
-     * Number of ticks associated to this configuration with Bad RSSI.
-     */
-    public int numTicksAtBadRSSI;
-
-    /**
-     * @hide
-     * Number of ticks associated to this configuration
-     * and RSSI was not HIGH.
-     */
-    public int numTicksAtNotHighRSSI;
-    /**
-     * @hide
-     * Number of time user (WifiManager) triggered association to this configuration.
-     * TODO: count this only for Wifi Settings uuid, so as to not count 3rd party apps
-     */
-    public int numUserTriggeredJoinAttempts;
-
     /** @hide
      * Boost given to RSSI on a home network for the purpose of calculating the score
      * This adds stickiness to home networks, as defined by:
@@ -1630,16 +1586,6 @@
                 sbuf.append('\n');
             }
         }
-        sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
-        sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
-        sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
-        sbuf.append('\n');
-        sbuf.append("ticksLow: ").append(this.numTicksAtLowRSSI);
-        sbuf.append(" ticksBad: ").append(this.numTicksAtBadRSSI);
-        sbuf.append(" ticksNotHigh: ").append(this.numTicksAtNotHighRSSI);
-        sbuf.append('\n');
-        sbuf.append("triggeredJoin: ").append(this.numUserTriggeredJoinAttempts);
-        sbuf.append('\n');
 
         return sbuf.toString();
     }
@@ -1946,13 +1892,6 @@
             numScorerOverride = source.numScorerOverride;
             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
             numAssociation = source.numAssociation;
-            numUserTriggeredWifiDisableLowRSSI = source.numUserTriggeredWifiDisableLowRSSI;
-            numUserTriggeredWifiDisableBadRSSI = source.numUserTriggeredWifiDisableBadRSSI;
-            numUserTriggeredWifiDisableNotHighRSSI = source.numUserTriggeredWifiDisableNotHighRSSI;
-            numTicksAtLowRSSI = source.numTicksAtLowRSSI;
-            numTicksAtBadRSSI = source.numTicksAtBadRSSI;
-            numTicksAtNotHighRSSI = source.numTicksAtNotHighRSSI;
-            numUserTriggeredJoinAttempts = source.numUserTriggeredJoinAttempts;
             userApproved = source.userApproved;
             numNoInternetAccessReports = source.numNoInternetAccessReports;
             noInternetAccessExpected = source.noInternetAccessExpected;
@@ -2018,13 +1957,6 @@
         dest.writeInt(numScorerOverride);
         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
         dest.writeInt(numAssociation);
-        dest.writeInt(numUserTriggeredWifiDisableLowRSSI);
-        dest.writeInt(numUserTriggeredWifiDisableBadRSSI);
-        dest.writeInt(numUserTriggeredWifiDisableNotHighRSSI);
-        dest.writeInt(numTicksAtLowRSSI);
-        dest.writeInt(numTicksAtBadRSSI);
-        dest.writeInt(numTicksAtNotHighRSSI);
-        dest.writeInt(numUserTriggeredJoinAttempts);
         dest.writeInt(userApproved);
         dest.writeInt(numNoInternetAccessReports);
         dest.writeInt(noInternetAccessExpected ? 1 : 0);
@@ -2090,13 +2022,6 @@
                 config.numScorerOverride = in.readInt();
                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
                 config.numAssociation = in.readInt();
-                config.numUserTriggeredWifiDisableLowRSSI = in.readInt();
-                config.numUserTriggeredWifiDisableBadRSSI = in.readInt();
-                config.numUserTriggeredWifiDisableNotHighRSSI = in.readInt();
-                config.numTicksAtLowRSSI = in.readInt();
-                config.numTicksAtBadRSSI = in.readInt();
-                config.numTicksAtNotHighRSSI = in.readInt();
-                config.numUserTriggeredJoinAttempts = in.readInt();
                 config.userApproved = in.readInt();
                 config.numNoInternetAccessReports = in.readInt();
                 config.noInternetAccessExpected = in.readInt() != 0;
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
new file mode 100644
index 0000000..5f949747
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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.wifi;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiConfiguration}.
+ */
+public class WifiConfigurationTest {
+
+    @Before
+    public void setUp() {
+    }
+
+    /**
+     * Check that parcel marshalling/unmarshalling works
+     *
+     * Create and populate a WifiConfiguration.
+     * Marshall and unmashall it, and expect to recover a copy of the original.
+     * Marshall the resulting object, and expect the bytes to match the
+     * first marshall result.
+     */
+    @Test
+    public void testWifiConfigurationParcel() {
+        String cookie = "C O.o |<IE";
+        WifiConfiguration config = new WifiConfiguration();
+        config.setPasspointManagementObjectTree(cookie);
+        Parcel parcelW = Parcel.obtain();
+        config.writeToParcel(parcelW, 0);
+        byte[] bytes = parcelW.marshall();
+        parcelW.recycle();
+
+        Parcel parcelR = Parcel.obtain();
+        parcelR.unmarshall(bytes, 0, bytes.length);
+        parcelR.setDataPosition(0);
+        WifiConfiguration reconfig = WifiConfiguration.CREATOR.createFromParcel(parcelR);
+
+        // lacking a useful config.equals, check one field near the end.
+        assertEquals(cookie, reconfig.getMoTree());
+
+        Parcel parcelWW = Parcel.obtain();
+        reconfig.writeToParcel(parcelWW, 0);
+        byte[] rebytes = parcelWW.marshall();
+        parcelWW.recycle();
+
+        assertArrayEquals(bytes, rebytes);
+    }
+}