Merge "Add new error codes in MbmsException"
diff --git a/Android.mk b/Android.mk
index 2571afb..435d571 100644
--- a/Android.mk
+++ b/Android.mk
@@ -772,7 +772,6 @@
 include libcore/Docs.mk
 
 non_base_dirs := \
-	../opt/telephony/src/java/android/provider \
 	../opt/telephony/src/java/android/telephony \
 	../opt/telephony/src/java/android/telephony/gsm \
 	../opt/net/voip/src/java/android/net/rtp \
diff --git a/api/current.txt b/api/current.txt
index 55dda04..4275e9d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23784,8 +23784,8 @@
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, int);
+    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler, int);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
     method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 5e9c7e3..f33d506 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -25572,8 +25572,8 @@
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, int);
+    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler, int);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
     method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 5487a97..bd96efb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -23858,8 +23858,8 @@
     method public boolean requestBandwidthUpdate(android.net.Network);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
     method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback);
-    method public void requestNetwork(android.net.NetworkRequest, int, android.net.ConnectivityManager.NetworkCallback, android.os.Handler);
+    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, int);
+    method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback, android.os.Handler, int);
     method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent);
     method public deprecated boolean requestRouteToHost(int, int);
     method public deprecated void setNetworkPreference(int);
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index f802e8d..914e8fd 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -47,7 +47,9 @@
     private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
     private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
     private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
-    private static final int DATA_TYPE_SERVICE_DATA = 0x16;
+    private static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16;
+    private static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20;
+    private static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21;
     private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
 
     // Flags of the advertising data.
@@ -224,10 +226,16 @@
                     case DATA_TYPE_TX_POWER_LEVEL:
                         txPowerLevel = scanRecord[currentPos];
                         break;
-                    case DATA_TYPE_SERVICE_DATA:
-                        // The first two bytes of the service data are service data UUID in little
-                        // endian. The rest bytes are service data.
+                    case DATA_TYPE_SERVICE_DATA_16_BIT:
+                    case DATA_TYPE_SERVICE_DATA_32_BIT:
+                    case DATA_TYPE_SERVICE_DATA_128_BIT:
                         int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
