Merge "Transplant the Logging system from Telecom"
diff --git a/api/current.txt b/api/current.txt
index 125e113..b391b00 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29169,6 +29169,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder detectDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder detectNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder detectResourceMismatches();
+    method public android.os.StrictMode.ThreadPolicy.Builder detectUnbufferedIo();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeathOnNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
@@ -29181,6 +29182,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder permitDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder permitNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder permitResourceMismatches();
+    method public android.os.StrictMode.ThreadPolicy.Builder permitUnbufferedIo();
   }
 
   public static final class StrictMode.VmPolicy {
@@ -51763,6 +51765,8 @@
     enum_constant public static final java.lang.annotation.ElementType PACKAGE;
     enum_constant public static final java.lang.annotation.ElementType PARAMETER;
     enum_constant public static final java.lang.annotation.ElementType TYPE;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
   }
 
   public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -51844,7 +51848,7 @@
     method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getAnnotations();
     method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
-    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
@@ -59113,8 +59117,10 @@
     method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
+    method public boolean hasExtensions();
     method public static synchronized void setDefault(java.util.Locale);
     method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+    method public java.util.Locale stripExtensions();
     method public java.lang.String toLanguageTag();
     method public final java.lang.String toString();
     field public static final java.util.Locale CANADA;
diff --git a/api/system-current.txt b/api/system-current.txt
index 6dc2bcf..68c7b48 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -31637,6 +31637,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder detectDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder detectNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder detectResourceMismatches();
+    method public android.os.StrictMode.ThreadPolicy.Builder detectUnbufferedIo();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeathOnNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
@@ -31649,6 +31650,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder permitDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder permitNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder permitResourceMismatches();
+    method public android.os.StrictMode.ThreadPolicy.Builder permitUnbufferedIo();
   }
 
   public static final class StrictMode.VmPolicy {
@@ -55120,6 +55122,8 @@
     enum_constant public static final java.lang.annotation.ElementType PACKAGE;
     enum_constant public static final java.lang.annotation.ElementType PARAMETER;
     enum_constant public static final java.lang.annotation.ElementType TYPE;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
   }
 
   public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -55201,7 +55205,7 @@
     method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getAnnotations();
     method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
-    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
@@ -62470,8 +62474,10 @@
     method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
+    method public boolean hasExtensions();
     method public static synchronized void setDefault(java.util.Locale);
     method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+    method public java.util.Locale stripExtensions();
     method public java.lang.String toLanguageTag();
     method public final java.lang.String toString();
     field public static final java.util.Locale CANADA;
diff --git a/api/test-current.txt b/api/test-current.txt
index 941790e..2aa6cfe 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -29238,6 +29238,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder detectDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder detectNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder detectResourceMismatches();
+    method public android.os.StrictMode.ThreadPolicy.Builder detectUnbufferedIo();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDeathOnNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder penaltyDialog();
@@ -29250,6 +29251,7 @@
     method public android.os.StrictMode.ThreadPolicy.Builder permitDiskWrites();
     method public android.os.StrictMode.ThreadPolicy.Builder permitNetwork();
     method public android.os.StrictMode.ThreadPolicy.Builder permitResourceMismatches();
+    method public android.os.StrictMode.ThreadPolicy.Builder permitUnbufferedIo();
   }
 
   public static final class StrictMode.VmPolicy {
@@ -51843,6 +51845,8 @@
     enum_constant public static final java.lang.annotation.ElementType PACKAGE;
     enum_constant public static final java.lang.annotation.ElementType PARAMETER;
     enum_constant public static final java.lang.annotation.ElementType TYPE;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+    enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
   }
 
   public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -51924,7 +51928,7 @@
     method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getAnnotations();
     method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
-    method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+    method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
     method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
     method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
@@ -59193,8 +59197,10 @@
     method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
     method public java.lang.String getUnicodeLocaleType(java.lang.String);
     method public java.lang.String getVariant();
+    method public boolean hasExtensions();
     method public static synchronized void setDefault(java.util.Locale);
     method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+    method public java.util.Locale stripExtensions();
     method public java.lang.String toLanguageTag();
     method public final java.lang.String toString();
     field public static final java.util.Locale CANADA;
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index e530184..b5f1c2a 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -62,7 +62,6 @@
 LOCAL_LDFLAGS := -ldl
 LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
 LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-LOCAL_CPPFLAGS := -std=c++11
 
 LOCAL_MODULE := app_process__asan
 LOCAL_MULTILIB := both
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index fa70c3f..ce54637 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -892,6 +892,14 @@
         return false;
     }
 