+                        if (fieldType == DATA_TYPE_SERVICE_DATA_32_BIT) {
+                         serviceUuidLength = BluetoothUuid.UUID_BYTES_32_BIT;
+                        } else if (fieldType == DATA_TYPE_SERVICE_DATA_128_BIT) {
+                         serviceUuidLength = BluetoothUuid.UUID_BYTES_128_BIT;
+                        }
+
                         byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
                                 serviceUuidLength);
                         ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom(
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 46b981e..2736ba6e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -467,21 +467,12 @@
     void notifyDexLoad(String loadingPackageName, in List<String> dexPaths, String loaderIsa);
 
     /**
-     * Ask the package manager to perform dex-opt (if needed) on the given
-     * package if it already hasn't done so.
-     *
-     * In most cases, apps are dexopted in advance and this function will
-     * be a no-op.
-     */
-    boolean performDexOptIfNeeded(String packageName);
-
-    /**
      * Ask the package manager to perform a dex-opt for the given reason. The package
      * manager will map the reason to a compiler filter according to the current system
      * configuration.
      */
     boolean performDexOpt(String packageName, boolean checkProfiles,
-            int compileReason, boolean force);
+            int compileReason, boolean force, boolean bootComplete);
 
     /**
      * Ask the package manager to perform a dex-opt with the given compiler filter.
@@ -490,7 +481,7 @@
      *       definite state.
      */
     boolean performDexOptMode(String packageName, boolean checkProfiles,
-            String targetCompilerFilter, boolean force);
+            String targetCompilerFilter, boolean force, boolean bootComplete);
 
     /**
      * Ask the package manager to perform a dex-opt with the given compiler filter on the
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 54286d1..9e8acd0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1466,9 +1466,7 @@
         // Map from type to transports.
         final int NOT_FOUND = -1;
         final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND);
-        if (transport == NOT_FOUND) {
-            throw new IllegalArgumentException("unknown legacy type: " + type);
-        }
+        Preconditions.checkArgument(transport != NOT_FOUND, "unknown legacy type: " + type);
         nc.addTransportType(transport);
 
         // Map from type to capabilities.
@@ -1814,9 +1812,7 @@
      */
     public void removeDefaultNetworkActiveListener(OnNetworkActiveListener l) {
         INetworkActivityListener rl = mNetworkActivityListeners.get(l);
-        if (rl == null) {
-            throw new IllegalArgumentException("Listener not registered: " + l);
-        }
+        Preconditions.checkArgument(rl != null, "Listener was not registered.");
         try {
             getNetworkManagementService().unregisterNetworkActivityListener(rl);
         } catch (RemoteException e) {
@@ -1873,9 +1869,8 @@
 
     /** {@hide} */
     public static final void enforceTetherChangePermission(Context context, String callingPkg) {
-        if (null == context || null == callingPkg) {
-            throw new IllegalArgumentException("arguments should not be null");
-        }
+        Preconditions.checkNotNull(context, "Context cannot be null");
+        Preconditions.checkNotNull(callingPkg, "callingPkg cannot be null");
 
         if (context.getResources().getStringArray(
                 com.android.internal.R.array.config_mobile_hotspot_provision_app).length == 2) {
@@ -2648,7 +2643,7 @@
 
         /**
          * Called if no network is found in the timeout time specified in
-         * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)} call. This callback is not
+         * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call. This callback is not
          * called for the version of {@link #requestNetwork(NetworkRequest, NetworkCallback)}
          * without timeout. When this callback is invoked the associated
          * {@link NetworkRequest} will have already been removed and released, as if
@@ -2773,84 +2768,67 @@
         }
 
         CallbackHandler(Handler handler) {
-            this(handler.getLooper());
+            this(Preconditions.checkNotNull(handler, "Handler cannot be null.").getLooper());
         }
 
         @Override
         public void handleMessage(Message message) {
-            NetworkRequest request = getObject(message, NetworkRequest.class);
-            Network network = getObject(message, Network.class);
+            if (message.what == EXPIRE_LEGACY_REQUEST) {
+                expireRequest((NetworkCapabilities) message.obj, message.arg1);
+                return;
+            }
+
+            final NetworkRequest request = getObject(message, NetworkRequest.class);
+            final Network network = getObject(message, Network.class);
+            final NetworkCallback callback;
+            synchronized (sCallbacks) {
+                callback = sCallbacks.get(request);
+            }
             if (DBG) {
                 Log.d(TAG, getCallbackName(message.what) + " for network " + network);
             }
+            if (callback == null) {
+                Log.w(TAG, "callback not found for " + getCallbackName(message.what) + " message");
+                return;
+            }
+
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        callback.onPreCheck(network);
-                    }
+                    callback.onPreCheck(network);
                     break;
                 }
                 case CALLBACK_AVAILABLE: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        callback.onAvailable(network);
-                    }
+                    callback.onAvailable(network);
                     break;
                 }
                 case CALLBACK_LOSING: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        callback.onLosing(network, message.arg1);
-                    }
+                    callback.onLosing(network, message.arg1);
                     break;
                 }
                 case CALLBACK_LOST: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        callback.onLost(network);
-                    }
+                    callback.onLost(network);
                     break;
                 }
                 case CALLBACK_UNAVAIL: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        callback.onUnavailable();
-                    }
+                    callback.onUnavailable();
                     break;
                 }
                 case CALLBACK_CAP_CHANGED: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
-                        callback.onCapabilitiesChanged(network, cap);
-                    }
+                    NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
+                    callback.onCapabilitiesChanged(network, cap);
                     break;
                 }
                 case CALLBACK_IP_CHANGED: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        LinkProperties lp = getObject(message, LinkProperties.class);
-                        callback.onLinkPropertiesChanged(network, lp);
-                    }
+                    LinkProperties lp = getObject(message, LinkProperties.class);
+                    callback.onLinkPropertiesChanged(network, lp);
                     break;
                 }
                 case CALLBACK_SUSPENDED: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        callback.onNetworkSuspended(network);
-                    }
+                    callback.onNetworkSuspended(network);
                     break;
                 }
                 case CALLBACK_RESUMED: {
-                    NetworkCallback callback = getCallback(message);
-                    if (callback != null) {
-                        callback.onNetworkResumed(network);
-                    }
-                    break;
-                }
-                case EXPIRE_LEGACY_REQUEST: {
-                    expireRequest((NetworkCapabilities)message.obj, message.arg1);
+                    callback.onNetworkResumed(network);
                     break;
                 }
             }
@@ -2859,18 +2837,6 @@
         private <T> T getObject(Message msg, Class<T> c) {
             return (T) msg.getData().getParcelable(c.getSimpleName());
         }
-
-        private NetworkCallback getCallback(Message msg) {
-            final NetworkRequest req = getObject(msg, NetworkRequest.class);
-            final NetworkCallback callback;
-            synchronized(sCallbacks) {
-                callback = sCallbacks.get(req);
-            }
-            if (callback == null) {
-                Log.w(TAG, "callback not found for " + getCallbackName(msg.what) + " message");
-            }
-            return callback;
-        }
     }
 
     private CallbackHandler getDefaultHandler() {
@@ -2890,7 +2856,7 @@
 
     private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
             int timeoutMs, int action, int legacyType, CallbackHandler handler) {
-        Preconditions.checkArgument(callback != null, "null NetworkCallback");
+        checkCallbackNotNull(callback);
         Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
         final NetworkRequest request;
         try {
@@ -2945,7 +2911,7 @@
      * This {@link NetworkRequest} will live until released via
      * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. A
      * version of the method which takes a timeout is
-     * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)}.
+     * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}.
      * Status of the request can be followed by listening to the various
      * callbacks described in {@link NetworkCallback}.  The {@link Network}
      * can be used to direct traffic to the network.
@@ -2980,7 +2946,7 @@
      * This {@link NetworkRequest} will live until released via
      * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. A
      * version of the method which takes a timeout is
-     * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)}.
+     * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}.
      * Status of the request can be followed by listening to the various
      * callbacks described in {@link NetworkCallback}.  The {@link Network}
      * can be used to direct traffic to the network.
@@ -3013,50 +2979,6 @@
     }
 
     /**
-     * Note: this is a deprecated version of
-     * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)} - please transition code to use
-     * the unhidden version of the function.
-     * TODO: replace all callers with the new version of the API
-     *
-     * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
-     * by a timeout.
-     *
-     * This function behaves identically to the non-timed-out version
-     * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, but if a suitable network
-     * is not found within the given time (in milliseconds) the
-     * {@link NetworkCallback#onUnavailable()} callback is called. The request can still be
-     * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
-     * not have to be released if timed-out (it is automatically released). Unregistering a
-     * request that timed out is not an error.
-     *
-     * <p>Do not use this method to poll for the existence of specific networks (e.g. with a small
-     * timeout) - the {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided
-     * for that purpose. Calling this method will attempt to bring up the requested network.
-     *
-     * <p>This method requires the caller to hold either the
-     * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
-     * or the ability to modify system settings as determined by
-     * {@link android.provider.Settings.System#canWrite}.</p>
-     *
-     * @param request {@link NetworkRequest} describing this request.
-     * @param networkCallback The callbacks to be utilized for this request.  Note
-     *                        the callbacks must not be shared - they uniquely specify
-     *                        this request.
-     * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
-     *                  before {@link NetworkCallback#onUnavailable()} is called. The timeout must
-     *                  be a positive value (i.e. >0).
-     * @hide
-     */
-    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
-            int timeoutMs) {
-        if (timeoutMs <= 0) {
-            throw new IllegalArgumentException("Non-positive timeoutMs: " + timeoutMs);
-        }
-        int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
-        requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
-    }
-
-    /**
      * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
      * by a timeout.
      *
@@ -3078,22 +3000,19 @@
      * {@link android.provider.Settings.System#canWrite}.</p>
      *
      * @param request {@link NetworkRequest} describing this request.
+     * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+     *                        the callback must not be shared - it uniquely specifies this request.
      * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
      *                  before {@link NetworkCallback#onUnavailable()} is called. The timeout must
      *                  be a positive value (i.e. >0).
-     * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
-     *                        the callback must not be shared - it uniquely specifies this request.
      */
-    public void requestNetwork(NetworkRequest request, int timeoutMs,
-            NetworkCallback networkCallback) {
-        if (timeoutMs <= 0) {
-            throw new IllegalArgumentException("Non-positive timeoutMs: " + timeoutMs);
-        }
+    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+            int timeoutMs) {
+        checkTimeout(timeoutMs);
         int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
         requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
     }
 
-
     /**
      * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
      * by a timeout.
@@ -3115,17 +3034,15 @@
      * {@link android.provider.Settings.System#canWrite}.</p>
      *
      * @param request {@link NetworkRequest} describing this request.
-     * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
-     *                  before {@link NetworkCallback#onUnavailable} is called.
      * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
      *                        the callback must not be shared - it uniquely specifies this request.
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+     *                  before {@link NetworkCallback#onUnavailable} is called.
      */
-    public void requestNetwork(NetworkRequest request, int timeoutMs,
-            NetworkCallback networkCallback, Handler handler) {
-        if (timeoutMs <= 0) {
-            throw new IllegalArgumentException("Non-positive timeoutMs");
-        }
+    public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+            Handler handler, int timeoutMs) {
+        checkTimeout(timeoutMs);
         int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
         CallbackHandler cbHandler = new CallbackHandler(handler);
         requestNetwork(request, networkCallback, timeoutMs, legacyType, cbHandler);
@@ -3197,7 +3114,7 @@
      *         {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
      */
     public void requestNetwork(NetworkRequest request, PendingIntent operation) {
-        checkPendingIntent(operation);
+        checkPendingIntentNotNull(operation);
         try {
             mService.pendingRequestForNetwork(request.networkCapabilities, operation);
         } catch (RemoteException e) {
@@ -3220,7 +3137,7 @@
      *                  corresponding NetworkRequest you'd like to remove. Cannot be null.
      */
     public void releaseNetworkRequest(PendingIntent operation) {
-        checkPendingIntent(operation);
+        checkPendingIntentNotNull(operation);
         try {
             mService.releasePendingNetworkRequest(operation);
         } catch (RemoteException e) {
@@ -3228,10 +3145,16 @@
         }
     }
 
-    private void checkPendingIntent(PendingIntent intent) {
-        if (intent == null) {
-            throw new IllegalArgumentException("PendingIntent cannot be null.");
-        }
+    private static void checkPendingIntentNotNull(PendingIntent intent) {
+        Preconditions.checkNotNull(intent, "PendingIntent cannot be null.");
+    }
+
+    private static void checkCallbackNotNull(NetworkCallback callback) {
+        Preconditions.checkNotNull(callback, "null NetworkCallback");
+    }
+
+    private static void checkTimeout(int timeoutMs) {
+        Preconditions.checkArgumentPositive(timeoutMs, "timeoutMs must be strictly positive.");
     }
 
     /**
@@ -3301,7 +3224,7 @@
      *                  comes from {@link PendingIntent#getBroadcast}. Cannot be null.
      */
     public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) {
-        checkPendingIntent(operation);
+        checkPendingIntentNotNull(operation);
         try {
             mService.pendingListenForNetwork(request.networkCapabilities, operation);
         } catch (RemoteException e) {
@@ -3345,8 +3268,9 @@
         // capabilities, this request is guaranteed, at all times, to be
         // satisfied by the same network, if any, that satisfies the default
         // request, i.e., the system default network.
+        NetworkCapabilities nullCapabilities = null;
         CallbackHandler cbHandler = new CallbackHandler(handler);
-        sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
+        sendRequestForNetwork(nullCapabilities, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
     }
 
     /**
@@ -3383,7 +3307,7 @@
      * @param networkCallback The {@link NetworkCallback} used when making the request.
      */
     public void unregisterNetworkCallback(NetworkCallback networkCallback) {
-        Preconditions.checkArgument(networkCallback != null, "null NetworkCallback");
+        checkCallbackNotNull(networkCallback);
         final List<NetworkRequest> reqs = new ArrayList<>();
         // Find all requests associated to this callback and stop callback triggers immediately.
         // Callback is reusable immediately. http://b/20701525, http://b/35921499.
@@ -3419,6 +3343,7 @@
      *                  Cannot be null.
      */
     public void unregisterNetworkCallback(PendingIntent operation) {
+        checkPendingIntentNotNull(operation);
         releaseNetworkRequest(operation);
     }
 
@@ -3487,8 +3412,8 @@
     /**
      * It is acceptable to briefly use multipath data to provide seamless connectivity for
      * time-sensitive user-facing operations when the system default network is temporarily
-     * unresponsive. The amount of data should be limited (less than one megabyte), and the
-     * operation should be infrequent to ensure that data usage is limited.
+     * unresponsive. The amount of data should be limited (less than one megabyte for every call to
+     * this method), and the operation should be infrequent to ensure that data usage is limited.
      *
      * An example of such an operation might be a time-sensitive foreground activity, such as a
      * voice command, that the user is performing while walking out of range of a Wi-Fi network.
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 7b845be..bccaf60 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -30,7 +30,6 @@
 import java.util.Collections;
 import java.util.Map;
 
-
 /**
  * A class representing service information for network service discovery
  * {@see NsdManager}
@@ -43,7 +42,7 @@
 
     private String mServiceType;
 
-    private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<String, byte[]>();
+    private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<>();
 
     private InetAddress mHost;
 
diff --git a/core/java/android/nfc/IAppCallback.aidl b/core/java/android/nfc/IAppCallback.aidl
index c027d54..133146d 100644
--- a/core/java/android/nfc/IAppCallback.aidl
+++ b/core/java/android/nfc/IAppCallback.aidl
@@ -25,6 +25,6 @@
 interface IAppCallback
 {
     BeamShareData createBeamShareData(byte peerLlcpVersion);
-    void onNdefPushComplete(byte peerLlcpVersion);
-    void onTagDiscovered(in Tag tag);
+    oneway void onNdefPushComplete(byte peerLlcpVersion);
+    oneway void onTagDiscovered(in Tag tag);
 }
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 2c9ce3f..093a9b4 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -938,7 +938,7 @@
      */
     void writeToByteBuffer(ByteBuffer buffer, boolean mb, boolean me) {
         boolean sr = mPayload.length < 256;
-        boolean il = mId.length > 0;
+        boolean il = mTnf == TNF_EMPTY ? true : mId.length > 0;
 
         byte flags = (byte)((mb ? FLAG_MB : 0) | (me ? FLAG_ME : 0) |
                 (sr ? FLAG_SR : 0) | (il ? FLAG_IL : 0) | mTnf);
@@ -966,7 +966,7 @@
         int length = 3 + mType.length + mId.length + mPayload.length;
 
         boolean sr = mPayload.length < 256;
-        boolean il = mId.length > 0;
+        boolean il = mTnf == TNF_EMPTY ? true : mId.length > 0;
 
         if (!sr) length += 3;
         if (il) length += 1;
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 37d6757..2b03ed6 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -16,25 +16,17 @@
 
 package android.util;
 
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
 import android.os.SystemClock;
-import android.text.format.DateUtils;
 
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
-import java.util.TimeZone;
-
+import java.util.List;
+import libcore.util.TimeZoneFinder;
 import libcore.util.ZoneInfoDB;
 
 /**
@@ -45,14 +37,9 @@
     private static final boolean DBG = false;
     private static final String TAG = "TimeUtils";
 
-    /** Cached results of getTineZones */
-    private static final Object sLastLockObj = new Object();
-    private static ArrayList<TimeZone> sLastZones = null;
-    private static String sLastCountry = null;
-
     /** Cached results of getTimeZonesWithUniqueOffsets */
     private static final Object sLastUniqueLockObj = new Object();
-    private static ArrayList<TimeZone> sLastUniqueZoneOffsets = null;
+    private static List<String> sLastUniqueZoneOffsets = null;
     private static String sLastUniqueCountry = null;
 
     /** {@hide} */
@@ -63,50 +50,39 @@
      * and DST value at the specified moment in the specified country.
      * Returns null if no suitable zone could be found.
      */
-    public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) {
-        TimeZone best = null;
-        final Date d = new Date(when);
+    public static java.util.TimeZone getTimeZone(
+            int offset, boolean dst, long when, String country) {
 
-        TimeZone current = TimeZone.getDefault();
-        String currentName = current.getID();
-        int currentOffset = current.getOffset(when);
-        boolean currentDst = current.inDaylightTime(d);
-
-        for (TimeZone tz : getTimeZones(country)) {
-            // If the current time zone is from the right country
-            // and meets the other known properties, keep it
-            // instead of changing to another one.
-
-            if (tz.getID().equals(currentName)) {
-                if (currentOffset == offset && currentDst == dst) {
-                    return current;
-                }
-            }
-
-            // Otherwise, take the first zone from the right
-            // country that has the correct current offset and DST.
-            // (Keep iterating instead of returning in case we
-            // haven't encountered the current time zone yet.)
-
-            if (best == null) {
-                if (tz.getOffset(when) == offset &&
-                    tz.inDaylightTime(d) == dst) {
-                    best = tz;
-                }
-            }
-        }
-
-        return best;
+        android.icu.util.TimeZone icuTimeZone = getIcuTimeZone(offset, dst, when, country);
+        // We must expose a java.util.TimeZone here for API compatibility because this is a public
+        // API method.
+        return icuTimeZone != null ? java.util.TimeZone.getTimeZone(icuTimeZone.getID()) : null;
     }
 
     /**
-     * Return list of unique time zones for the country. Do not modify
+     * Tries to return a frozen ICU time zone that would have had the specified offset
+     * and DST value at the specified moment in the specified country.
+     * Returns null if no suitable zone could be found.
+     */
+    private static android.icu.util.TimeZone getIcuTimeZone(
+            int offset, boolean dst, long when, String country) {
+        if (country == null) {
+            return null;
+        }
+
+        android.icu.util.TimeZone bias = android.icu.util.TimeZone.getDefault();
+        return TimeZoneFinder.getInstance()
+                .lookupTimeZoneByCountryAndOffset(country, offset, dst, when, bias);
+    }
+
+    /**
+     * Returns an immutable list of unique time zone IDs for the country.
      *
      * @param country to find
-     * @return list of unique time zones, maybe empty but never null. Do not modify.
+     * @return unmodifiable list of unique time zones, maybe empty but never null.
      * @hide
      */
-    public static ArrayList<TimeZone> getTimeZonesWithUniqueOffsets(String country) {
+    public static List<String> getTimeZoneIdsWithUniqueOffsets(String country) {
         synchronized(sLastUniqueLockObj) {
             if ((country != null) && country.equals(sLastUniqueCountry)) {
                 if (DBG) {
@@ -117,9 +93,9 @@
             }
         }
 
-        Collection<TimeZone> zones = getTimeZones(country);
-        ArrayList<TimeZone> uniqueTimeZones = new ArrayList<TimeZone>();
-        for (TimeZone zone : zones) {
+        Collection<android.icu.util.TimeZone> zones = getIcuTimeZones(country);
+        ArrayList<android.icu.util.TimeZone> uniqueTimeZones = new ArrayList<>();
+        for (android.icu.util.TimeZone zone : zones) {
             // See if we already have this offset,
             // Using slow but space efficient and these are small.
             boolean found = false;
@@ -129,7 +105,7 @@
                     break;
                 }
             }
-            if (found == false) {
+            if (!found) {
                 if (DBG) {
                     Log.d(TAG, "getTimeZonesWithUniqueOffsets: add unique offset=" +
                             zone.getRawOffset() + " zone.getID=" + zone.getID());
@@ -140,81 +116,43 @@
 
         synchronized(sLastUniqueLockObj) {
             // Cache the last result
-            sLastUniqueZoneOffsets = uniqueTimeZones;
+            sLastUniqueZoneOffsets = extractZoneIds(uniqueTimeZones);
             sLastUniqueCountry = country;
 
             return sLastUniqueZoneOffsets;
         }
     }
 
+    private static List<String> extractZoneIds(List<android.icu.util.TimeZone> timeZones) {
+        List<String> ids = new ArrayList<>(timeZones.size());
+        for (android.icu.util.TimeZone timeZone : timeZones) {
+            ids.add(timeZone.getID());
+        }
+        return Collections.unmodifiableList(ids);
+    }
+
     /**
-     * Returns the time zones for the country, which is the code
-     * attribute of the timezone element in time_zones_by_country.xml. Do not modify.
+     * Returns an immutable list of frozen ICU time zones for the country.
      *
-     * @param country is a two character country code.
-     * @return TimeZone list, maybe empty but never null. Do not modify.
+     * @param countryIso is a two character country code.
+     * @return TimeZone list, maybe empty but never null.
      * @hide
      */
-    public static ArrayList<TimeZone> getTimeZones(String country) {
-        synchronized (sLastLockObj) {
-            if ((country != null) && country.equals(sLastCountry)) {
-                if (DBG) Log.d(TAG, "getTimeZones(" + country + "): return cached version");
-                return sLastZones;
+    private static List<android.icu.util.TimeZone> getIcuTimeZones(String countryIso) {
+        if (countryIso == null) {
+            if (DBG) Log.d(TAG, "getIcuTimeZones(null): return empty list");
+            return Collections.emptyList();
+        }
+        List<android.icu.util.TimeZone> timeZones =
+                TimeZoneFinder.getInstance().lookupTimeZonesByCountry(countryIso);
+        if (timeZones == null) {
+            if (DBG) {
+                Log.d(TAG, "getIcuTimeZones(" + countryIso
+                        + "): returned null, converting to empty list");
             }
+            return Collections.emptyList();
         }
-
-        ArrayList<TimeZone> tzs = new ArrayList<TimeZone>();
-
-        if (country == null) {
-            if (DBG) Log.d(TAG, "getTimeZones(null): return empty list");
-            return tzs;
-        }
-
-        Resources r = Resources.getSystem();
-        XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country);
-
-        try {
-            XmlUtils.beginDocument(parser, "timezones");
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-
-                String element = parser.getName();
-                if (element == null || !(element.equals("timezone"))) {
-                    break;
-                }
-
-                String code = parser.getAttributeValue(null, "code");
-
-                if (country.equals(code)) {
-                    if (parser.next() == XmlPullParser.TEXT) {
-                        String zoneIdString = parser.getText();
-                        TimeZone tz = TimeZone.getTimeZone(zoneIdString);
-                        if (tz.getID().startsWith("GMT") == false) {
-                            // tz.getID doesn't start not "GMT" so its valid
-                            tzs.add(tz);
-                            if (DBG) {
-                                Log.d(TAG, "getTimeZone('" + country + "'): found tz.getID=="
-                                    + ((tz != null) ? tz.getID() : "<no tz>"));
-                            }
-                        }
-                    }
-                }
-            }
-        } catch (XmlPullParserException e) {
-            Log.e(TAG, "Got xml parser exception getTimeZone('" + country + "'): e=", e);
-        } catch (IOException e) {
-            Log.e(TAG, "Got IO exception getTimeZone('" + country + "'): e=", e);
-        } finally {
-            parser.close();
-        }
-
-        synchronized(sLastLockObj) {
-            // Cache the last result;
-            sLastZones = tzs;
-            sLastCountry = country;
-            return sLastZones;
-        }
+        return timeZones;
     }
 
     /**
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index c8784f8..a5f7d4f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -282,4 +282,13 @@
         // GraphicsJNI.h includes hwui headers
         "libhwui",
     ],
+
+    product_variables: {
+        debuggable: {
+            cflags: ["-D__ANDROID_DEBUGGABLE__"]
+        },
+        treble: {
+            cflags: ["-D__ANDROID_TREBLE__"]
+        },
+    },
 }
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 577cd49..b5c8815 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -23,6 +23,8 @@
 #include "android_os_HwParcel.h"
 #include "android_os_HwRemoteBinder.h"
 
+#include <cstring>
+
 #include <JNIHelp.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <android/hidl/base/1.0/IBase.h>
@@ -329,8 +331,19 @@
 
     IServiceManager::Transport transport = transportRet;
 
-    if (   transport != IServiceManager::Transport::EMPTY
-        && transport != IServiceManager::Transport::HWBINDER) {
+#ifdef __ANDROID_TREBLE__
+#ifdef __ANDROID_DEBUGGABLE__
+    const char* testingOverride = std::getenv("TREBLE_TESTING_OVERRIDE");
+    const bool vintfLegacy = (transport == IServiceManager::Transport::EMPTY)
+            && testingOverride && !strcmp(testingOverride, "true");
+#else // __ANDROID_TREBLE__ but not __ANDROID_DEBUGGABLE__
+    const bool vintfLegacy = false;
+#endif // __ANDROID_DEBUGGABLE__
+#else // not __ANDROID_TREBLE__
+    const bool vintfLegacy = (transport == IServiceManager::Transport::EMPTY);
+#endif // __ANDROID_TREBLE__";
+
+    if (transport != IServiceManager::Transport::HWBINDER && !vintfLegacy) {
         LOG(ERROR) << "service " << ifaceName << " declares transport method "
                    << toString(transport) << " but framework expects hwbinder.";
         signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f3ce719..270a215 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1433,7 +1433,6 @@
   <java-symbol type="xml" name="password_kbd_symbols" />
   <java-symbol type="xml" name="password_kbd_symbols_shift" />
   <java-symbol type="xml" name="power_profile" />
-  <java-symbol type="xml" name="time_zones_by_country" />
   <java-symbol type="xml" name="sms_short_codes" />
   <java-symbol type="xml" name="audio_assets" />
   <java-symbol type="xml" name="global_keys" />
diff --git a/core/res/res/xml/time_zones_by_country.xml b/core/res/res/xml/time_zones_by_country.xml
deleted file mode 100644
index 22bfea1..0000000
--- a/core/res/res/xml/time_zones_by_country.xml
+++ /dev/null
@@ -1,1372 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2006, 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.
-*/
--->
-<timezones>
-    <!-- ANDORRA, 1:00 -->
-
-    <timezone code="ad">Europe/Andorra</timezone>
-
-    <!-- UNITED ARAB EMIRATES, 4:00 -->
-
-    <timezone code="ae">Asia/Dubai</timezone>
-
-    <!-- AFGHANISTAN, 4:30 -->
-
-    <timezone code="af">Asia/Kabul</timezone>
-
-    <!-- ANTIGUA AND BARBUDA, -4:00 -->
-
-    <timezone code="ag">America/Antigua</timezone>
-
-    <!-- ANGUILLA, -4:00 -->
-
-    <timezone code="ai">America/Anguilla</timezone>
-
-    <!-- ALBANIA, 1:00 -->
-
-    <timezone code="al">Europe/Tirane</timezone>
-
-    <!-- ARMENIA, 4:00 -->
-
-    <timezone code="am">Asia/Yerevan</timezone>
-
-    <!-- ANGOLA, 1:00 -->
-
-    <timezone code="ao">Africa/Luanda</timezone>
-
-    <!-- ANTARCTICA, 12:00 -->
-
-    <timezone code="aq">Antarctica/McMurdo</timezone>
-
-    <!-- ANTARCTICA, 10:00 -->
-
-    <timezone code="aq">Antarctica/DumontDUrville</timezone>
-
-    <!-- ANTARCTICA, 8:00 -->
-
-    <timezone code="aq">Antarctica/Casey</timezone>
-
-    <!-- ANTARCTICA, 7:00 -->
-
-    <timezone code="aq">Antarctica/Davis</timezone>
-
-    <!-- ANTARCTICA, 5:00 -->
-
-    <timezone code="aq">Antarctica/Mawson</timezone>
-
-    <!-- ANTARCTICA, 6:00 -->
-
-    <timezone code="aq">Antarctica/Vostok</timezone>
-
-    <!-- ANTARCTICA, 3:00 -->
-
-    <timezone code="aq">Antarctica/Syowa</timezone>
-
-    <!-- ANTARCTICA, 0:00 -->
-
-    <timezone code="aq">Antarctica/Troll</timezone>
-
-    <!-- ANTARCTICA, -3:00 -->
-
-    <timezone code="aq">Antarctica/Rothera</timezone>
-
-    <!-- ANTARCTICA, -4:00 -->
-
-    <timezone code="aq">Antarctica/Palmer</timezone>
-
-    <!-- ARGENTINA, -3:00 -->
-
-    <timezone code="ar">America/Argentina/Buenos_Aires</timezone>
-    <timezone code="ar">America/Argentina/Cordoba</timezone>
-    <timezone code="ar">America/Argentina/Salta</timezone>
-    <timezone code="ar">America/Argentina/Jujuy</timezone>
-    <timezone code="ar">America/Argentina/Tucuman</timezone>
-    <timezone code="ar">America/Argentina/Catamarca</timezone>
-    <timezone code="ar">America/Argentina/La_Rioja</timezone>
-    <timezone code="ar">America/Argentina/San_Juan</timezone>
-    <timezone code="ar">America/Argentina/Mendoza</timezone>
-    <timezone code="ar">America/Argentina/San_Luis</timezone>
-    <timezone code="ar">America/Argentina/Rio_Gallegos</timezone>
-    <timezone code="ar">America/Argentina/Ushuaia</timezone>
-
-    <!-- AMERICAN SAMOA, -11:00 -->
-
-    <timezone code="as">Pacific/Pago_Pago</timezone>
-
-    <!-- AUSTRIA, 1:00 -->
-
-    <timezone code="at">Europe/Vienna</timezone>
-
-    <!-- AUSTRALIA, 10:00 -->
-
-    <timezone code="au">Australia/Sydney</timezone>
-    <timezone code="au">Australia/Melbourne</timezone>
-    <timezone code="au">Australia/Brisbane</timezone>
-    <timezone code="au">Australia/Hobart</timezone>
-    <timezone code="au">Australia/Currie</timezone>
-    <timezone code="au">Australia/Lindeman</timezone>
-
-    <!-- AUSTRALIA, 11:00 -->
-    <timezone code="au">Antarctica/Macquarie</timezone>
-
-    <!-- AUSTRALIA, 10:30 -->
-
-    <timezone code="au">Australia/Lord_Howe</timezone>
-
-    <!-- AUSTRALIA, 9:30 -->
-
-    <timezone code="au">Australia/Adelaide</timezone>
-    <timezone code="au">Australia/Broken_Hill</timezone>
-    <timezone code="au">Australia/Darwin</timezone>
-
-    <!-- AUSTRALIA, 8:00 -->
-
-    <timezone code="au">Australia/Perth</timezone>
-
-    <!-- AUSTRALIA, 8:45 -->
-
-    <timezone code="au">Australia/Eucla</timezone>
-
-    <!-- ARUBA, -4:00 -->
-
-    <timezone code="aw">America/Aruba</timezone>
-
-    <!-- ALAND ISLANDS, 2:00 -->
-
-    <timezone code="ax">Europe/Mariehamn</timezone>
-
-    <!-- AZERBAIJAN, 4:00 -->
-
-    <timezone code="az">Asia/Baku</timezone>
-
-    <!-- BOSNIA AND HERZEGOVINA, 1:00 -->
-
-    <timezone code="ba">Europe/Sarajevo</timezone>
-
-    <!-- BARBADOS, -4:00 -->
-
-    <timezone code="bb">America/Barbados</timezone>
-
-    <!-- BANGLADESH, 6:00 -->
-
-    <timezone code="bd">Asia/Dhaka</timezone>
-
-    <!-- BELGIUM, 1:00 -->
-
-    <timezone code="be">Europe/Brussels</timezone>
-
-    <!-- BURKINA FASO, 0:00 -->
-
-    <timezone code="bf">Africa/Ouagadougou</timezone>
-
-    <!-- BULGARIA, 2:00 -->
-
-    <timezone code="bg">Europe/Sofia</timezone>
-
-    <!-- BAHRAIN, 3:00 -->
-
-    <timezone code="bh">Asia/Bahrain</timezone>
-
-    <!-- BURUNDI, 2:00 -->
-
-    <timezone code="bi">Africa/Bujumbura</timezone>
-
-    <!-- BENIN, 1:00 -->
-
-    <timezone code="bj">Africa/Porto-Novo</timezone>
-
-    <!-- Saint Barthélemy, -4:00 -->
-
-    <timezone code="bl">America/St_Barthelemy</timezone>
-
-    <!-- BERMUDA, -4:00 -->
-
-    <timezone code="bm">Atlantic/Bermuda</timezone>
-
-    <!-- BRUNEI DARUSSALAM, 8:00 -->
-
-    <timezone code="bn">Asia/Brunei</timezone>
-
-    <!-- BOLIVIA, -4:00 -->
-
-    <timezone code="bo">America/La_Paz</timezone>
-
-    <!-- Caribbean Netherlands, -4:00 -->
-
-    <timezone code="bq">America/Kralendijk</timezone>
-
-    <!-- BRAZIL, -2:00 -->
-
-    <timezone code="br">America/Noronha</timezone>
-
-    <!-- BRAZIL, -3:00 -->
-
-    <timezone code="br">America/Sao_Paulo</timezone>
-    <timezone code="br">America/Belem</timezone>
-    <timezone code="br">America/Fortaleza</timezone>
-    <timezone code="br">America/Recife</timezone>
-    <timezone code="br">America/Araguaina</timezone>
-    <timezone code="br">America/Maceio</timezone>
-    <timezone code="br">America/Bahia</timezone>
-    <timezone code="br">America/Santarem</timezone>
-
-    <!-- BRAZIL, -4:00 -->
-
-    <timezone code="br">America/Manaus</timezone>
-    <timezone code="br">America/Campo_Grande</timezone>
-    <timezone code="br">America/Cuiaba</timezone>
-    <timezone code="br">America/Porto_Velho</timezone>
-    <timezone code="br">America/Boa_Vista</timezone>
-
-    <!-- BRAZIL, -5:00 -->
-
-    <timezone code="br">America/Eirunepe</timezone>
-    <timezone code="br">America/Rio_Branco</timezone>
-
-    <!-- BAHAMAS, -5:00 -->
-
-    <timezone code="bs">America/Nassau</timezone>
-
-    <!-- BHUTAN, 6:00 -->
-
-    <timezone code="bt">Asia/Thimphu</timezone>
-
-    <!-- BOTSWANA, 2:00 -->
-
-    <timezone code="bw">Africa/Gaborone</timezone>
-
-    <!-- BELARUS, 3:00 -->
-
-    <timezone code="by">Europe/Minsk</timezone>
-
-    <!-- BELIZE, -6:00 -->
-
-    <timezone code="bz">America/Belize</timezone>
-
-    <!-- CANADA, -3:30 -->
-
-    <timezone code="ca">America/St_Johns</timezone>
-
-    <!-- CANADA, -4:00 -->
-
-    <timezone code="ca">America/Halifax</timezone>
-    <timezone code="ca">America/Glace_Bay</timezone>
-    <timezone code="ca">America/Moncton</timezone>
-    <timezone code="ca">America/Goose_Bay</timezone>
-    <timezone code="ca">America/Blanc-Sablon</timezone>
-
-    <!-- CANADA, -5:00 -->
-
-    <timezone code="ca">America/Toronto</timezone>
-    <timezone code="ca">America/Nipigon</timezone>
-    <timezone code="ca">America/Thunder_Bay</timezone>
-    <timezone code="ca">America/Iqaluit</timezone>
-    <timezone code="ca">America/Pangnirtung</timezone>
-    <timezone code="ca">America/Atikokan</timezone>
-
-    <!-- CANADA, -6:00 -->
-
-    <timezone code="ca">America/Winnipeg</timezone>
-    <timezone code="ca">America/Regina</timezone>
-    <timezone code="ca">America/Rankin_Inlet</timezone>
-    <timezone code="ca">America/Rainy_River</timezone>
-    <timezone code="ca">America/Swift_Current</timezone>
-    <timezone code="ca">America/Resolute</timezone>
-
-    <!-- CANADA, -7:00 -->
-
-    <timezone code="ca">America/Edmonton</timezone>
-    <timezone code="ca">America/Cambridge_Bay</timezone>
-    <timezone code="ca">America/Yellowknife</timezone>
-    <timezone code="ca">America/Inuvik</timezone>
-    <timezone code="ca">America/Dawson_Creek</timezone>
-    <timezone code="ca">America/Creston</timezone>
-    <timezone code="ca">America/Fort_Nelson</timezone>
-
-    <!-- CANADA, -8:00 -->
-
-    <timezone code="ca">America/Vancouver</timezone>
-    <timezone code="ca">America/Whitehorse</timezone>
-    <timezone code="ca">America/Dawson</timezone>
-
-    <!-- COCOS (KEELING) ISLANDS, 6:30 -->
-
-    <timezone code="cc">Indian/Cocos</timezone>
-
-    <!-- CONGO, THE DEMOCRATIC REPUBLIC OF THE, 2:00 -->
-
-    <timezone code="cd">Africa/Lubumbashi</timezone>
-
-    <!-- CONGO, THE DEMOCRATIC REPUBLIC OF THE, 1:00 -->
-
-    <timezone code="cd">Africa/Kinshasa</timezone>
-
-    <!-- CENTRAL AFRICAN REPUBLIC, 1:00 -->
-
-    <timezone code="cf">Africa/Bangui</timezone>
-
-    <!-- CONGO, 1:00 -->
-
-    <timezone code="cg">Africa/Brazzaville</timezone>
-
-    <!-- SWITZERLAND, 1:00 -->
-
-    <timezone code="ch">Europe/Zurich</timezone>
-
-    <!-- COTE D'IVOIRE, 0:00 -->
-
-    <timezone code="ci">Africa/Abidjan</timezone>
-
-    <!-- COOK ISLANDS, -10:00 -->
-
-    <timezone code="ck">Pacific/Rarotonga</timezone>
-
-    <!-- CHILE, -3:00 -->
-
-    <timezone code="cl">America/Punta_Arenas</timezone>
-
-    <!-- CHILE, -4:00 -->
-
-    <timezone code="cl">America/Santiago</timezone>
-
-    <!-- CHILE, -6:00 -->
-
-    <timezone code="cl">Pacific/Easter</timezone>
-
-    <!-- CAMEROON, 1:00 -->
-
-    <timezone code="cm">Africa/Douala</timezone>
-
-    <!-- CHINA, 8:00 -->
-
-    <timezone code="cn">Asia/Shanghai</timezone>
-
-    <!-- CHINA, 6:00 -->
-
-    <timezone code="cn">Asia/Urumqi</timezone>
-
-    <!-- COLOMBIA, -5:00 -->
-
-    <timezone code="co">America/Bogota</timezone>
-
-    <!-- COSTA RICA, -6:00 -->
-
-    <timezone code="cr">America/Costa_Rica</timezone>
-
-    <!-- CUBA, -5:00 -->
-
-    <timezone code="cu">America/Havana</timezone>
-
-    <!-- CAPE VERDE, -1:00 -->
-
-    <timezone code="cv">Atlantic/Cape_Verde</timezone>
-
-    <!-- Curaçao, -4:00 -->
-
-    <timezone code="cw">America/Curacao</timezone>
-
-    <!-- CHRISTMAS ISLAND, 7:00 -->
-
-    <timezone code="cx">Indian/Christmas</timezone>
-
-    <!-- CYPRUS, 2:00 -->
-
-    <timezone code="cy">Asia/Nicosia</timezone>
-
-    <!-- CYPRUS, 3:00 -->
-
-    <timezone code="cy">Asia/Famagusta</timezone>
-
-    <!-- CZECH REPUBLIC, 1:00 -->
-
-    <timezone code="cz">Europe/Prague</timezone>
-
-    <!-- GERMANY, 1:00 -->
-
-    <timezone code="de">Europe/Berlin</timezone>
-    <timezone code="de">Europe/Busingen</timezone>
-
-    <!-- DJIBOUTI, 3:00 -->
-
-    <timezone code="dj">Africa/Djibouti</timezone>
-
-    <!-- DENMARK, 1:00 -->
-
-    <timezone code="dk">Europe/Copenhagen</timezone>
-
-    <!-- DOMINICA, -4:00 -->
-
-    <timezone code="dm">America/Dominica</timezone>
-
-    <!-- DOMINICAN REPUBLIC, -4:00 -->
-
-    <timezone code="do">America/Santo_Domingo</timezone>
-
-    <!-- ALGERIA, 1:00 -->
-
-    <timezone code="dz">Africa/Algiers</timezone>
-
-    <!-- ECUADOR, -5:00 -->
-
-    <timezone code="ec">America/Guayaquil</timezone>
-
-    <!-- ECUADOR, -6:00 -->
-
-    <timezone code="ec">Pacific/Galapagos</timezone>
-
-    <!-- ESTONIA, 2:00 -->
-
-    <timezone code="ee">Europe/Tallinn</timezone>
-
-    <!-- EGYPT, 2:00 -->
-
-    <timezone code="eg">Africa/Cairo</timezone>
-
-    <!-- WESTERN SAHARA, 0:00 -->
-
-    <timezone code="eh">Africa/El_Aaiun</timezone>
-
-    <!-- ERITREA, 3:00 -->
-
-    <timezone code="er">Africa/Asmara</timezone>
-
-    <!-- SPAIN, 1:00 -->
-
-    <timezone code="es">Europe/Madrid</timezone>
-    <timezone code="es">Africa/Ceuta</timezone>
-
-    <!-- SPAIN, 0:00 -->
-
-    <timezone code="es">Atlantic/Canary</timezone>
-
-    <!-- ETHIOPIA, 3:00 -->
-
-    <timezone code="et">Africa/Addis_Ababa</timezone>
-
-    <!-- FINLAND, 2:00 -->
-
-    <timezone code="fi">Europe/Helsinki</timezone>
-
-    <!-- FIJI, 12:00 -->
-
-    <timezone code="fj">Pacific/Fiji</timezone>
-
-    <!-- FALKLAND ISLANDS (MALVINAS), -3:00 -->
-
-    <timezone code="fk">Atlantic/Stanley</timezone>
-
-    <!-- MICRONESIA, FEDERATED STATES OF, 11:00 -->
-
-    <timezone code="fm">Pacific/Pohnpei</timezone>
-    <timezone code="fm">Pacific/Kosrae</timezone>
-
-    <!-- MICRONESIA, FEDERATED STATES OF, 10:00 -->
-
-    <timezone code="fm">Pacific/Chuuk</timezone>
-
-    <!-- FAROE ISLANDS, 0:00 -->
-
-    <timezone code="fo">Atlantic/Faroe</timezone>
-
-    <!-- FRANCE, 1:00 -->
-
-    <timezone code="fr">Europe/Paris</timezone>
-
-    <!-- GABON, 1:00 -->
-
-    <timezone code="ga">Africa/Libreville</timezone>
-
-    <!-- UNITED KINGDOM, 0:00 -->
-
-    <timezone code="gb">Europe/London</timezone>
-
-    <!-- GRENADA, -4:00 -->
-
-    <timezone code="gd">America/Grenada</timezone>
-
-    <!-- GEORGIA, 4:00 -->
-
-    <timezone code="ge">Asia/Tbilisi</timezone>
-
-    <!-- FRENCH GUIANA, -3:00 -->
-
-    <timezone code="gf">America/Cayenne</timezone>
-
-    <!-- GUERNSEY, 0:00 -->
-
-    <timezone code="gg">Europe/Guernsey</timezone>
-
-    <!-- GHANA, 0:00 -->
-
-    <timezone code="gh">Africa/Accra</timezone>
-
-    <!-- GIBRALTAR, 1:00 -->
-
-    <timezone code="gi">Europe/Gibraltar</timezone>
-
-    <!-- GREENLAND, 0:00 -->
-
-    <timezone code="gl">America/Danmarkshavn</timezone>
-
-    <!-- GREENLAND, -1:00 -->
-
-    <timezone code="gl">America/Scoresbysund</timezone>
-
-    <!-- GREENLAND, -3:00 -->
-
-    <timezone code="gl">America/Godthab</timezone>
-
-    <!-- GREENLAND, -4:00 -->
-
-    <timezone code="gl">America/Thule</timezone>
-
-    <!-- GAMBIA, 0:00 -->
-
-    <timezone code="gm">Africa/Banjul</timezone>
-
-    <!-- GUINEA, 0:00 -->
-
-    <timezone code="gn">Africa/Conakry</timezone>
-
-    <!-- GUADELOUPE, -4:00 -->
-
-    <timezone code="gp">America/Guadeloupe</timezone>
-
-    <!-- EQUATORIAL GUINEA, 1:00 -->
-
-    <timezone code="gq">Africa/Malabo</timezone>
-
-    <!-- GREECE, 2:00 -->
-
-    <timezone code="gr">Europe/Athens</timezone>
-
-    <!-- SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS, -2:00 -->
-
-    <timezone code="gs">Atlantic/South_Georgia</timezone>
-
-    <!-- GUATEMALA, -6:00 -->
-
-    <timezone code="gt">America/Guatemala</timezone>
-
-    <!-- GUAM, 10:00 -->
-
-    <timezone code="gu">Pacific/Guam</timezone>
-
-    <!-- GUINEA-BISSAU, 0:00 -->
-
-    <timezone code="gw">Africa/Bissau</timezone>
-
-    <!-- GUYANA, -4:00 -->
-
-    <timezone code="gy">America/Guyana</timezone>
-
-    <!-- HONG KONG, 8:00 -->
-
-    <timezone code="hk">Asia/Hong_Kong</timezone>
-
-    <!-- HONDURAS, -6:00 -->
-
-    <timezone code="hn">America/Tegucigalpa</timezone>
-
-    <!-- CROATIA, 1:00 -->
-
-    <timezone code="hr">Europe/Zagreb</timezone>
-
-    <!-- HAITI, -5:00 -->
-
-    <timezone code="ht">America/Port-au-Prince</timezone>
-
-    <!-- HUNGARY, 1:00 -->
-
-    <timezone code="hu">Europe/Budapest</timezone>
-
-    <!-- INDONESIA, 9:00 -->
-
-    <timezone code="id">Asia/Jayapura</timezone>
-
-    <!-- INDONESIA, 8:00 -->
-
-    <timezone code="id">Asia/Makassar</timezone>
-
-    <!-- INDONESIA, 7:00 -->
-
-    <timezone code="id">Asia/Jakarta</timezone>
-    <timezone code="id">Asia/Pontianak</timezone>
-
-    <!-- IRELAND, 0:00 -->
-
-    <timezone code="ie">Europe/Dublin</timezone>
-
-    <!-- ISRAEL, 2:00 -->
-
-    <timezone code="il">Asia/Jerusalem</timezone>
-
-    <!-- ISLE OF MAN, 0:00 -->
-
-    <timezone code="im">Europe/Isle_of_Man</timezone>
-
-    <!-- INDIA, 5:30 -->
-
-    <timezone code="in">Asia/Kolkata</timezone>
-
-    <!-- BRITISH INDIAN OCEAN TERRITORY, 6:00 -->
-
-    <timezone code="io">Indian/Chagos</timezone>
-
-    <!-- IRAQ, 3:00 -->
-
-    <timezone code="iq">Asia/Baghdad</timezone>
-
-    <!-- IRAN, ISLAMIC REPUBLIC OF, 3:30 -->
-
-    <timezone code="ir">Asia/Tehran</timezone>
-
-    <!-- ICELAND, 0:00 -->
-
-    <timezone code="is">Atlantic/Reykjavik</timezone>
-
-    <!-- ITALY, 1:00 -->
-
-    <timezone code="it">Europe/Rome</timezone>
-
-    <!-- JERSEY, 0:00 -->
-
-    <timezone code="je">Europe/Jersey</timezone>
-
-    <!-- JAMAICA, -5:00 -->
-
-    <timezone code="jm">America/Jamaica</timezone>
-
-    <!-- JORDAN, 2:00 -->
-
-    <timezone code="jo">Asia/Amman</timezone>
-
-    <!-- JAPAN, 9:00 -->
-
-    <timezone code="jp">Asia/Tokyo</timezone>
-
-    <!-- KENYA, 3:00 -->
-
-    <timezone code="ke">Africa/Nairobi</timezone>
-
-    <!-- KYRGYZSTAN, 6:00 -->
-
-    <timezone code="kg">Asia/Bishkek</timezone>
-
-    <!-- CAMBODIA, 7:00 -->
-
-    <timezone code="kh">Asia/Phnom_Penh</timezone>
-
-    <!-- KIRIBATI, 14:00 -->
-
-    <timezone code="ki">Pacific/Kiritimati</timezone>
-
-    <!-- KIRIBATI, 13:00 -->
-
-    <timezone code="ki">Pacific/Enderbury</timezone>
-
-    <!-- KIRIBATI, 12:00 -->
-
-    <timezone code="ki">Pacific/Tarawa</timezone>
-
-    <!-- COMOROS, 3:00 -->
-
-    <timezone code="km">Indian/Comoro</timezone>
-
-    <!-- SAINT KITTS AND NEVIS, -4:00 -->
-
-    <timezone code="kn">America/St_Kitts</timezone>
-
-    <!-- KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF, 8:30 -->
-
-    <timezone code="kp">Asia/Pyongyang</timezone>
-
-    <!-- KOREA, REPUBLIC OF, 9:00 -->
-
-    <timezone code="kr">Asia/Seoul</timezone>
-
-    <!-- KUWAIT, 3:00 -->
-
-    <timezone code="kw">Asia/Kuwait</timezone>
-
-    <!-- CAYMAN ISLANDS, -5:00 -->
-
-    <timezone code="ky">America/Cayman</timezone>
-
-    <!-- KAZAKHSTAN, 6:00 -->
-
-    <timezone code="kz">Asia/Almaty</timezone>
-    <timezone code="kz">Asia/Qyzylorda</timezone>
-
-    <!-- KAZAKHSTAN, 5:00 -->
-
-    <timezone code="kz">Asia/Aqtau</timezone>
-    <timezone code="kz">Asia/Oral</timezone>
-    <timezone code="kz">Asia/Aqtobe</timezone>
-    <timezone code="kz">Asia/Atyrau</timezone>
-
-    <!-- LAO PEOPLE'S DEMOCRATIC REPUBLIC, 7:00 -->
-
-    <timezone code="la">Asia/Vientiane</timezone>
-
-    <!-- LEBANON, 2:00 -->
-
-    <timezone code="lb">Asia/Beirut</timezone>
-
-    <!-- SAINT LUCIA, -4:00 -->
-
-    <timezone code="lc">America/St_Lucia</timezone>
-
-    <!-- LIECHTENSTEIN, 1:00 -->
-
-    <timezone code="li">Europe/Vaduz</timezone>
-
-    <!-- SRI LANKA, 5:30 -->
-
-    <timezone code="lk">Asia/Colombo</timezone>
-
-    <!-- LIBERIA, 0:00 -->
-
-    <timezone code="lr">Africa/Monrovia</timezone>
-
-    <!-- LESOTHO, 2:00 -->
-
-    <timezone code="ls">Africa/Maseru</timezone>
-
-    <!-- LITHUANIA, 2:00 -->
-
-    <timezone code="lt">Europe/Vilnius</timezone>
-
-    <!-- LUXEMBOURG, 1:00 -->
-
-    <timezone code="lu">Europe/Luxembourg</timezone>
-
-    <!-- LATVIA, 2:00 -->
-
-    <timezone code="lv">Europe/Riga</timezone>
-
-    <!-- LIBYAN ARAB JAMAHIRIYA, 2:00 -->
-
-    <timezone code="ly">Africa/Tripoli</timezone>
-
-    <!-- MOROCCO, 0:00 -->
-
-    <timezone code="ma">Africa/Casablanca</timezone>
-
-    <!-- MONACO, 1:00 -->
-
-    <timezone code="mc">Europe/Monaco</timezone>
-
-    <!-- MOLDOVA, 2:00 -->
-
-    <timezone code="md">Europe/Chisinau</timezone>
-
-    <!-- MONTENEGRO, 1:00 -->
-
-    <timezone code="me">Europe/Podgorica</timezone>
-
-    <!-- Collectivity of Saint Martin, -4:00 -->
-
-    <timezone code="mf">America/Marigot</timezone>
-
-    <!-- MADAGASCAR, 3:00 -->
-
-    <timezone code="mg">Indian/Antananarivo</timezone>
-
-    <!-- MARSHALL ISLANDS, 12:00 -->
-
-    <timezone code="mh">Pacific/Majuro</timezone>
-    <timezone code="mh">Pacific/Kwajalein</timezone>
-
-    <!-- MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF, 1:00 -->
-
-    <timezone code="mk">Europe/Skopje</timezone>
-
-    <!-- MALI, 0:00 -->
-
-    <timezone code="ml">Africa/Bamako</timezone>
-
-    <!-- MYANMAR, 6:30 -->
-
-    <timezone code="mm">Asia/Yangon</timezone>
-
-    <!-- MONGOLIA, 8:00 -->
-
-    <timezone code="mn">Asia/Choibalsan</timezone>
-    <timezone code="mn">Asia/Ulaanbaatar</timezone>
-
-    <!-- MONGOLIA, 7:00 -->
-
-    <timezone code="mn">Asia/Hovd</timezone>
-
-    <!-- MACAO, 8:00 -->
-
-    <timezone code="mo">Asia/Macau</timezone>
-
-    <!-- NORTHERN MARIANA ISLANDS, 10:00 -->
-
-    <timezone code="mp">Pacific/Saipan</timezone>
-
-    <!-- MARTINIQUE, -4:00 -->
-
-    <timezone code="mq">America/Martinique</timezone>
-
-    <!-- MAURITANIA, 0:00 -->
-
-    <timezone code="mr">Africa/Nouakchott</timezone>
-
-    <!-- MONTSERRAT, -4:00 -->
-
-    <timezone code="ms">America/Montserrat</timezone>
-
-    <!-- MALTA, 1:00 -->
-
-    <timezone code="mt">Europe/Malta</timezone>
-
-    <!-- MAURITIUS, 4:00 -->
-
-    <timezone code="mu">Indian/Mauritius</timezone>
-
-    <!-- MALDIVES, 5:00 -->
-
-    <timezone code="mv">Indian/Maldives</timezone>
-
-    <!-- MALAWI, 2:00 -->
-
-    <timezone code="mw">Africa/Blantyre</timezone>
-
-    <!-- MEXICO, -6:00 -->
-
-    <timezone code="mx">America/Mexico_City</timezone>
-    <timezone code="mx">America/Merida</timezone>
-    <timezone code="mx">America/Monterrey</timezone>
-    <timezone code="mx">America/Matamoros</timezone>
-    <timezone code="mx">America/Bahia_Banderas</timezone>
-
-    <!-- MEXICO, -5:00 -->
-
-    <timezone code="mx">America/Cancun</timezone>
-
-    <!-- MEXICO, -7:00 -->
-
-    <timezone code="mx">America/Chihuahua</timezone>
-    <timezone code="mx">America/Hermosillo</timezone>
-    <timezone code="mx">America/Mazatlan</timezone>
-    <timezone code="mx">America/Ojinaga</timezone>
-
-    <!-- MEXICO, -8:00 -->
-
-    <timezone code="mx">America/Tijuana</timezone>
-
-    <!-- MALAYSIA, 8:00 -->
-
-    <timezone code="my">Asia/Kuala_Lumpur</timezone>
-    <timezone code="my">Asia/Kuching</timezone>
-
-    <!-- MOZAMBIQUE, 2:00 -->
-
-    <timezone code="mz">Africa/Maputo</timezone>
-
-    <!-- NAMIBIA, 1:00 -->
-
-    <timezone code="na">Africa/Windhoek</timezone>
-
-    <!-- NEW CALEDONIA, 11:00 -->
-
-    <timezone code="nc">Pacific/Noumea</timezone>
-
-    <!-- NIGER, 1:00 -->
-
-    <timezone code="ne">Africa/Niamey</timezone>
-
-    <!-- NORFOLK ISLAND, 11:30 -->
-
-    <timezone code="nf">Pacific/Norfolk</timezone>
-
-    <!-- NIGERIA, 1:00 -->
-
-    <timezone code="ng">Africa/Lagos</timezone>
-
-    <!-- NICARAGUA, -6:00 -->
-
-    <timezone code="ni">America/Managua</timezone>
-
-    <!-- NETHERLANDS, 1:00 -->
-
-    <timezone code="nl">Europe/Amsterdam</timezone>
-
-    <!-- NORWAY, 1:00 -->
-
-    <timezone code="no">Europe/Oslo</timezone>
-
-    <!-- NEPAL, 5:45 -->
-
-    <timezone code="np">Asia/Kathmandu</timezone>
-
-    <!-- NAURU, 12:00 -->
-
-    <timezone code="nr">Pacific/Nauru</timezone>
-
-    <!-- NIUE, -11:00 -->
-
-    <timezone code="nu">Pacific/Niue</timezone>
-
-    <!-- NEW ZEALAND, 12:00 -->
-
-    <timezone code="nz">Pacific/Auckland</timezone>
-
-    <!-- NEW ZEALAND, 12:45 -->
-
-    <timezone code="nz">Pacific/Chatham</timezone>
-
-    <!-- OMAN, 4:00 -->
-
-    <timezone code="om">Asia/Muscat</timezone>
-
-    <!-- PANAMA, -5:00 -->
-
-    <timezone code="pa">America/Panama</timezone>
-
-    <!-- PERU, -5:00 -->
-
-    <timezone code="pe">America/Lima</timezone>
-
-    <!-- FRENCH POLYNESIA, -9:00 -->
-
-    <timezone code="pf">Pacific/Gambier</timezone>
-
-    <!-- FRENCH POLYNESIA, -9:30 -->
-
-    <timezone code="pf">Pacific/Marquesas</timezone>
-
-    <!-- FRENCH POLYNESIA, -10:00 -->
-
-    <timezone code="pf">Pacific/Tahiti</timezone>
-
-    <!-- PAPUA NEW GUINEA, 10:00 -->
-
-    <timezone code="pg">Pacific/Port_Moresby</timezone>
-
-    <!-- PAPUA NEW GUINEA, 11:00 -->
-
-    <timezone code="pg">Pacific/Bougainville</timezone>
-
-    <!-- PHILIPPINES, 8:00 -->
-
-    <timezone code="ph">Asia/Manila</timezone>
-
-    <!-- PAKISTAN, 5:00 -->
-
-    <timezone code="pk">Asia/Karachi</timezone>
-
-    <!-- POLAND, 1:00 -->
-
-    <timezone code="pl">Europe/Warsaw</timezone>
-
-    <!-- SAINT PIERRE AND MIQUELON, -3:00 -->
-
-    <timezone code="pm">America/Miquelon</timezone>
-
-    <!-- PITCAIRN, -8:00 -->
-
-    <timezone code="pn">Pacific/Pitcairn</timezone>
-
-    <!-- PUERTO RICO, -4:00 -->
-
-    <timezone code="pr">America/Puerto_Rico</timezone>
-
-    <!-- PALESTINE, 2:00 -->
-
-    <timezone code="ps">Asia/Gaza</timezone>
-    <timezone code="ps">Asia/Hebron</timezone>
-
-    <!-- PORTUGAL, 0:00 -->
-
-    <timezone code="pt">Europe/Lisbon</timezone>
-    <timezone code="pt">Atlantic/Madeira</timezone>
-
-    <!-- PORTUGAL, -1:00 -->
-
-    <timezone code="pt">Atlantic/Azores</timezone>
-
-    <!-- PALAU, 9:00 -->
-
-    <timezone code="pw">Pacific/Palau</timezone>
-
-    <!-- PARAGUAY, -4:00 -->
-
-    <timezone code="py">America/Asuncion</timezone>
-
-    <!-- QATAR, 3:00 -->
-
-    <timezone code="qa">Asia/Qatar</timezone>
-
-    <!-- REUNION, 4:00 -->
-
-    <timezone code="re">Indian/Reunion</timezone>
-
-    <!-- ROMANIA, 2:00 -->
-
-    <timezone code="ro">Europe/Bucharest</timezone>
-
-    <!-- SERBIA, 1:00 -->
-
-    <timezone code="rs">Europe/Belgrade</timezone>
-
-    <!-- RUSSIAN FEDERATION, 12:00 -->
-
-    <timezone code="ru">Asia/Kamchatka</timezone>
-    <timezone code="ru">Asia/Anadyr</timezone>
-
-    <!-- RUSSIAN FEDERATION, 11:00 -->
-
-    <timezone code="ru">Asia/Magadan</timezone>
-    <timezone code="ru">Asia/Sakhalin</timezone>
-    <timezone code="ru">Asia/Srednekolymsk</timezone>
-
-    <!-- RUSSIAN FEDERATION, 10:00 -->
-
-    <timezone code="ru">Asia/Vladivostok</timezone>
-    <timezone code="ru">Asia/Ust-Nera</timezone>
-
-    <!-- RUSSIAN FEDERATION, 9:00 -->
-
-    <timezone code="ru">Asia/Yakutsk</timezone>
-    <timezone code="ru">Asia/Chita</timezone>
-    <timezone code="ru">Asia/Khandyga</timezone>
-
-    <!-- RUSSIAN FEDERATION, 8:00 -->
-
-    <timezone code="ru">Asia/Irkutsk</timezone>
-
-    <!-- RUSSIAN FEDERATION, 7:00 -->
-
-    <timezone code="ru">Asia/Krasnoyarsk</timezone>
-    <timezone code="ru">Asia/Novosibirsk</timezone>
-    <timezone code="ru">Asia/Barnaul</timezone>
-    <timezone code="ru">Asia/Novokuznetsk</timezone>
-    <timezone code="ru">Asia/Tomsk</timezone>
-
-    <!-- RUSSIAN FEDERATION, 6:00 -->
-
-    <timezone code="ru">Asia/Omsk</timezone>
-
-    <!-- RUSSIAN FEDERATION, 5:00 -->
-
-    <timezone code="ru">Asia/Yekaterinburg</timezone>
-
-    <!-- RUSSIAN FEDERATION, 4:00 -->
-
-    <timezone code="ru">Europe/Samara</timezone>
-    <timezone code="ru">Europe/Astrakhan</timezone>
-    <timezone code="ru">Europe/Ulyanovsk</timezone>
-    <timezone code="ru">Europe/Saratov</timezone>
-
-    <!-- RUSSIAN FEDERATION, 3:00 -->
-
-    <timezone code="ru">Europe/Moscow</timezone>
-    <timezone code="ru">Europe/Volgograd</timezone>
-    <timezone code="ru">Europe/Kirov</timezone>
-    <timezone code="ru">Europe/Simferopol</timezone>
-
-    <!-- RUSSIAN FEDERATION, 2:00 -->
-
-    <timezone code="ru">Europe/Kaliningrad</timezone>
-
-    <!-- RWANDA, 2:00 -->
-
-    <timezone code="rw">Africa/Kigali</timezone>
-
-    <!-- SAUDI ARABIA, 3:00 -->
-
-    <timezone code="sa">Asia/Riyadh</timezone>
-
-    <!-- SOLOMON ISLANDS, 11:00 -->
-
-    <timezone code="sb">Pacific/Guadalcanal</timezone>
-
-    <!-- SEYCHELLES, 4:00 -->
-
-    <timezone code="sc">Indian/Mahe</timezone>
-
-    <!-- SUDAN, 3:00 -->
-
-    <timezone code="sd">Africa/Khartoum</timezone>
-
-    <!-- SWEDEN, 1:00 -->
-
-    <timezone code="se">Europe/Stockholm</timezone>
-
-    <!-- SINGAPORE, 8:00 -->
-
-    <timezone code="sg">Asia/Singapore</timezone>
-
-    <!-- SAINT HELENA, 0:00 -->
-
-    <timezone code="sh">Atlantic/St_Helena</timezone>
-
-    <!-- SLOVENIA, 1:00 -->
-
-    <timezone code="si">Europe/Ljubljana</timezone>
-
-    <!-- SVALBARD AND JAN MAYEN, 1:00 -->
-
-    <timezone code="sj">Arctic/Longyearbyen</timezone>
-
-    <!-- SLOVAKIA, 1:00 -->
-
-    <timezone code="sk">Europe/Bratislava</timezone>
-
-    <!-- SIERRA LEONE, 0:00 -->
-
-    <timezone code="sl">Africa/Freetown</timezone>
-
-    <!-- SAN MARINO, 1:00 -->
-
-    <timezone code="sm">Europe/San_Marino</timezone>
-
-    <!-- SENEGAL, 0:00 -->
-
-    <timezone code="sn">Africa/Dakar</timezone>
-
-    <!-- SOMALIA, 3:00 -->
-
-    <timezone code="so">Africa/Mogadishu</timezone>
-
-    <!-- SURINAME, -3:00 -->
-
-    <timezone code="sr">America/Paramaribo</timezone>
-
-    <!-- South Sudan, 3:00 -->
-
-    <timezone code="ss">Africa/Juba</timezone>
-
-    <!-- SAO TOME AND PRINCIPE, 0:00 -->
-
-    <timezone code="st">Africa/Sao_Tome</timezone>
-
-    <!-- EL SALVADOR, -6:00 -->
-
-    <timezone code="sv">America/El_Salvador</timezone>
-
-    <!-- Sint Maarten, -4:00 -->
-
-    <timezone code="sx">America/Lower_Princes</timezone>
-
-    <!-- SYRIAN ARAB REPUBLIC, 2:00 -->
-
-    <timezone code="sy">Asia/Damascus</timezone>
-
-    <!-- SWAZILAND, 2:00 -->
-
-    <timezone code="sz">Africa/Mbabane</timezone>
-
-    <!-- TURKS AND CAICOS ISLANDS, -4:00 -->
-
-    <timezone code="tc">America/Grand_Turk</timezone>
-
-    <!-- CHAD, 1:00 -->
-
-    <timezone code="td">Africa/Ndjamena</timezone>
-
-    <!-- FRENCH SOUTHERN TERRITORIES, 5:00 -->
-
-    <timezone code="tf">Indian/Kerguelen</timezone>
-
-    <!-- TOGO, 0:00 -->
-
-    <timezone code="tg">Africa/Lome</timezone>
-
-    <!-- THAILAND, 7:00 -->
-
-    <timezone code="th">Asia/Bangkok</timezone>
-
-    <!-- TAJIKISTAN, 5:00 -->
-
-    <timezone code="tj">Asia/Dushanbe</timezone>
-
-    <!-- TOKELAU, +13:00 -->
-
-    <timezone code="tk">Pacific/Fakaofo</timezone>
-
-    <!-- TIMOR-LESTE, 9:00 -->
-
-    <timezone code="tl">Asia/Dili</timezone>
-
-    <!-- TURKMENISTAN, 5:00 -->
-
-    <timezone code="tm">Asia/Ashgabat</timezone>
-
-    <!-- TUNISIA, 1:00 -->
-
-    <timezone code="tn">Africa/Tunis</timezone>
-
-    <!-- TONGA, 13:00 -->
-
-    <timezone code="to">Pacific/Tongatapu</timezone>
-
-    <!-- TURKEY, 3:00 -->
-
-    <timezone code="tr">Europe/Istanbul</timezone>
-
-    <!-- TRINIDAD AND TOBAGO, -4:00 -->
-
-    <timezone code="tt">America/Port_of_Spain</timezone>
-
-    <!-- TUVALU, 12:00 -->
-
-    <timezone code="tv">Pacific/Funafuti</timezone>
-
-    <!-- TAIWAN, PROVINCE OF CHINA, 8:00 -->
-
-    <timezone code="tw">Asia/Taipei</timezone>
-
-    <!-- TANZANIA, UNITED REPUBLIC OF, 3:00 -->
-
-    <timezone code="tz">Africa/Dar_es_Salaam</timezone>
-
-    <!-- UKRAINE, 2:00 -->
-
-    <timezone code="ua">Europe/Kiev</timezone>
-    <timezone code="ua">Europe/Uzhgorod</timezone>
-    <timezone code="ua">Europe/Zaporozhye</timezone>
-
-    <!-- UGANDA, 3:00 -->
-
-    <timezone code="ug">Africa/Kampala</timezone>
-
-    <!-- UNITED STATES MINOR OUTLYING ISLANDS, 12:00 -->
-
-    <timezone code="um">Pacific/Wake</timezone>
-
-    <!-- UNITED STATES MINOR OUTLYING ISLANDS, -11:00 -->
-
-    <timezone code="um">Pacific/Midway</timezone>
-
-    <!-- UNITED STATES, -5:00 -->
-
-    <timezone code="us">America/New_York</timezone>
-    <timezone code="us">America/Detroit</timezone>
-    <timezone code="us">America/Kentucky/Louisville</timezone>
-    <timezone code="us">America/Kentucky/Monticello</timezone>
-    <timezone code="us">America/Indiana/Indianapolis</timezone>
-    <timezone code="us">America/Indiana/Vincennes</timezone>
-    <timezone code="us">America/Indiana/Winamac</timezone>
-    <timezone code="us">America/Indiana/Marengo</timezone>
-    <timezone code="us">America/Indiana/Petersburg</timezone>
-    <timezone code="us">America/Indiana/Vevay</timezone>
-
-    <!-- UNITED STATES, -6:00 -->
-
-    <timezone code="us">America/Chicago</timezone>
-    <timezone code="us">America/Indiana/Knox</timezone>
-    <timezone code="us">America/Menominee</timezone>
-    <timezone code="us">America/North_Dakota/Center</timezone>
-    <timezone code="us">America/North_Dakota/New_Salem</timezone>
-    <timezone code="us">America/Indiana/Tell_City</timezone>
-    <timezone code="us">America/North_Dakota/Beulah</timezone>
-
-    <!-- UNITED STATES, -7:00 -->
-
-    <timezone code="us">America/Denver</timezone>
-    <timezone code="us">America/Boise</timezone>
-    <timezone code="us">America/Phoenix</timezone>
-
-    <!-- UNITED STATES, -8:00 -->
-
-    <timezone code="us">America/Los_Angeles</timezone>
-
-    <!-- UNITED STATES, -9:00 -->
-
-    <timezone code="us">America/Anchorage</timezone>
-    <timezone code="us">America/Juneau</timezone>
-    <timezone code="us">America/Yakutat</timezone>
-    <timezone code="us">America/Nome</timezone>
-    <timezone code="us">America/Metlakatla</timezone>
-    <timezone code="us">America/Sitka</timezone>
-
-    <!-- UNITED STATES, -10:00 -->
-
-    <timezone code="us">Pacific/Honolulu</timezone>
-    <timezone code="us">America/Adak</timezone>
-
-    <!-- URUGUAY, -3:00 -->
-
-    <timezone code="uy">America/Montevideo</timezone>
-
-    <!-- UZBEKISTAN, 5:00 -->
-
-    <timezone code="uz">Asia/Tashkent</timezone>
-    <timezone code="uz">Asia/Samarkand</timezone>
-
-    <!-- HOLY SEE (VATICAN CITY STATE), 1:00 -->
-
-    <timezone code="va">Europe/Vatican</timezone>
-
-    <!-- SAINT VINCENT AND THE GRENADINES, -4:00 -->
-
-    <timezone code="vc">America/St_Vincent</timezone>
-
-    <!-- VENEZUELA, -4:00 -->
-
-    <timezone code="ve">America/Caracas</timezone>
-
-    <!-- VIRGIN ISLANDS, BRITISH, -4:00 -->
-
-    <timezone code="vg">America/Tortola</timezone>
-
-    <!-- VIRGIN ISLANDS, U.S., -4:00 -->
-
-    <timezone code="vi">America/St_Thomas</timezone>
-
-    <!-- VIET NAM, 7:00 -->
-
-    <timezone code="vn">Asia/Ho_Chi_Minh</timezone>
-
-    <!-- VANUATU, 11:00 -->
-
-    <timezone code="vu">Pacific/Efate</timezone>
-
-    <!-- WALLIS AND FUTUNA, 12:00 -->
-
-    <timezone code="wf">Pacific/Wallis</timezone>
-
-    <!-- SAMOA, 13:00 -->
-
-    <timezone code="ws">Pacific/Apia</timezone>
-
-    <!-- YEMEN, 3:00 -->
-
-    <timezone code="ye">Asia/Aden</timezone>
-
-    <!-- MAYOTTE, 3:00 -->
-
-    <timezone code="yt">Indian/Mayotte</timezone>
-
-    <!-- SOUTH AFRICA, 2:00 -->
-
-    <timezone code="za">Africa/Johannesburg</timezone>
-
-    <!-- ZAMBIA, 2:00 -->
-
-    <timezone code="zm">Africa/Lusaka</timezone>
-
-    <!-- ZIMBABWE, 2:00 -->
-
-    <timezone code="zw">Africa/Harare</timezone>
-</timezones>
diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk
index cd7a45b..dc45a50 100644
--- a/nfc-extras/Android.mk
+++ b/nfc-extras/Android.mk
@@ -4,10 +4,10 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
 
 LOCAL_MODULE:= com.android.nfc_extras
 
 include $(BUILD_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/nfc-extras/tests/Android.mk b/nfc-extras/tests/Android.mk
index 3eca76d..d8fe5a6 100644
--- a/nfc-extras/tests/Android.mk
+++ b/nfc-extras/tests/Android.mk
@@ -22,6 +22,8 @@
     android.test.runner \
     com.android.nfc_extras
 
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/obex/javax/obex/ApplicationParameter.java b/obex/javax/obex/ApplicationParameter.java
index a62210f..16770a1a 100644
--- a/obex/javax/obex/ApplicationParameter.java
+++ b/obex/javax/obex/ApplicationParameter.java
@@ -55,7 +55,7 @@
 
         public static final byte LISTSTARTOFFSET_TAGID = 0x05;
 
-        public static final byte FILTER_TAGID = 0x06;
+        public static final byte PROPERTY_SELECTOR_TAGID = 0x06;
 
         public static final byte FORMAT_TAGID = 0x07;
 
@@ -64,6 +64,20 @@
 
         // only used in "mch" in response
         public static final byte NEWMISSEDCALLS_TAGID = 0x09;
+
+        public static final byte SUPPORTEDFEATURE_TAGID = 0x10;
+
+        public static final byte PRIMARYVERSIONCOUNTER_TAGID = 0x0A;
+
+        public static final byte SECONDARYVERSIONCOUNTER_TAGID = 0x0B;
+
+        public static final byte VCARDSELECTOR_TAGID = 0x0C;
+
+        public static final byte DATABASEIDENTIFIER_TAGID = 0x0D;
+
+        public static final byte VCARDSELECTOROPERATOR_TAGID = 0x0E;
+
+        public static final byte RESET_NEW_MISSED_CALLS_TAGID = 0x0F;
     }
 
     public static class TRIPLET_VALUE {
@@ -99,13 +113,27 @@
 
         public static final byte LISTSTARTOFFSET_LENGTH = 2;
 
-        public static final byte FILTER_LENGTH = 8;
+        public static final byte PROPERTY_SELECTOR_LENGTH = 8;
 
         public static final byte FORMAT_LENGTH = 1;
 
         public static final byte PHONEBOOKSIZE_LENGTH = 2;
 
         public static final byte NEWMISSEDCALLS_LENGTH = 1;
+
+        public static final byte SUPPORTEDFEATURE_LENGTH = 4;
+
+        public static final byte PRIMARYVERSIONCOUNTER_LENGTH = 16;
+
+        public static final byte SECONDARYVERSIONCOUNTER_LENGTH = 16;
+
+        public static final byte VCARDSELECTOR_LENGTH = 8;
+
+        public static final byte DATABASEIDENTIFIER_LENGTH = 16;
+
+        public static final byte VCARDSELECTOROPERATOR_LENGTH = 1;
+
+        public static final byte RESETNEWMISSEDCALLS_LENGTH = 1;
     }
 
     public ApplicationParameter() {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 7e1a1ca..ac2f4d0 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -149,7 +149,7 @@
      */
     public static final String PERMISSION_SYSTEM = "SYSTEM";
 
-    class NetdResponseCode {
+    static class NetdResponseCode {
         /* Keep in sync with system/netd/server/ResponseCode.h */
         public static final int InterfaceListResult       = 110;
         public static final int TetherInterfaceListResult = 111;
@@ -220,7 +220,7 @@
 
     private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
 
-    private Object mQuotaLock = new Object();
+    private final Object mQuotaLock = new Object();
 
     /** Set of interfaces with active quotas. */
     @GuardedBy("mQuotaLock")
@@ -265,7 +265,7 @@
     @GuardedBy("mQuotaLock")
     private boolean mDataSaverMode;
 
-    private Object mIdleTimerLock = new Object();
+    private final Object mIdleTimerLock = new Object();
     /** Set of interfaces with active idle timers. */
     private static class IdleTimerParams {
         public final int timeout;
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 2158f60..5f6bd59 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
+import android.net.Uri;
 import android.net.nsd.NsdServiceInfo;
 import android.net.nsd.DnsSdTxtRecord;
 import android.net.nsd.INsdManager;
@@ -96,16 +97,15 @@
          * Observes the NSD on/off setting, and takes action when changed.
          */
         private void registerForNsdSetting() {
-            ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
+            final ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
                 @Override
                 public void onChange(boolean selfChange) {
                     notifyEnabled(isNsdEnabled());
                 }
             };
 
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.NSD_ON),
-                    false, contentObserver);
+            final Uri uri = Settings.Global.getUriFor(Settings.Global.NSD_ON);
+            mNsdSettings.registerContentObserver(uri, contentObserver);
         }
 
         NsdStateMachine(String name, Handler handler) {
@@ -885,13 +885,18 @@
         }
     }
 
+    /**
+     * Interface which encapsulates dependencies of NsdService that are hard to mock, hard to
+     * override, or have side effects on global state in unit tests.
+     */
     @VisibleForTesting
     public interface NsdSettings {
         boolean isEnabled();
         void putEnabledStatus(boolean isEnabled);
+        void registerContentObserver(Uri uri, ContentObserver observer);
 
         static NsdSettings makeDefault(Context context) {
-            ContentResolver resolver = context.getContentResolver();
+            final ContentResolver resolver = context.getContentResolver();
             return new NsdSettings() {
                 @Override
                 public boolean isEnabled() {
@@ -902,6 +907,11 @@
                 public void putEnabledStatus(boolean isEnabled) {
                     Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0);
                 }
+
+                @Override
+                public void registerContentObserver(Uri uri, ContentObserver observer) {
+                    resolver.registerContentObserver(uri, false, observer);
+                }
             };
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 3c46226..f212c80 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -52,6 +52,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
@@ -195,8 +196,10 @@
         mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
         mTetherMasterSM.start();
 
-        mOffloadController = new OffloadController(mTetherMasterSM.getHandler(),
-                deps.getOffloadHardwareInterface(), mLog);
+        final Handler smHandler = mTetherMasterSM.getHandler();
+        mOffloadController = new OffloadController(smHandler,
+                deps.getOffloadHardwareInterface(smHandler, mLog),
+                mLog);
         mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
                 mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK, mLog);
         mForwardedDownstreams = new HashSet<>();
@@ -241,21 +244,11 @@
         // See NetlinkHandler.cpp:71.
         if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
         synchronized (mPublicSync) {
-            int interfaceType = ifaceNameToType(iface);
-            if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
-                return;
-            }
-
-            TetherState tetherState = mTetherStates.get(iface);
             if (up) {
-                if (tetherState == null) {
-                    trackNewTetherableInterface(iface, interfaceType);
-                }
+                maybeTrackNewInterfaceLocked(iface);
             } else {
-                if (interfaceType == ConnectivityManager.TETHERING_BLUETOOTH) {
-                    tetherState.stateMachine.sendMessage(
-                            TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-                    mTetherStates.remove(iface);
+                if (ifaceNameToType(iface) == ConnectivityManager.TETHERING_BLUETOOTH) {
+                    stopTrackingInterfaceLocked(iface);
                 } else {
                     // Ignore usb0 down after enabling RNDIS.
                     // We will handle disconnect in interfaceRemoved.
@@ -289,18 +282,7 @@
     public void interfaceAdded(String iface) {
         if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
         synchronized (mPublicSync) {
-            int interfaceType = ifaceNameToType(iface);
-            if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
-                if (VDBG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
-                return;
-            }
-
-            TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState == null) {
-                trackNewTetherableInterface(iface, interfaceType);
-            } else {
-                if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
-            }
+            maybeTrackNewInterfaceLocked(iface);
         }
     }
 
@@ -308,15 +290,7 @@
     public void interfaceRemoved(String iface) {
         if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
         synchronized (mPublicSync) {
-            TetherState tetherState = mTetherStates.get(iface);
-            if (tetherState == null) {
-                if (VDBG) {
-                    Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
-                }
-                return;
-            }
-            tetherState.stateMachine.sendMessage(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-            mTetherStates.remove(iface);
+            stopTrackingInterfaceLocked(iface);
         }
     }
 
@@ -755,7 +729,7 @@
         mLastNotificationId = icon;
 
         notificationManager.notifyAsUser(null, mLastNotificationId,
-                mTetheredNotificationBuilder.build(), UserHandle.ALL);
+                mTetheredNotificationBuilder.buildInto(new Notification()), UserHandle.ALL);
     }
 
     private void clearTetheredNotification() {
@@ -1112,7 +1086,6 @@
         TetherMasterSM(String name, Looper looper) {
             super(name, looper);
 
-            //Add states
             mInitialState = new InitialState();
             mTetherModeAliveState = new TetherModeAliveState();
             mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
@@ -1426,10 +1399,11 @@
 
                 mSimChange.startListening();
                 mUpstreamNetworkMonitor.start();
-                mOffloadController.start();
 
+                // TODO: De-duplicate with updateUpstreamWanted() below.
                 if (upstreamWanted()) {
                     mUpstreamWanted = true;
+                    mOffloadController.start();
                     chooseUpstreamType(true);
                     mTryCell = false;
                 }
@@ -1448,6 +1422,13 @@
             private boolean updateUpstreamWanted() {
                 final boolean previousUpstreamWanted = mUpstreamWanted;
                 mUpstreamWanted = upstreamWanted();
+                if (mUpstreamWanted != previousUpstreamWanted) {
+                    if (mUpstreamWanted) {
+                        mOffloadController.start();
+                    } else {
+                        mOffloadController.stop();
+                    }
+                }
                 return previousUpstreamWanted;
             }
 
@@ -1774,15 +1755,40 @@
         sendTetherStateChangedBroadcast();
     }
 
-    private void trackNewTetherableInterface(String iface, int interfaceType) {
-        TetherState tetherState;
-        tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
-                interfaceType, mLog, mNMService, mStatsService, this,
-                new IPv6TetheringInterfaceServices(iface, mNMService, mLog)));
+    private void maybeTrackNewInterfaceLocked(final String iface) {
+        // If we don't care about this type of interface, ignore.
+        final int interfaceType = ifaceNameToType(iface);
+        if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
+            mLog.log(iface + " is not a tetherable iface, ignoring");
+            return;
+        }
+
+        // If we have already started a TISM for this interface, skip.
+        if (mTetherStates.containsKey(iface)) {
+            mLog.log("active iface (" + iface + ") reported as added, ignoring");
+            return;
+        }
+
+        mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
+        final TetherState tetherState = new TetherState(
+                new TetherInterfaceStateMachine(
+                    iface, mLooper, interfaceType, mLog, mNMService, mStatsService, this,
+                    new IPv6TetheringInterfaceServices(iface, mNMService, mLog)));
         mTetherStates.put(iface, tetherState);
         tetherState.stateMachine.start();
     }
 
+    private void stopTrackingInterfaceLocked(final String iface) {
+        final TetherState tetherState = mTetherStates.get(iface);
+        if (tetherState == null) {
+            mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
+            return;
+        }
+        tetherState.stateMachine.sendMessage(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
+        mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
+        mTetherStates.remove(iface);
+    }
+
     private static String[] copy(String[] strarray) {
         return Arrays.copyOf(strarray, strarray.length);
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index ec7ab5b..12899d8 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -49,12 +49,30 @@
             mConfigInitialized = mHwInterface.initOffloadConfig();
             if (!mConfigInitialized) {
                 mLog.i("tethering offload config not supported");
+                stop();
                 return;
             }
         }
 
-        // TODO: Create and register ITetheringOffloadCallback.
-        mControlInitialized = mHwInterface.initOffloadControl();
+        mControlInitialized = mHwInterface.initOffloadControl(
+                new OffloadHardwareInterface.ControlCallback() {
+                    @Override
+                    public void onOffloadEvent(int event) {
+                        mLog.log("got offload event: " + event);
+                    }
+
+                    @Override
+                    public void onNatTimeoutUpdate(int proto,
+                                                   String srcAddr, int srcPort,
+                                                   String dstAddr, int dstPort) {
+                        mLog.log(String.format("NAT timeout update: %s (%s,%s) -> (%s,%s)",
+                                proto, srcAddr, srcPort, dstAddr, dstPort));
+                    }
+                });
+        if (!mControlInitialized) {
+            mLog.i("tethering offload control not supported");
+            stop();
+        }
     }
 
     public void stop() {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 87fc491..0429ab3 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -17,9 +17,11 @@
 package com.android.server.connectivity.tethering;
 
 import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
-import android.hardware.tetheroffload.control.V1_0.IOffloadControl.stopOffloadCallback;
+import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
+import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
+import android.os.Handler;
 import android.os.RemoteException;
-import android.util.Log;
+import android.net.util.SharedLog;
 
 
 /**
@@ -32,46 +34,102 @@
 
     private static native boolean configOffload();
 
+    private final Handler mHandler;
+    private final SharedLog mLog;
     private IOffloadControl mOffloadControl;
+    private TetheringOffloadCallback mTetheringOffloadCallback;
+    private ControlCallback mControlCallback;
 
-    public OffloadHardwareInterface() {}
+    public static class ControlCallback {
+        public void onOffloadEvent(int event) {}
+
+        public void onNatTimeoutUpdate(int proto,
+                                       String srcAddr, int srcPort,
+                                       String dstAddr, int dstPort) {}
+    }
+
+    public OffloadHardwareInterface(Handler h, SharedLog log) {
+        mHandler = h;
+        mLog = log.forSubComponent(TAG);
+    }
 
     public boolean initOffloadConfig() {
         return configOffload();
     }
 
-    // TODO: Extend this to take a TetheringControlCallback for registration.
-    public boolean initOffloadControl() {
+    public boolean initOffloadControl(ControlCallback controlCb) {
+        mControlCallback = controlCb;
+
         if (mOffloadControl == null) {
             try {
                 mOffloadControl = IOffloadControl.getService();
             } catch (RemoteException e) {
-                Log.d(TAG, "tethering offload control not supported: " + e);
+                mLog.e("tethering offload control not supported: " + e);
                 return false;
             }
         }
 
-        // TODO: call mOffloadControl.initOffload(...callback...);
+        mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback);
+        final CbResults results = new CbResults();
+        try {
+            mOffloadControl.initOffload(
+                    mTetheringOffloadCallback,
+                    (boolean success, String errMsg) -> {
+                        results.success = success;
+                        results.errMsg = errMsg;
+                    });
+        } catch (RemoteException e) {
+            mLog.e("failed to initOffload: " + e);
+            return false;
+        }
 
-        return true;
+        if (!results.success) mLog.e("initOffload failed: " + results.errMsg);
+        return results.success;
     }
 
     public void stopOffloadControl() {
-        if (mOffloadControl == null) return;
-
-        try {
-            final stopOffloadCallback cb = new stopOffloadCallback() {
-                @Override
-                public void onValues(boolean success, String errMsg) {
-                    if (success) return;
-
-                    Log.e(TAG, "stopOffload failed: " + errMsg);
-                }
-            };
-            mOffloadControl.stopOffload(cb);
-        } catch (RemoteException e) {
-            Log.d(TAG, "failed to stopOffload: " + e);
+        if (mOffloadControl != null) {
+            try {
+                mOffloadControl.stopOffload(
+                        (boolean success, String errMsg) -> {
+                            if (!success) mLog.e("stopOffload failed: " + errMsg);
+                        });
+            } catch (RemoteException e) {
+                mLog.e("failed to stopOffload: " + e);
+            }
         }
         mOffloadControl = null;
+        mTetheringOffloadCallback = null;
+        mControlCallback = null;
+    }
+
+    private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
+        public final Handler handler;
+        public final ControlCallback controlCb;
+
+        public TetheringOffloadCallback(Handler h, ControlCallback cb) {
+            handler = h;
+            controlCb = cb;
+        }
+
+        @Override
+        public void onEvent(int event) {
+            handler.post(() -> { controlCb.onOffloadEvent(event); });
+        }
+
+        @Override
+        public void updateTimeout(NatTimeoutUpdate params) {
+            handler.post(() -> {
+                    controlCb.onNatTimeoutUpdate(
+                        params.proto,
+                        params.src.addr, params.src.port,
+                        params.dst.addr, params.dst.port);
+            });
+        }
+    }
+
+    private static class CbResults {
+        boolean success;
+        String errMsg;
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 44c61f0..6941193 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -163,20 +163,31 @@
         }
 
         // Fix up upstream interface types for DUN or mobile. NOTE: independent
-        // of the value of |requiresDun|, cell data of one form or another is
+        // of the value of |dunCheck|, cell data of one form or another is
         // *always* an upstream, regardless of the upstream interface types
         // specified by configuration resources.
         if (dunCheck == DUN_REQUIRED) {
             if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) {
                 upstreamIfaceTypes.add(TYPE_MOBILE_DUN);
             }
-        } else {
+        } else if (dunCheck == DUN_NOT_REQUIRED) {
             if (!upstreamIfaceTypes.contains(TYPE_MOBILE)) {
                 upstreamIfaceTypes.add(TYPE_MOBILE);
             }
             if (!upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)) {
                 upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
             }
+        } else {
+            // Fix upstream interface types for case DUN_UNSPECIFIED.
+            // Do not modify if a cellular interface type is already present in the
+            // upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no
+            // cellular interface types are found in the upstream interface types.
+            if (!(upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)
+                    || upstreamIfaceTypes.contains(TYPE_MOBILE)
+                    || upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI))) {
+                upstreamIfaceTypes.add(TYPE_MOBILE);
+                upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
+            }
         }
 
         return upstreamIfaceTypes;
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index be2cf08..b8174b6 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -16,6 +16,9 @@
 
 package com.android.server.connectivity.tethering;
 
+import android.os.Handler;
+import android.net.util.SharedLog;
+
 
 /**
  * Capture tethering dependencies, for injection.
@@ -23,7 +26,7 @@
  * @hide
  */
 public class TetheringDependencies {
-    public OffloadHardwareInterface getOffloadHardwareInterface() {
-        return new OffloadHardwareInterface();
+    public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
+        return new OffloadHardwareInterface(h, log);
     }
 }
diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
index 98771df..a91fe77 100644
--- a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
+++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
@@ -219,6 +219,7 @@
         List<SubscriptionInfo> activeSubscriptionInfoList =
                 mSubscriptionManager.getActiveSubscriptionInfoList();
         if (activeSubscriptionInfoList == null) {
+            setSimNeedsEmergencyAffordance(neededNow);
             return neededNow;
         }
         for (SubscriptionInfo info : activeSubscriptionInfoList) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index df7c660..9949af3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -847,8 +847,8 @@
         public void update(Uri uri) {
             ContentResolver resolver = getContext().getContentResolver();
             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
-                boolean pulseEnabled = Settings.System.getInt(resolver,
-                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
+                boolean pulseEnabled = Settings.System.getIntForUser(resolver,
+                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
                 if (mNotificationPulseEnabled != pulseEnabled) {
                     mNotificationPulseEnabled = pulseEnabled;
                     updateNotificationPulse();
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index d364d17..adfd7b3 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -211,7 +211,8 @@
             pm.performDexOpt(pkg,
                     /* checkProfiles */ false,
                     PackageManagerService.REASON_BOOT,
-                    /* force */ false);
+                    /* force */ false,
+                    /* bootComplete */ true);
         }
         // Ran to completion, so we abandon our timeslice and do not reschedule.
         jobFinished(jobParams, /* reschedule */ false);
@@ -288,7 +289,8 @@
                     ? pm.performDexOpt(pkg,
                             /* checkProfiles */ true,
                             PackageManagerService.REASON_BACKGROUND_DEXOPT,
-                            /* force */ false)
+                            /* force */ false,
+                            /* bootComplete */ true)
                     : pm.performDexOptSecondary(pkg,
                             PackageManagerService.REASON_BACKGROUND_DEXOPT,
                             /* force */ false);
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index d93d620..317250b 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -315,7 +315,8 @@
                 null /* ISAs */, false /* checkProfiles */,
                 getCompilerFilterForReason(compilationReason),
                 null /* CompilerStats.PackageStats */,
-                mPackageManagerService.getDexManager().isUsedByOtherApps(pkg.packageName));
+                mPackageManagerService.getDexManager().isUsedByOtherApps(pkg.packageName),
+                true /* bootComplete */);
 
         return commands;
     }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 126ad26..49639b0 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -104,7 +104,8 @@
      */
     int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
             String[] instructionSets, boolean checkProfiles, String targetCompilationFilter,
-            CompilerStats.PackageStats packageStats, boolean isUsedByOtherApps) {
+            CompilerStats.PackageStats packageStats, boolean isUsedByOtherApps,
+            boolean bootComplete) {
         if (!canOptimizePackage(pkg)) {
             return DEX_OPT_SKIPPED;
         }
@@ -119,7 +120,7 @@
             }
             try {
                 return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
-                        targetCompilationFilter, packageStats, isUsedByOtherApps);
+                        targetCompilationFilter, packageStats, isUsedByOtherApps, bootComplete);
             } finally {
                 if (useLock) {
                     mDexoptWakeLock.release();
@@ -136,7 +137,7 @@
     private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
             String[] targetInstructionSets, boolean checkForProfileUpdates,
             String targetCompilerFilter, CompilerStats.PackageStats packageStats,
-            boolean isUsedByOtherApps) {
+            boolean isUsedByOtherApps, boolean bootComplete) {
         final String[] instructionSets = targetInstructionSets != null ?
                 targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
@@ -152,7 +153,7 @@
         // paths (b/34169257).
         String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
         // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
-        final int dexoptFlags = getDexFlags(pkg, compilerFilter);
+        final int dexoptFlags = getDexFlags(pkg, compilerFilter, bootComplete);
 
         int result = DEX_OPT_SKIPPED;
         // TODO: Iterate based on dependency hierarchy (currently alphabetically by name)
@@ -274,7 +275,9 @@
     @GuardedBy("mInstallLock")
     private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, Set<String> isas,
             String compilerFilter, boolean isUsedByOtherApps) {
-        int dexoptFlags = getDexFlags(info, compilerFilter) | DEXOPT_SECONDARY_DEX;
+        // Secondary dex files are currently not compiled at boot.
+        int dexoptFlags = getDexFlags(info, compilerFilter, /* bootComplete */ true)
+                | DEXOPT_SECONDARY_DEX;
         // Check the app storage and add the appropriate flags.
         if (info.dataDir.equals(info.deviceProtectedDataDir)) {
             dexoptFlags |= DEXOPT_STORAGE_DE;
@@ -374,11 +377,12 @@
      * Computes the dex flags that needs to be pass to installd for the given package and compiler
      * filter.
      */
-    private int getDexFlags(PackageParser.Package pkg, String compilerFilter) {
-        return getDexFlags(pkg.applicationInfo, compilerFilter);
+    private int getDexFlags(PackageParser.Package pkg, String compilerFilter,
+            boolean bootComplete) {
+        return getDexFlags(pkg.applicationInfo, compilerFilter, bootComplete);
     }
 
-    private int getDexFlags(ApplicationInfo info, String compilerFilter) {
+    private int getDexFlags(ApplicationInfo info, String compilerFilter, boolean bootComplete) {
         int flags = info.flags;
         boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         // Profile guide compiled oat files should not be public.
@@ -389,7 +393,7 @@
                 (isPublic ? DEXOPT_PUBLIC : 0)
                 | (debuggable ? DEXOPT_DEBUGGABLE : 0)
                 | profileFlag
-                | DEXOPT_BOOTCOMPLETE;
+                | (bootComplete ? DEXOPT_BOOTCOMPLETE : 0);
         return adjustDexoptFlags(dexFlags);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2391abd..4c732d7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2662,7 +2662,7 @@
                 }
 
                 int[] stats = performDexOptUpgrade(coreApps, false,
-                        getCompilerFilterForReason(REASON_CORE_APP));
+                        getCompilerFilterForReason(REASON_CORE_APP), /* bootComplete */ false);
 
                 final int elapsedTimeSeconds =
                         (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);
@@ -7305,7 +7305,8 @@
 
         final long startTime = System.nanoTime();
         final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
-                    getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT));
+                    getCompilerFilterForReason(causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT),
+                    false /* bootComplete */);
 
         final int elapsedTimeSeconds =
                 (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
@@ -7324,7 +7325,7 @@
      * and {@code numberOfPackagesFailed}.
      */
     private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
-            String compilerFilter) {
+            String compilerFilter, boolean bootComplete) {
 
         int numberOfPackagesVisited = 0;
         int numberOfPackagesOptimized = 0;
@@ -7381,7 +7382,8 @@
             int dexOptStatus = performDexOptTraced(pkg.packageName,
                     false /* checkProfiles */,
                     compilerFilter,
-                    false /* force */);
+                    false /* force */,
+                    bootComplete);
             switch (dexOptStatus) {
                 case PackageDexOptimizer.DEX_OPT_PERFORMED:
                     numberOfPackagesOptimized++;
@@ -7425,36 +7427,30 @@
         mDexManager.notifyDexLoad(ai, dexPaths, loaderIsa, userId);
     }
 
-    // TODO: this is not used nor needed. Delete it.
-    @Override
-    public boolean performDexOptIfNeeded(String packageName) {
-        int dexOptStatus = performDexOptTraced(packageName,
-                false /* checkProfiles */, getFullCompilerFilter(), false /* force */);
-        return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
-    }
-
     @Override
     public boolean performDexOpt(String packageName,
-            boolean checkProfiles, int compileReason, boolean force) {
+            boolean checkProfiles, int compileReason, boolean force, boolean bootComplete) {
         int dexOptStatus = performDexOptTraced(packageName, checkProfiles,
-                getCompilerFilterForReason(compileReason), force);
+                getCompilerFilterForReason(compileReason), force, bootComplete);
         return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
     }
 
     @Override
     public boolean performDexOptMode(String packageName,
-            boolean checkProfiles, String targetCompilerFilter, boolean force) {
+            boolean checkProfiles, String targetCompilerFilter, boolean force,
+            boolean bootComplete) {
         int dexOptStatus = performDexOptTraced(packageName, checkProfiles,
-                targetCompilerFilter, force);
+                targetCompilerFilter, force, bootComplete);
         return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
     }
 
     private int performDexOptTraced(String packageName,
-                boolean checkProfiles, String targetCompilerFilter, boolean force) {
+                boolean checkProfiles, String targetCompilerFilter, boolean force,
+                boolean bootComplete) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
         try {
             return performDexOptInternal(packageName, checkProfiles,
-                    targetCompilerFilter, force);
+                    targetCompilerFilter, force, bootComplete);
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -7463,7 +7459,8 @@
     // Run dexopt on a given package. Returns true if dexopt did not fail, i.e.
     // if the package can now be considered up to date for the given filter.
     private int performDexOptInternal(String packageName,
-                boolean checkProfiles, String targetCompilerFilter, boolean force) {
+                boolean checkProfiles, String targetCompilerFilter, boolean force,
+                boolean bootComplete) {
         PackageParser.Package p;
         synchronized (mPackages) {
             p = mPackages.get(packageName);
@@ -7478,7 +7475,7 @@
         try {
             synchronized (mInstallLock) {
                 return performDexOptInternalWithDependenciesLI(p, checkProfiles,
-                        targetCompilerFilter, force);
+                        targetCompilerFilter, force, bootComplete);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -7499,7 +7496,7 @@
 
     private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
             boolean checkProfiles, String targetCompilerFilter,
-            boolean force) {
+            boolean force, boolean bootComplete) {
         // Select the dex optimizer based on the force parameter.
         // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
         //       allocate an object here.
@@ -7519,12 +7516,13 @@
                         false /* checkProfiles */,
                         getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY),
                         getOrCreateCompilerPackageStats(depPackage),
-                        mDexManager.isUsedByOtherApps(p.packageName));
+                        mDexManager.isUsedByOtherApps(p.packageName),
+                        bootComplete);
             }
         }
         return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets, checkProfiles,
                 targetCompilerFilter, getOrCreateCompilerPackageStats(p),
-                mDexManager.isUsedByOtherApps(p.packageName));
+                mDexManager.isUsedByOtherApps(p.packageName), bootComplete);
     }
 
     // Performs dexopt on the used secondary dex files belonging to the given package.
@@ -7670,7 +7668,8 @@
             // Don't use profiles since that may cause compilation to be skipped.
             final int res = performDexOptInternalWithDependenciesLI(pkg,
                     false /* checkProfiles */, getCompilerFilterForReason(REASON_FORCED_DEXOPT),
-                    true /* force */);
+                    true /* force */,
+                    true /* bootComplete */);
 
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -15242,7 +15241,8 @@
                     null /* instructionSets */, false /* checkProfiles */,
                     getCompilerFilterForReason(REASON_INSTALL),
                     getOrCreateCompilerPackageStats(pkg),
-                    mDexManager.isUsedByOtherApps(pkg.packageName));
+                    mDexManager.isUsedByOtherApps(pkg.packageName),
+                    true /* bootComplete */);
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
 
             // Notify BackgroundDexOptService that the package has been changed.
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 2f000c2..dd3af66 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -399,7 +399,8 @@
                     ? mInterface.performDexOptSecondary(packageName,
                             targetCompilerFilter, forceCompilation)
                     : mInterface.performDexOptMode(packageName,
-                            checkProfiles, targetCompilerFilter, forceCompilation);
+                            checkProfiles, targetCompilerFilter, forceCompilation,
+                            true /* bootComplete */);
             if (!result) {
                 failedPackages.add(packageName);
             }
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 985a12c..71201ce 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -193,6 +193,11 @@
     private static final int IPV4_ANY_HOST_ADDRESS = 0;
     private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
 
+    // Traffic class and Flow label are not byte aligned. Luckily we
+    // don't care about either value so we'll consider bytes 1-3 of the
+    // IPv6 header as don't care.
+    private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
+    private static final int IPV6_FLOW_LABEL_LEN = 3;
     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
     private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
     private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
@@ -472,8 +477,13 @@
 
             RaEvent.Builder builder = new RaEvent.Builder();
 
-            // Ignore the checksum.
+            // Ignore the flow label and low 4 bits of traffic class.
             int lastNonLifetimeStart = addNonLifetime(0,
+                    IPV6_FLOW_LABEL_OFFSET,
+                    IPV6_FLOW_LABEL_LEN);
+
+            // Ignore the checksum.
+            lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
                     ICMP6_RA_CHECKSUM_OFFSET,
                     ICMP6_RA_CHECKSUM_LEN);
 
@@ -564,9 +574,14 @@
             for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
                 int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
 
+                // The flow label is in mNonLifetimes, but it's not a lifetime.
+                if (offset == IPV6_FLOW_LABEL_OFFSET) {
+                    continue;
+                }
+
                 // The checksum is in mNonLifetimes, but it's not a lifetime.
                 if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
-                     continue;
+                    continue;
                 }
 
                 final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
@@ -628,6 +643,11 @@
                 if ((i + 1) < mNonLifetimes.size()) {
                     Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
                     int offset = nonLifetime.first + nonLifetime.second;
+
+                    // Skip the Flow label.
+                    if (offset == IPV6_FLOW_LABEL_OFFSET) {
+                        continue;
+                    }
                     // Skip the checksum.
                     if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
                         continue;
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 6107895..640c9e1 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -269,6 +269,23 @@
     }
 
     /**
+     * Dumps the events in a timeline format.
+     * @param pw The {@link IndentingPrintWriter} to write to.
+     * @hide
+     */
+    public static void dumpEventsTimeline(IndentingPrintWriter pw) {
+        // If the Events logger has not been initialized, then there have been no events logged.
+        // Don't load it now!
+        synchronized (sSingletonSync) {
+            if (sEventManager != null) {
+                getEventManager().dumpEventsTimeline(pw);
+            } else {
+                pw.println("No Historical Events Logged.");
+            }
+        }
+    }
+
+    /**
      * Enable or disable extended telecom logging.
      *
      * @param isExtendedLoggingEnabled {@code true} if extended logging should be enabled,
diff --git a/telecomm/java/android/telecom/Logging/EventManager.java b/telecomm/java/android/telecom/Logging/EventManager.java
index 2cd1b96..fddbfce 100644
--- a/telecomm/java/android/telecom/Logging/EventManager.java
+++ b/telecomm/java/android/telecom/Logging/EventManager.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.telecom.Log;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IndentingPrintWriter;
@@ -27,6 +28,7 @@
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.IllegalFormatException;
@@ -35,6 +37,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.stream.Collectors;
 
 /**
  * A utility class that provides the ability to define Events that a subsystem deems important, and
@@ -49,6 +52,7 @@
     public static final String TAG = "Logging.Events";
     @VisibleForTesting
     public static final int DEFAULT_EVENTS_TO_CACHE = 10;  // Arbitrarily chosen.
+    private final DateFormat sDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
 
     public interface Loggable {
         /**
@@ -169,7 +173,6 @@
             }
         }
 
-        private final DateFormat sDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
         private final List<Event> mEvents = new LinkedList<>();
         private final Loggable mRecordEntry;
 
@@ -308,6 +311,41 @@
         pw.decreaseIndent();
     }
 
+    /**
+     * Dumps events in a timeline format.
+     * @param pw The {@link IndentingPrintWriter} to output the timeline to.
+     * @hide
+     */
+    public void dumpEventsTimeline(IndentingPrintWriter pw) {
+        pw.println("Historical Events (sorted by time):");
+
+        // Flatten event records out for sorting.
+        List<Pair<Loggable, Event>> events = new ArrayList<>();
+        for (EventRecord er : mEventRecords) {
+            for (Event ev : er.getEvents()) {
+                events.add(new Pair<>(er.getRecordEntry(), ev));
+            }
+        }
+
+        // Sort by event time.
+        Comparator<Pair<Loggable, Event>> byEventTime = (e1, e2) -> {
+          return Long.compare(e1.second.time, e2.second.time);
+        };
+        events.sort(byEventTime);
+
+        pw.increaseIndent();
+        for (Pair<Loggable, Event> event : events) {
+            pw.print(sDateFormat.format(new Date(event.second.time)));
+            pw.print(",");
+            pw.print(event.first.getId());
+            pw.print(",");
+            pw.print(event.second.eventId);
+            pw.print(",");
+            pw.println(event.second.data);
+        }
+        pw.decreaseIndent();
+    }
+
     public void changeEventCacheSize(int newSize) {
 
         // Resize the event queue.
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7d22a2c..e3d66e7 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -574,11 +574,19 @@
     public static final String KEY_CARRIER_METERED_APN_TYPES_STRINGS =
             "carrier_metered_apn_types_strings";
     /**
-     * Default APN types that are roamig-metered by the carrier
+     * Default APN types that are roaming-metered by the carrier
      * @hide
      */
     public static final String KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS =
             "carrier_metered_roaming_apn_types_strings";
+
+    /**
+     * Default APN types that are metered on IWLAN by the carrier
+     * @hide
+     */
+    public static final String KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS =
+            "carrier_metered_iwlan_apn_types_strings";
+
     /**
      * CDMA carrier ERI (Enhanced Roaming Indicator) file name
      * @hide
@@ -1443,6 +1451,9 @@
                 new String[]{"default", "mms", "dun", "supl"});
         sDefaults.putStringArray(KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{"default", "mms", "dun", "supl"});
+        // By default all APNs are unmetered if the device is on IWLAN.
+        sDefaults.putStringArray(KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+                new String[]{});
 
         sDefaults.putIntArray(KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY,
                 new int[]{
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index bc5e4d5..07259cf 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -3093,34 +3093,20 @@
     /*
      * The config held calling number conversion map, expected to convert to emergency number.
      */
-    private static final String[] CONVERT_TO_EMERGENCY_MAP = Resources.getSystem().getStringArray(
-            com.android.internal.R.array.config_convert_to_emergency_number_map);
-    /**
-     * Check whether conversion to emergency number is enabled
-     *
-     * @return {@code true} when conversion to emergency numbers is enabled,
-     *         {@code false} otherwise
-     *
-     * @hide
-     */
-    public static boolean isConvertToEmergencyNumberEnabled() {
-        return CONVERT_TO_EMERGENCY_MAP != null && CONVERT_TO_EMERGENCY_MAP.length > 0;
-    }
+    private static String[] sConvertToEmergencyMap = null;
 
     /**
      * Converts to emergency number based on the conversion map.
      * The conversion map is declared as config_convert_to_emergency_number_map.
      *
-     * Make sure {@link #isConvertToEmergencyNumberEnabled} is true before calling
-     * this function.
-     *
+     * @param context a context to use for accessing resources
      * @return The converted emergency number if the number matches conversion map,
      * otherwise original number.
      *
      * @hide
      */
-    public static String convertToEmergencyNumber(String number) {
-        if (TextUtils.isEmpty(number)) {
+    public static String convertToEmergencyNumber(Context context, String number) {
+        if (context == null || TextUtils.isEmpty(number)) {
             return number;
         }
 
@@ -3131,7 +3117,17 @@
             return number;
         }
 
-        for (String convertMap : CONVERT_TO_EMERGENCY_MAP) {
+        if (sConvertToEmergencyMap == null) {
+            sConvertToEmergencyMap = context.getResources().getStringArray(
+                    com.android.internal.R.array.config_convert_to_emergency_number_map);
+        }
+
+        // The conversion map is not defined (this is default). Skip conversion.
+        if (sConvertToEmergencyMap == null || sConvertToEmergencyMap.length == 0 ) {
+            return number;
+        }
+
+        for (String convertMap : sConvertToEmergencyMap) {
             if (DBG) log("convertToEmergencyNumber: " + convertMap);
             String[] entry = null;
             String[] filterNumbers = null;
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index bd8492b3..3b5d887 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -105,6 +105,10 @@
     //Call failures for FDN
     public static final int CODE_FDN_BLOCKED = 241;
 
+    // Network does not accept the emergency call request because IMEI was used as identification
+    // and this capability is not supported by the network.
+    public static final int CODE_IMEI_NOT_ACCEPTED = 243;
+
     /**
      * STATUSCODE (SIP response code) (IMS -> Telephony)
      */
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index d4896264..6bf3b6b 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -1066,10 +1066,15 @@
         final int ROUTE_LIFETIME  = 400;
         // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
         final int DNSSL_LIFETIME  = 2000;
+        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
+        // IPv6, traffic class = 0, flow label = 0x12345
+        final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
 
         // Verify RA is passed the first time
         ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
         basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
+                VERSION_TRAFFIC_CLASS_FLOW_LABEL);
         basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
         basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
         basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
@@ -1080,6 +1085,13 @@
         testRaLifetime(apfFilter, ipManagerCallback, basePacket, ROUTER_LIFETIME);
         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
 
+        ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
+        basePacket.clear();
+        newFlowLabelPacket.put(basePacket);
+        // Check that changes are ignored in every byte of the flow label.
+        newFlowLabelPacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
+                VERSION_TRAFFIC_CLASS_FLOW_LABEL + 0x11111);
+
         // Ensure zero-length options cause the packet to be silently skipped.
         // Do this before we test other packets. http://b/29586253
         ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
@@ -1145,6 +1157,7 @@
         // Verify that current program filters all five RAs:
         program = ipManagerCallback.getApfProgram();
         verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
+        verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
         verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
         verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
         verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
diff --git a/tests/CoreTests/android/core/NsdServiceInfoTest.java b/tests/net/java/android/net/nsd/NsdServiceInfoTest.java
similarity index 78%
rename from tests/CoreTests/android/core/NsdServiceInfoTest.java
rename to tests/net/java/android/net/nsd/NsdServiceInfoTest.java
index 5bf0167..e48b522 100644
--- a/tests/CoreTests/android/core/NsdServiceInfoTest.java
+++ b/tests/net/java/android/net/nsd/NsdServiceInfoTest.java
@@ -1,11 +1,32 @@
-package android.core;
+/*
+ * Copyright (C) 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.
+ */
 
-import android.test.AndroidTestCase;
+package android.net.nsd;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.StrictMode;
 import android.net.nsd.NsdServiceInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
 import java.util.Arrays;
@@ -14,8 +35,12 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class NsdServiceInfoTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NsdServiceInfoTest {
 
     public final static InetAddress LOCALHOST;
     static {
@@ -30,6 +55,7 @@
         LOCALHOST = _host;
     }
 
+    @Test
     public void testLimits() throws Exception {
         NsdServiceInfo info = new NsdServiceInfo();
 
@@ -85,6 +111,7 @@
         assertTrue(info.getTxtRecord().length == 1300);
     }
 
+    @Test
     public void testParcel() throws Exception {
         NsdServiceInfo emptyInfo = new NsdServiceInfo();
         checkParcelable(emptyInfo);
@@ -139,25 +166,25 @@
         NsdServiceInfo result = reader.getParcelable("test_info");
 
         // Assert equality of base fields.
-        assertEquality(original.getServiceName(), result.getServiceName());
-        assertEquality(original.getServiceType(), result.getServiceType());
-        assertEquality(original.getHost(), result.getHost());
+        assertEquals(original.getServiceName(), result.getServiceName());
+        assertEquals(original.getServiceType(), result.getServiceType());
+        assertEquals(original.getHost(), result.getHost());
         assertTrue(original.getPort() == result.getPort());
 
         // Assert equality of attribute map.
         Map<String, byte[]> originalMap = original.getAttributes();
         Map<String, byte[]> resultMap = result.getAttributes();
-        assertEquality(originalMap.keySet(), resultMap.keySet());
+        assertEquals(originalMap.keySet(), resultMap.keySet());
         for (String key : originalMap.keySet()) {
             assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key)));
         }
     }
 
-    public void assertEquality(Object expected, Object result) {
-        assertTrue(expected == result || expected.equals(result));
-    }
-
     public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) {
-        assertTrue(null == shouldBeEmpty.getTxtRecord());
+        byte[] txtRecord = shouldBeEmpty.getTxtRecord();
+        if (txtRecord == null || txtRecord.length == 0) {
+            return;
+        }
+        fail("NsdServiceInfo.getTxtRecord did not return null but " + Arrays.toString(txtRecord));
     }
 }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bbbf626..4fdbfe7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -97,6 +97,7 @@
 import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
 import com.android.server.net.NetworkPinner;
 
+import org.junit.Ignore;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
@@ -115,7 +116,7 @@
  * Tests for {@link ConnectivityService}.
  *
  * Build, install and run with:
- *  runtest frameworks-services -c com.android.server.ConnectivityServiceTest
+ *  runtest frameworks-net -c com.android.server.ConnectivityServiceTest
  */
 public class ConnectivityServiceTest extends AndroidTestCase {
     private static final String TAG = "ConnectivityServiceTest";
@@ -223,13 +224,32 @@
         }
     }
 
+    public void waitForIdle(int timeoutMs) {
+        waitForIdleHandler(mService.mHandlerThread, timeoutMs);
+        waitForIdle(mCellNetworkAgent, timeoutMs);
+        waitForIdle(mWiFiNetworkAgent, timeoutMs);
+        waitForIdle(mEthernetNetworkAgent, timeoutMs);
+        waitForIdleHandler(mService.mHandlerThread, timeoutMs);
+    }
+
+    public void waitForIdle(MockNetworkAgent agent, int timeoutMs) {
+        if (agent == null) {
+            return;
+        }
+        waitForIdleHandler(agent.mHandlerThread, timeoutMs);
+    }
+
+    private void waitForIdle() {
+        waitForIdle(TIMEOUT_MS);
+    }
+
     @SmallTest
     public void testWaitForIdle() {
         final int attempts = 50;  // Causes the test to take about 200ms on bullhead-eng.
 
         // Tests that waitForIdle returns immediately if the service is already idle.
         for (int i = 0; i < attempts; i++) {
-            mService.waitForIdle();
+            waitForIdle();
         }
 
         // Bring up a network that we can use to send messages to ConnectivityService.
@@ -243,7 +263,7 @@
         // Tests that calling waitForIdle waits for messages to be processed.
         for (int i = 0; i < attempts; i++) {
             mWiFiNetworkAgent.setSignalStrength(i);
-            mService.waitForIdle();
+            waitForIdle();
             assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength());
         }
     }