+    /** @hide */
+    public boolean isBondingInitiatedLocally() {
+        try {
+            return sService.isBondingInitiatedLocally(this);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
     /**
      * Set the Out Of Band data for a remote device to be used later
      * in the pairing mechanism. Users can obtain this data through other
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a420539..8c98536 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -62,6 +62,7 @@
     boolean cancelBondProcess(in BluetoothDevice device);
     boolean removeBond(in BluetoothDevice device);
     int getBondState(in BluetoothDevice device);
+    boolean isBondingInitiatedLocally(in BluetoothDevice device);
     int getConnectionState(in BluetoothDevice device);
 
     String getRemoteName(in BluetoothDevice device);
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index 12830a4..c5ceecd 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -25,4 +25,5 @@
     boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
     boolean setupBcb(in String command);
     boolean clearBcb();
+    void rebootRecoveryWithCommand(in String command);
 }
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 2d5a144..662e14c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -671,28 +671,22 @@
      * @throws IOException if something goes wrong.
      */
     private static void bootCommand(Context context, String... args) throws IOException {
-        synchronized (sRequestLock) {
-            LOG_FILE.delete();
+        LOG_FILE.delete();
 
-            StringBuilder command = new StringBuilder();
-            for (String arg : args) {
-                if (!TextUtils.isEmpty(arg)) {
-                    command.append(arg);
-                    command.append("\n");
-                }
+        StringBuilder command = new StringBuilder();
+        for (String arg : args) {
+            if (!TextUtils.isEmpty(arg)) {
+                command.append(arg);
+                command.append("\n");
             }
-
-            // Write the command into BCB (bootloader control block).
-            RecoverySystem rs = (RecoverySystem) context.getSystemService(
-                    Context.RECOVERY_SERVICE);
-            rs.setupBcb(command.toString());
-
-            // Having set up the BCB, go ahead and reboot.
-            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-            pm.reboot(PowerManager.REBOOT_RECOVERY);
-
-            throw new IOException("Reboot failed (no permissions?)");
         }
+
+        // Write the command into BCB (bootloader control block) and boot from
+        // there. Will not return unless failed.
+        RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+        rs.rebootRecoveryWithCommand(command.toString());
+
+        throw new IOException("Reboot failed (no permissions?)");
     }
 
     // Read last_install; then report time (in seconds) and I/O (in MiB) for
@@ -887,6 +881,17 @@
     }
 
     /**
+     * Talks to RecoverySystemService via Binder to set up the BCB command and
+     * reboot into recovery accordingly.
+     */
+    private void rebootRecoveryWithCommand(String command) {
+        try {
+            mService.rebootRecoveryWithCommand(command);
+        } catch (RemoteException ignored) {
+        }
+    }
+
+    /**
      * Internally, recovery treats each line of the command file as a separate
      * argv, so we only need to protect against newlines and nulls.
      */
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index c36b488..ff69cf6 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -191,9 +191,14 @@
      */
     public static final int DETECT_RESOURCE_MISMATCH = 0x10;  // for ThreadPolicy
 
+    /**
+     * @hide
+     */
+    public static final int DETECT_UNBUFFERED_IO = 0x20;  // for ThreadPolicy
+
     private static final int ALL_THREAD_DETECT_BITS =
             DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM |
-            DETECT_RESOURCE_MISMATCH;
+            DETECT_RESOURCE_MISMATCH | DETECT_UNBUFFERED_IO;
 
     // Byte 2: Process-policy
 
@@ -465,6 +470,20 @@
             }
 
             /**
+             * Detect unbuffered input/output operations.
+             */
+            public Builder detectUnbufferedIo() {
+                return enable(DETECT_UNBUFFERED_IO);
+            }
+
+            /**
+             * Detect unbuffered input/output operations.
+             */
+            public Builder permitUnbufferedIo() {
+                return disable(DETECT_UNBUFFERED_IO);
+            }
+
+            /**
              * Enables detection of mismatches between defined resource types
              * and getter calls.
              * <p>
@@ -974,6 +993,15 @@
     }
 
     /**
+     * @hide
+     */
+    private static class StrictModeUnbufferedIOViolation extends StrictModeViolation {
+        public StrictModeUnbufferedIOViolation(int policyMask) {
+            super(policyMask, DETECT_UNBUFFERED_IO, null);
+        }
+    }
+
+    /**
      * Returns the bitmask of the current thread's policy.
      *
      * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
@@ -1281,6 +1309,20 @@
             startHandlingViolationException(e);
         }
 
+        // Part of BlockGuard.Policy; just part of StrictMode:
+        public void onUnbufferedIO() {
+            if ((mPolicyMask & DETECT_UNBUFFERED_IO) == 0) {
+                return;
+            }
+            if (tooManyViolationsThisLoop()) {
+                return;
+            }
+            BlockGuard.BlockGuardPolicyException e =
+                    new StrictModeUnbufferedIOViolation(mPolicyMask);
+            e.fillInStackTrace();
+            startHandlingViolationException(e);
+        }
+
         // Part of BlockGuard.Policy interface:
         public void onReadFromDisk() {
             if ((mPolicyMask & DETECT_DISK_READ) == 0) {
@@ -2208,6 +2250,18 @@
     /**
      * @hide
      */
+    public static void noteUnbufferedIO() {
+        BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
+        if (!(policy instanceof AndroidBlockGuardPolicy)) {
+            // StrictMode not enabled.
+            return;
+        }
+        ((AndroidBlockGuardPolicy) policy).onUnbufferedIO();
+    }
+
+    /**
+     * @hide
+     */
     public static void noteDiskRead() {
         BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
         if (!(policy instanceof AndroidBlockGuardPolicy)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6d2d7c0..25cc961 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8189,6 +8189,13 @@
         public static final String CALL_AUTO_RETRY = "call_auto_retry";
 
         /**
+         * A setting that can be read whether the emergency affordance is currently needed.
+         * The value is a boolean (1 or 0).
+         * @hide
+         */
+        public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
+
+        /**
          * See RIL_PreferredNetworkType in ril.h
          * @hide
          */
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 8c5df08..8c2c236 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -379,7 +379,7 @@
 
     public void setState(int state, long now) {
         ensureNotDead();
-        if (mCurState != state) {
+        if (!mDead && (mCurState != state)) {
             //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
             commitStateTime(now);
             mCurState = state;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 52b72a4..1c307c9 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -476,11 +476,11 @@
      */
     private static PathClassLoader createSystemServerClassLoader(String systemServerClasspath,
                                                                  int targetSdkVersion) {
-      String librarySearchPath = System.getProperty("java.library.path");
+      String libraryPath = System.getProperty("java.library.path");
 
       return PathClassLoaderFactory.createClassLoader(systemServerClasspath,
-                                                      librarySearchPath,
-                                                      null /* libraryPermittedPath */,
+                                                      libraryPath,
+                                                      libraryPath,
                                                       ClassLoader.getSystemClassLoader(),
                                                       targetSdkVersion,
                                                       true /* isNamespaceShared */);
diff --git a/core/java/com/android/internal/policy/EmergencyAffordanceManager.java b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
new file mode 100644
index 0000000..bed7c1ba
--- /dev/null
+++ b/core/java/com/android/internal/policy/EmergencyAffordanceManager.java
@@ -0,0 +1,101 @@
+/*
+ * 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 com.android.internal.policy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.Settings;
+
+/**
+ * A class that manages emergency affordances and enables immediate calling to emergency services
+ */
+public class EmergencyAffordanceManager {
+
+    public static final boolean ENABLED = true;
+
+    /**
+     * Global setting override with the number to call with the emergency affordance.
+     * @hide
+     */
+    private static final String EMERGENCY_CALL_NUMBER_SETTING = "emergency_affordance_number";
+
+    /**
+     * Global setting, whether the emergency affordance should be shown regardless of device state.
+     * The value is a boolean (1 or 0).
+     * @hide
+     */
+    private static final String FORCE_EMERGENCY_AFFORDANCE_SETTING = "force_emergency_affordance";
+
+    private final Context mContext;
+
+    public EmergencyAffordanceManager(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * perform an emergency call.
+     */
+    public final void performEmergencyCall() {
+        performEmergencyCall(mContext);
+    }
+
+    private static Uri getPhoneUri(Context context) {
+        String number = context.getResources().getString(
+                com.android.internal.R.string.config_emergency_call_number);
+        if (Build.IS_DEBUGGABLE) {
+            String override = Settings.Global.getString(
+                    context.getContentResolver(), EMERGENCY_CALL_NUMBER_SETTING);
+            if (override != null) {
+                number = override;
+            }
+        }
+        return Uri.fromParts("tel", number, null);
+    }
+
+    private static void performEmergencyCall(Context context) {
+        Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
+        intent.setData(getPhoneUri(context));
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+    }
+
+    /**
+     * @return whether emergency affordance should be active.
+     */
+    public boolean needsEmergencyAffordance() {
+        if (!ENABLED) {
+            return false;
+        }
+        if (forceShowing()) {
+            return true;
+        }
+        return isEmergencyAffordanceNeeded();
+    }
+
+    private boolean isEmergencyAffordanceNeeded() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.EMERGENCY_AFFORDANCE_NEEDED, 0) != 0;
+    }
+
+
+    private boolean forceShowing() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                FORCE_EMERGENCY_AFFORDANCE_SETTING, 0) != 0;
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 7e1a0ab..bb55610 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -220,6 +220,7 @@
 LOCAL_SHARED_LIBRARIES := \
     libmemtrack \
     libandroidfw \
+    libbase \
     libexpat \
     libnativehelper \
     liblog \
diff --git a/core/jni/android_app_admin_SecurityLog.cpp b/core/jni/android_app_admin_SecurityLog.cpp
index da47c4c..e8ca793 100644
--- a/core/jni/android_app_admin_SecurityLog.cpp
+++ b/core/jni/android_app_admin_SecurityLog.cpp
@@ -19,7 +19,7 @@
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
-#include "log/logger.h"
+#include <private/android_logger.h>
 
 // The size of the tag number comes out of the payload size.
 #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index e0bfecb..2a46edf 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -15,15 +15,7 @@
  */
 
 #define LOG_TAG "android.os.Debug"
-#include "JNIHelp.h"
-#include "jni.h"
-#include <utils/String8.h>
-#include "utils/misc.h"
-#include "cutils/debugger.h"
-#include <memtrack/memtrack.h>
-#include <memunreachable/memunreachable.h>
 
-#include <cutils/log.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <stdio.h>
@@ -40,9 +32,26 @@
 #include <iomanip>
 #include <string>
 
+#include "jni.h"
+
+#include "android-base/stringprintf.h"
+#include "cutils/debugger.h"
+#include "cutils/log.h"
+#include "JNIHelp.h"
+#include "memtrack/memtrack.h"
+#include "memunreachable/memunreachable.h"
+#include "utils/misc.h"
+#include "utils/String8.h"
+
 namespace android
 {
 
+using UniqueFile = std::unique_ptr<FILE, decltype(&fclose)>;
+
+static inline UniqueFile MakeUniqueFile(const char* path, const char* mode) {
+    return UniqueFile(fopen(path, mode), fclose);
+}
+
 enum {
     HEAP_UNKNOWN,
     HEAP_DALVIK,
@@ -427,15 +436,13 @@
 
 static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
 {
-    char tmp[128];
-    FILE *fp;
+    *foundSwapPss = false;
 
-    sprintf(tmp, "/proc/%d/smaps", pid);
-    fp = fopen(tmp, "r");
-    if (fp == 0) return;
+    std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
+    UniqueFile fp = MakeUniqueFile(smaps_path.c_str(), "re");
+    if (fp == nullptr) return;
 
-    read_mapinfo(fp, stats, foundSwapPss);
-    fclose(fp);
+    read_mapinfo(fp.get(), stats, foundSwapPss);
 }
 
 static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
@@ -517,51 +524,48 @@
     jlong uss = 0;
     jlong memtrack = 0;
 
-    char tmp[128];
-    FILE *fp;
-
     struct graphics_memory_pss graphics_mem;
     if (read_memtrack_memory(pid, &graphics_mem) == 0) {
         pss = uss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
     }
 
-    sprintf(tmp, "/proc/%d/smaps", pid);
-    fp = fopen(tmp, "r");
+    {
+        std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
+        UniqueFile fp = MakeUniqueFile(smaps_path.c_str(), "re");
 
-    if (fp != 0) {
-        while (true) {
-            if (fgets(line, 1024, fp) == NULL) {
-                break;
-            }
+        if (fp != nullptr) {
+            while (true) {
+                if (fgets(line, 1024, fp.get()) == NULL) {
+                    break;
+                }
 
-            if (line[0] == 'P') {
-                if (strncmp(line, "Pss:", 4) == 0) {
-                    char* c = line + 4;
+                if (line[0] == 'P') {
+                    if (strncmp(line, "Pss:", 4) == 0) {
+                        char* c = line + 4;
+                        while (*c != 0 && (*c < '0' || *c > '9')) {
+                            c++;
+                        }
+                        pss += atoi(c);
+                    } else if (strncmp(line, "Private_Clean:", 14) == 0
+                                || strncmp(line, "Private_Dirty:", 14) == 0) {
+                        char* c = line + 14;
+                        while (*c != 0 && (*c < '0' || *c > '9')) {
+                            c++;
+                        }
+                        uss += atoi(c);
+                    }
+                } else if (line[0] == 'S' && strncmp(line, "SwapPss:", 8) == 0) {
+                    char* c = line + 8;
+                    jlong lSwapPss;
                     while (*c != 0 && (*c < '0' || *c > '9')) {
                         c++;
                     }
-                    pss += atoi(c);
-                } else if (strncmp(line, "Private_Clean:", 14) == 0
-                        || strncmp(line, "Private_Dirty:", 14) == 0) {
-                    char* c = line + 14;
-                    while (*c != 0 && (*c < '0' || *c > '9')) {
-                        c++;
-                    }
-                    uss += atoi(c);
+                    lSwapPss = atoi(c);
+                    swapPss += lSwapPss;
+                    pss += lSwapPss; // Also in swap, those pages would be accounted as Pss without SWAP
                 }
-            } else if (line[0] == 'S' && strncmp(line, "SwapPss:", 8) == 0) {
-                char* c = line + 8;
-                jlong lSwapPss;
-                while (*c != 0 && (*c < '0' || *c > '9')) {
-                    c++;
-                }
-                lSwapPss = atoi(c);
-                swapPss += lSwapPss;
-                pss += lSwapPss; // Also in swap, those pages would be accounted as Pss without SWAP
             }
         }
-
-        fclose(fp);
     }
 
     if (outUssSwapPss != NULL) {
@@ -605,12 +609,14 @@
             NULL
     };
     long size, vmalloc_allocated_size = 0;
-    FILE* fp = fopen("/proc/vmallocinfo", "r");
-    if (fp == NULL) {
+
+    UniqueFile fp = MakeUniqueFile("/proc/vmallocinfo", "re");
+    if (fp == nullptr) {
         return 0;
     }
+
     while (true) {
-        if (fgets(line, 1024, fp) == NULL) {
+        if (fgets(line, 1024, fp.get()) == NULL) {
             break;
         }
         bool valid_line = true;
@@ -626,7 +632,6 @@
             vmalloc_allocated_size += size;
         }
     }
-    fclose(fp);
     return vmalloc_allocated_size;
 }
 
@@ -650,27 +655,25 @@
 static long long get_zram_mem_used()
 {
 #define ZRAM_SYSFS "/sys/block/zram0/"
-    FILE *f = fopen(ZRAM_SYSFS "mm_stat", "r");
-    if (f) {
+    UniqueFile mm_stat_file = MakeUniqueFile(ZRAM_SYSFS "mm_stat", "re");
+    if (mm_stat_file) {
         long long mem_used_total = 0;
 
-        int matched = fscanf(f, "%*d %*d %lld %*d %*d %*d %*d", &mem_used_total);
+        int matched = fscanf(mm_stat_file.get(), "%*d %*d %lld %*d %*d %*d %*d", &mem_used_total);
         if (matched != 1)
             ALOGW("failed to parse " ZRAM_SYSFS "mm_stat");
 
-        fclose(f);
         return mem_used_total;
     }
 
-    f = fopen(ZRAM_SYSFS "mem_used_total", "r");
-    if (f) {
+    UniqueFile mem_used_total_file = MakeUniqueFile(ZRAM_SYSFS "mem_used_total", "re");
+    if (mem_used_total_file) {
         long long mem_used_total = 0;
 
-        int matched = fscanf(f, "%lld", &mem_used_total);
+        int matched = fscanf(mem_used_total_file.get(), "%lld", &mem_used_total);
         if (matched != 1)
             ALOGW("failed to parse " ZRAM_SYSFS "mem_used_total");
 
-        fclose(f);
         return mem_used_total;
     }
 
@@ -783,8 +786,8 @@
 
 static jint read_binder_stat(const char* stat)
 {
-    FILE* fp = fopen(BINDER_STATS, "r");
-    if (fp == NULL) {
+    UniqueFile fp = MakeUniqueFile(BINDER_STATS, "re");
+    if (fp == nullptr) {
         return -1;
     }
 
@@ -795,8 +798,7 @@
 
     // loop until we have the block that represents this process
     do {
-        if (fgets(line, 1024, fp) == 0) {
-            fclose(fp);
+        if (fgets(line, 1024, fp.get()) == 0) {
             return -1;
         }
     } while (strncmp(compare, line, len));
@@ -805,8 +807,7 @@
     len = snprintf(compare, 128, "  %s: ", stat);
 
     do {
-        if (fgets(line, 1024, fp) == 0) {
-            fclose(fp);
+        if (fgets(line, 1024, fp.get()) == 0) {
             return -1;
         }
     } while (strncmp(compare, line, len));
@@ -814,7 +815,6 @@
     // we have the line, now increment the line ptr to the value
     char* ptr = line + len;
     jint result = atoi(ptr);
-    fclose(fp);
     return result;
 }
 
@@ -839,7 +839,8 @@
     size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
 extern "C" void free_malloc_leak_info(uint8_t* info);
 #define SIZE_FLAG_ZYGOTE_CHILD  (1<<31)
-#define BACKTRACE_SIZE          32
+
+static size_t gNumBacktraceElements;
 
 /*
  * This is a qsort() callback.
@@ -859,11 +860,11 @@
         return -1;
     }
 
-    intptr_t* bt1 = (intptr_t*)(rec1 + 2);
-    intptr_t* bt2 = (intptr_t*)(rec2 + 2);
-    for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) {
-        intptr_t addr1 = bt1[idx];
-        intptr_t addr2 = bt2[idx];
+    uintptr_t* bt1 = (uintptr_t*)(rec1 + 2);
+    uintptr_t* bt2 = (uintptr_t*)(rec2 + 2);
+    for (size_t idx = 0; idx < gNumBacktraceElements; idx++) {
+        uintptr_t addr1 = bt1[idx];
+        uintptr_t addr2 = bt2[idx];
         if (addr1 == addr2) {
             if (addr1 == 0)
                 break;
@@ -907,9 +908,10 @@
     if (info == NULL) {
         fprintf(fp, "Native heap dump not available. To enable, run these"
                     " commands (requires root):\n");
-        fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n");
-        fprintf(fp, "$ adb shell stop\n");
-        fprintf(fp, "$ adb shell start\n");
+        fprintf(fp, "# adb shell stop\n");
+        fprintf(fp, "# adb shell setprop libc.debug.malloc.options "
+                    "backtrace\n");
+        fprintf(fp, "# adb shell start\n");
         return;
     }
     assert(infoSize != 0);
@@ -920,13 +922,11 @@
     size_t recordCount = overallSize / infoSize;
     fprintf(fp, "Total memory: %zu\n", totalMemory);
     fprintf(fp, "Allocation records: %zd\n", recordCount);
-    if (backtraceSize != BACKTRACE_SIZE) {
-        fprintf(fp, "WARNING: mismatched backtrace sizes (%zu vs. %d)\n",
-            backtraceSize, BACKTRACE_SIZE);
-    }
+    fprintf(fp, "Backtrace size: %zd\n", backtraceSize);
     fprintf(fp, "\n");
 
     /* re-sort the entries */
+    gNumBacktraceElements = backtraceSize;
     qsort(info, recordCount, infoSize, compareHeapRecords);
 
     /* dump the entries to the file */
@@ -934,7 +934,7 @@
     for (size_t idx = 0; idx < recordCount; idx++) {
         size_t size = *(size_t*) ptr;
         size_t allocations = *(size_t*) (ptr + sizeof(size_t));
-        intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2);
+        uintptr_t* backtrace = (uintptr_t*) (ptr + sizeof(size_t) * 2);
 
         fprintf(fp, "z %d  sz %8zu  num %4zu  bt",
                 (size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
@@ -960,16 +960,15 @@
 
     fprintf(fp, "MAPS\n");
     const char* maps = "/proc/self/maps";
-    FILE* in = fopen(maps, "r");
-    if (in == NULL) {
+    UniqueFile in = MakeUniqueFile(maps, "re");
+    if (in == nullptr) {
         fprintf(fp, "Could not open %s\n", maps);
         return;
     }
     char buf[BUFSIZ];
-    while (size_t n = fread(buf, sizeof(char), BUFSIZ, in)) {
+    while (size_t n = fread(buf, sizeof(char), BUFSIZ, in.get())) {
         fwrite(buf, sizeof(char), n, fp);
     }
-    fclose(in);
 
     fprintf(fp, "END\n");
 }
@@ -999,8 +998,8 @@
         return;
     }
 
-    FILE* fp = fdopen(fd, "w");
-    if (fp == NULL) {
+    UniqueFile fp(fdopen(fd, "w"), fclose);
+    if (fp == nullptr) {
         ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
         close(fd);
         jniThrowRuntimeException(env, "fdopen() failed");
@@ -1008,10 +1007,8 @@
     }
 
     ALOGD("Native heap dump starting...\n");
-    dumpNativeHeap(fp);
+    dumpNativeHeap(fp.get());
     ALOGD("Native heap dump complete.\n");
-
-    fclose(fp);
 }
 
 
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 7da0314..13e3f0d 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -266,6 +266,9 @@
         return NULL;
     }
 
+    LOG(INFO) << "Starting thread pool.";
+    ::android::hardware::ProcessState::self()->startThreadPool();
+
     return JHwRemoteBinder::NewObject(env, service);
 }
 
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 4f8a2cb..173afd8 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -19,7 +19,7 @@
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
-#include "log/logger.h"
+#include <log/logger.h>
 
 #define UNUSED  __attribute__((__unused__))
 
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 4fc546c..b0028e1 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -573,8 +573,9 @@
                 bounds.roundOut();
             }
 
+            incStrong(0);
             auto functor = std::bind(
-                std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePosition), this,
+                std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePositionAsync), this,
                 (jlong) info.canvasContext.getFrameNumber(),
                 (jint) bounds.left, (jint) bounds.top,
                 (jint) bounds.right, (jint) bounds.bottom);
@@ -585,15 +586,18 @@
         virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override {
             if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return;
 
-            if (info) {
-                auto functor = std::bind(
-                    std::mem_fn(&SurfaceViewPositionUpdater::doNotifyPositionLost), this,
-                    (jlong) info->canvasContext.getFrameNumber());
-
-                info->canvasContext.enqueueFrameWork(std::move(functor));
-            } else {
-                doNotifyPositionLost(0);
+            ATRACE_NAME("SurfaceView position lost");
+            JNIEnv* env = jnienv();
+            jobject localref = env->NewLocalRef(mWeakRef);
+            if (CC_UNLIKELY(!localref)) {
+                jnienv()->DeleteWeakGlobalRef(mWeakRef);
+                mWeakRef = nullptr;
+                return;
             }
+
+            env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod,
+                    info ? info->canvasContext.getFrameNumber() : 0);
+            env->DeleteLocalRef(localref);
         }
 
     private:
@@ -605,36 +609,23 @@
             return env;
         }
 
-        void doUpdatePosition(jlong frameNumber, jint left, jint top,
+        void doUpdatePositionAsync(jlong frameNumber, jint left, jint top,
                 jint right, jint bottom) {
             ATRACE_NAME("Update SurfaceView position");
 
             JNIEnv* env = jnienv();
             jobject localref = env->NewLocalRef(mWeakRef);
             if (CC_UNLIKELY(!localref)) {
-                jnienv()->DeleteWeakGlobalRef(mWeakRef);
+                env->DeleteWeakGlobalRef(mWeakRef);
                 mWeakRef = nullptr;
-                return;
+            } else {
+                env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
+                        frameNumber, left, top, right, bottom);
+                env->DeleteLocalRef(localref);
             }
 
-            env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
-                    frameNumber, left, top, right, bottom);
-            env->DeleteLocalRef(localref);
-        }
-
-        void doNotifyPositionLost(jlong frameNumber) {
-            ATRACE_NAME("SurfaceView position lost");
-
-            JNIEnv* env = jnienv();
-            jobject localref = env->NewLocalRef(mWeakRef);
-            if (CC_UNLIKELY(!localref)) {
-                jnienv()->DeleteWeakGlobalRef(mWeakRef);
-                mWeakRef = nullptr;
-                return;
-            }
-
-            env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod, frameNumber);
-            env->DeleteLocalRef(localref);
+            // We need to release ourselves here
+            decStrong(0);
         }
 
         JavaVM* mVm;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b0b57d9..372dc7f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -148,6 +148,8 @@
     <protected-broadcast
         android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
     <protected-broadcast
+        android:name="android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED" />
+    <protected-broadcast
         android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast
         android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
@@ -289,6 +291,7 @@
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
+    <protected-broadcast android:name="android.net.wifi.nan.action.WIFI_NAN_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
     <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.STATE_CHANGE" />
diff --git a/core/res/res/drawable/emergency_icon.xml b/core/res/res/drawable/emergency_icon.xml
new file mode 100644
index 0000000..8e460d7
--- /dev/null
+++ b/core/res/res/drawable/emergency_icon.xml
@@ -0,0 +1,34 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24.0dp"
+    android:height="24.0dp"
+    android:viewportWidth="68.0"
+    android:viewportHeight="68.0"
+    android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M55.2,58.3l-6.3,-7.8C54.0,46.3 57.0,40.1 57.0,33.4c0.0,-6.2 -2.6,-12.1 -7.2,-16.3l6.7,-7.4C63.2,15.8 67.0,24.4 67.0,33.4C67.0,43.1 62.7,52.2 55.2,58.3z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.9,58.3C5.3,52.2 1.0,43.1 1.0,33.4c0.0,-9.0 3.8,-17.6 10.5,-23.7l6.7,7.4C13.6,21.3 11.0,27.2 11.0,33.4c0.0,6.7 3.0,12.9 8.2,17.1L12.9,58.3z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M29.0,11.4l10.0,0.0l0.0,29.0l-10.0,0.0z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M29.0,48.4l10.0,0.0l0.0,9.0l-10.0,0.0z"/>
+</vector>
diff --git a/core/res/res/values-mcc204-mnc04/config.xml b/core/res/res/values-mcc204-mnc04/config.xml
index 0f39e42..ddf0e9f 100755
--- a/core/res/res/values-mcc204-mnc04/config.xml
+++ b/core/res/res/values-mcc204-mnc04/config.xml
@@ -25,13 +25,6 @@
     -->
     <integer name="config_mobile_mtu">1358</integer>
 
-    <!-- service number convert map in roaming network. -->
-    <!-- [dialstring],[replacement][,optional gid] -->
-    <string-array translatable="false" name="dial_string_replace">
-        <item>"*611:+19085594899,BAE0000000000000"</item>
-        <item>"*86:+1MDN,BAE0000000000000"</item>
-    </string-array>
-
     <!-- Flag indicating whether strict threshold is used, or lenient threshold is used,
           when evaluating RSRP for LTE antenna bar display
            0. Strict threshold
diff --git a/core/res/res/values-mcc238-mnc06/config.xml b/core/res/res/values-mcc238-mnc06/config.xml
deleted file mode 100644
index afc0cc4..0000000
--- a/core/res/res/values-mcc238-mnc06/config.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- SIM does not save, but the voice mail number to be changed. -->
-    <bool name="editable_voicemailnumber">true</bool>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml
index 4b61688..413c698 100644
--- a/core/res/res/values-mcc310-mnc120/config.xml
+++ b/core/res/res/values-mcc310-mnc120/config.xml
@@ -25,9 +25,6 @@
     -->
     <integer name="config_mobile_mtu">1422</integer>
 
-    <!-- Sprint need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">70</integer>
-
     <!-- If this value is true, The mms content-disposition field is supported correctly.
          If false, Content-disposition fragments are ignored -->
     <bool name="config_mms_content_disposition_support">false</bool>
diff --git a/core/res/res/values-mcc310-mnc160/config.xml b/core/res/res/values-mcc310-mnc160/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc160/config.xml
+++ b/core/res/res/values-mcc310-mnc160/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc200/config.xml b/core/res/res/values-mcc310-mnc200/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc200/config.xml
+++ b/core/res/res/values-mcc310-mnc200/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc210/config.xml b/core/res/res/values-mcc310-mnc210/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc210/config.xml
+++ b/core/res/res/values-mcc310-mnc210/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc220/config.xml b/core/res/res/values-mcc310-mnc220/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc220/config.xml
+++ b/core/res/res/values-mcc310-mnc220/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc230/config.xml b/core/res/res/values-mcc310-mnc230/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc230/config.xml
+++ b/core/res/res/values-mcc310-mnc230/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc240/config.xml b/core/res/res/values-mcc310-mnc240/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc240/config.xml
+++ b/core/res/res/values-mcc310-mnc240/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc250/config.xml b/core/res/res/values-mcc310-mnc250/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc250/config.xml
+++ b/core/res/res/values-mcc310-mnc250/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc270/config.xml b/core/res/res/values-mcc310-mnc270/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc270/config.xml
+++ b/core/res/res/values-mcc310-mnc270/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc300/config.xml b/core/res/res/values-mcc310-mnc300/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc300/config.xml
+++ b/core/res/res/values-mcc310-mnc300/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc310/config.xml b/core/res/res/values-mcc310-mnc310/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc310/config.xml
+++ b/core/res/res/values-mcc310-mnc310/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc490/config.xml b/core/res/res/values-mcc310-mnc490/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc490/config.xml
+++ b/core/res/res/values-mcc310-mnc490/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc530/config.xml b/core/res/res/values-mcc310-mnc530/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc530/config.xml
+++ b/core/res/res/values-mcc310-mnc530/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc580/config.xml b/core/res/res/values-mcc310-mnc580/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc580/config.xml
+++ b/core/res/res/values-mcc310-mnc580/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc590/config.xml b/core/res/res/values-mcc310-mnc590/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc590/config.xml
+++ b/core/res/res/values-mcc310-mnc590/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc640/config.xml b/core/res/res/values-mcc310-mnc640/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc640/config.xml
+++ b/core/res/res/values-mcc310-mnc640/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc660/config.xml b/core/res/res/values-mcc310-mnc660/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc660/config.xml
+++ b/core/res/res/values-mcc310-mnc660/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc800/config.xml b/core/res/res/values-mcc310-mnc800/config.xml
index 2cae7cc..5a6a84b 100644
--- a/core/res/res/values-mcc310-mnc800/config.xml
+++ b/core/res/res/values-mcc310-mnc800/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Flag specifying whether VoLTE TTY is supported -->
     <bool name="config_carrier_volte_tty_supported">false</bool>
-
-    <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
-         carrier provisioning. If false: hard disabled. If true: then depends on carrier
-         provisioning, availability etc -->
-    <bool name="config_carrier_wfc_ims_available">true</bool>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc220/config.xml b/core/res/res/values-mcc311-mnc220/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc220/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc221/config.xml b/core/res/res/values-mcc311-mnc221/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc221/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc222/config.xml b/core/res/res/values-mcc311-mnc222/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc222/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc223/config.xml b/core/res/res/values-mcc311-mnc223/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc223/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc224/config.xml b/core/res/res/values-mcc311-mnc224/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc224/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc225/config.xml b/core/res/res/values-mcc311-mnc225/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc225/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc226/config.xml b/core/res/res/values-mcc311-mnc226/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc226/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc227/config.xml b/core/res/res/values-mcc311-mnc227/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc227/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc228/config.xml b/core/res/res/values-mcc311-mnc228/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc228/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc229/config.xml b/core/res/res/values-mcc311-mnc229/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc229/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 39ea2bf..8d7fd61 100755
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -52,11 +52,6 @@
     <bool name="config_carrier_volte_provisioned">true</bool>
 
     <bool name="config_auto_attach_data_on_creation">false</bool>
-    <!-- service number convert map in roaming network. -->
-    <string-array translatable="false" name="dial_string_replace">
-        <item>"*611:+19085594899,"</item>
-        <item>"*86:+1MDN,"</item>
-    </string-array>
 
     <!-- Flag indicating whether strict threshold is used, or lenient threshold is used,
           when evaluating RSRP for LTE antenna bar display
diff --git a/core/res/res/values-mcc311-mnc490/config.xml b/core/res/res/values-mcc311-mnc490/config.xml
index d481c97..836abdf 100644
--- a/core/res/res/values-mcc311-mnc490/config.xml
+++ b/core/res/res/values-mcc311-mnc490/config.xml
@@ -21,9 +21,6 @@
      for different hardware and product builds. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Sprint need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">70</integer>
-
     <!-- An array of CDMA roaming indicators which means international roaming -->
     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" >
         <item>2</item>
diff --git a/core/res/res/values-mcc311-mnc580/config.xml b/core/res/res/values-mcc311-mnc580/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc580/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc581/config.xml b/core/res/res/values-mcc311-mnc581/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc581/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc582/config.xml b/core/res/res/values-mcc311-mnc582/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc582/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc583/config.xml b/core/res/res/values-mcc311-mnc583/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc583/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc584/config.xml b/core/res/res/values-mcc311-mnc584/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc584/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc585/config.xml b/core/res/res/values-mcc311-mnc585/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc585/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc586/config.xml b/core/res/res/values-mcc311-mnc586/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc586/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc587/config.xml b/core/res/res/values-mcc311-mnc587/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc587/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc588/config.xml b/core/res/res/values-mcc311-mnc588/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc588/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc589/config.xml b/core/res/res/values-mcc311-mnc589/config.xml
deleted file mode 100644
index 811e9c7..0000000
--- a/core/res/res/values-mcc311-mnc589/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- USC need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">300</integer>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc870/config.xml b/core/res/res/values-mcc311-mnc870/config.xml
index 98cb72e..f6aed13 100644
--- a/core/res/res/values-mcc311-mnc870/config.xml
+++ b/core/res/res/values-mcc311-mnc870/config.xml
@@ -25,9 +25,6 @@
     -->
     <integer name="config_mobile_mtu">1422</integer>
 
-    <!-- Sprint need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">70</integer>
-
     <!-- An array of CDMA roaming indicators which means international roaming -->
     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" >
         <item>2</item>
diff --git a/core/res/res/values-mcc312-mnc530/config.xml b/core/res/res/values-mcc312-mnc530/config.xml
index 98cb72e..f6aed13 100644
--- a/core/res/res/values-mcc312-mnc530/config.xml
+++ b/core/res/res/values-mcc312-mnc530/config.xml
@@ -25,9 +25,6 @@
     -->
     <integer name="config_mobile_mtu">1422</integer>
 
-    <!-- Sprint need a 70 ms delay for 3way call -->
-    <integer name="config_cdma_3waycall_flash_delay">70</integer>
-
     <!-- An array of CDMA roaming indicators which means international roaming -->
     <integer-array translatable="false" name="config_cdma_international_roaming_indicators" >
         <item>2</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 44cbc0f..587bc55 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2212,6 +2212,21 @@
     <!-- Sprint need a 70 ms delay for 3way call -->
     <integer name="config_cdma_3waycall_flash_delay">0</integer>
 
+    <!-- If there is no preload VM number in the sim card, carriers such as
+         Verizon require to load a default vm number from the configurantion.
+         Define config_default_vm_number for this purpose. And there are two
+         optional formats for this configuration as below:
+         (1)<item>voicemail number</item>
+         (2)<item>voicemail number;gid</item>
+         The logic to pick up the correct voicemail number:
+         (1) If the config_default_vm_number array has no gid special item, the last one will be
+         picked
+         (2) If the config_default_vm_number array has gid special item and  it matches the current
+         sim's gid, it will be picked.
+         (3) If the config_default_vm_number array has gid special item but it doesn't match the
+         current sim's gid, the last one without gid will be picked -->
+    <string-array translatable="false" name="config_default_vm_number" />
+
     <!--SIM does not save, but the voice mail number to be changed. -->
     <bool name="editable_voicemailnumber">false</bool>
 
@@ -2220,6 +2235,10 @@
     <string-array translatable="false" name="dial_string_replace">
     </string-array>
 
+    <!-- Flag indicating whether radio is to be restarted on the error of
+         PDP_FAIL_REGULAR_DEACTIVATION/0x24 -->
+    <bool name="config_restart_radio_on_pdp_fail_regular_deactivation">false</bool>
+
     <!-- networks that don't want data deactivate when shutdown the phone
          note this is dependent on the operator of the network we're on,
          not operator on the SIM -->
@@ -2488,4 +2507,14 @@
     <string-array translatable="false" name="config_defaultPinnerServiceFiles">
     </string-array>
 
+    <!-- emergency call number for the emergency affordance -->
+    <string name="config_emergency_call_number" translatable="false">112</string>
+
+    <!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
+         affordances-->
+    <integer-array name="config_emergency_mcc_codes" translatable="false">
+        <item>404</item>
+        <item>405</item>
+    </integer-array>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b55a9b22..ceb79ed 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -482,6 +482,9 @@
     <!-- label for item that turns off power in phone options dialog -->
     <string name="global_action_power_off">Power off</string>
 
+    <!-- label for item that starts emergency call -->
+    <string name="global_action_emergency">Emergency</string>
+
     <!-- label for item that generates a bug report in the phone options dialog -->
     <string name="global_action_bug_report">Bug report</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 206a910..6877624 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -345,8 +345,6 @@
   <java-symbol type="integer"  name="config_wifi_operating_voltage_mv" />
   <java-symbol type="string"  name="config_wifi_framework_sap_2G_channel_list" />
 
-  <java-symbol type="bool" name="editable_voicemailnumber" />
-
   <java-symbol type="bool" name="config_wifi_framework_cellular_handover_enable_user_triggered_adjustment" />
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_tx_packet_threshold" />
   <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_rx_packet_threshold" />
@@ -2237,9 +2235,11 @@
   <java-symbol type="layout" name="resolver_different_item_header" />
   <java-symbol type="array" name="config_default_vm_number" />
   <java-symbol type="integer" name="config_cdma_3waycall_flash_delay"/>
+  <java-symbol type="array" name="config_default_vm_number" />
   <java-symbol type="attr" name="windowBackgroundFallback" />
   <java-symbol type="id" name="textSpacerNoButtons" />
   <java-symbol type="array" name="dial_string_replace" />
+  <java-symbol type="bool" name="config_restart_radio_on_pdp_fail_regular_deactivation" />
   <java-symbol type="array" name="networks_not_clear_data" />
   <java-symbol type="bool" name="config_switch_phone_on_voice_reg_state_change" />
   <java-symbol type="string" name="whichHomeApplicationNamed" />
@@ -2612,4 +2612,9 @@
 
   <java-symbol type="layout" name="unsupported_display_size_dialog_content" />
   <java-symbol type="string" name="unsupported_display_size_message" />
+  <java-symbol type="string" name="global_action_emergency" />
+  <java-symbol type="string" name="config_emergency_call_number" />
+  <java-symbol type="array" name="config_emergency_mcc_codes" />
+
+  <java-symbol type="drawable" name="emergency_icon" />
 </resources>
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
index 88c7d1b..efb78d7 100644
--- a/core/tests/coretests/src/com/android/internal/os/DebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -64,4 +64,12 @@
     public void testGetCallers() {
         assertTrue(callDepth1().matches(EXPECTED_GET_CALLERS));
     }
+
+    /**
+     * Regression test for b/31943543. Note: must be run under CheckJNI to detect the issue.
+     */
+    public void testGetMemoryInfo() {
+        Debug.MemoryInfo info = new Debug.MemoryInfo();
+        Debug.getMemoryInfo(-1, info);
+    }
 }
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index ffc1282..e16c367 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -11,7 +11,6 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
 LOCAL_JAVA_LIBRARIES := android.test.runner
 LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 
 LOCAL_CERTIFICATE := platform
 
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index f50cff4..8ea25d6 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -1892,6 +1892,7 @@
 
 Asset* AssetManager::SharedZip::getResourceTableAsset()
 {
+    AutoMutex _l(gLock);
     ALOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
     return mResourceTableAsset;
 }
@@ -1901,10 +1902,10 @@
     {
         AutoMutex _l(gLock);
         if (mResourceTableAsset == NULL) {
-            mResourceTableAsset = asset;
             // This is not thread safe the first time it is called, so
             // do it here with the global lock held.
             asset->getBuffer(true);
+            mResourceTableAsset = asset;
             return asset;
         }
     }
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 1eaf5d6..f9735a2 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -232,7 +232,7 @@
     // the frameNumber to appropriately batch/synchronize these transactions.
     // There is no other filtering/batching to ensure that only the "final"
     // state called once per frame.
-    class ANDROID_API PositionListener {
+    class ANDROID_API PositionListener : public VirtualLightRefBase {
     public:
         virtual ~PositionListener() {}
         // Called when the RenderNode's position changes
@@ -247,7 +247,7 @@
     // before the RenderNode is used for drawing.
     // RenderNode takes ownership of the pointer
     ANDROID_API void setPositionListener(PositionListener* listener) {
-        mPositionListener.reset(listener);
+        mPositionListener = listener;
     }
 
     // This is only modified in MODE_FULL, so it can be safely accessed
@@ -366,7 +366,7 @@
     // mDisplayList, not mStagingDisplayList.
     uint32_t mParentCount;
 
-    std::unique_ptr<PositionListener> mPositionListener;
+    sp<PositionListener> mPositionListener;
 }; // class RenderNode
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c626c54..75e7fdf 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -783,6 +783,7 @@
     }
     sp<FuncTask> task(new FuncTask());
     task->func = func;
+    mFrameFences.push_back(task);
     mFrameWorkProcessor->add(task);
 }
 
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index c0c47ef..d68bb53 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -31,7 +31,7 @@
 struct AMessage;
 struct AString;
 struct ICrypto;
-struct IGraphicBufferProducer;
+class IGraphicBufferProducer;
 struct MediaCodec;
 struct PersistentSurface;
 class Surface;
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 7e438a1..29557be 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -7,8 +7,6 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
-
 LOCAL_STATIC_JAVA_LIBRARIES := easymocklib \
     mockito-target \
     android-support-test \
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 8d41145..7256843 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -28,13 +28,16 @@
 import android.telecom.TelecomManager;
 import android.util.AttributeSet;
 import android.util.Slog;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.widget.Button;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.policy.EmergencyAffordanceManager;
 
 /**
  * This class implements a smart emergency button that updates itself based
@@ -51,7 +54,10 @@
                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
 
     private static final String LOG_TAG = "EmergencyButton";
+    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
 
+    private int mDownX;
+    private int mDownY;
     KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
@@ -64,6 +70,7 @@
             updateEmergencyCallButton();
         }
     };
+    private boolean mLongPressWasDragged;
 
     public interface EmergencyButtonCallback {
         public void onEmergencyButtonClickedWhenInCall();
@@ -86,6 +93,7 @@
                 com.android.internal.R.bool.config_voice_capable);
         mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
+        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
     }
 
     @Override
@@ -110,10 +118,40 @@
                 takeEmergencyCallAction();
             }
         });
+        setOnLongClickListener(new OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                if (!mLongPressWasDragged
+                        && mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+                    mEmergencyAffordanceManager.performEmergencyCall();
+                    return true;
+                }
+                return false;
+            }
+        });
         updateEmergencyCallButton();
     }
 
     @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            mDownX = x;
+            mDownY = y;
+            mLongPressWasDragged = false;
+        } else {
+            final int xDiff = Math.abs(x - mDownX);
+            final int yDiff = Math.abs(y - mDownY);
+            int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+            if (Math.abs(yDiff) > touchSlop || Math.abs(xDiff) > touchSlop) {
+                mLongPressWasDragged = true;
+            }
+        }
+        return super.onTouchEvent(event);
+    }
+
+    @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         updateEmergencyCallButton();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index a7e4e12..61e2fc0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -173,6 +173,7 @@
         final AlertDialog dialog = new AlertDialog.Builder(mContext)
             .setTitle(title)
             .setMessage(message)
+            .setCancelable(false)
             .setNeutralButton(R.string.ok, null)
             .create();
         if (!(mContext instanceof Activity)) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index c075703..281f1db 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -102,9 +102,6 @@
     private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
     private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
 
-    /** Auto-connect after pairing only if locally initiated. */
-    private boolean mConnectAfterPairing;
-
     /**
      * Describes the current device and profile for logging.
      *
@@ -300,7 +297,6 @@
             return false;
         }
 
-        mConnectAfterPairing = true;  // auto-connect after pairing
         return true;
     }
 
@@ -309,7 +305,7 @@
      * slightly different for local vs. remote initiated pairing dialogs.
      */
     boolean isUserInitiatedPairing() {
-        return mConnectAfterPairing;
+        return mDevice.isBondingInitiatedLocally();
     }
 
     public void unpair() {
@@ -549,7 +545,6 @@
     void onBondingStateChanged(int bondState) {
         if (bondState == BluetoothDevice.BOND_NONE) {
             mProfiles.clear();
-            mConnectAfterPairing = false;  // cancel auto-connect
             setPhonebookPermissionChoice(ACCESS_UNKNOWN);
             setMessagePermissionChoice(ACCESS_UNKNOWN);
             setSimPermissionChoice(ACCESS_UNKNOWN);
@@ -562,10 +557,9 @@
         if (bondState == BluetoothDevice.BOND_BONDED) {
             if (mDevice.isBluetoothDock()) {
                 onBondingDockConnect();
-            } else if (mConnectAfterPairing) {
+            } else if (mDevice.isBondingInitiatedLocally()) {
                 connect(false);
             }
-            mConnectAfterPairing = false;
         }
     }
 
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 0658620..bf3681b 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -28,7 +28,7 @@
     frameworks/base/libs/hwui \
     $(rs_generated_include_dir)
 
-LOCAL_CFLAGS += -Wno-unused-parameter -std=c++11
+LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 06c4350..af370ff 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -644,7 +644,7 @@
     in_allocs[2] = (RsAllocation)C;
 
     rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                         in_allocs, sizeof(in_allocs), nullptr,
+                         in_allocs, NELEM(in_allocs), nullptr,
                          &call, sizeof(call), nullptr, 0);
 }
 
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
index 276687f..3c8c699 100644
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -21,6 +21,7 @@
 import android.net.LocalSocketAddress;
 import android.os.IRecoverySystem;
 import android.os.IRecoverySystemProgressListener;
+import android.os.PowerManager;
 import android.os.RecoverySystem;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -50,8 +51,15 @@
     // The socket at /dev/socket/uncrypt to communicate with uncrypt.
     private static final String UNCRYPT_SOCKET = "uncrypt";
 
+    // The init services that communicate with /system/bin/uncrypt.
+    private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
+    private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
+    private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
+
     private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
 
+    private static final Object sRequestLock = new Object();
+
     private Context mContext;
 
     public RecoverySystemService(Context context) {
@@ -69,95 +77,155 @@
         public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
             if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
 
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+            synchronized (sRequestLock) {
+                mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
 
-            // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
-            // uncrypt.
-            RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
-
-            try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
-                uncryptFile.write(filename + "\n");
-            } catch (IOException e) {
-                Slog.e(TAG, "IOException when writing \"" + RecoverySystem.UNCRYPT_PACKAGE_FILE +
-                        "\": ", e);
-                return false;
-            }
-
-            // Trigger uncrypt via init.
-            SystemProperties.set("ctl.start", "uncrypt");
-
-            // Connect to the uncrypt service socket.
-            LocalSocket socket = connectService();
-            if (socket == null) {
-                Slog.e(TAG, "Failed to connect to uncrypt socket");
-                return false;
-            }
-
-            // Read the status from the socket.
-            DataInputStream dis = null;
-            DataOutputStream dos = null;
-            try {
-                dis = new DataInputStream(socket.getInputStream());
-                dos = new DataOutputStream(socket.getOutputStream());
-                int lastStatus = Integer.MIN_VALUE;
-                while (true) {
-                    int status = dis.readInt();
-                    // Avoid flooding the log with the same message.
-                    if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
-                        continue;
-                    }
-                    lastStatus = status;
-
-                    if (status >= 0 && status <= 100) {
-                        // Update status
-                        Slog.i(TAG, "uncrypt read status: " + status);
-                        if (listener != null) {
-                            try {
-                                listener.onProgress(status);
-                            } catch (RemoteException ignored) {
-                                Slog.w(TAG, "RemoteException when posting progress");
-                            }
-                        }
-                        if (status == 100) {
-                            Slog.i(TAG, "uncrypt successfully finished.");
-                            // Ack receipt of the final status code. uncrypt
-                            // waits for the ack so the socket won't be
-                            // destroyed before we receive the code.
-                            dos.writeInt(0);
-                            break;
-                        }
-                    } else {
-                        // Error in /system/bin/uncrypt.
-                        Slog.e(TAG, "uncrypt failed with status: " + status);
-                        // Ack receipt of the final status code. uncrypt waits
-                        // for the ack so the socket won't be destroyed before
-                        // we receive the code.
-                        dos.writeInt(0);
-                        return false;
-                    }
+                final boolean available = checkAndWaitForUncryptService();
+                if (!available) {
+                    Slog.e(TAG, "uncrypt service is unavailable.");
+                    return false;
                 }
-            } catch (IOException e) {
-                Slog.e(TAG, "IOException when reading status: ", e);
-                return false;
-            } finally {
-                IoUtils.closeQuietly(dis);
-                IoUtils.closeQuietly(dos);
-                IoUtils.closeQuietly(socket);
-            }
 
-            return true;
+                // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
+                // uncrypt.
+                RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+
+                try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
+                    uncryptFile.write(filename + "\n");
+                } catch (IOException e) {
+                    Slog.e(TAG, "IOException when writing \"" +
+                            RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e);
+                    return false;
+                }
+
+                // Trigger uncrypt via init.
+                SystemProperties.set("ctl.start", "uncrypt");
+
+                // Connect to the uncrypt service socket.
+                LocalSocket socket = connectService();
+                if (socket == null) {
+                    Slog.e(TAG, "Failed to connect to uncrypt socket");
+                    return false;
+                }
+
+                // Read the status from the socket.
+                DataInputStream dis = null;
+                DataOutputStream dos = null;
+                try {
+                    dis = new DataInputStream(socket.getInputStream());
+                    dos = new DataOutputStream(socket.getOutputStream());
+                    int lastStatus = Integer.MIN_VALUE;
+                    while (true) {
+                        int status = dis.readInt();
+                        // Avoid flooding the log with the same message.
+                        if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+                            continue;
+                        }
+                        lastStatus = status;
+
+                        if (status >= 0 && status <= 100) {
+                            // Update status
+                            Slog.i(TAG, "uncrypt read status: " + status);
+                            if (listener != null) {
+                                try {
+                                    listener.onProgress(status);
+                                } catch (RemoteException ignored) {
+                                    Slog.w(TAG, "RemoteException when posting progress");
+                                }
+                            }
+                            if (status == 100) {
+                                Slog.i(TAG, "uncrypt successfully finished.");
+                                // Ack receipt of the final status code. uncrypt
+                                // waits for the ack so the socket won't be
+                                // destroyed before we receive the code.
+                                dos.writeInt(0);
+                                break;
+                            }
+                        } else {
+                            // Error in /system/bin/uncrypt.
+                            Slog.e(TAG, "uncrypt failed with status: " + status);
+                            // Ack receipt of the final status code. uncrypt waits
+                            // for the ack so the socket won't be destroyed before
+                            // we receive the code.
+                            dos.writeInt(0);
+                            return false;
+                        }
+                    }
+                } catch (IOException e) {
+                    Slog.e(TAG, "IOException when reading status: ", e);
+                    return false;
+                } finally {
+                    IoUtils.closeQuietly(dis);
+                    IoUtils.closeQuietly(dos);
+                    IoUtils.closeQuietly(socket);
+                }
+
+                return true;
+            }
         }
 
         @Override // Binder call
         public boolean clearBcb() {
             if (DEBUG) Slog.d(TAG, "clearBcb");
-            return setupOrClearBcb(false, null);
+            synchronized (sRequestLock) {
+                return setupOrClearBcb(false, null);
+            }
         }
 
         @Override // Binder call
         public boolean setupBcb(String command) {
             if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
-            return setupOrClearBcb(true, command);
+            synchronized (sRequestLock) {
+                return setupOrClearBcb(true, command);
+            }
+        }
+
+        @Override // Binder call
+        public void rebootRecoveryWithCommand(String command) {
+            if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
+            synchronized (sRequestLock) {
+                if (!setupOrClearBcb(true, command)) {
+                    return;
+                }
+
+                // Having set up the BCB, go ahead and reboot.
+                PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+                pm.reboot(PowerManager.REBOOT_RECOVERY);
+            }
+        }
+
+        /**
+         * Check if any of the init services is still running. If so, we cannot
+         * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
+         * it may break the socket communication since init creates / deletes
+         * the socket (/dev/socket/uncrypt) on service start / exit.
+         */
+        private boolean checkAndWaitForUncryptService() {
+            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+                final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT);
+                final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB);
+                final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB);
+                final boolean busy = "running".equals(uncryptService) ||
+                        "running".equals(setupBcbService) || "running".equals(clearBcbService);
+                if (DEBUG) {
+                    Slog.i(TAG, "retry: " + retry + " busy: " + busy +
+                            " uncrypt: [" + uncryptService + "]" +
+                            " setupBcb: [" + setupBcbService + "]" +
+                            " clearBcb: [" + clearBcbService + "]");
+                }
+
+                if (!busy) {
+                    return true;
+                }
+
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    Slog.w(TAG, "Interrupted:", e);
+                }
+            }
+
+            return false;
         }
 
         private LocalSocket connectService() {
@@ -176,7 +244,7 @@
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
-                        Slog.w(TAG, "Interrupted: ", e);
+                        Slog.w(TAG, "Interrupted:", e);
                     }
                 }
             }
@@ -190,6 +258,12 @@
         private boolean setupOrClearBcb(boolean isSetup, String command) {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
 
+            final boolean available = checkAndWaitForUncryptService();
+            if (!available) {
+                Slog.e(TAG, "uncrypt service is unavailable.");
+                return false;
+            }
+
             if (isSetup) {
                 SystemProperties.set("ctl.start", "setup-bcb");
             } else {
@@ -232,7 +306,7 @@
                     return false;
                 }
             } catch (IOException e) {
-                Slog.e(TAG, "IOException when communicating with uncrypt: ", e);
+                Slog.e(TAG, "IOException when communicating with uncrypt:", e);
                 return false;
             } finally {
                 IoUtils.closeQuietly(dis);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 74af37f..eb5bf22 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6098,6 +6098,8 @@
                 ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
                 packageName == null ? ("stop user " + userId) : ("stop " + packageName));
 
+        didSomething |= mActivityStarter.clearPendingActivityLaunchesLocked(packageName);
+
         if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
                 packageName, null, doit, evenPersistent, userId)) {
             if (!doit) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4ead64b..eaeb1a7 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3157,7 +3157,8 @@
     }
 
     private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