@@ -344,18 +364,10 @@
             };
             // Waits for the NetworkAgent to be registered, which includes the creation of the
             // NetworkMonitor.
-            mService.waitForIdle();
+            waitForIdle();
             mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
         }
 
-        public void waitForIdle(int timeoutMs) {
-            waitForIdleHandler(mHandlerThread, timeoutMs);
-        }
-
-        public void waitForIdle() {
-            waitForIdle(TIMEOUT_MS);
-        }
-
         public void adjustScore(int change) {
             mScore += change;
             mNetworkAgent.sendNetworkScore(mScore);
@@ -802,13 +814,22 @@
 
     public void tearDown() throws Exception {
         setMobileDataAlwaysOn(false);
-        if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); }
-        if (mWiFiNetworkAgent != null) { mWiFiNetworkAgent.disconnect(); }
-        mCellNetworkAgent = mWiFiNetworkAgent = null;
+        if (mCellNetworkAgent != null) {
+            mCellNetworkAgent.disconnect();
+            mCellNetworkAgent = null;
+        }
+        if (mWiFiNetworkAgent != null) {
+            mWiFiNetworkAgent.disconnect();
+            mWiFiNetworkAgent = null;
+        }
+        if (mEthernetNetworkAgent != null) {
+            mEthernetNetworkAgent.disconnect();
+            mEthernetNetworkAgent = null;
+        }
         super.tearDown();
     }
 