-        if (!mStackSupervisor.isFocusedStack(this) || mService.mFocusedActivity != r) {
+        if (!mStackSupervisor.isFocusedStack(this) || (mService.mFocusedActivity != r
+                && mService.mFocusedActivity != null)) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 7b3f65a..85fa139 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -2006,4 +2006,18 @@
             }
         }
     }
+
+    boolean clearPendingActivityLaunchesLocked(String packageName) {
+        boolean didSomething = false;
+
+        for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
+            PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
+            ActivityRecord r = pal.r;
+            if (r != null && r.packageName.equals(packageName)) {
+                mPendingActivityLaunches.remove(palNdx);
+                didSomething = true;
+            }
+        }
+        return didSomething;
+    }
 }
diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
new file mode 100644
index 0000000..cca9f10
--- /dev/null
+++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
@@ -0,0 +1,312 @@
+/*
+ * 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 com.android.server.emergency;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoWcdma;
+import android.telephony.CellLocation;
+import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.server.SystemService;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A service that listens to connectivity and SIM card changes and determines if the emergency mode
+ * should be enabled
+ */
+public class EmergencyAffordanceService extends SystemService {
+
+    private static final String TAG = "EmergencyAffordanceService";
+
+    private static final int NUM_SCANS_UNTIL_ABORT = 4;
+
+    private static final int INITIALIZE_STATE = 1;
+    private static final int CELL_INFO_STATE_CHANGED = 2;
+    private static final int SUBSCRIPTION_CHANGED = 3;
+
+    /**
+     * Global setting, whether the last scan of the sim cards reveal that a sim was inserted that
+     * requires the emergency affordance. The value is a boolean (1 or 0).
+     * @hide
+     */
+    private static final String EMERGENCY_SIM_INSERTED_SETTING = "emergency_sim_inserted_before";
+
+    private final Context mContext;
+    private final ArrayList<Integer> mEmergencyCallMccNumbers;
+
+    private final Object mLock = new Object();
+
+    private TelephonyManager mTelephonyManager;
+    private SubscriptionManager mSubscriptionManager;
+    private boolean mEmergencyAffordanceNeeded;
+    private MyHandler mHandler;
+    private int mScansCompleted;
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onCellInfoChanged(List<CellInfo> cellInfo) {
+            if (!isEmergencyAffordanceNeeded()) {
+                requestCellScan();
+            }
+        }
+
+        @Override
+        public void onCellLocationChanged(CellLocation location) {
+            if (!isEmergencyAffordanceNeeded()) {
+                requestCellScan();
+            }
+        }
+    };
+    private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Settings.Global.getInt(context.getContentResolver(),
+                    Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
+                startScanning();
+                requestCellScan();
+            }
+        }
+    };
+    private boolean mSimNeedsEmergencyAffordance;
+    private boolean mNetworkNeedsEmergencyAffordance;
+
+    private void requestCellScan() {
+        mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
+    }
+
+    private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener
+            = new SubscriptionManager.OnSubscriptionsChangedListener() {
+        @Override
+        public void onSubscriptionsChanged() {
+            mHandler.obtainMessage(SUBSCRIPTION_CHANGED).sendToTarget();
+        }
+    };
+
+    public EmergencyAffordanceService(Context context) {
+        super(context);
+        mContext = context;
+        int[] numbers = context.getResources().getIntArray(
+                com.android.internal.R.array.config_emergency_mcc_codes);
+        mEmergencyCallMccNumbers = new ArrayList<>(numbers.length);
+        for (int i = 0; i < numbers.length; i++) {
+            mEmergencyCallMccNumbers.add(numbers[i]);
+        }
+    }
+
+    private void updateEmergencyAffordanceNeeded() {
+        synchronized (mLock) {
+            mEmergencyAffordanceNeeded = mSimNeedsEmergencyAffordance ||
+                    mNetworkNeedsEmergencyAffordance;
+            Settings.Global.putInt(mContext.getContentResolver(),
+                    Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
+                    mEmergencyAffordanceNeeded ? 1 : 0);
+            if (mEmergencyAffordanceNeeded) {
+                stopScanning();
+            }
+        }
+    }
+
+    private void stopScanning() {
+        synchronized (mLock) {
+            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+            mScansCompleted = 0;
+        }
+    }
+
+    private boolean isEmergencyAffordanceNeeded() {
+        synchronized (mLock) {
+            return mEmergencyAffordanceNeeded;
+        }
+    }
+
+    @Override
+    public void onStart() {
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+            mSubscriptionManager = SubscriptionManager.from(mContext);
+            HandlerThread thread = new HandlerThread(TAG);
+            thread.start();
+            mHandler = new MyHandler(thread.getLooper());
+            mHandler.obtainMessage(INITIALIZE_STATE).sendToTarget();
+            startScanning();
+            IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+            mContext.registerReceiver(mAirplaneModeReceiver, filter);
+            mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionChangedListener);
+        }
+    }
+
+    private void startScanning() {
+        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
+                | PhoneStateListener.LISTEN_CELL_LOCATION);
+    }
+
+    /** Handler to do the heavier work on */
+    private class MyHandler extends Handler {
+
+        public MyHandler(Looper l) {
+            super(l);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case INITIALIZE_STATE:
+                    handleInitializeState();
+                    break;
+                case CELL_INFO_STATE_CHANGED:
+                    handleUpdateCellInfo();
+                    break;
+                case SUBSCRIPTION_CHANGED:
+                    handleUpdateSimSubscriptionInfo();
+                    break;
+            }
+        }
+    }
+
+    private void handleInitializeState() {
+        if (handleUpdateSimSubscriptionInfo()) {
+            return;
+        }
+        if (handleUpdateCellInfo()) {
+            return;
+        }
+        updateEmergencyAffordanceNeeded();
+    }
+
+    private boolean handleUpdateSimSubscriptionInfo() {
+        boolean neededBefore = simNeededAffordanceBefore();
+        boolean neededNow = neededBefore;
+        List<SubscriptionInfo> activeSubscriptionInfoList =
+                mSubscriptionManager.getActiveSubscriptionInfoList();
+        if (activeSubscriptionInfoList == null) {
+            return neededNow;
+        }
+        for (SubscriptionInfo info : activeSubscriptionInfoList) {
+            int mcc = info.getMcc();
+            if (mccRequiresEmergencyAffordance(mcc)) {
+                neededNow = true;
+                break;
+            } else if (mcc != 0 && mcc != Integer.MAX_VALUE){
+                // a Sim with a different mcc code was found
+                neededNow = false;
+            }
+            String simOperator  = mTelephonyManager.getSimOperator(info.getSubscriptionId());
+            mcc = 0;
+            if (simOperator != null && simOperator.length() >= 3) {
+                mcc = Integer.parseInt(simOperator.substring(0, 3));
+            }
+            if (mcc != 0) {
+                if (mccRequiresEmergencyAffordance(mcc)) {
+                    neededNow = true;
+                    break;
+                } else {
+                    // a Sim with a different mcc code was found
+                    neededNow = false;
+                }
+            }
+        }
+        if (neededNow != neededBefore) {
+            setSimNeedsEmergencyAffordance(neededNow);
+        }
+        return neededNow;
+    }
+
+    private void setSimNeedsEmergencyAffordance(boolean simNeedsEmergencyAffordance) {
+        mSimNeedsEmergencyAffordance = simNeedsEmergencyAffordance;
+        Settings.Global.putInt(mContext.getContentResolver(),
+                EMERGENCY_SIM_INSERTED_SETTING,
+                simNeedsEmergencyAffordance ? 1 : 0);
+        updateEmergencyAffordanceNeeded();
+    }
+
+    private boolean simNeededAffordanceBefore() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                "emergency_sim_inserted_before", 0) != 0;
+    }
+
+    private boolean handleUpdateCellInfo() {
+        List<CellInfo> cellInfos = mTelephonyManager.getAllCellInfo();
+        if (cellInfos == null) {
+            return false;
+        }
+        boolean stopScanningAfterScan = false;
+        for (CellInfo cellInfo : cellInfos) {
+            int mcc = 0;
+            if (cellInfo instanceof CellInfoGsm) {
+                mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMcc();
+            } else if (cellInfo instanceof CellInfoLte) {
+                mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMcc();
+            } else if (cellInfo instanceof CellInfoWcdma) {
+                mcc = ((CellInfoWcdma) cellInfo).getCellIdentity().getMcc();
+            }
+            if (mccRequiresEmergencyAffordance(mcc)) {
+                setNetworkNeedsEmergencyAffordance(true);
+                return true;
+            } else if (mcc != 0 && mcc != Integer.MAX_VALUE) {
+                // we found an mcc that isn't in the list, abort
+                stopScanningAfterScan = true;
+            }
+        }
+        if (stopScanningAfterScan) {
+            stopScanning();
+        } else {
+            onCellScanFinishedUnsuccessful();
+        }
+        setNetworkNeedsEmergencyAffordance(false);
+        return false;
+    }
+
+    private void setNetworkNeedsEmergencyAffordance(boolean needsAffordance) {
+        synchronized (mLock) {
+            mNetworkNeedsEmergencyAffordance = needsAffordance;
+            updateEmergencyAffordanceNeeded();
+        }
+    }
+
+    private void onCellScanFinishedUnsuccessful() {
+        synchronized (mLock) {
+            mScansCompleted++;
+            if (mScansCompleted >= NUM_SCANS_UNTIL_ABORT) {
+                stopScanning();
+            }
+        }
+    }
+
+    private boolean mccRequiresEmergencyAffordance(int mcc) {
+        return mEmergencyCallMccNumbers.contains(mcc);
+    }
+}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index cc556c7..a12a92c 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -178,6 +178,7 @@
     public void binderDied() {
         Slog.v(TAG, "fingerprintd died");
         mDaemon = null;
+        mCurrentUserId = UserHandle.USER_CURRENT;
         handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
     }
 
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 72c549f..2e18b1c 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -230,6 +230,11 @@
         mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
     }
 