-    private int transportToLegacyType(int transport) {
+    private static int transportToLegacyType(int transport) {
         switch (transport) {
             case TRANSPORT_ETHERNET:
                 return TYPE_ETHERNET;
@@ -840,7 +861,8 @@
         }
         // Test getNetworkInfo(Network)
         assertNotNull(mCm.getNetworkInfo(mCm.getActiveNetwork()));
-        assertEquals(transportToLegacyType(transport), mCm.getNetworkInfo(mCm.getActiveNetwork()).getType());
+        assertEquals(transportToLegacyType(transport),
+                mCm.getNetworkInfo(mCm.getActiveNetwork()).getType());
         // Test getNetworkCapabilities(Network)
         assertNotNull(mCm.getNetworkCapabilities(mCm.getActiveNetwork()));
         assertTrue(mCm.getNetworkCapabilities(mCm.getActiveNetwork()).hasTransport(transport));
@@ -911,7 +933,7 @@
                 mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
         // Test cellular linger timeout.
         waitFor(mCellNetworkAgent.getDisconnectedCV());
-        mService.waitForIdle();
+        waitForIdle();
         assertEquals(1, mCm.getAllNetworks().length);
         verifyActiveNetwork(TRANSPORT_WIFI);
         assertEquals(1, mCm.getAllNetworks().length);
@@ -934,11 +956,11 @@
         // Test bringing up unvalidated cellular
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.connect(false);
-        mService.waitForIdle();
+        waitForIdle();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test cellular disconnect.
         mCellNetworkAgent.disconnect();
-        mService.waitForIdle();
+        waitForIdle();
         verifyActiveNetwork(TRANSPORT_WIFI);
         // Test bringing up validated cellular
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -1290,7 +1312,7 @@
         }
 
         void assertNoCallback() {
-            mService.waitForIdle();
+            waitForIdle();
             CallbackInfo c = mCallbacks.peek();
             assertNull("Unexpected callback: " + c, c);
         }
@@ -1331,7 +1353,7 @@
 
         // This should not trigger spurious onAvailable() callbacks, b/21762680.
         mCellNetworkAgent.adjustScore(-1);
-        mService.waitForIdle();
+        waitForIdle();
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
@@ -1369,7 +1391,7 @@
 
         // This should not trigger spurious onAvailable() callbacks, b/21762680.
         mCellNetworkAgent.adjustScore(-1);
-        mService.waitForIdle();
+        waitForIdle();
         assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
 
@@ -1481,7 +1503,7 @@
         defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
 
         mCm.unregisterNetworkCallback(callback);
-        mService.waitForIdle();
+        waitForIdle();
 
         // Check that a network is only lingered or torn down if it would not satisfy a request even
         // if it validated.
@@ -1842,26 +1864,30 @@
         ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
         mCellNetworkAgent.connectWithoutInternet();
         waitFor(cv);
-        mService.waitForIdle();
+        waitForIdle();
         assertEquals(0, mCm.getAllNetworks().length);
         verifyNoNetwork();
+
         // Test bringing up validated WiFi.
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         cv = waitForConnectivityBroadcasts(1);
         mWiFiNetworkAgent.connect(true);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
+
         // Register MMS NetworkRequest
         NetworkRequest.Builder builder = new NetworkRequest.Builder();
         builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
         final TestNetworkCallback networkCallback = new TestNetworkCallback();
         mCm.requestNetwork(builder.build(), networkCallback);
+
         // Test bringing up unvalidated cellular with MMS
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mCellNetworkAgent.connectWithoutInternet();
         networkCallback.expectAvailableCallbacks(mCellNetworkAgent);
         verifyActiveNetwork(TRANSPORT_WIFI);
+
         // Test releasing NetworkRequest disconnects cellular with MMS
         cv = mCellNetworkAgent.getDisconnectedCV();
         mCm.unregisterNetworkCallback(networkCallback);
@@ -1877,17 +1903,20 @@
         mCellNetworkAgent.connect(false);
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
+
         // Register MMS NetworkRequest
         NetworkRequest.Builder builder = new NetworkRequest.Builder();
         builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
         final TestNetworkCallback networkCallback = new TestNetworkCallback();
         mCm.requestNetwork(builder.build(), networkCallback);
+
         // Test bringing up MMS cellular network
         MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
         mmsNetworkAgent.connectWithoutInternet();
         networkCallback.expectAvailableCallbacks(mmsNetworkAgent);
         verifyActiveNetwork(TRANSPORT_CELLULAR);
+
         // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
         cv = mmsNetworkAgent.getDisconnectedCV();
         mCm.unregisterNetworkCallback(networkCallback);
@@ -2294,7 +2323,7 @@
         ContentResolver cr = mServiceContext.getContentResolver();
         Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
         mService.updateMobileDataAlwaysOn();
-        mService.waitForIdle();
+        waitForIdle();
     }
 
     private boolean isForegroundNetwork(MockNetworkAgent network) {
@@ -2336,7 +2365,7 @@
         assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
 
         // When lingering is complete, cell is still there but is now in the background.
-        mService.waitForIdle();
+        waitForIdle();
         int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
         fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
         // Expect a network capabilities update sans FOREGROUND.
@@ -2381,6 +2410,7 @@
         mCm.unregisterNetworkCallback(fgCallback);
     }
 
+    @Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
     @SmallTest
     public void testRequestBenchmark() throws Exception {
         // TODO: turn this unit test into a real benchmarking test.
@@ -2392,6 +2422,11 @@
         //    and NUM_REQUESTS onAvailable callbacks to fire.
         // See how long it took.
         final int NUM_REQUESTS = 90;
+        final int REGISTER_TIME_LIMIT_MS = 180;
+        final int CONNECT_TIME_LIMIT_MS = 50;
+        final int SWITCH_TIME_LIMIT_MS = 50;
+        final int UNREGISTER_TIME_LIMIT_MS = 20;
+
         final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
         final NetworkCallback[] callbacks = new NetworkCallback[NUM_REQUESTS];
         final CountDownLatch availableLatch = new CountDownLatch(NUM_REQUESTS);
@@ -2404,14 +2439,12 @@
             };
         }
 
-        final int REGISTER_TIME_LIMIT_MS = 180;
         assertTimeLimit("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
             for (NetworkCallback cb : callbacks) {
                 mCm.registerNetworkCallback(request, cb);
             }
         });
 
-        final int CONNECT_TIME_LIMIT_MS = 40;
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         // Don't request that the network validate, because otherwise connect() will block until
         // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
@@ -2419,31 +2452,29 @@
         mCellNetworkAgent.connect(false);
 
         long onAvailableDispatchingDuration = durationOf(() -> {
-            if (!awaitLatch(availableLatch, CONNECT_TIME_LIMIT_MS)) {
-                fail(String.format("Only dispatched %d/%d onAvailable callbacks in %dms",
-                        NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
-                        CONNECT_TIME_LIMIT_MS));
-            }
+            awaitLatch(availableLatch, 10 * CONNECT_TIME_LIMIT_MS);
         });