+    public void deleteOdex(String apkPath, String instructionSet, String outputPath)
+            throws InstallerException {
+        mInstaller.execute("delete_odex", apkPath, instructionSet, outputPath);
+    }
+
     private static void assertValidInstructionSet(String instructionSet)
             throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index bff6d2d..689917c 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -31,7 +31,7 @@
 import android.os.storage.StorageManager;
 import android.util.Log;
 import android.util.Slog;
-
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.InstallerConnection;
 import com.android.internal.os.InstallerConnection.InstallerException;
 
@@ -40,6 +40,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A service for A/B OTA dexopting.
@@ -53,6 +54,10 @@
     // The synthetic library dependencies denoting "no checks."
     private final static String[] NO_LIBRARIES = new String[] { "&" };
 
+    // The amount of "available" (free - low threshold) space necessary at the start of an OTA to
+    // not bulk-delete unused apps' odex files.
+    private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024;  // 1GB.
+
     private final Context mContext;
     private final PackageManagerService mPackageManagerService;
 
@@ -65,6 +70,25 @@
 
     private int completeSize;
 
+    // MetricsLogger properties.
+
+    // Space before and after.
+    private long availableSpaceBefore;
+    private long availableSpaceAfterBulkDelete;
+    private long availableSpaceAfterDexopt;
+
+    // Packages.
+    private int importantPackageCount;
+    private int otherPackageCount;
+
+    // Number of dexopt commands. This may be different from the count of packages.
+    private int dexoptCommandCountTotal;
+    private int dexoptCommandCountExecuted;
+
+    // For spent time.
+    private long otaDexoptTimeStart;
+
+
     public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
         this.mContext = context;
         this.mPackageManagerService = packageManagerService;
@@ -128,6 +152,18 @@
                     generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
         }
         completeSize = mDexoptCommands.size();
+
+        long spaceAvailable = getAvailableSpace();
+        if (spaceAvailable < BULK_DELETE_THRESHOLD) {
+            Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
+                    + PackageManagerServiceUtils.packagesToString(others));
+            for (PackageParser.Package pkg : others) {
+                deleteOatArtifactsOfPackage(pkg);
+            }
+        }
+        long spaceAvailableNow = getAvailableSpace();
+
+        prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow);
     }
 
     @Override
@@ -136,6 +172,9 @@
             Log.i(TAG, "Cleaning up OTA Dexopt state.");
         }
         mDexoptCommands = null;
+        availableSpaceAfterDexopt = getAvailableSpace();
+
+        performMetricsLogging();
     }
 
     @Override
@@ -169,28 +208,67 @@
 
         String next = mDexoptCommands.remove(0);
 
-        if (IsFreeSpaceAvailable()) {
+        if (getAvailableSpace() > 0) {
+            dexoptCommandCountExecuted++;
+
             return next;
         } else {
+            if (DEBUG_DEXOPT) {
+                Log.w(TAG, "Not enough space for OTA dexopt, stopping with "
+                        + (mDexoptCommands.size() + 1) + " commands left.");
+            }
             mDexoptCommands.clear();
             return "(no free space)";
         }
     }
 