-        Log.d(TAG, String.format("Connect, %d callbacks: %dms, acceptable %dms",
-                NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS));
+        Log.d(TAG, String.format("Dispatched %d of %d onAvailable callbacks in %dms",
+                NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
+                onAvailableDispatchingDuration));
+        assertTrue(String.format("Dispatching %d onAvailable callbacks in %dms, expected %dms",
+                NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS),
+                onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS);
 
-        final int SWITCH_TIME_LIMIT_MS = 40;
-        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         // Give wifi a high enough score that we'll linger cell when wifi comes up.
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
         mWiFiNetworkAgent.adjustScore(40);
         mWiFiNetworkAgent.connect(false);
 
         long onLostDispatchingDuration = durationOf(() -> {
-            if (!awaitLatch(losingLatch, SWITCH_TIME_LIMIT_MS)) {
-                fail(String.format("Only dispatched %d/%d onLosing callbacks in %dms",
-                        NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, SWITCH_TIME_LIMIT_MS));
-            }
+            awaitLatch(losingLatch, 10 * SWITCH_TIME_LIMIT_MS);
         });
-        Log.d(TAG, String.format("Linger, %d callbacks: %dms, acceptable %dms",
-                NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS));
+        Log.d(TAG, String.format("Dispatched %d of %d onLosing callbacks in %dms",
+                NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, onLostDispatchingDuration));
+        assertTrue(String.format("Dispatching %d onLosing callbacks in %dms, expected %dms",
+                NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS),
+                onLostDispatchingDuration <= SWITCH_TIME_LIMIT_MS);
 