-    /**
-     * Check for low space. Returns true if there's space left.
-     */
-    private boolean IsFreeSpaceAvailable() {
-        // TODO: If apps are not installed in the internal /data partition, we should compare
-        //       against that storage's free capacity.
+    private long getMainLowSpaceThreshold() {
         File dataDir = Environment.getDataDirectory();
         @SuppressWarnings("deprecation")
         long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
         if (lowThreshold == 0) {
             throw new IllegalStateException("Invalid low memory threshold");
         }
+        return lowThreshold;
+    }
+
+    /**
+     * Returns the difference of free space to the low-storage-space threshold. Positive values
+     * indicate free bytes.
+     */
+    private long getAvailableSpace() {
+        // TODO: If apps are not installed in the internal /data partition, we should compare
+        //       against that storage's free capacity.
+        long lowThreshold = getMainLowSpaceThreshold();
+
+        File dataDir = Environment.getDataDirectory();
         long usableSpace = dataDir.getUsableSpace();
-        return (usableSpace >= lowThreshold);
+
+        return usableSpace - lowThreshold;
+    }
+
+    private static String getOatDir(PackageParser.Package pkg) {
+        if (!pkg.canHaveOatDir()) {
+            return null;
+        }
+        File codePath = new File(pkg.codePath);
+        if (codePath.isDirectory()) {
+            return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
+        }
+        return null;
+    }
+
+    private void deleteOatArtifactsOfPackage(PackageParser.Package pkg) {
+        String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+        for (String codePath : pkg.getAllCodePaths()) {
+            for (String isa : instructionSets) {
+                try {
+                    mPackageManagerService.mInstaller.deleteOdex(codePath, isa, getOatDir(pkg));
+                } catch (InstallerException e) {
+                    Log.e(TAG, "Failed deleting oat files for " + codePath, e);
+                }
+            }
+        }
     }
 
     /**
@@ -271,6 +349,55 @@
         }
     }
 
+    /**
+     * Initialize logging fields.
+     */
+    private void prepareMetricsLogging(int important, int others, long spaceBegin, long spaceBulk) {
+        availableSpaceBefore = spaceBegin;
+        availableSpaceAfterBulkDelete = spaceBulk;
+        availableSpaceAfterDexopt = 0;
+
+        importantPackageCount = important;
+        otherPackageCount = others;
+
+        dexoptCommandCountTotal = mDexoptCommands.size();
+        dexoptCommandCountExecuted = 0;
+
+        otaDexoptTimeStart = System.nanoTime();
+    }
+
+    private static int inMegabytes(long value) {
+        long in_mega_bytes = value / (1024 * 1024);
+        if (in_mega_bytes > Integer.MAX_VALUE) {
+            Log.w(TAG, "Recording " + in_mega_bytes + "MB of free space, overflowing range");
+            return Integer.MAX_VALUE;
+        }
+        return (int)in_mega_bytes;
+    }
+
+    private void performMetricsLogging() {
+        long finalTime = System.nanoTime();
+
+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_before_mb",
+                inMegabytes(availableSpaceBefore));
+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_bulk_delete_mb",
+                inMegabytes(availableSpaceAfterBulkDelete));
+        MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_dexopt_mb",
+                inMegabytes(availableSpaceAfterDexopt));
+
+        MetricsLogger.histogram(mContext, "ota_dexopt_num_important_packages",
+                importantPackageCount);
+        MetricsLogger.histogram(mContext, "ota_dexopt_num_other_packages", otherPackageCount);
+
+        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands", dexoptCommandCountTotal);
+        MetricsLogger.histogram(mContext, "ota_dexopt_num_commands_executed",
+                dexoptCommandCountExecuted);
+
+        final int elapsedTimeSeconds =
+                (int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart);
+        MetricsLogger.histogram(mContext, "ota_dexopt_time_s", elapsedTimeSeconds);
+    }
+
     private static class OTADexoptPackageDexOptimizer extends
             PackageDexOptimizer.ForcedUpdatePackageDexOptimizer {
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 751c585..cfd0af7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -19,6 +19,7 @@
 import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
 import static com.android.server.pm.PackageManagerService.TAG;
 
+import android.annotation.NonNull;
 import android.app.AppGlobals;
 import android.content.Intent;
 import android.content.pm.PackageParser;
@@ -35,13 +36,9 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
+import java.util.function.Predicate;
 
 /**
  * Class containing helper methods for the PackageManagerService.
@@ -67,34 +64,51 @@
         return pkgNames;
     }
 
-    private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs,
-            long estimatedPreviousSystemUseTime,
-            long dexOptLRUThresholdInMills) {
-        // Filter out packages that aren't recently used.
-        int total = pkgs.size();
-        int skipped = 0;
-        for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
-            PackageParser.Package pkg = i.next();
-            long then = pkg.getLatestForegroundPackageUseTimeInMills();
-            if (then < estimatedPreviousSystemUseTime - dexOptLRUThresholdInMills) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Skipping dexopt of " + pkg.packageName +
-                            " last used in foreground: " +
-                            ((then == 0) ? "never" : new Date(then)));
-                }
-                i.remove();
-                skipped++;
-            } else {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Will dexopt " + pkg.packageName +
-                            " last used in foreground: " +
-                            ((then == 0) ? "never" : new Date(then)));
-                }
+    // Sort a list of apps by their last usage, most recently used apps first. The order of
+    // packages without usage data is undefined (but they will be sorted after the packages
+    // that do have usage data).
+    public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs,
+            PackageManagerService packageManagerService) {
+        if (!packageManagerService.isHistoricalPackageUsageAvailable()) {
+            return;
+        }
+
+        Collections.sort(pkgs, (pkg1, pkg2) ->
+                Long.compare(pkg2.getLatestForegroundPackageUseTimeInMills(),
+                        pkg1.getLatestForegroundPackageUseTimeInMills()));
+    }
+
+    // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the
+    // package will be removed from {@code packages} and added to {@code result} with its
+    // dependencies. If usage data is available, the positive packages will be sorted by usage
+    // data (with {@code sortTemp} as temporary storage).
+    private static void applyPackageFilter(Predicate<PackageParser.Package> filter,
+            Collection<PackageParser.Package> result,
+            Collection<PackageParser.Package> packages,
+            @NonNull List<PackageParser.Package> sortTemp,
+            PackageManagerService packageManagerService) {
+        for (PackageParser.Package pkg : packages) {
+            if (filter.test(pkg)) {
+                sortTemp.add(pkg);
             }
         }
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "Skipped dexopt " + skipped + " of " + total);
+
+        sortPackagesByUsageDate(sortTemp, packageManagerService);
+        packages.removeAll(sortTemp);
+
+        for (PackageParser.Package pkg : sortTemp) {
+            result.add(pkg);
+
+            Collection<PackageParser.Package> deps =
+                    packageManagerService.findSharedNonSystemLibraries(pkg);
+            if (!deps.isEmpty()) {
+                deps.removeAll(result);
+                result.addAll(deps);
+                packages.removeAll(deps);
+            }
         }
+
+        sortTemp.clear();
     }
 
     // Sort apps by importance for dexopt ordering. Important apps are given
@@ -104,46 +118,25 @@
             PackageManagerService packageManagerService) {
         ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages);
         LinkedList<PackageParser.Package> result = new LinkedList<>();
+        ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size());
 
         // Give priority to core apps.
-        for (PackageParser.Package pkg : remainingPkgs) {
-            if (pkg.coreApp) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Adding core app " + result.size() + ": " + pkg.packageName);
-                }
-                result.add(pkg);
-            }
-        }
-        remainingPkgs.removeAll(result);
+        applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp,
+                packageManagerService);
 
         // Give priority to system apps that listen for pre boot complete.
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
-        ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
-        for (PackageParser.Package pkg : remainingPkgs) {
-            if (pkgNames.contains(pkg.packageName)) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Adding pre boot system app " + result.size() + ": " +
-                            pkg.packageName);
-                }
-                result.add(pkg);
-            }
-        }
-        remainingPkgs.removeAll(result);
+        final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
+        applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs,
+                sortTemp, packageManagerService);
 
         // Give priority to apps used by other apps.
-        for (PackageParser.Package pkg : remainingPkgs) {
-            if (PackageDexOptimizer.isUsedByOtherApps(pkg)) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Adding app used by other apps " + result.size() + ": " +
-                            pkg.packageName);
-                }
-                result.add(pkg);
-            }
-        }
-        remainingPkgs.removeAll(result);
+        applyPackageFilter((pkg) -> PackageDexOptimizer.isUsedByOtherApps(pkg), result,
+                remainingPkgs, sortTemp, packageManagerService);
 
         // Filter out packages that aren't recently used, add all remaining apps.
         // TODO: add a property to control this?
+        Predicate<PackageParser.Package> remainingPredicate;
         if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) {
             if (DEBUG_DEXOPT) {
                 Log.i(TAG, "Looking at historical package use");
@@ -159,34 +152,24 @@
                     lastUsed.getLatestForegroundPackageUseTimeInMills();
             // Be defensive if for some reason package usage has bogus data.
             if (estimatedPreviousSystemUseTime != 0) {
-                filterRecentlyUsedApps(remainingPkgs, estimatedPreviousSystemUseTime,
-                        SEVEN_DAYS_IN_MILLISECONDS);
+                final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS;
+                remainingPredicate =
+                        (pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime;
+            } else {
+                // No meaningful historical info. Take all.
+                remainingPredicate = (pkg) -> true;
             }
+            sortPackagesByUsageDate(remainingPkgs, packageManagerService);
+        } else {
+            // No historical info. Take all.
+            remainingPredicate = (pkg) -> true;
         }
-        result.addAll(remainingPkgs);
-
-        // Now go ahead and also add the libraries required for these packages.
-        // TODO: Think about interleaving things.
-        Set<PackageParser.Package> dependencies = new HashSet<>();
-        for (PackageParser.Package p : result) {
-            dependencies.addAll(packageManagerService.findSharedNonSystemLibraries(p));
-        }
-        if (!dependencies.isEmpty()) {
-            // We might have packages already in `result` that are dependencies
-            // of other packages. Make sure we don't add those to the list twice.
-            dependencies.removeAll(result);
-        }
-        result.addAll(dependencies);
+        applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp,
+                packageManagerService);
 
         if (DEBUG_DEXOPT) {
-            StringBuilder sb = new StringBuilder();
-            for (PackageParser.Package pkg : result) {
-                if (sb.length() > 0) {
-                    sb.append(", ");
-                }
-                sb.append(pkg.packageName);
-            }
-            Log.i(TAG, "Packages to be dexopted: " + sb.toString());
+            Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
+            Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
         }
 
         return result;
@@ -203,4 +186,15 @@
             throw ee.rethrowAsIOException();
         }
     }
+
+    public static String packagesToString(Collection<PackageParser.Package> c) {
+        StringBuilder sb = new StringBuilder();
+        for (PackageParser.Package pkg : c) {
+            if (sb.length() > 0) {
+                sb.append(", ");
+            }
+            sb.append(pkg.packageName);
+        }
+        return sb.toString();
+    }
 }
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 5ef518e..6e2fb10 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -20,6 +20,7 @@
 import com.android.internal.app.AlertController.AlertParams;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.internal.policy.EmergencyAffordanceManager;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.R;
@@ -124,6 +125,7 @@
     private boolean mHasTelephony;
     private boolean mHasVibrator;
     private final boolean mShowSilentToggle;
+    private final EmergencyAffordanceManager mEmergencyAffordanceManager;
 
     /**
      * @param context everything needs a context :(
@@ -158,6 +160,8 @@
 
         mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useFixedVolume);
+
+        mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
     }
 
     /**
@@ -305,6 +309,10 @@
             addedKeys.add(actionKey);
         }
 
+        if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+            mItems.add(getEmergencyAction());
+        }
+
         mAdapter = new MyAdapter();
 
         AlertParams params = new AlertParams(mContext);
@@ -458,6 +466,26 @@
         };
     }
 
+    private Action getEmergencyAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.emergency_icon,
+                R.string.global_action_emergency) {
+            @Override
+            public void onPress() {
+                mEmergencyAffordanceManager.performEmergencyCall();
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
     private Action getAssistAction() {
         return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
                 R.string.global_action_assist) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 36d9697..afd451d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1033,7 +1033,7 @@
             mDtDy = tmpFloats[Matrix.MSCALE_Y];
             float x = tmpFloats[Matrix.MTRANS_X];
             float y = tmpFloats[Matrix.MTRANS_Y];
-            mWin.mShownPosition.set((int) x, (int) y);
+            mWin.mShownPosition.set(Math.round(x), Math.round(y));
 
             // Now set the alpha...  but because our current hardware
             // can't do alpha transformation on a non-opaque surface,
@@ -1129,7 +1129,7 @@
             mDtDy = tmpFloats[Matrix.MSCALE_Y];
             float x = tmpFloats[Matrix.MTRANS_X];
             float y = tmpFloats[Matrix.MTRANS_Y];
-            mWin.mShownPosition.set((int) x, (int) y);
+            mWin.mShownPosition.set(Math.round(x), Math.round(y));
 
             mShownAlpha = mAlpha;
         } else {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1242560..58b71f5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -52,6 +52,7 @@
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.SamplingProfilerIntegration;
 import com.android.internal.os.ZygoteInit;
+import com.android.internal.policy.EmergencyAffordanceManager;
 import com.android.internal.widget.ILockSettings;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.am.ActivityManagerService;
@@ -62,6 +63,7 @@
 import com.android.server.devicepolicy.DevicePolicyManagerService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
+import com.android.server.emergency.EmergencyAffordanceService;
 import com.android.server.fingerprint.FingerprintService;
 import com.android.server.hdmi.HdmiControlService;
 import com.android.server.input.InputManagerService;
@@ -1077,6 +1079,11 @@
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
+            if (!disableNetwork && !disableNonCoreServices && EmergencyAffordanceManager.ENABLED) {
+                // EmergencyMode sevice
+                mSystemServiceManager.startService(EmergencyAffordanceService.class);
+            }
+
             if (!disableNonCoreServices) {
                 // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
                 mSystemServiceManager.startService(DreamManagerService.class);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6eb792b..17f0da0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -182,6 +182,14 @@
     public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
 
     /**
+     * Since the default voicemail number is empty, if a SIM card does not have a voicemail number
+     * available the user cannot use voicemail. This flag allows the user to edit the voicemail
+     * number in such cases, and is false by default.
+     * @hide
+     */
+    public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL= "editable_voicemail_number_bool";
+
+    /**
      * Determine whether the voicemail notification is persistent in the notification bar. If true,
      * the voicemail notifications cannot be dismissed from the notification bar.
      */
@@ -261,6 +269,17 @@
     public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
 
     /**
+     * Specifies a map from dialstrings to replacements for roaming network service numbers which
+     * cannot be replaced on the carrier side.
+     * <p>
+     * Individual entries have the format:
+     * [dialstring to replace]:[replacement]
+     * @hide
+     */
+    public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY =
+            "dial_string_replace_string_array";
+
+    /**
      * Flag specifying whether WFC over IMS supports the "wifi only" option.  If false, the wifi
      * calling settings will not include an option for "wifi only".  If true, the wifi calling
      * settings will include an option for "wifi only"
@@ -710,6 +729,15 @@
             "duration_blocking_disabled_after_emergency_int";
 
     /**
+     * For carriers which require an empty flash to be sent before sending the normal 3-way calling
+     * flash, the duration in milliseconds of the empty flash to send.  When {@code 0}, no empty
+     * flash is sent.
+     * @hide
+     */
+    public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
+
+
+    /**
      * @hide
      * The default value for preferred CDMA roaming mode (aka CDMA system select.)
      *          CDMA_ROAMING_MODE_RADIO_DEFAULT = the default roaming mode from the radio
@@ -772,6 +800,7 @@
         sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL, true);
         sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
+        sDefaults.putBoolean(KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL, false);
         sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
         sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
         sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
@@ -813,10 +842,12 @@
         sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_DIAL_STRING_REPLACE_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, false);
         sDefaults.putInt(KEY_GSM_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
+        sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 2e5fbdc..d86de1e 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -141,7 +141,7 @@
 cFlags := -Wall -Werror -Wno-unused-parameter -UNDEBUG
 cFlags_darwin := -D_DARWIN_UNLIMITED_STREAMS
 cFlags_windows := -Wno-maybe-uninitialized # Incorrectly marking use of Maybe.value() as error.
-cppFlags := -std=c++11 -Wno-missing-field-initializers -fno-exceptions -fno-rtti
+cppFlags := -Wno-missing-field-initializers -fno-exceptions -fno-rtti
 protoIncludes := $(call generated-sources-dir-for,STATIC_LIBRARIES,libaapt2,HOST)
 
 # ==========================================================
diff --git a/wifi/java/android/net/wifi/ParcelUtil.java b/wifi/java/android/net/wifi/ParcelUtil.java
new file mode 100644
index 0000000..a26877d
--- /dev/null
+++ b/wifi/java/android/net/wifi/ParcelUtil.java
@@ -0,0 +1,165 @@
+/**
+ * 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 android.os.Parcel;
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+/**
+ * Provides utilities for writing/reading a non-Parcelable objects to/from
+ * a Parcel object.
+ *
+ * @hide
+ */
+public class ParcelUtil {
+    /**
+     * Write a PrivateKey object |key| to the specified Parcel |dest|.
+     *
+     * Below is the data format:
+     * |algorithm|     -> String of algorithm name
+     * |endcodedKey|  -> byte[] of key data
+     *
+     * For a null PrivateKey object, a null string will be written to |algorithm| and
+     * |encodedKey| will be skipped. Since a PrivateKey can only be constructed with
+     * a valid algorithm String.
+     *
+     * @param dest Parcel object to write to
+     * @param key PrivateKey object to read from.
+     */
+    public static void writePrivateKey(Parcel dest, PrivateKey key) {
+        if (key == null) {
+            dest.writeString(null);
+            return;
+        }
+
+        dest.writeString(key.getAlgorithm());
+        dest.writeByteArray(key.getEncoded());
+    }
+
+    /**
+     * Read/create a PrivateKey object from a specified Parcel object |in|.
+     *
+     * Refer to the function above for the expected data format.
+     *
+     * @param in Parcel object to read from
+     * @return a PrivateKey object or null
+     */
+    public static PrivateKey readPrivateKey(Parcel in) {
+        String algorithm = in.readString();
+        if (algorithm == null) {
+            return null;
+        }
+
+        byte[] userKeyBytes = in.createByteArray();
+        try {
+            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
+            return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(userKeyBytes));
+       } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+            return null;
+       }
+    }
+
+    /**
+     * Write a X509Certificate object |cert| to a Parcel object |dest|.
+     * The data being written to the Parcel is just a byte[] of the encoded certificate data.
+     *
+     * @param dest Parcel object to write to
+     * @param cert X509Certificate object to read from
+     */
+    public static void writeCertificate(Parcel dest, X509Certificate cert) {
+        byte[] certBytes = null;
+        if (cert != null) {
+            try {
+                certBytes = cert.getEncoded();
+            } catch (CertificateEncodingException e) {
+                /* empty, write null. */
+            }
+        }
+        dest.writeByteArray(certBytes);
+    }
+
+    /**
+     * Read/create a X509Certificate object from a specified Parcel object |in|.
+     *
+     * @param in Parcel object to read from
+     * @return a X509Certficate object or null
+     */
+    public static X509Certificate readCertificate(Parcel in) {
+        byte[] certBytes = in.createByteArray();
+        if (certBytes == null) {
+            return null;
+        }
+
+        try {
+            CertificateFactory cFactory = CertificateFactory.getInstance("X.509");
+            return (X509Certificate) cFactory
+                    .generateCertificate(new ByteArrayInputStream(certBytes));
+        } catch (CertificateException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Write an array of X509Certificate objects |certs| to a Parcel object |dest|.
+     * The data being written to the Parcel are consist of an integer indicating
+     * the size of the array and the certificates data.  Certificates data will be
+     * skipped for a null array or size of 0 array.
+     *
+     * @param dest Parcel object to write to
+     * @param certs array of X509Certificate objects to read from
+     */
+    public static void writeCertificates(Parcel dest, X509Certificate[] certs) {
+        if (certs == null || certs.length == 0) {
+            dest.writeInt(0);
+            return;
+        }
+
+        dest.writeInt(certs.length);
+        for (int i = 0; i < certs.length; i++) {
+            writeCertificate(dest, certs[i]);
+        }
+    }
+
+    /**
+     * Read/create an array of X509Certificate objects from a specified Parcel object |in|.
+     *
+     * @param in Parcel object to read from
+     * @return X509Certficate[] or null
+     */
+    public static X509Certificate[] readCertificates(Parcel in) {
+        int length = in.readInt();
+        if (length == 0) {
+            return null;
+        }
+
+        X509Certificate[] certs = new X509Certificate[length];
+        for (int i = 0; i < length; i++) {
+            certs[i] = readCertificate(in);
+        }
+        return certs;
+    }
+}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 67cf107..465addf 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -139,12 +139,6 @@
     public long seen;
 
     /**
-     * If the scan result is a valid autojoin candidate
-     * {@hide}
-     */
-    public int isAutoJoinCandidate;
-
-    /**
      * @hide
      * Update RSSI of the scan result
      * @param previousRssi
@@ -452,7 +446,6 @@
             numConnection = source.numConnection;
             numUsage = source.numUsage;
             numIpConfigFailures = source.numIpConfigFailures;
-            isAutoJoinCandidate = source.isAutoJoinCandidate;
             venueName = source.venueName;
             operatorFriendlyName = source.operatorFriendlyName;
             flags = source.flags;
@@ -530,7 +523,6 @@
         dest.writeInt(numConnection);
         dest.writeInt(numUsage);
         dest.writeInt(numIpConfigFailures);
-        dest.writeInt(isAutoJoinCandidate);
         dest.writeString((venueName != null) ? venueName.toString() : "");
         dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
         dest.writeLong(this.flags);
@@ -600,7 +592,6 @@
                 sr.numConnection = in.readInt();
                 sr.numUsage = in.readInt();
                 sr.numIpConfigFailures = in.readInt();
-                sr.isAutoJoinCandidate = in.readInt();
                 sr.venueName = in.readString();
                 sr.operatorFriendlyName = in.readString();
                 sr.flags = in.readLong();
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index c0e8bc2..e410a9c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -183,48 +183,14 @@
 
         dest.writeInt(mEapMethod);
         dest.writeInt(mPhase2Method);
-        writeCertificates(dest, mCaCerts);
-
-        if (mClientPrivateKey != null) {
-            String algorithm = mClientPrivateKey.getAlgorithm();
-            byte[] userKeyBytes = mClientPrivateKey.getEncoded();
-            dest.writeInt(userKeyBytes.length);
-            dest.writeByteArray(userKeyBytes);
-            dest.writeString(algorithm);
-        } else {
-            dest.writeInt(0);
-        }
-
-        writeCertificate(dest, mClientCertificate);
-    }
-
-    private void writeCertificates(Parcel dest, X509Certificate[] cert) {
-        if (cert != null && cert.length != 0) {
-            dest.writeInt(cert.length);
-            for (int i = 0; i < cert.length; i++) {
-                writeCertificate(dest, cert[i]);
-            }
-        } else {
-            dest.writeInt(0);
-        }
-    }
-
-    private void writeCertificate(Parcel dest, X509Certificate cert) {
-        if (cert != null) {
-            try {
-                byte[] certBytes = cert.getEncoded();
-                dest.writeInt(certBytes.length);
-                dest.writeByteArray(certBytes);
-            } catch (CertificateEncodingException e) {
-                dest.writeInt(0);
-            }
-        } else {
-            dest.writeInt(0);
-        }
+        ParcelUtil.writeCertificates(dest, mCaCerts);
+        ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
+        ParcelUtil.writeCertificate(dest, mClientCertificate);
     }
 
     public static final Creator<WifiEnterpriseConfig> CREATOR =
             new Creator<WifiEnterpriseConfig>() {
+                @Override
                 public WifiEnterpriseConfig createFromParcel(Parcel in) {
                     WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
                     int count = in.readInt();
@@ -236,58 +202,13 @@
 
                     enterpriseConfig.mEapMethod = in.readInt();
                     enterpriseConfig.mPhase2Method = in.readInt();
-                    enterpriseConfig.mCaCerts = readCertificates(in);
-
-                    PrivateKey userKey = null;
-                    int len = in.readInt();
-                    if (len > 0) {
-                        try {
-                            byte[] bytes = new byte[len];
-                            in.readByteArray(bytes);
-                            String algorithm = in.readString();
-                            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
-                            userKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
-                        } catch (NoSuchAlgorithmException e) {
-                            userKey = null;
-                        } catch (InvalidKeySpecException e) {
-                            userKey = null;
-                        }
-                    }
-
-                    enterpriseConfig.mClientPrivateKey = userKey;
-                    enterpriseConfig.mClientCertificate = readCertificate(in);
+                    enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in);
+                    enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in);
+                    enterpriseConfig.mClientCertificate = ParcelUtil.readCertificate(in);
                     return enterpriseConfig;
                 }
 
-                private X509Certificate[] readCertificates(Parcel in) {
-                    X509Certificate[] certs = null;
-                    int len = in.readInt();
-                    if (len > 0) {
-                        certs = new X509Certificate[len];
-                        for (int i = 0; i < len; i++) {
-                            certs[i] = readCertificate(in);
-                        }
-                    }
-                    return certs;
-                }
-
-                private X509Certificate readCertificate(Parcel in) {
-                    X509Certificate cert = null;
-                    int len = in.readInt();
-                    if (len > 0) {
-                        try {
-                            byte[] bytes = new byte[len];
-                            in.readByteArray(bytes);
-                            CertificateFactory cFactory = CertificateFactory.getInstance("X.509");
-                            cert = (X509Certificate) cFactory
-                                    .generateCertificate(new ByteArrayInputStream(bytes));
-                        } catch (CertificateException e) {
-                            cert = null;
-                        }
-                    }
-                    return cert;
-                }
-
+                @Override
                 public WifiEnterpriseConfig[] newArray(int size) {
                     return new WifiEnterpriseConfig[size];
                 }
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index 56baba9..5485824 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -23,6 +23,7 @@
 import android.net.wifi.nan.IWifiNanEventCallback;
 import android.net.wifi.nan.PublishConfig;
 import android.net.wifi.nan.SubscribeConfig;
+import android.net.wifi.nan.WifiNanCharacteristics;
 import android.net.wifi.RttManager;
 
 /**
@@ -36,6 +37,7 @@
     void enableUsage();
     void disableUsage();
     boolean isUsageEnabled();
+    WifiNanCharacteristics getCharacteristics();
 
     // client API
     void connect(in IBinder binder, in String callingPackage, in IWifiNanEventCallback callback,
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java
index 4b67f9a..30c5bc0 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.java
+++ b/wifi/java/android/net/wifi/nan/PublishConfig.java
@@ -182,7 +182,7 @@
      *
      * @hide
      */
-    public void validate() throws IllegalArgumentException {
+    public void assertValid(WifiNanCharacteristics characteristics) throws IllegalArgumentException {
         WifiNanUtils.validateServiceName(mServiceName);
 
         if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
@@ -198,6 +198,26 @@
         if (mTtlSec < 0) {
             throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
         }
+
+        if (characteristics != null) {
+            int maxServiceNameLength = characteristics.getMaxServiceNameLength();
+            if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) {
+                throw new IllegalArgumentException(
+                        "Service name longer than supported by device characteristics");
+            }
+            int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength();
+            if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null
+                    && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) {
+                throw new IllegalArgumentException(
+                        "Service specific info longer than supported by device characteristics");
+            }
+            int maxMatchFilterLength = characteristics.getMaxMatchFilterLength();
+            if (maxMatchFilterLength != 0 && mMatchFilter != null
+                    && mMatchFilter.length > maxMatchFilterLength) {
+                throw new IllegalArgumentException(
+                        "Match filter longer than supported by device characteristics");
+            }
+        }
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
index 4352fcf..ea7b8e4 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
@@ -209,7 +209,7 @@
      *
      * @hide
      */
-    public void validate() throws IllegalArgumentException {
+    public void assertValid(WifiNanCharacteristics characteristics) throws IllegalArgumentException {
         WifiNanUtils.validateServiceName(mServiceName);
 
         if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
@@ -229,6 +229,26 @@
             throw new IllegalArgumentException(
                     "Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL");
         }
+
+        if (characteristics != null) {
+            int maxServiceNameLength = characteristics.getMaxServiceNameLength();
+            if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) {
+                throw new IllegalArgumentException(
+                        "Service name longer than supported by device characteristics");
+            }
+            int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength();
+            if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null
+                    && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) {
+                throw new IllegalArgumentException(
+                        "Service specific info longer than supported by device characteristics");
+            }
+            int maxMatchFilterLength = characteristics.getMaxMatchFilterLength();
+            if (maxMatchFilterLength != 0 && mMatchFilter != null
+                    && mMatchFilter.length > maxMatchFilterLength) {
+                throw new IllegalArgumentException(
+                        "Match filter longer than supported by device characteristics");
+            }
+        }
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl
new file mode 100644
index 0000000..e562a00
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.nan;
+
+parcelable WifiNanCharacteristics;
diff --git a/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java
new file mode 100644
index 0000000..f43ed4d
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java
@@ -0,0 +1,103 @@
+/*
+ * 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.nan;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The characteristics of the Wi-Fi NAN implementation.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanCharacteristics implements Parcelable {
+    /** @hide */
+    public static final String KEY_MAX_SERVICE_NAME_LENGTH = "key_max_service_name_length";
+    /** @hide */
+    public static final String KEY_MAX_SERVICE_SPECIFIC_INFO_LENGTH =
+            "key_max_service_specific_info_length";
+    /** @hide */
+    public static final String KEY_MAX_MATCH_FILTER_LENGTH = "key_max_match_filter_length";
+
+    private Bundle mCharacteristics = new Bundle();
+
+    /** @hide : should not be created by apps */
+    public WifiNanCharacteristics(Bundle characteristics) {
+        mCharacteristics = characteristics;
+    }
+
+    /**
+     * Returns the maximum string length that can be used to specify a NAN service name. Restricts
+     * the parameters of the {@link PublishConfig.Builder#setServiceName(String)} and
+     * {@link SubscribeConfig.Builder#setServiceName(String)}.
+     *
+     * @return A positive integer, maximum string length of NAN service name.
+     */
+    public int getMaxServiceNameLength() {
+        return mCharacteristics.getInt(KEY_MAX_SERVICE_NAME_LENGTH);
+    }
+
+    /**
+     * Returns the maximum length of byte array that can be used to specify a NAN service specific
+     * information field: the arbitrary load used in discovery or the message length of NAN
+     * message exchange. Restricts the parameters of the
+     * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])},
+     * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and
+     * {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])} variants.
+     *
+     * @return A positive integer, maximum length of byte array for NAN messaging.
+     */
+    public int getMaxServiceSpecificInfoLength() {
+        return mCharacteristics.getInt(KEY_MAX_SERVICE_SPECIFIC_INFO_LENGTH);
+    }
+
+    /**
+     * Returns the maximum length of byte array that can be used to specify a NAN match filter.
+     * Restricts the parameters of the {@link PublishConfig.Builder#setMatchFilter(byte[])} and
+     * {@link SubscribeConfig.Builder#setMatchFilter(byte[])}.
+     *
+     * @return A positive integer, maximum legngth of byte array for NAN discovery match filter.
+     */
+    public int getMaxMatchFilterLength() {
+        return mCharacteristics.getInt(KEY_MAX_MATCH_FILTER_LENGTH);
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeBundle(mCharacteristics);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<WifiNanCharacteristics> CREATOR =
+            new Creator<WifiNanCharacteristics>() {
+                @Override
+                public WifiNanCharacteristics createFromParcel(Parcel in) {
+                    WifiNanCharacteristics c = new WifiNanCharacteristics(in.readBundle());
+                    return c;
+                }
+
+                @Override
+                public WifiNanCharacteristics[] newArray(int size) {
+                    return new WifiNanCharacteristics[size];
+                }
+            };
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 705ba4a..002b953 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -201,6 +201,8 @@
      * Use the {@link #isAvailable()} to query the current status.
      * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
      * the broadcast to check the current state of Wi-Fi NAN.
+     * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
+     * components will be launched.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_WIFI_NAN_STATE_CHANGED =
@@ -291,6 +293,20 @@
     }
 
     /**
+     * Returns the characteristics of the Wi-Fi NAN interface: a set of parameters which specify
+     * limitations on configurations, e.g. the maximum service name length.
+     *
+     * @return An object specifying configuration limitations of NAN.
+     */
+    public WifiNanCharacteristics getCharacteristics() {
+        try {
+            return mService.getCharacteristics();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Attach to the Wi-Fi NAN service - enabling the application to create discovery sessions or
      * create connections to peers. The device will attach to an existing cluster if it can find
      * one or create a new cluster (if it is the first to enable NAN in its vicinity). Results
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index 5fb2c06..df5e3c1 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -113,6 +113,8 @@
      *      An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to
      *      terminate the publish discovery session once it isn't needed. This will free
      *      resources as well terminate any on-air transmissions.
+     * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+     * permission to start a publish discovery session.
      *
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * callback} object. If a null is provided then the application's main thread will be used.
@@ -156,6 +158,8 @@
      *      An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to
      *      terminate the subscribe discovery session once it isn't needed. This will free
      *      resources as well terminate any on-air transmissions.
+     * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+     * permission to start a subscribe discovery session.
      *
      * @param handler The Handler on whose thread to execute the callbacks of the {@code
      * callback} object. If a null is provided then the application's main thread will be used.
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
new file mode 100644
index 0000000..5850fee
--- /dev/null
+++ b/wifi/tests/Android.mk
@@ -0,0 +1,61 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Make test APK
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+# This list is generated from the java source files in this module
+# The list is a comma separated list of class names with * matching zero or more characters.
+# Example:
+#   Input files: src/com/android/server/wifi/Test.java src/com/android/server/wifi/AnotherTest.java
+#   Generated exclude list: com.android.server.wifi.Test*,com.android.server.wifi.AnotherTest*
+
+# Filter all src files to just java files
+local_java_files := $(filter %.java,$(LOCAL_SRC_FILES))
+# Transform java file names into full class names.
+# This only works if the class name matches the file name and the directory structure
+# matches the package.
+local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
+# Utility variables to allow replacing a space with a comma
+comma:= ,
+empty:=
+space:= $(empty) $(empty)
+# Convert class name list to jacoco exclude list
+# This appends a * to all classes and replace the space separators with commas.
+# These patterns will match all classes in this module and their inner classes.
+jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
+
+jacoco_include := android.net.wifi.*
+
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include)
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	android-support-test \
+	mockito-target-minus-junit4 \
+	frameworks-base-testutils \
+
+LOCAL_JAVA_LIBRARIES := \
+	android.test.runner \
+
+LOCAL_PACKAGE_NAME := FrameworksWifiApiTests
+
+include $(BUILD_PACKAGE)
diff --git a/wifi/tests/AndroidManifest.xml b/wifi/tests/AndroidManifest.xml
new file mode 100644
index 0000000..4eaca2b
--- /dev/null
+++ b/wifi/tests/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.net.wifi.test">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:label="WifiTestDummyLabel"
+                  android:name="WifiTestDummyName">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.net.wifi.test"
+        android:label="Frameworks Wifi API Tests">
+    </instrumentation>
+
+</manifest>
diff --git a/wifi/tests/README.md b/wifi/tests/README.md
new file mode 100644
index 0000000..b418abd
--- /dev/null
+++ b/wifi/tests/README.md
@@ -0,0 +1,50 @@
+# Wifi Unit Tests
+This package contains unit tests for the android wifi framework APIs based on the
+[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html).
+The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/)
+libraries.
+
+## Running Tests
+The easiest way to run tests is simply run
+
+```
+frameworks/base/wifi/tests/runtests.sh
+```
+
+`runtests.sh` will build the test project and all of its dependencies and push the APK to the
+connected device. It will then run the tests on the device.
+
+To pick up changes in framework/base, you will need to:
+1. rebuild the framework library 'make -j32'
+2. sync over the updated library to the device 'adb sync'
+3. restart framework on the device 'adb shell stop' then 'adb shell start'
+
+To enable syncing data to the device for first time after clean reflash:
+1. adb disable-verity
+2. adb reboot
+3. adb remount
+
+See below for a few example of options to limit which tests are run.
+See the
+[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html)
+for more details on the supported options.
+
+```
+runtests.sh -e package android.net.wifi
+runtests.sh -e class android.net.wifi.WifiScannerTest
+```
+
+If you manually build and push the test APK to the device you can run tests using
+
+```
+adb shell am instrument -w 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
+```
+
+## Adding Tests
+Tests can be added by adding classes to the src directory. JUnit4 style test cases can
+be written by simply annotating test methods with `org.junit.Test`.
+
+## Debugging Tests
+If you are trying to debug why tests are not doing what you expected, you can add android log
+statements and use logcat to view them. The beginning and end of every tests is automatically logged
+with the tag `TestRunner`.
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
new file mode 100755
index 0000000..ebcc2a2
--- /dev/null
+++ b/wifi/tests/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/wifi/tests"
+# 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-wifi-tests
+
+set -x # print commands
+
+adb root
+adb wait-for-device
+
+adb install -r -g "$OUT/data/app/FrameworksWifiApiTests/FrameworksWifiApiTests.apk"
+
+adb shell am instrument -w "$@" 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
diff --git a/wifi/tests/src/android/net/wifi/FakeKeys.java b/wifi/tests/src/android/net/wifi/FakeKeys.java
new file mode 100644
index 0000000..c0d60c3
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/FakeKeys.java
@@ -0,0 +1,237 @@
+/*
+ * 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 java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+/**
+ * A class containing test certificates and private keys.
+ */
+public class FakeKeys {
+    private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDKDCCAhCgAwIBAgIJAILlFdwzLVurMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" +
+            "BAMTB0VBUCBDQTEwHhcNMTYwMTEyMTE1MDE1WhcNMjYwMTA5MTE1MDE1WjASMRAw\n" +
+            "DgYDVQQDEwdFQVAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+            "znAPUz26Msae4ws43czR41/J2QtrSIZUKmVUsVumDbYHrPNvTXKSMXAcewORDQYX\n" +
+            "RqvHvpn8CscB1+oGXZvHwxj4zV0WKoK2zeXkau3vcyl3HIKupJfq2TEACefVjj0t\n" +
+            "JW+X35PGWp9/H5zIUNVNVjS7Ums84IvKhRB8512PB9UyHagXYVX5GWpAcVpyfrlR\n" +
+            "FI9Qdhh+Pbk0uyktdbf/CdfgHOoebrTtwRljM0oDtX+2Cv6j0wBK7hD8pPvf1+uy\n" +
+            "GzczigAU/4Kw7eZqydf9B+5RupR+IZipX41xEiIrKRwqi517WWzXcjaG2cNbf451\n" +
+            "xpH5PnV3i1tq04jMGQUzFwIDAQABo4GAMH4wHQYDVR0OBBYEFIwX4vs8BiBcScod\n" +
+            "5noZHRM8E4+iMEIGA1UdIwQ7MDmAFIwX4vs8BiBcScod5noZHRM8E4+ioRakFDAS\n" +
+            "MRAwDgYDVQQDEwdFQVAgQ0ExggkAguUV3DMtW6swDAYDVR0TBAUwAwEB/zALBgNV\n" +
+            "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAFfQqOTA7Rv7K+luQ7pnas4BYwHE\n" +
+            "9GEP/uohv6KOy0TGQFbrRTjFoLVNB9BZ1ymMDZ0/TIwIUc7wi7a8t5mEqYH153wW\n" +
+            "aWooiSjyLLhuI4sNrNCOtisdBq2r2MFXt6h0mAQYOPv8R8K7/fgSxGFqzhyNmmVL\n" +
+            "1qBJldx34SpwsTALQVPb4hGwJzZfr1PcpEQx6xMnTl8xEWZE3Ms99uaUxbQqIwRu\n" +
+            "LgAOkNCmY2m89VhzaHJ1uV85AdM/tD+Ysmlnnjt9LRCejbBipjIGjOXrg1JP+lxV\n" +
+            "muM4vH+P/mlmxsPPz0d65b+EGmJZpoLkO/tdNNvCYzjJpTEWpEsO6NMhKYo=\n" +
+            "-----END CERTIFICATE-----\n";
+    public static final X509Certificate CA_CERT0 = loadCertificate(CA_CERT0_STRING);
+
+    private static final String CA_CERT1_STRING = "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDKDCCAhCgAwIBAgIJAOM5SzKO2pzCMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV\n" +
+            "BAMTB0VBUCBDQTAwHhcNMTYwMTEyMDAxMDQ3WhcNMjYwMTA5MDAxMDQ3WjASMRAw\n" +
+            "DgYDVQQDEwdFQVAgQ0EwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+            "89ug+IEKVQXnJGKg5g4uVHg6J/8iRUxR5k2eH5o03hrJNMfN2D+cBe/wCiZcnWbI\n" +
+            "GbGZACWm2nQth2wy9Zgm2LOd3b4ocrHYls3XLq6Qb5Dd7a0JKU7pdGufiNVEkrmF\n" +
+            "EB+N64wgwH4COTvCiN4erp5kyJwkfqAl2xLkZo0C464c9XoyQOXbmYD9A8v10wZu\n" +
+            "jyNsEo7Nr2USyw+qhjWSbFbEirP77Tvx+7pJQJwdtk1V9Tn73T2dGF2WHYejei9S\n" +
+            "mcWpdIUqsu9etYH+zDmtu7I1xlkwiaVsNr2+D+qaCJyOYqrDTKVNK5nmbBPXDWZc\n" +
+            "NoDbTOoqquX7xONpq9M6jQIDAQABo4GAMH4wHQYDVR0OBBYEFAZ3A2S4qJZZwuNY\n" +
+            "wkJ6mAdc0gVdMEIGA1UdIwQ7MDmAFAZ3A2S4qJZZwuNYwkJ6mAdc0gVdoRakFDAS\n" +
+            "MRAwDgYDVQQDEwdFQVAgQ0EwggkA4zlLMo7anMIwDAYDVR0TBAUwAwEB/zALBgNV\n" +
+            "HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAHmdMwEhtys4d0E+t7owBmoVR+lU\n" +
+            "hMCcRtWs8YKX5WIM2kTweT0h/O1xwE1mWmRv/IbDAEb8od4BjAQLhIcolStr2JaO\n" +
+            "9ZzyxjOnNzqeErh/1DHDbb/moPpqfeJ8YiEz7nH/YU56Q8iCPO7TsgS0sNNE7PfN\n" +
+            "IUsBW0yHRgpQ4OxWmiZG2YZWiECRzAC0ecPzo59N5iH4vLQIMTMYquiDeMPQnn1e\n" +
+            "NDGxG8gCtDKIaS6tMg3a28MvWB094pr2ETou8O1C8Ji0Y4hE8QJmSdT7I4+GZjgW\n" +
+            "g94DZ5RiL7sdp3vC48CXOmeT61YBIvhGUsE1rPhXqkpqQ3Z3C4TFF0jXZZc=\n" +
+            "-----END CERTIFICATE-----\n";
+    public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING);
+
+    private static final String CLIENT_CERT_STR = "-----BEGIN CERTIFICATE-----\n" +
+            "MIIE/DCCAuQCAQEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxCzAJBgNV\n" +
+            "BAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdUZXN0aW5n\n" +
+            "MB4XDTE2MDkzMDIwNTQyOFoXDTE3MDkzMDIwNTQyOFowRDELMAkGA1UEBhMCVVMx\n" +
+            "CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdU\n" +
+            "ZXN0aW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnpmcbuaeHfnJ\n" +
+            "k+2QNvxmdVFTawyFMNk0USCq5sexscwmxbewG/Rb8YnixwJWS44v2XkSujB67z5C\n" +
+            "s2qudFEhRXKdEuC6idbAuA97KjipHh0AAniWMsyv61fvbgsUC0b0canx3LiDq81p\n" +
+            "y28NNGmAvoazLZUZ4AhBRiwYZY6FKk723gmZoGbEIeG7J1dlXPusc1662rIjz4eU\n" +
+            "zlmmlvqyHfNqnNk8L14Vug6Xh+lOEGN85xhu1YHAEKGrS89kZxs5rum/cZU8KH2V\n" +
+            "v6eKnY03kxjiVLQtnLpm/7VUEoCMGHyruRj+p3my4+DgqMsmsH52RZCBsjyGlpbU\n" +
+            "NOwOTIX6xh+Rqloduz4AnrMYYIiIw2s8g+2zJM7VbcVKx0fGS26BKdrxgrXWfmNE\n" +
+            "nR0/REQ5AxDGw0jfTUvtdTkXAf+K4MDjcNLEZ+MA4rHfAfQWZtUR5BkHCQYxNpJk\n" +
+            "pA0gyk+BpKdC4WdzI14NSWsu5sRCmBCFqH6BTOSEq/V1cNorBxNwLSSTwFFqUDqx\n" +
+            "Y5nQLXygkJf9WHZWtSKeSjtOYgilz7UKzC2s3CsjmIyGFe+SwpuHJnuE4Uc8Z5Cb\n" +
+            "bjNGHPzqL6XnmzZHJp7RF8kBdKdjGC7dCUltzOfICZeKlzOOq+Kw42T/nXjuXvpb\n" +
+            "nkXNxg741Nwd6RecykXJbseFwm3EYxkCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEA\n" +
+            "Ga1mGwI9aXkL2fTPXO9YkAPzoGeX8aeuVYSQaSkNq+5vnogYCyAt3YDHjRG+ewTT\n" +
+            "WbnPA991xRAPac+biJeXWmwvgGj0YuT7e79phAiGkTTnbAjFHGfYnBy/tI/v7btO\n" +
+            "hRNElA5yTJ1m2fVbBEKXzMR83jrT9iyI+YLRN86zUZIaC86xxSbqnrdWN2jOK6MX\n" +
+            "dS8Arp9tPQjC/4gW+2Ilxv68jiYh+5auWHQZVjppWVY//iu4mAbkq1pTwQEhZ8F8\n" +
+            "Zrmh9DHh60hLFcfSuhIAwf/NMzppwdkjy1ruKVrpijhGKGp4OWu8nvOUgHSzxc7F\n" +
+            "PwpVZ5N2Ku4L8MLO6BG2VasRJK7l17TzDXlfLZHJjkuryOFxVaQKt8ZNFgTOaCXS\n" +
+            "E+gpTLksKU7riYckoiP4+H1sn9qcis0e8s4o/uf1UVc8GSdDw61ReGM5oZEDm1u8\n" +
+            "H9x20QU6igLqzyBpqvCKv7JNgU1uB2PAODHH78zJiUfnKd1y+o+J1iWzaGj3EFji\n" +
+            "T8AXksbTP733FeFXfggXju2dyBH+Z1S5BBTEOd1brWgXlHSAZGm97MKZ94r6/tkX\n" +
+            "qfv3fCos0DKz0oV7qBxYS8wiYhzrRVxG6ITAoH8uuUVVQaZF+G4nJ2jEqNbfuKyX\n" +
+            "ATQsVNjNNlDA0J33GobPMjT326wa4YAWMx8PI5PJZ3g=\n" +
+            "-----END CERTIFICATE-----\n";
+    public static final X509Certificate CLIENT_CERT = loadCertificate(CLIENT_CERT_STR);
+
+    private static final byte[] FAKE_RSA_KEY_1 = new byte[] {
+            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01,
+            (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
+            (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
+            (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82,
+            (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e,
+            (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81,
+            (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b,
+            (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66,
+            (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a,
+            (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02,
+            (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3,
+            (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d,
+            (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67,
+            (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb,
+            (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2,
+            (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79,
+            (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce,
+            (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08,
+            (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b,
+            (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4,
+            (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d,
+            (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23,
+            (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08,
+            (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1,
+            (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4,
+            (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16,
+            (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e,
+            (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01,
+            (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16,
+            (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98,
+            (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf,
+            (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a,
+            (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2,
+            (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc,
+            (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5,
+            (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a,
+            (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b,
+            (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9,
+            (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12,
+            (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e,
+            (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d,
+            (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2,
+            (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d,
+            (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc,
+            (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98,
+            (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96,
+            (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30,
+            (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e,
+            (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad,
+            (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f,
+            (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89,
+            (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13,
+            (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a,
+            (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e,
+            (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa,
+            (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47,
+            (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44,
+            (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22,
+            (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10,
+            (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45,
+            (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4,
+            (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda,
+            (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1,
+            (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab,
+            (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7,
+            (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc,
+            (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d,
+            (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82,
+            (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3,
+            (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a,
+            (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9,
+            (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6,
+            (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00,
+            (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd,
+            (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb,
+            (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4,
+            (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0,
+            (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2,
+            (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce,
+            (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a,
+            (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21,
+            (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d,
+            (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1,
+            (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41,
+            (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce,
+            (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0,
+            (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40,
+            (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a,
+            (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c,
+            (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90,
+            (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf,
+            (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb,
+            (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14,
+            (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab,
+            (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02,
+            (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67,
+            (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d,
+            (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d,
+            (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b,
+            (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2,
+            (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28,
+            (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd,
+            (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d,
+            (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b,
+            (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1,
+            (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51
+    };
+    public static final PrivateKey RSA_KEY1 = loadPrivateRSAKey(FAKE_RSA_KEY_1);
+
+    private static X509Certificate loadCertificate(String blob) {
+        try {
+            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            InputStream stream = new ByteArrayInputStream(blob.getBytes(StandardCharsets.UTF_8));
+
+            return (X509Certificate) certFactory.generateCertificate(stream);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    private static PrivateKey loadPrivateRSAKey(byte[] fakeKey) {
+        try {
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            return kf.generatePrivate(new PKCS8EncodedKeySpec(fakeKey));
+        } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+            return null;
+        }
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/ParcelUtilTest.java b/wifi/tests/src/android/net/wifi/ParcelUtilTest.java
new file mode 100644
index 0000000..6787594
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/ParcelUtilTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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 static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * Unit tests for {@link android.net.wifi.ParcelUtil}.
+ */
+@SmallTest
+public class ParcelUtilTest {
+    private Parcel mParcel;
+
+    @Before
+    public void setUp() throws Exception {
+        mParcel = Parcel.obtain();
+    }
+
+    @Test
+    public void readWriteNullPrivateKey() throws Exception {
+        ParcelUtil.writePrivateKey(mParcel, null);
+
+        mParcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        PrivateKey readKey = ParcelUtil.readPrivateKey(mParcel);
+        assertNull(readKey);
+    }
+
+    @Test
+    public void readWriteValidPrivateKey() throws Exception {
+        PrivateKey writeKey = FakeKeys.RSA_KEY1;
+        ParcelUtil.writePrivateKey(mParcel, writeKey);
+
+        mParcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        PrivateKey readKey = ParcelUtil.readPrivateKey(mParcel);
+        assertNotNull(readKey);
+        assertEquals(writeKey.getAlgorithm(), readKey.getAlgorithm());
+        assertArrayEquals(writeKey.getEncoded(), readKey.getEncoded());
+    }
+
+    @Test
+    public void readWriteNullCertificate() throws Exception {
+        ParcelUtil.writeCertificate(mParcel, null);
+
+        mParcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        X509Certificate readCert = ParcelUtil.readCertificate(mParcel);
+        assertNull(readCert);
+    }
+
+    @Test
+    public void readWriteValidCertificate() throws Exception {
+        X509Certificate writeCert = FakeKeys.CA_CERT1;
+        ParcelUtil.writeCertificate(mParcel, writeCert);
+
+        mParcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        X509Certificate readCert = ParcelUtil.readCertificate(mParcel);
+        assertNotNull(readCert);
+        assertArrayEquals(writeCert.getEncoded(), readCert.getEncoded());
+    }
+
+    @Test
+    public void readWriteNullCertificates() throws Exception {
+        ParcelUtil.writeCertificates(mParcel, null);
+
+        mParcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        X509Certificate[] readCerts = ParcelUtil.readCertificates(mParcel);
+        assertNull(readCerts);
+    }
+
+    @Test
+    public void readWriteValidCertificates() throws Exception {
+        X509Certificate[] writeCerts = new X509Certificate[2];
+        writeCerts[0] = FakeKeys.CA_CERT0;
+        writeCerts[1] = FakeKeys.CA_CERT1;
+        ParcelUtil.writeCertificates(mParcel, writeCerts);
+
+        mParcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
+        X509Certificate[] readCerts = ParcelUtil.readCertificates(mParcel);
+        assertNotNull(readCerts);
+        assertEquals(writeCerts.length, readCerts.length);
+        for (int i = 0; i < writeCerts.length; i++) {
+            assertNotNull(readCerts[i]);
+            assertArrayEquals(writeCerts[i].getEncoded(), readCerts[i].getEncoded());
+        }
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
new file mode 100644
index 0000000..0e503d5
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -0,0 +1,324 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.wifi.WifiEnterpriseConfig.Eap;
+import android.net.wifi.WifiEnterpriseConfig.Phase2;
+import android.os.Parcel;
+import android.security.Credentials;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiEnterpriseConfig}.
+ */
+@SmallTest
+public class WifiEnterpriseConfigTest {
+    // Maintain a ground truth of the keystore uri prefix which is expected by wpa_supplicant.
+    public static final String KEYSTORE_URI = "keystore://";
+    public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
+    public static final String KEYSTORES_URI = "keystores://";
+
+    private WifiEnterpriseConfig mEnterpriseConfig;
+
+    @Before
+    public void setUp() throws Exception {
+        mEnterpriseConfig = new WifiEnterpriseConfig();
+    }
+
+    @Test
+    public void testGetEmptyCaCertificate() {
+        // A newly-constructed WifiEnterpriseConfig object should have no CA certificate.
+        assertNull(mEnterpriseConfig.getCaCertificate());
+        assertNull(mEnterpriseConfig.getCaCertificates());
+        // Setting CA certificate to null explicitly.
+        mEnterpriseConfig.setCaCertificate(null);
+        assertNull(mEnterpriseConfig.getCaCertificate());
+        // Setting CA certificate to null using setCaCertificates().
+        mEnterpriseConfig.setCaCertificates(null);
+        assertNull(mEnterpriseConfig.getCaCertificates());
+        // Setting CA certificate to zero-length array.
+        mEnterpriseConfig.setCaCertificates(new X509Certificate[0]);
+        assertNull(mEnterpriseConfig.getCaCertificates());
+    }
+
+    @Test
+    public void testSetGetSingleCaCertificate() {
+        X509Certificate cert0 = FakeKeys.CA_CERT0;
+        mEnterpriseConfig.setCaCertificate(cert0);
+        assertEquals(mEnterpriseConfig.getCaCertificate(), cert0);
+    }
+
+    @Test
+    public void testSetGetMultipleCaCertificates() {
+        X509Certificate cert0 = FakeKeys.CA_CERT0;
+        X509Certificate cert1 = FakeKeys.CA_CERT1;
+        mEnterpriseConfig.setCaCertificates(new X509Certificate[] {cert0, cert1});
+        X509Certificate[] result = mEnterpriseConfig.getCaCertificates();
+        assertEquals(result.length, 2);
+        assertTrue(result[0] == cert0 && result[1] == cert1);
+    }
+
+    @Test
+    public void testSaveSingleCaCertificateAlias() {
+        final String alias = "single_alias 0";
+        mEnterpriseConfig.setCaCertificateAliases(new String[] {alias});
+        assertEquals(getCaCertField(), CA_CERT_PREFIX + alias);
+    }
+
+    @Test
+    public void testLoadSingleCaCertificateAlias() {
+        final String alias = "single_alias 1";
+        setCaCertField(CA_CERT_PREFIX + alias);
+        String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
+        assertEquals(aliases.length, 1);
+        assertEquals(aliases[0], alias);
+    }
+
+    @Test
+    public void testSaveMultipleCaCertificates() {
+        final String alias0 = "single_alias 0";
+        final String alias1 = "single_alias 1";
+        mEnterpriseConfig.setCaCertificateAliases(new String[] {alias0, alias1});
+        assertEquals(getCaCertField(), String.format("%s%s %s",
+                KEYSTORES_URI,
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
+    }
+
+    @Test
+    public void testLoadMultipleCaCertificates() {
+        final String alias0 = "single_alias 0";
+        final String alias1 = "single_alias 1";
+        setCaCertField(String.format("%s%s %s",
+                KEYSTORES_URI,
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias0),
+                WifiEnterpriseConfig.encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + alias1)));
+        String[] aliases = mEnterpriseConfig.getCaCertificateAliases();
+        assertEquals(aliases.length, 2);
+        assertEquals(aliases[0], alias0);
+        assertEquals(aliases[1], alias1);
+    }
+
+    private String getCaCertField() {
+        return mEnterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY);
+    }
+
+    private void setCaCertField(String value) {
+        mEnterpriseConfig.setFieldValue(WifiEnterpriseConfig.CA_CERT_KEY, value);
+    }
+
+    // Retrieves the value for a specific key supplied to wpa_supplicant.
+    private class SupplicantConfigExtractor implements WifiEnterpriseConfig.SupplicantSaver {
+        private String mValue = null;
+        private String mKey;
+
+        SupplicantConfigExtractor(String key) {
+            mKey = key;
+        }
+
+        @Override
+        public boolean saveValue(String key, String value) {
+            if (key.equals(mKey)) {
+                mValue = value;
+            }
+            return true;
+        }
+
+        public String getValue() {
+            return mValue;
+        }
+    }
+
+    private String getSupplicantEapMethod() {
+        SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
+                WifiEnterpriseConfig.EAP_KEY);
+        mEnterpriseConfig.saveToSupplicant(entryExtractor);
+        return entryExtractor.getValue();
+    }
+
+    private String getSupplicantPhase2Method() {
+        SupplicantConfigExtractor entryExtractor = new SupplicantConfigExtractor(
+                WifiEnterpriseConfig.PHASE2_KEY);
+        mEnterpriseConfig.saveToSupplicant(entryExtractor);
+        return entryExtractor.getValue();
+    }
+
+    /** Verifies the default value for EAP outer and inner methods */
+    @Test
+    public void eapInnerDefault() {
+        assertEquals(null, getSupplicantEapMethod());
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verifies that the EAP inner method is reset when we switch to TLS */
+    @Test
+    public void eapPhase2MethodForTls() {
+        // Initially select an EAP method that supports an phase2.
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the EAP method to another type which supports a phase2.
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the EAP method to TLS which does not support a phase2.
+        mEnterpriseConfig.setEapMethod(Eap.TLS);
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the EAP inner method is reset when we switch phase2 to NONE */
+    @Test
+    public void eapPhase2None() {
+        // Initially select an EAP method that supports an phase2.
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=MSCHAPV2\"", getSupplicantPhase2Method());
+
+        // Change the phase2 method to NONE and ensure the value is cleared.
+        mEnterpriseConfig.setPhase2Method(Phase2.NONE);
+        assertEquals(null, getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the correct "autheap" parameter is supplied for TTLS/GTC. */
+    @Test
+    public void peapGtcToTtls() {
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the correct "auth" parameter is supplied for PEAP/GTC. */
+    @Test
+    public void ttlsGtcToPeap() {
+        mEnterpriseConfig.setEapMethod(Eap.TTLS);
+        mEnterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        assertEquals("PEAP", getSupplicantEapMethod());
+        assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that the copy constructor preseves the inner method information. */
+    @Test
+    public void copyConstructor() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /** Verfies that parceling a WifiEnterpriseConfig preseves method information. */
+    @Test
+    public void parcelConstructor() {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        Parcel parcel = Parcel.obtain();
+        enterpriseConfig.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);  // Allow parcel to be read from the beginning.
+        mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
+        assertEquals("TTLS", getSupplicantEapMethod());
+        assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
+    }
+
+    /**
+     * Verifies that parceling a WifiEnterpriseConfig preserves the key
+     * and certificates information.
+     */
+    @Test
+    public void parcelConfigWithKeyAndCerts() throws Exception {
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        PrivateKey clientKey = FakeKeys.RSA_KEY1;
+        X509Certificate clientCert = FakeKeys.CLIENT_CERT;
+        X509Certificate[] caCerts = new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1};
+        enterpriseConfig.setClientKeyEntry(clientKey, clientCert);
+        enterpriseConfig.setCaCertificates(caCerts);
+        Parcel parcel = Parcel.obtain();
+        enterpriseConfig.writeToParcel(parcel, 0);
+
+        parcel.setDataPosition(0);  // Allow parcel to be read from the beginning.
+        mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
+        PrivateKey actualClientKey = mEnterpriseConfig.getClientPrivateKey();
+        X509Certificate actualClientCert = mEnterpriseConfig.getClientCertificate();
+        X509Certificate[] actualCaCerts = mEnterpriseConfig.getCaCertificates();
+
+        /* Verify client private key. */
+        assertNotNull(actualClientKey);
+        assertEquals(clientKey.getAlgorithm(), actualClientKey.getAlgorithm());
+        assertArrayEquals(clientKey.getEncoded(), actualClientKey.getEncoded());
+
+        /* Verify client certificate. */
+        assertNotNull(actualClientCert);
+        assertArrayEquals(clientCert.getEncoded(), actualClientCert.getEncoded());
+
+        /* Verify CA certificates. */
+        assertNotNull(actualCaCerts);
+        assertEquals(caCerts.length, actualCaCerts.length);
+        for (int i = 0; i < caCerts.length; i++) {
+            assertNotNull(actualCaCerts[i]);
+            assertArrayEquals(caCerts[i].getEncoded(), actualCaCerts[i].getEncoded());
+        }
+    }
+
+    /** Verifies proper operation of the getKeyId() method. */
+    @Test
+    public void getKeyId() {
+        assertEquals("NULL", mEnterpriseConfig.getKeyId(null));
+        WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+        enterpriseConfig.setEapMethod(Eap.TTLS);
+        enterpriseConfig.setPhase2Method(Phase2.GTC);
+        assertEquals("TTLS_GTC", mEnterpriseConfig.getKeyId(enterpriseConfig));
+        mEnterpriseConfig.setEapMethod(Eap.PEAP);
+        mEnterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
+        assertEquals("PEAP_MSCHAPV2", mEnterpriseConfig.getKeyId(enterpriseConfig));
+    }
+
+    /** Verifies that passwords are not displayed in toString. */
+    @Test
+    public void passwordNotInToString() {
+        String password = "supersecret";
+        mEnterpriseConfig.setPassword(password);
+        assertFalse(mEnterpriseConfig.toString().contains(password));
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
new file mode 100644
index 0000000..a829eb9
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.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;
+
+import com.android.internal.util.test.BidirectionalAsyncChannelServer;
+
+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}.
+ */
+@SmallTest
+public class WifiScannerTest {
+    @Mock
+    private Context mContext;
+    @Mock
+    private IWifiScanner mService;
+    @Mock
+    private BssidListener mBssidListener;
+
+    private WifiScanner mWifiScanner;
+    private TestLooper mLooper;
+    private Handler mHandler;
+
+    /**
+     * Setup before tests.
+     */
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mLooper = new TestLooper();
+        mHandler = mock(Handler.class);
+        BidirectionalAsyncChannelServer server = new BidirectionalAsyncChannelServer(
+                mContext, mLooper.getLooper(), mHandler);
+        when(mService.getMessenger()).thenReturn(server.getMessenger());
+        mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
+        mLooper.dispatchAll();
+    }
+
+    /**
+     * Clean up after tests.
+     */
+    @After
+    public void cleanup() {
+        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());
+    }
+}