-        final int UNREGISTER_TIME_LIMIT_MS = 10;
         assertTimeLimit("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
             for (NetworkCallback cb : callbacks) {
                 mCm.unregisterNetworkCallback(cb);
@@ -2466,9 +2497,7 @@
 
     private boolean awaitLatch(CountDownLatch l, long timeoutMs) {
         try {
-            if (l.await(timeoutMs, TimeUnit.MILLISECONDS)) {
-                return true;
-            }
+            return l.await(timeoutMs, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {}
         return false;
     }
@@ -2520,7 +2549,7 @@
         assertFalse(testFactory.getMyStartRequested());  // Because the cell network outscores us.
 
         // Check that cell data stays up.
-        mService.waitForIdle();
+        waitForIdle();
         verifyActiveNetwork(TRANSPORT_WIFI);
         assertEquals(2, mCm.getAllNetworks().length);
 
@@ -2549,7 +2578,7 @@
         for (int i = 0; i < values.length; i++) {
             Settings.Global.putInt(cr, settingName, 1);
             tracker.reevaluate();
-            mService.waitForIdle();
+            waitForIdle();
             String msg = String.format("config=false, setting=%s", values[i]);
             assertTrue(mService.avoidBadWifi());
             assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
@@ -2559,19 +2588,19 @@
 
         Settings.Global.putInt(cr, settingName, 0);
         tracker.reevaluate();
-        mService.waitForIdle();
+        waitForIdle();
         assertFalse(mService.avoidBadWifi());
         assertFalse(tracker.shouldNotifyWifiUnvalidated());
 
         Settings.Global.putInt(cr, settingName, 1);
         tracker.reevaluate();
-        mService.waitForIdle();
+        waitForIdle();
         assertTrue(mService.avoidBadWifi());
         assertFalse(tracker.shouldNotifyWifiUnvalidated());
 
         Settings.Global.putString(cr, settingName, null);
         tracker.reevaluate();
-        mService.waitForIdle();
+        waitForIdle();
         assertFalse(mService.avoidBadWifi());
         assertTrue(tracker.shouldNotifyWifiUnvalidated());
     }
@@ -2714,7 +2743,7 @@
                 tracker.configMeteredMultipathPreference = config;
                 Settings.Global.putString(cr, settingName, setting);
                 tracker.reevaluate();
-                mService.waitForIdle();
+                waitForIdle();
 
                 final int expected = (setting != null) ? Integer.parseInt(setting) : config;
                 String msg = String.format("config=%d, setting=%s", config, setting);
@@ -2902,7 +2931,7 @@
         waitFor(cv);
         verifyActiveNetwork(TRANSPORT_WIFI);
         mWiFiNetworkAgent.sendLinkProperties(lp);
-        mService.waitForIdle();
+        waitForIdle();
         return mWiFiNetworkAgent.getNetwork();
     }
 
@@ -2981,7 +3010,7 @@
         callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
 
         // ... and that stopping it after that has no adverse effects.
-        mService.waitForIdle();
+        waitForIdle();
         final Network myNetAlias = myNet;
         assertNull(mCm.getNetworkCapabilities(myNetAlias));
         ka.stop();
@@ -2996,7 +3025,7 @@
         ka.stop();
         mWiFiNetworkAgent.disconnect();
         waitFor(mWiFiNetworkAgent.getDisconnectedCV());
-        mService.waitForIdle();
+        waitForIdle();
         callback.expectStopped();
 
         // Reconnect.
@@ -3197,7 +3226,7 @@
             mCm.unregisterNetworkCallback(pendingIntent);
         }
         pendingIntents.clear();
-        mService.waitForIdle(5000);
+        waitForIdle(5000);
 
         // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
         for (int i = 0; i < MAX_REQUESTS; i++) {
@@ -3205,20 +3234,20 @@
             mCm.requestNetwork(networkRequest, networkCallback);
             mCm.unregisterNetworkCallback(networkCallback);
         }
-        mService.waitForIdle();
+        waitForIdle();
         for (int i = 0; i < MAX_REQUESTS; i++) {
             NetworkCallback networkCallback = new NetworkCallback();
             mCm.registerNetworkCallback(networkRequest, networkCallback);
             mCm.unregisterNetworkCallback(networkCallback);
         }
-        mService.waitForIdle();
+        waitForIdle();
         for (int i = 0; i < MAX_REQUESTS; i++) {
             PendingIntent pendingIntent =
                     PendingIntent.getBroadcast(mContext, 0, new Intent("b" + i), 0);
             mCm.requestNetwork(networkRequest, pendingIntent);
             mCm.unregisterNetworkCallback(pendingIntent);
         }
-        mService.waitForIdle();
+        waitForIdle();
         for (int i = 0; i < MAX_REQUESTS; i++) {
             PendingIntent pendingIntent =
                     PendingIntent.getBroadcast(mContext, 0, new Intent("c" + i), 0);
diff --git a/tests/net/java/android/net/nsd/NsdServiceTest.java b/tests/net/java/com/android/server/NsdServiceTest.java
similarity index 100%
rename from tests/net/java/android/net/nsd/NsdServiceTest.java
rename to tests/net/java/com/android/server/NsdServiceTest.java
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index bc89c0f..d5a0b86 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -43,6 +43,7 @@
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
 import android.net.NetworkRequest;
+import android.net.util.SharedLog;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
@@ -142,8 +143,8 @@
         };
         mServiceContext.registerReceiver(mBroadcastReceiver,
                 new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
-        when(mTetheringDependencies.getOffloadHardwareInterface())
-                .thenReturn(mOffloadHardwareInterface);
+        when(mTetheringDependencies.getOffloadHardwareInterface(
+                any(Handler.class), any(SharedLog.class))).thenReturn(mOffloadHardwareInterface);
         mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
                                    mLooper.getLooper(), mSystemProperties,
                                    mTetheringDependencies);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 9fcd1b5..ddceea2 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -128,5 +128,8 @@
         assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
         // Just to prove we haven't clobbered Wi-Fi:
         assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI));
+        // Check that we have not added new cellular interface types
+        assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
+        assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI));
     }
 }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
index e6b1c6d..23318c2 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.net;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.when;
 
 import android.Manifest;
@@ -26,17 +27,21 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
 
 import com.android.server.LocalServices;
 
-import junit.framework.TestCase;
-
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@RunWith(AndroidJUnit4.class)
 @SmallTest
-public class NetworkStatsAccessTest extends TestCase {
+public class NetworkStatsAccessTest {
     private static final String TEST_PKG = "com.example.test";
     private static final int TEST_UID = 12345;
 
@@ -48,9 +53,8 @@
     // Hold the real service so we can restore it when tearing down the test.
     private DevicePolicyManagerInternal mSystemDpmi;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
 
         mSystemDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
@@ -61,13 +65,13 @@
         when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOps);
     }
 
-    @Override
+    @After
     public void tearDown() throws Exception {
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
         LocalServices.addService(DevicePolicyManagerInternal.class, mSystemDpmi);
-        super.tearDown();
     }
 
+    @Test
     public void testCheckAccessLevel_hasCarrierPrivileges() throws Exception {
         setHasCarrierPrivileges(true);
         setIsDeviceOwner(false);
@@ -78,6 +82,7 @@
                 NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
     }
 
+    @Test
     public void testCheckAccessLevel_isDeviceOwner() throws Exception {
         setHasCarrierPrivileges(false);
         setIsDeviceOwner(true);
@@ -88,6 +93,7 @@
                 NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
     }
 
+    @Test
     public void testCheckAccessLevel_isProfileOwner() throws Exception {
         setHasCarrierPrivileges(false);
         setIsDeviceOwner(false);
@@ -98,36 +104,40 @@
                 NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
     }
 
+    @Test
     public void testCheckAccessLevel_hasAppOpsBitAllowed() throws Exception {
         setHasCarrierPrivileges(false);
         setIsDeviceOwner(false);
         setIsProfileOwner(true);
         setHasAppOpsPermission(AppOpsManager.MODE_ALLOWED, false);
         setHasReadHistoryPermission(false);
-        assertEquals(NetworkStatsAccess.Level.USER,
+        assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
                 NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
     }
 
+    @Test
     public void testCheckAccessLevel_hasAppOpsBitDefault_grantedPermission() throws Exception {
         setHasCarrierPrivileges(false);
         setIsDeviceOwner(false);
         setIsProfileOwner(true);
         setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, true);
         setHasReadHistoryPermission(false);
-        assertEquals(NetworkStatsAccess.Level.USER,
+        assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
                 NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
     }
 
+    @Test
     public void testCheckAccessLevel_hasReadHistoryPermission() throws Exception {
         setHasCarrierPrivileges(false);
         setIsDeviceOwner(false);
         setIsProfileOwner(true);
         setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
         setHasReadHistoryPermission(true);
-        assertEquals(NetworkStatsAccess.Level.USER,
+        assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
                 NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
     }
 
+    @Test
     public void testCheckAccessLevel_deniedAppOpsBit() throws Exception {
         setHasCarrierPrivileges(false);
         setIsDeviceOwner(false);
@@ -138,6 +148,7 @@
                 NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
     }
 
+    @Test
     public void testCheckAccessLevel_deniedAppOpsBit_deniedPermission() throws Exception {
         setHasCarrierPrivileges(false);
         setIsDeviceOwner(false);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index fe7840d..92dcdac 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -18,21 +18,23 @@
 
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.when;
-
-import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.METERED_NO;
 import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.SET_DEFAULT;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.when;
+
 import android.app.usage.NetworkStatsManager;
 import android.net.DataUsageRequest;
 import android.net.NetworkIdentity;
@@ -48,6 +50,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 
@@ -60,8 +63,9 @@
 import java.util.Objects;
 import java.util.List;
 
-import junit.framework.TestCase;
-
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
@@ -69,8 +73,9 @@
 /**
  * Tests for {@link NetworkStatsObservers}.
  */
+@RunWith(AndroidJUnit4.class)
 @SmallTest
-public class NetworkStatsObserversTest extends TestCase {
+public class NetworkStatsObserversTest {
     private static final String TEST_IFACE = "test0";
     private static final String TEST_IFACE2 = "test1";
     private static final long TEST_START = 1194220800000L;
@@ -88,7 +93,7 @@
     private static final int UID_GREEN = UserHandle.PER_USER_RANGE + 3;
     private static final int UID_ANOTHER_USER = 2 * UserHandle.PER_USER_RANGE + 4;
 
-    private static final long WAIT_TIMEOUT = 500;  // 1/2 sec
+    private static final long WAIT_TIMEOUT_MS = 500;
     private static final long THRESHOLD_BYTES = 2 * MB_IN_BYTES;
     private static final long BASE_BYTES = 7 * MB_IN_BYTES;
     private static final int INVALID_TYPE = -1;
@@ -101,7 +106,6 @@
     private Handler mObserverNoopHandler;
 
     private LatchedHandler mHandler;
-    private ConditionVariable mCv;
 
     private NetworkStatsObservers mStatsObservers;
     private Messenger mMessenger;
@@ -110,9 +114,8 @@
 
     @Mock private IBinder mockBinder;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
         MockitoAnnotations.initMocks(this);
 
         mObserverHandlerThread = new IdleableHandlerThread("HandlerThread");
@@ -125,14 +128,14 @@
             }
         };
 
-        mCv = new ConditionVariable();
-        mHandler = new LatchedHandler(Looper.getMainLooper(), mCv);
+        mHandler = new LatchedHandler(Looper.getMainLooper(), new ConditionVariable());
         mMessenger = new Messenger(mHandler);
 
         mActiveIfaces = new ArrayMap<>();
         mActiveUidIfaces = new ArrayMap<>();
     }
 
+    @Test
     public void testRegister_thresholdTooLow_setsDefaultThreshold() throws Exception {
         long thresholdTooLowBytes = 1L;
         DataUsageRequest inputRequest = new DataUsageRequest(
@@ -145,6 +148,7 @@
         assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
     }
 
+    @Test
     public void testRegister_highThreshold_accepted() throws Exception {
         long highThresholdBytes = 2 * THRESHOLD_BYTES;
         DataUsageRequest inputRequest = new DataUsageRequest(
@@ -157,6 +161,7 @@
         assertEquals(highThresholdBytes, request.thresholdInBytes);
     }
 
+    @Test
     public void testRegister_twoRequests_twoIds() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, THRESHOLD_BYTES);
@@ -174,6 +179,7 @@
         assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
     }
 
+    @Test
     public void testUnregister_unknownRequest_noop() throws Exception {
         DataUsageRequest unknownRequest = new DataUsageRequest(
                 123456 /* id */, sTemplateWifi, THRESHOLD_BYTES);
@@ -181,6 +187,7 @@
         mStatsObservers.unregister(unknownRequest, UID_RED);
     }
 
+    @Test
     public void testUnregister_knownRequest_releasesCaller() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -198,6 +205,7 @@
         Mockito.verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
     }
 
+    @Test
     public void testUnregister_knownRequest_invalidUid_doesNotUnregister() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -215,6 +223,7 @@
         Mockito.verifyZeroInteractions(mockBinder);
     }
 
+    @Test
     public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -240,11 +249,9 @@
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
         waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
-        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
     }
 
+    @Test
     public void testUpdateStats_belowThreshold_doesNotNotify() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -276,12 +283,10 @@
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
         waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
-        mCv.block(WAIT_TIMEOUT);
-        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
     }
 
+
+    @Test
     public void testUpdateStats_deviceAccess_notifies() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -314,11 +319,10 @@
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
         waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
         assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
     }
 
+    @Test
     public void testUpdateStats_defaultAccess_notifiesSameUid() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -352,11 +356,10 @@
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
         waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
         assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
     }
 
+    @Test
     public void testUpdateStats_defaultAccess_usageOtherUid_doesNotNotify() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -390,11 +393,9 @@
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
         waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
-        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
     }
 
+    @Test
     public void testUpdateStats_userAccess_usageSameUser_notifies() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -428,11 +429,10 @@
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
         waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
         assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
     }
 
+    @Test
     public void testUpdateStats_userAccess_usageAnotherUser_doesNotNotify() throws Exception {
         DataUsageRequest inputRequest = new DataUsageRequest(
                 DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
@@ -467,14 +467,22 @@
                 xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
                 VPN_INFO, TEST_START);
         waitForObserverToIdle();
-
-        assertTrue(mCv.block(WAIT_TIMEOUT));
-        assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
     }
 
     private void waitForObserverToIdle() {
-        // Send dummy message to make sure that any previous message has been handled
-        mHandler.sendMessage(mHandler.obtainMessage(-1));
-        mObserverHandlerThread.waitForIdle(WAIT_TIMEOUT);
+        waitForIdleLooper(mObserverHandlerThread.getLooper(), WAIT_TIMEOUT_MS);
+        waitForIdleLooper(mHandler.getLooper(), WAIT_TIMEOUT_MS);
     }
+
+    // TODO: unify with ConnectivityService.waitForIdleHandler and
+    // NetworkServiceStatsTest.IdleableHandlerThread
+    private static void waitForIdleLooper(Looper looper, long timeoutMs) {
+        final ConditionVariable cv = new ConditionVariable();
+        final Handler handler = new Handler(looper);
+        handler.post(() -> cv.open());
+        if (!cv.block(timeoutMs)) {
+            fail("Looper did not become idle after " + timeoutMs + " ms");
+        }
+    }
+
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b7fe9c7..2333d7e 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -378,6 +378,21 @@
     @SystemApi
     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
     /**
+     * The interface used for the softap.
+     *
+     * @hide
+     */
+    public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "wifi_ap_interface_name";
+    /**
+     * The intended ip mode for this softap.
+     * @see #IFACE_IP_MODE_TETHERED
+     * @see #IFACE_IP_MODE_LOCAL_ONLY
+     *
+     * @hide
+     */
+    public static final String EXTRA_WIFI_AP_MODE = "wifi_ap_mode";
+
+    /**
      * Wi-Fi AP is currently being disabled. The state will change to
      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
      *