Merge "Don't call ConnectivityService when holding ActivityManagerService lock."
diff --git a/Android.bp b/Android.bp
index 523e356..57f6513 100644
--- a/Android.bp
+++ b/Android.bp
@@ -687,6 +687,7 @@
     static_libs: [
         "apex_aidl_interface-java",
         "framework-protos",
+        "game-driver-protos",
         "android.hidl.base-V1.0-java",
         "android.hardware.cas-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
@@ -842,6 +843,7 @@
         "core/java/com/android/internal/util/RingBufferIndices.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
+        "core/java/com/android/internal/util/TrafficStatsConstants.java",
         "core/java/com/android/internal/util/WakeupMessage.java",
         "core/java/android/net/shared/*.java",
     ]
diff --git a/api/current.txt b/api/current.txt
index 84aa984..4dcba83 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -29116,7 +29116,6 @@
     method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
-    method @NonNull public java.util.List<java.lang.String> getSupportedOffHostSecureElements();
     method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
     method @Deprecated public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
@@ -29209,10 +29208,10 @@
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
     method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
     method public boolean removeAidsForService(android.content.ComponentName, String);
-    method public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.NFC) @NonNull public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
     method public boolean supportsAidPrefixRegistration();
-    method public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
+    method @RequiresPermission(android.Manifest.permission.NFC) @NonNull public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
     method public boolean unsetPreferredService(android.app.Activity);
     field public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
     field public static final String CATEGORY_OTHER = "other";
@@ -37345,7 +37344,7 @@
     field @Deprecated public static final String BEARER = "bearer";
     field public static final String CARRIER_ENABLED = "carrier_enabled";
     field public static final String CARRIER_ID = "carrier_id";
-    field public static final android.net.Uri CONTENT_URI;
+    field @NonNull public static final android.net.Uri CONTENT_URI;
     field public static final String CURRENT = "current";
     field public static final String DEFAULT_SORT_ORDER = "name ASC";
     field @Deprecated public static final String MCC = "mcc";
@@ -37364,7 +37363,7 @@
     field public static final String PROXY = "proxy";
     field public static final String ROAMING_PROTOCOL = "roaming_protocol";
     field public static final String SERVER = "server";
-    field public static final android.net.Uri SIM_APN_URI;
+    field @NonNull public static final android.net.Uri SIM_APN_URI;
     field public static final String SUBSCRIPTION_ID = "sub_id";
     field public static final String TYPE = "type";
     field public static final String USER = "user";
diff --git a/api/system-current.txt b/api/system-current.txt
index 5bf5380..3b4a868 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -727,30 +727,29 @@
 package android.bluetooth {
 
   public final class BluetoothAdapter {
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
     method public boolean disableBLE();
     method public boolean enableBLE();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
     method public boolean isBleScanAlwaysAvailable();
     method public boolean isLeEnabled();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean registerMetadataListener(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothAdapter.MetadataListener, android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean unregisterMetadataListener(android.bluetooth.BluetoothDevice);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
     field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
     field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
   }
 
-  public abstract static class BluetoothAdapter.MetadataListener {
-    ctor public BluetoothAdapter.MetadataListener();
-    method public void onMetadataChanged(android.bluetooth.BluetoothDevice, int, String);
+  public static interface BluetoothAdapter.OnMetadataChangedListener {
+    method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
   }
 
   public final class BluetoothDevice implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
     field public static final int ACCESS_ALLOWED = 1; // 0x1
@@ -760,21 +759,21 @@
     field public static final int METADATA_COMPANION_APP = 4; // 0x4
     field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
     field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
-    field public static final int METADATA_IS_UNTHETHERED_HEADSET = 6; // 0x6
+    field public static final int METADATA_IS_UNTETHERED_HEADSET = 6; // 0x6
     field public static final int METADATA_MAIN_ICON = 5; // 0x5
     field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0
     field public static final int METADATA_MAX_LENGTH = 2048; // 0x800
     field public static final int METADATA_MODEL_NAME = 1; // 0x1
     field public static final int METADATA_SOFTWARE_VERSION = 2; // 0x2
-    field public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12; // 0xc
-    field public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15; // 0xf
-    field public static final int METADATA_UNTHETHERED_CASE_ICON = 9; // 0x9
-    field public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10; // 0xa
-    field public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13; // 0xd
-    field public static final int METADATA_UNTHETHERED_LEFT_ICON = 7; // 0x7
-    field public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11; // 0xb
-    field public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14; // 0xe
-    field public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8; // 0x8
+    field public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; // 0xc
+    field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf
+    field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9
+    field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa
+    field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd
+    field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7
+    field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb
+    field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe
+    field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8
   }
 
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
@@ -3293,9 +3292,12 @@
     method public static void setThreadStatsTagApp();
     method public static void setThreadStatsTagBackup();
     method public static void setThreadStatsTagRestore();
-    field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40
-    field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46
-    field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42
+    field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f
+    field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80
+    field public static final int TAG_NETWORK_STACK_RANGE_END = -257; // 0xfffffeff
+    field public static final int TAG_NETWORK_STACK_RANGE_START = -768; // 0xfffffd00
+    field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = -241; // 0xffffff0f
+    field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00
   }
 
   public class VpnService extends android.app.Service {
@@ -7710,8 +7712,6 @@
     method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
     method public void dispose(int) throws android.os.RemoteException;
     method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
-    method public static String getDefaultTransactionName(int);
-    method public String getTransactionName(int);
     method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
     method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
     method public void onAppCallbackDied(int, int);
@@ -7739,9 +7739,7 @@
     ctor public MbmsStreamingServiceBase();
     method public android.os.IBinder asBinder();
     method public void dispose(int) throws android.os.RemoteException;
-    method public static String getDefaultTransactionName(int);
     method @Nullable public android.net.Uri getPlaybackUri(int, String) throws android.os.RemoteException;
-    method public String getTransactionName(int);
     method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException;
     method public void onAppCallbackDied(int, int);
     method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
@@ -7779,6 +7777,10 @@
     method public int getUid();
   }
 
+  public final class StatsLog {
+    method public static void writeRaw(@NonNull byte[], int);
+  }
+
 }
 
 package android.view {
diff --git a/api/test-current.txt b/api/test-current.txt
index 524c1fb..dc5ff8f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -730,9 +730,6 @@
     method public static long getLoopbackRxPackets();
     method public static long getLoopbackTxBytes();
     method public static long getLoopbackTxPackets();
-    field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40
-    field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46
-    field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42
   }
 
 }
@@ -1594,8 +1591,6 @@
     method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
     method public void dispose(int) throws android.os.RemoteException;
     method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
-    method public static String getDefaultTransactionName(int);
-    method public String getTransactionName(int);
     method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
     method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
     method public void onAppCallbackDied(int, int);
@@ -1623,9 +1618,7 @@
     ctor public MbmsStreamingServiceBase();
     method public android.os.IBinder asBinder();
     method public void dispose(int) throws android.os.RemoteException;
-    method public static String getDefaultTransactionName(int);
     method @Nullable public android.net.Uri getPlaybackUri(int, String) throws android.os.RemoteException;
-    method public String getTransactionName(int);
     method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException;
     method public void onAppCallbackDied(int, int);
     method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 564e918..1ac6ea8 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -134,7 +134,7 @@
         LowMemReported low_mem_reported = 81;
         ThermalThrottlingStateChanged thermal_throttling = 86;
         NetworkDnsEventReported network_dns_event_reported = 116;
-        DataStallEvent data_stall_event = 121;
+        DataStallEvent data_stall_event = 121 [(log_from_module) = "network_stack"];
         BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event = 125;
         BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed = 126;
         BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed = 127;
@@ -165,7 +165,7 @@
         BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167;
         ProcessStartTime process_start_time = 169;
         BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171;
-        NetworkStackReported network_stack_reported = 182;
+        NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"];
     }
 
     // Pulled events will start at field 10000.
diff --git a/config/Android.bp b/config/Android.bp
new file mode 100644
index 0000000..0fb56cb
--- /dev/null
+++ b/config/Android.bp
@@ -0,0 +1,18 @@
+// Copyright (C) 2019 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.
+
+filegroup {
+    name: "preloaded-classes-blacklist",
+    srcs: ["preloaded-classes-blacklist"],
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a86015f6..d9c82ea 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5593,7 +5593,7 @@
             }
         }
 
-        GraphicsEnvironment.getInstance().setup(context);
+        GraphicsEnvironment.getInstance().setup(context, mCoreSettings);
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b8a741a..31bbd16 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,6 +20,7 @@
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -37,7 +38,6 @@
 import android.content.Context;
 import android.os.BatteryStats;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -61,6 +61,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -650,7 +651,7 @@
 
     private final Object mLock = new Object();
     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
-    private static final Map<BluetoothDevice, List<Pair<MetadataListener, Handler>>>
+    private static final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
                 sMetadataListeners = new HashMap<>();
 
     /**
@@ -660,14 +661,15 @@
     private static final IBluetoothMetadataListener sBluetoothMetadataListener =
             new IBluetoothMetadataListener.Stub() {
         @Override
-        public void onMetadataChanged(BluetoothDevice device, int key, String value) {
+        public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) {
             synchronized (sMetadataListeners) {
                 if (sMetadataListeners.containsKey(device)) {
-                    List<Pair<MetadataListener, Handler>> list = sMetadataListeners.get(device);
-                    for (Pair<MetadataListener, Handler> pair : list) {
-                        MetadataListener listener = pair.first;
-                        Handler handler = pair.second;
-                        handler.post(() -> {
+                    List<Pair<OnMetadataChangedListener, Executor>> list =
+                            sMetadataListeners.get(device);
+                    for (Pair<OnMetadataChangedListener, Executor> pair : list) {
+                        OnMetadataChangedListener listener = pair.first;
+                        Executor executor = pair.second;
+                        executor.execute(() -> {
                             listener.onMetadataChanged(device, key, value);
                         });
                     }
@@ -3153,30 +3155,30 @@
     }
 
     /**
-     * Register a {@link #MetadataListener} to receive update about metadata
+     * Register a {@link #OnMetadataChangedListener} to receive update about metadata
      * changes for this {@link BluetoothDevice}.
      * Registration must be done when Bluetooth is ON and will last until
-     * {@link #unregisterMetadataListener(BluetoothDevice)} is called, even when Bluetooth
+     * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth
      * restarted in the middle.
      * All input parameters should not be null or {@link NullPointerException} will be triggered.
-     * The same {@link BluetoothDevice} and {@link #MetadataListener} pair can only be registered
-     * once, double registration would cause {@link IllegalArgumentException}.
+     * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be
+     * registered once, double registration would cause {@link IllegalArgumentException}.
      *
      * @param device {@link BluetoothDevice} that will be registered
-     * @param listener {@link #MetadataListener} that will receive asynchronous callbacks
-     * @param handler the handler for listener callback
+     * @param executor the executor for listener callback
+     * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks
      * @return true on success, false on error
-     * @throws NullPointerException If one of {@code listener}, {@code device} or {@code handler}
+     * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor}
      * is null.
-     * @throws IllegalArgumentException The same {@link #MetadataListener} and
+     * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and
      * {@link BluetoothDevice} are registered twice.
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean registerMetadataListener(BluetoothDevice device, MetadataListener listener,
-            Handler handler) {
-        if (DBG) Log.d(TAG, "registerMetdataListener()");
+    public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device,
+            @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) {
+        if (DBG) Log.d(TAG, "addOnMetadataChangedListener()");
 
         final IBluetooth service = mService;
         if (service == null) {
@@ -3189,14 +3191,15 @@
         if (device == null) {
             throw new NullPointerException("device is null");
         }
-        if (handler == null) {
-            throw new NullPointerException("handler is null");
+        if (executor == null) {
+            throw new NullPointerException("executor is null");
         }
 
         synchronized (sMetadataListeners) {
-            List<Pair<MetadataListener, Handler>> listenerList = sMetadataListeners.get(device);
+            List<Pair<OnMetadataChangedListener, Executor>> listenerList =
+                    sMetadataListeners.get(device);
             if (listenerList == null) {
-                // Create new listener/handler list for registeration
+                // Create new listener/executor list for registeration
                 listenerList = new ArrayList<>();
                 sMetadataListeners.put(device, listenerList);
             } else {
@@ -3207,7 +3210,7 @@
                 }
             }
 
-            Pair<MetadataListener, Handler> listenerPair = new Pair(listener, handler);
+            Pair<OnMetadataChangedListener, Executor> listenerPair = new Pair(listener, executor);
             listenerList.add(listenerPair);
 
             boolean ret = false;
@@ -3230,63 +3233,74 @@
     }
 
     /**
-     * Unregister all {@link MetadataListener} from this {@link BluetoothDevice}.
+     * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}.
      * Unregistration can be done when Bluetooth is either ON or OFF.
-     * {@link #registerMetadataListener(MetadataListener, BluetoothDevice, Handler)} must
-     * be called before unregisteration.
-     * Unregistering a device that is not regestered would cause {@link IllegalArgumentException}.
+     * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)}
+     * must be called before unregisteration.
      *
-     * @param device {@link BluetoothDevice} that will be unregistered. it
+     * @param device {@link BluetoothDevice} that will be unregistered. It
+     * should not be null or {@link NullPointerException} will be triggered.
+     * @param listener {@link OnMetadataChangedListener} that will be unregistered. It
      * should not be null or {@link NullPointerException} will be triggered.
      * @return true on success, false on error
-     * @throws NullPointerException If {@code device} is null.
+     * @throws NullPointerException If {@code listener} or {@code device} is null.
      * @throws IllegalArgumentException If {@code device} has not been registered before.
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean unregisterMetadataListener(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "unregisterMetdataListener()");
+    public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device,
+            @NonNull OnMetadataChangedListener listener) {
+        if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()");
         if (device == null) {
             throw new NullPointerException("device is null");
         }
+        if (listener == null) {
+            throw new NullPointerException("listener is null");
+        }
 
         synchronized (sMetadataListeners) {
-            if (sMetadataListeners.containsKey(device)) {
-                sMetadataListeners.remove(device);
-            } else {
+            if (!sMetadataListeners.containsKey(device)) {
                 throw new IllegalArgumentException("device was not registered");
             }
+            // Remove issued listener from the registered device
+            sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener)));
 
-            final IBluetooth service = mService;
-            if (service == null) {
-                // Bluetooth is OFF, do nothing to Bluetooth service.
-                return true;
-            }
-            try {
-                return service.unregisterMetadataListener(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, "unregisterMetadataListener fail", e);
-                return false;
+            if (sMetadataListeners.get(device).isEmpty()) {
+                // Unregister to Bluetooth service if all listeners are removed from
+                // the registered device
+                sMetadataListeners.remove(device);
+                final IBluetooth service = mService;
+                if (service == null) {
+                    // Bluetooth is OFF, do nothing to Bluetooth service.
+                    return true;
+                }
+                try {
+                    return service.unregisterMetadataListener(device);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "unregisterMetadataListener fail", e);
+                    return false;
+                }
             }
         }
+        return true;
     }
 
     /**
-     * This abstract class is used to implement {@link BluetoothAdapter} metadata listener.
+     * This interface is used to implement {@link BluetoothAdapter} metadata listener.
      * @hide
      */
     @SystemApi
-    public abstract static class MetadataListener {
+    public interface OnMetadataChangedListener {
         /**
          * Callback triggered if the metadata of {@link BluetoothDevice} registered in
-         * {@link #registerMetadataListener}.
+         * {@link #addOnMetadataChangedListener}.
          *
          * @param device changed {@link BluetoothDevice}.
          * @param key changed metadata key, one of BluetoothDevice.METADATA_*.
-         * @param value the new value of metadata.
+         * @param value the new value of metadata as byte array.
          */
-        public void onMetadataChanged(BluetoothDevice device, int key, String value) {
-        }
+        void onMetadataChanged(@NonNull BluetoothDevice device, int key,
+                @Nullable byte[] value);
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 6af1096..1e12801 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -351,6 +352,7 @@
 
     /**
      * Manufacturer name of this Bluetooth device
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -358,6 +360,7 @@
 
     /**
      * Model name of this Bluetooth device
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -365,6 +368,7 @@
 
     /**
      * Software version of this Bluetooth device
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -372,6 +376,7 @@
 
     /**
      * Hardware version of this Bluetooth device
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -379,6 +384,7 @@
 
     /**
      * Package name of the companion app, if any
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -386,6 +392,7 @@
 
     /**
      * URI to the main icon shown on the settings UI
+     * Data type should be {@link Byte} array.
      * @hide
      */
     @SystemApi
@@ -393,80 +400,91 @@
 
     /**
      * Whether this device is an untethered headset with left, right and case
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_IS_UNTHETHERED_HEADSET = 6;
+    public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
 
     /**
      * URI to icon of the left headset
+     * Data type should be {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_LEFT_ICON = 7;
+    public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
 
     /**
      * URI to icon of the right headset
+     * Data type should be {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8;
+    public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
 
     /**
      * URI to icon of the headset charging case
+     * Data type should be {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_CASE_ICON = 9;
+    public static final int METADATA_UNTETHERED_CASE_ICON = 9;
 
     /**
-     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
-     * is invalid, of the left headset
+     * Battery level of left headset
+     * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+     * as invalid.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10;
+    public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
 
     /**
-     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
-     * is invalid, of the right headset
+     * Battery level of rigth headset
+     * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+     * as invalid.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11;
+    public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
 
     /**
-     * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
-     * is invalid, of the headset charging case
+     * Battery level of the headset charging case
+     * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+     * as invalid.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12;
+    public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
 
     /**
      * Whether the left headset is charging
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13;
+    public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
 
     /**
      * Whether the right headset is charging
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14;
+    public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
 
     /**
      * Whether the headset charging case is charging
+     * Data type should be {@String} as {@link Byte} array.
      * @hide
      */
     @SystemApi
-    public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15;
+    public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
 
     /**
-     * URI to the enhanced settings UI slice, null or empty String means
-     * the UI does not exist
+     * URI to the enhanced settings UI slice
+     * Data type should be {@String} as {@link Byte} array, null means
+     * the UI does not exist.
      * @hide
      */
     @SystemApi
@@ -2243,21 +2261,21 @@
      * {@link #BOND_NONE}.
      *
      * @param key must be within the list of BluetoothDevice.METADATA_*
-     * @param value the string data to set for key. Must be less than
+     * @param value a byte array data to set for key. Must be less than
      * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
      * @return true on success, false on error
      * @hide
     */
     @SystemApi
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public boolean setMetadata(int key, String value) {
+    public boolean setMetadata(int key, @NonNull byte[] value) {
         final IBluetooth service = sService;
         if (service == null) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
             return false;
         }
-        if (value.length() > METADATA_MAX_LENGTH) {
-            throw new IllegalArgumentException("value length is " + value.length()
+        if (value.length > METADATA_MAX_LENGTH) {
+            throw new IllegalArgumentException("value length is " + value.length
                     + ", should not over " + METADATA_MAX_LENGTH);
         }
         try {
@@ -2272,12 +2290,13 @@
      * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
      *
      * @param key must be within the list of BluetoothDevice.METADATA_*
-     * @return Metadata of the key as string, null on error or not found
+     * @return Metadata of the key as byte array, null on error or not found
      * @hide
      */
     @SystemApi
+    @Nullable
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
-    public String getMetadata(int key) {
+    public byte[] getMetadata(int key) {
         final IBluetooth service = sService;
         if (service == null) {
             Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2906710..0e10de8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -510,7 +510,7 @@
      * The absence of a connection type.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     public static final int TYPE_NONE        = -1;
 
     /**
@@ -627,7 +627,7 @@
      * {@hide}
      */
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     public static final int TYPE_MOBILE_FOTA = 10;
 
     /**
@@ -645,7 +645,7 @@
      * {@hide}
      */
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     public static final int TYPE_MOBILE_CBS  = 12;
 
     /**
@@ -655,7 +655,7 @@
      * {@hide}
      */
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     public static final int TYPE_WIFI_P2P    = 13;
 
     /**
@@ -674,7 +674,7 @@
      * {@hide}
      */
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     public static final int TYPE_MOBILE_EMERGENCY = 15;
 
     /**
@@ -775,7 +775,7 @@
      */
     public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     private final IConnectivityManager mService;
     /**
      * A kludge to facilitate static access where a Context pointer isn't available, like in the
@@ -867,7 +867,7 @@
      * {@hide}
      */
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     public static boolean isNetworkTypeMobile(int networkType) {
         switch (networkType) {
             case TYPE_MOBILE:
@@ -1304,7 +1304,7 @@
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     public LinkProperties getLinkProperties(int networkType) {
         try {
             return mService.getLinkPropertiesForType(networkType);
@@ -3042,7 +3042,7 @@
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     public boolean isNetworkSupported(int networkType) {
         try {
             return mService.isNetworkSupported(networkType);
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index b6c4fe2..68826cb 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -197,7 +197,7 @@
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkSend((network != null
-                ? network.netId : NETID_UNSET), query, query.length, flags);
+                ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags);
         } catch (ErrnoException e) {
             executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
             return;
@@ -238,7 +238,7 @@
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkQuery((network != null
-                    ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
+                    ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags);
         } catch (ErrnoException e) {
             executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
             return;
@@ -346,7 +346,8 @@
         if (queryIpv6) {
             try {
                 v6fd = resNetworkQuery((network != null
-                        ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
+                        ? network.getNetIdForResolv() : NETID_UNSET),
+                        domain, CLASS_IN, TYPE_AAAA, flags);
             } catch (ErrnoException e) {
                 executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
                 return;
@@ -365,7 +366,8 @@
         if (queryIpv4) {
             try {
                 v4fd = resNetworkQuery((network != null
-                        ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
+                        ? network.getNetIdForResolv() : NETID_UNSET),
+                        domain, CLASS_IN, TYPE_A, flags);
             } catch (ErrnoException e) {
                 if (queryIpv6) resNetworkCancel(v6fd);  // Closes fd, marks it invalid.
                 executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
@@ -423,7 +425,7 @@
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkQuery((network != null
-                    ? network.netId : NETID_UNSET), domain, CLASS_IN, nsType, flags);
+                    ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags);
         } catch (ErrnoException e) {
             executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
             return;
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index b8d7cf1..a55d9d0 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -20,6 +20,8 @@
 import android.os.SystemClock;
 import android.util.Log;
 
+import com.android.internal.util.TrafficStatsConstants;
+
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
@@ -99,7 +101,8 @@
 
     public boolean requestTime(InetAddress address, int port, int timeout, Network network) {
         DatagramSocket socket = null;
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NTP);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                TrafficStatsConstants.TAG_SYSTEM_NTP);
         try {
             socket = new DatagramSocket();
             network.bindSocket(socket);
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 49c6f74..1c6a484 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -25,6 +25,7 @@
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
 import android.media.MediaPlayer;
+import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.DataUnit;
@@ -90,6 +91,42 @@
     public static final int UID_TETHERING = -5;
 
     /**
+     * Tag values in this range are reserved for the network stack. The network stack is
+     * running as UID {@link android.os.Process.NETWORK_STACK_UID} when in the mainline
+     * module separate process, and as the system UID otherwise.
+     */
+    /** @hide */
+    @SystemApi
+    public static final int TAG_NETWORK_STACK_RANGE_START = 0xFFFFFD00;
+    /** @hide */
+    @SystemApi
+    public static final int TAG_NETWORK_STACK_RANGE_END = 0xFFFFFEFF;
+
+    /**
+     * Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used internally by system services
+     * like DownloadManager when performing traffic on behalf of an application.
+     */
+    // Please note there is no enforcement of these constants, so do not rely on them to
+    // determine that the caller is a system caller.
+    /** @hide */
+    @SystemApi
+    public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = 0xFFFFFF00;
+    /** @hide */
+    @SystemApi
+    public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = 0xFFFFFF0F;
+
+    /**
+     * Tag values between these ranges are reserved for the network stack to do traffic
+     * on behalf of applications. It is a subrange of the range above.
+     */
+    /** @hide */
+    @SystemApi
+    public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = 0xFFFFFF80;
+    /** @hide */
+    @SystemApi
+    public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = 0xFFFFFF8F;
+
+    /**
      * Default tag value for {@link DownloadManager} traffic.
      *
      * @hide
@@ -127,30 +164,13 @@
      */
     public static final int TAG_SYSTEM_APP = 0xFFFFFF05;
 
+    // TODO : remove this constant when Wifi code is updated
     /** @hide */
-    @SystemApi
-    @TestApi
-    public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40;
-    /** @hide */
-    public static final int TAG_SYSTEM_NTP = 0xFFFFFF41;
-    /** @hide */
-    @SystemApi
-    @TestApi
     public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42;
-    /** @hide */
-    public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43;
-    /** @hide */
-    public static final int TAG_SYSTEM_GPS = 0xFFFFFF44;
-    /** @hide */
-    public static final int TAG_SYSTEM_PAC = 0xFFFFFF45;
-    /** @hide */
-    @SystemApi
-    @TestApi
-    public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46;
 
     private static INetworkStatsService sStatsService;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     private synchronized static INetworkStatsService getStatsService() {
         if (sStatsService == null) {
             sStatsService = INetworkStatsService.Stub.asInterface(
@@ -960,7 +980,7 @@
      * Interfaces are never removed from this list, so counters should always be
      * monotonic.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
     private static String[] getMobileIfaces() {
         try {
             return getStatsService().getMobileIfaces();
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index b90a60e..eb347e7 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -526,6 +526,7 @@
      * @return List<String> containing secure elements on the device which supports
      *                      off host card emulation. eSE for Embedded secure element,
      *                      SIM for UICC and so on.
+     * @hide
      */
     public @NonNull List<String> getSupportedOffHostSecureElements() {
         List<String> offHostSE = new ArrayList<String>();
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 911ec84..ab0a0ef 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -432,7 +432,15 @@
         mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Sets the off host Secure Element.
+     * @param  offHost  Secure Element to set. Only accept strings with prefix SIM or prefix eSE.
+     *                  Ref: GSMA TS.26 - NFC Handset Requirements
+     *                  TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be SIM[smartcard slot]
+     *                                    (e.g. SIM/SIM1, SIM2… SIMn).
+     *                  TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be eSE[number]
+     *                                    (e.g. eSE/eSE1, eSE2, etc.).
+     */
     public void setOffHostSecureElement(String offHost) {
         mOffHostName = offHost;
     }
@@ -441,7 +449,6 @@
      * Resets the off host Secure Element to statically defined
      * by the service in the manifest file.
      */
-    @UnsupportedAppUsage
     public void unsetOffHostSecureElement() {
         mOffHostName = mStaticOffHostName;
     }
@@ -581,10 +588,9 @@
             pw.println("    On Host Service");
         } else {
             pw.println("    Off-host Service");
-            pw.println("        " + "Current off-host SE" + mOffHostName
-                    + " static off-host: " + mOffHostName);
+            pw.println("        " + "Current off-host SE:" + mOffHostName
+                    + " static off-host SE:" + mStaticOffHostName);
         }
-        pw.println("    Static off-host Secure Element:");
         pw.println("    Static AID groups:");
         for (AidGroup group : mStaticAidGroups.values()) {
             pw.println("        Category: " + group.category);
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index f23dc2d..4c9885c 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -17,6 +17,7 @@
 package android.nfc.cardemulation;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Activity;
@@ -360,6 +361,8 @@
      * @param service The component name of the service
      * @return whether the registration was successful.
      */
+    @RequiresPermission(android.Manifest.permission.NFC)
+    @NonNull
     public boolean unsetOffHostForService(@NonNull ComponentName service) {
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
         if (adapter == null) {
@@ -391,7 +394,9 @@
      * through the manifest, or dynamically by using this API),
      * it will be replaced with this one. All AIDs registered by
      * this service will be re-routed to this Secure Element if
-     * successful.
+     * successful. AIDs that was statically assigned using manifest
+     * will re-route to off-host SE that stated in manifest after NFC
+     * toggle.
      *
      * <p>Note that you can only set off-host SE for a service that
      * is running under the same UID as the caller of this API. Typically
@@ -403,9 +408,19 @@
      * exists on the device.
      *
      * @param service The component name of the service
-     * @param offHostSecureElement Secure Element to register the AID to
+     * @param offHostSecureElement Secure Element to register the AID to. Only accept strings with
+     *                             prefix SIM or prefix eSE.
+     *                             Ref: GSMA TS.26 - NFC Handset Requirements
+     *                             TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be
+     *                                               SIM[smartcard slot]
+     *                                               (e.g. SIM/SIM1, SIM2… SIMn).
+     *                             TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be
+     *                                               eSE[number]
+     *                                               (e.g. eSE/eSE1, eSE2, etc.).
      * @return whether the registration was successful.
      */
+    @RequiresPermission(android.Manifest.permission.NFC)
+    @NonNull
     public boolean setOffHostForService(@NonNull ComponentName service,
             @NonNull String offHostSecureElement) {
         boolean validSecureElement = false;
@@ -421,6 +436,10 @@
             return false;
         }
 
+        if (!offHostSecureElement.startsWith("eSE") && !offHostSecureElement.startsWith("SIM")) {
+            return false;
+        }
+
         if (offHostSecureElement.equals("eSE")) {
             offHostSecureElement = "eSE1";
         } else if (offHostSecureElement.equals("SIM")) {
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 0feed68..e366fe0 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -175,6 +175,7 @@
             // Need to delete the file if it was created but failed while trying to get fd
             deleteFile(tmpScreenshotFile);
             Log.e(TAG, "Not able to create/open temporary screenshot file ", e);
+            callback.onError(BugreportCallback.BUGREPORT_ERROR_RUNTIME);
         } finally {
             // We can close the file descriptors here because binder would have duped them.
             IoUtils.closeQuietly(bugreportFd);
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index f2e0bdd..d46cf3c 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -19,15 +19,28 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
+import android.gamedriver.GameDriverProto.Blacklist;
+import android.gamedriver.GameDriverProto.Blacklists;
 import android.opengl.EGL14;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.provider.Settings;
+import android.util.Base64;
 import android.util.Log;
 
+import com.android.framework.protobuf.InvalidProtocolBufferException;
+
 import dalvik.system.VMRuntime;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /** @hide */
 public class GraphicsEnvironment {
@@ -44,6 +57,9 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "GraphicsEnvironment";
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
+    private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt";
+    private static final String GAME_DRIVER_BLACKLIST_FLAG = "blacklist";
+    private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
 
     private ClassLoader mClassLoader;
     private String mLayerPath;
@@ -52,9 +68,9 @@
     /**
      * Set up GraphicsEnvironment
      */
-    public void setup(Context context) {
+    public void setup(Context context, Bundle coreSettings) {
         setupGpuLayers(context);
-        chooseDriver(context);
+        chooseDriver(context, coreSettings);
     }
 
     /**
@@ -130,22 +146,28 @@
         setLayerPaths(mClassLoader, layerPaths);
     }
 
+    private static List<String> getGlobalSettingsString(Bundle bundle, String globalSetting) {
+        List<String> valueList = null;
+        String settingsValue = bundle.getString(globalSetting);
+
+        if (settingsValue != null) {
+            valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
+        } else {
+            valueList = new ArrayList<>();
+        }
+
+        return valueList;
+    }
+
     /**
      * Choose whether the current process should use the builtin or an updated driver.
      */
-    private static void chooseDriver(Context context) {
+    private static void chooseDriver(Context context, Bundle coreSettings) {
         String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
         if (driverPackageName == null || driverPackageName.isEmpty()) {
             return;
         }
-        // To minimize risk of driver updates crippling the device beyond user repair, never use an
-        // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
-        // were tested thoroughly with the pre-installed driver.
-        ApplicationInfo ai = context.getApplicationInfo();
-        if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
-            if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
-            return;
-        }
+
         ApplicationInfo driverInfo;
         try {
             driverInfo = context.getPackageManager().getApplicationInfo(driverPackageName,
@@ -154,6 +176,88 @@
             Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
             return;
         }
+
+        // O drivers are restricted to the sphal linker namespace, so don't try to use
+        // packages unless they declare they're compatible with that restriction.
+        if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+            if (DEBUG) {
+                Log.w(TAG, "updated driver package is not known to be compatible with O");
+            }
+            return;
+        }
+
+        // To minimize risk of driver updates crippling the device beyond user repair, never use an
+        // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
+        // were tested thoroughly with the pre-installed driver.
+        ApplicationInfo ai = context.getApplicationInfo();
+        if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
+            if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
+            return;
+        }
+
+        // GAME_DRIVER_ALL_APPS
+        // 0: Default (Invalid values fallback to default as well)
+        // 1: All apps use Game Driver
+        // 2: All apps use system graphics driver
+        int gameDriverAllApps = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0);
+        if (gameDriverAllApps == 2) {
+            if (DEBUG) {
+                Log.w(TAG, "Game Driver is turned off on this device");
+            }
+            return;
+        }
+
+        if (gameDriverAllApps != 1) {
+            // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
+            if (getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_OUT_APPS)
+                            .contains(ai.packageName)) {
+                if (DEBUG) {
+                    Log.w(TAG, ai.packageName + " opts out from Game Driver.");
+                }
+                return;
+            }
+            boolean isOptIn =
+                    getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
+                            .contains(ai.packageName);
+
+            if (!isOptIn && !onWhitelist(context, driverPackageName, ai.packageName)) {
+                if (DEBUG) {
+                    Log.w(TAG, ai.packageName + " is not on the whitelist.");
+                }
+                return;
+            }
+
+            if (!isOptIn) {
+                // At this point, the application is on the whitelist only, check whether it's
+                // on the blacklist, terminate early when it's on the blacklist.
+                try {
+                    // TODO(b/121350991) Switch to DeviceConfig with property listener.
+                    String base64String =
+                            coreSettings.getString(Settings.Global.GAME_DRIVER_BLACKLIST);
+                    if (base64String != null && !base64String.isEmpty()) {
+                        Blacklists blacklistsProto = Blacklists.parseFrom(
+                                Base64.decode(base64String, BASE64_FLAGS));
+                        List<Blacklist> blacklists = blacklistsProto.getBlacklistsList();
+                        long driverVersionCode = driverInfo.longVersionCode;
+                        for (Blacklist blacklist : blacklists) {
+                            if (blacklist.getVersionCode() == driverVersionCode) {
+                                for (String packageName : blacklist.getPackageNamesList()) {
+                                    if (packageName == ai.packageName) {
+                                        return;
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    }
+                } catch (InvalidProtocolBufferException e) {
+                    if (DEBUG) {
+                        Log.w(TAG, "Can't parse blacklist, skip and continue...");
+                    }
+                }
+            }
+        }
+
         String abi = chooseAbi(driverInfo);
         if (abi == null) {
             if (DEBUG) {
@@ -164,12 +268,6 @@
             }
             return;
         }
-        if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) {
-            // O drivers are restricted to the sphal linker namespace, so don't try to use
-            // packages unless they declare they're compatible with that restriction.
-            Log.w(TAG, "updated driver package is not known to be compatible with O");
-            return;
-        }
 
         StringBuilder sb = new StringBuilder();
         sb.append(driverInfo.nativeLibraryDir)
@@ -215,6 +313,31 @@
         return null;
     }
 
+    private static boolean onWhitelist(Context context, String driverPackageName,
+            String applicationPackageName) {
+        try {
+            Context driverContext = context.createPackageContext(driverPackageName,
+                                                                 Context.CONTEXT_RESTRICTED);
+            AssetManager assets = driverContext.getAssets();
+            InputStream stream = assets.open(GAME_DRIVER_WHITELIST_FILENAME);
+            BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+            for (String packageName; (packageName = reader.readLine()) != null; ) {
+                if (packageName.equals(applicationPackageName)) {
+                    return true;
+                }
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            if (DEBUG) {
+                Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
+            }
+        } catch (IOException e) {
+            if (DEBUG) {
+                Log.w(TAG, "Failed to load whitelist driver package, abort.");
+            }
+        }
+        return false;
+    }
+
     private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
     private static native void setDebugLayers(String layers);
     private static native void setDriverPath(String path);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 34e9eb3..a0e4d0d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11446,6 +11446,43 @@
         public static final String GPU_DEBUG_APP = "gpu_debug_app";
 
         /**
+         * Game Driver global preference for all Apps.
+         * 0 = Default
+         * 1 = All Apps use Game Driver
+         * 2 = All Apps use system graphics driver
+         * @hide
+         */
+        public static final String GAME_DRIVER_ALL_APPS = "game_driver_all_apps";
+
+        /**
+         * List of Apps selected to use Game Driver.
+         * i.e. <pkg1>,<pkg2>,...,<pkgN>
+         * @hide
+         */
+        public static final String GAME_DRIVER_OPT_IN_APPS = "game_driver_opt_in_apps";
+
+        /**
+         * List of Apps selected not to use Game Driver.
+         * i.e. <pkg1>,<pkg2>,...,<pkgN>
+         * @hide
+         */
+        public static final String GAME_DRIVER_OPT_OUT_APPS = "game_driver_opt_out_apps";
+
+        /**
+         * Apps on the blacklist that are forbidden to use Game Driver.
+         * @hide
+         */
+        public static final String GAME_DRIVER_BLACKLIST = "game_driver_blacklist";
+
+        /**
+         * Apps on the whitelist that are allowed to use Game Driver.
+         * The string is a list of application package names, seperated by comma.
+         * i.e. <apk1>,<apk2>,...,<apkN>
+         * @hide
+         */
+        public static final String GAME_DRIVER_WHITELIST = "game_driver_whitelist";
+
+        /**
          * Ordered GPU debug layer list
          * i.e. <layer1>:<layer2>:...:<layerN>
          * @hide
diff --git a/core/java/android/util/ByteStringUtils.java b/core/java/android/util/ByteStringUtils.java
index f6460ad..e4798f0 100644
--- a/core/java/android/util/ByteStringUtils.java
+++ b/core/java/android/util/ByteStringUtils.java
@@ -16,14 +16,14 @@
 
 package android.util;
 
+import libcore.util.HexEncoding;
+
 /**
  * A utility class for common byte array to hex string operations and vise versa.
  *
  * @hide
  */
 public final class ByteStringUtils {
-    private static final char[] HEX_LOWERCASE_ARRAY = "0123456789abcdef".toCharArray();
-    private static final char[] HEX_UPPERCASE_ARRAY = "0123456789ABCDEF".toCharArray();
 
     private ByteStringUtils() {
     /* hide constructor */
@@ -39,16 +39,7 @@
             return null;
         }
 
-        final int byteLength = bytes.length;
-        final int charCount = 2 * byteLength;
-        final char[] chars = new char[charCount];
-
-        for (int i = 0; i < byteLength; i++) {
-            final int byteHex = bytes[i] & 0xFF;
-            chars[i * 2] = HEX_UPPERCASE_ARRAY[byteHex >>> 4];
-            chars[i * 2 + 1] = HEX_UPPERCASE_ARRAY[byteHex & 0x0F];
-        }
-        return new String(chars);
+        return HexEncoding.encodeToString(bytes, true /* upperCase */);
     }
 
     /**
@@ -61,24 +52,6 @@
             return null;
         }
 
-        final char[] chars = str.toCharArray();
-        final int charLength = chars.length;
-        final byte[] bytes = new byte[charLength / 2];
-
-        for (int i = 0; i < bytes.length; i++) {
-            bytes[i] =
-                    (byte) (((getIndex(chars[i * 2]) << 4) & 0xF0)
-                            | (getIndex(chars[i * 2 + 1]) & 0x0F));
-        }
-        return bytes;
-    }
-
-    private static int getIndex(char c) {
-        for (int i = 0; i < HEX_UPPERCASE_ARRAY.length; i++) {
-            if (HEX_UPPERCASE_ARRAY[i] == c || HEX_LOWERCASE_ARRAY[i] == c) {
-                return i;
-            }
-        }
-        return -1;
+        return HexEncoding.decode(str, false /* allowSingleChar */);
     }
 }
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index e3de307..020205f 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.IStatsManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -113,4 +115,14 @@
         sService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
         return sService;
     }
+
+    /**
+     * Write an event to stats log using the raw format.
+     *
+     * @param buffer    The encoded buffer of data to write..
+     * @param size      The number of bytes from the buffer to write.
+     * @hide
+     */
+    @SystemApi
+    public static native void writeRaw(@NonNull byte[] buffer, int size);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5a1089b..d176462 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1365,6 +1365,7 @@
                 renderer.setStopped(mStopped);
             }
             if (!mStopped) {
+                mNewSurfaceNeeded = true;
                 scheduleTraversals();
             } else {
                 if (renderer != null) {
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index e40023d..53e145e 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -581,7 +581,7 @@
         return DatePicker.class.getName();
     }
 
-    public static int getDaysInMonth(int month, int year) {
+    private static int getDaysInMonth(int month, int year) {
         switch (month) {
             case Calendar.JANUARY:
             case Calendar.MARCH:
@@ -597,7 +597,7 @@
             case Calendar.NOVEMBER:
                 return 30;
             case Calendar.FEBRUARY:
-                return (year % 4 == 0) ? 29 : 28;
+                return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 29 : 28;
             default:
                 throw new IllegalArgumentException("Invalid Month");
         }
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 9982732..80de6fc 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -850,7 +850,7 @@
             case Calendar.NOVEMBER:
                 return 30;
             case Calendar.FEBRUARY:
-                return (year % 4 == 0) ? 29 : 28;
+                return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 29 : 28;
             default:
                 throw new IllegalArgumentException("Invalid Month");
         }
diff --git a/core/java/com/android/internal/util/TrafficStatsConstants.java b/core/java/com/android/internal/util/TrafficStatsConstants.java
new file mode 100644
index 0000000..2806ae2
--- /dev/null
+++ b/core/java/com/android/internal/util/TrafficStatsConstants.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+/**
+ * Constants for traffic stats.
+ * @hide
+ */
+public class TrafficStatsConstants {
+    // These tags are used by the network stack to do traffic for its own purposes. Traffic
+    // tagged with these will be counted toward the network stack and must stay inside the
+    // range defined by
+    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_START} and
+    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_END}.
+    public static final int TAG_SYSTEM_DHCP = 0xFFFFFE01;
+    public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFE02;
+    public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFE03;
+
+    public static final int TAG_SYSTEM_NTP = 0xFFFFFF41;
+    public static final int TAG_SYSTEM_GPS = 0xFFFFFF44;
+    public static final int TAG_SYSTEM_PAC = 0xFFFFFF45;
+
+    // These tags are used by the network stack to do traffic on behalf of apps. Traffic
+    // tagged with these will be counted toward the app on behalf of which the network
+    // stack is doing this traffic. These values must stay inside the range defined by
+    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_START} and
+    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_END}.
+    public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81;
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index e508b02..6fcb78b 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -1,10 +1,10 @@
 
 genrule {
-    name: "android_util_StatsLog.cpp",
+    name: "android_util_StatsLogInternal.cpp",
     tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLog.cpp",
+    cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLogInternal.cpp",
     out: [
-        "android_util_StatsLog.cpp",
+        "android_util_StatsLogInternal.cpp",
     ],
 }
 
@@ -112,6 +112,7 @@
         "android_util_Binder.cpp",
         "android_util_EventLog.cpp",
         "android_util_Log.cpp",
+        "android_util_StatsLog.cpp",
         "android_util_MemoryIntArray.cpp",
         "android_util_PathParser.cpp",
         "android_util_Process.cpp",
@@ -292,7 +293,7 @@
         "server_configurable_flags",
     ],
 
-    generated_sources: ["android_util_StatsLog.cpp"],
+    generated_sources: ["android_util_StatsLogInternal.cpp"],
 
     local_include_dirs: ["android/graphics"],
     export_include_dirs: [
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a4be784..1854ea9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -120,6 +120,7 @@
 extern int register_android_content_AssetManager(JNIEnv* env);
 extern int register_android_util_EventLog(JNIEnv* env);
 extern int register_android_util_StatsLog(JNIEnv* env);
+extern int register_android_util_StatsLogInternal(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
 extern int register_android_util_MemoryIntArray(JNIEnv* env);
 extern int register_android_util_PathParser(JNIEnv* env);
@@ -1396,6 +1397,7 @@
     REG_JNI(register_android_util_MemoryIntArray),
     REG_JNI(register_android_util_PathParser),
     REG_JNI(register_android_util_StatsLog),
+    REG_JNI(register_android_util_StatsLogInternal),
     REG_JNI(register_android_app_admin_SecurityLog),
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 42e3942..9c60e6b 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -224,6 +224,21 @@
     return err;
 }
 
+bool validateCanUseHwBinder(const sp<hardware::IBinder>& binder) {
+    if (binder != nullptr && binder->localBinder() != nullptr) {
+        // untested/unsupported/inefficient
+        // see b/129150021, doesn't work with scatter-gather
+        //
+        // explicitly disabling until it is supported
+        // (note, even if this is fixed to work with scatter gather, we would also need
+        // to convert this to the Java object rather than re-wrapping with a proxy)
+        LOG(ERROR) << "Local Java Binder not supported.";
+        return false;
+    }
+
+    return true;
+}
+
 }  // namespace android
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -324,9 +339,9 @@
     sp<IBase> ret = getRawServiceInternal(ifaceName, serviceName, retry /* retry */, false /* getStub */);
     sp<hardware::IBinder> service = hardware::toBinder<hidl::base::V1_0::IBase>(ret);
 
-    if (service == NULL) {
+    if (service == nullptr || !validateCanUseHwBinder(service)) {
         signalExceptionForError(env, NAME_NOT_FOUND);
-        return NULL;
+        return nullptr;
     }
 
     LOG(INFO) << "HwBinder: Starting thread pool for getting: " << ifaceName << "/" << serviceName;
diff --git a/core/jni/android_os_HwBinder.h b/core/jni/android_os_HwBinder.h
index 5352f1e..99195b1 100644
--- a/core/jni/android_os_HwBinder.h
+++ b/core/jni/android_os_HwBinder.h
@@ -54,6 +54,8 @@
 
 int register_android_os_HwBinder(JNIEnv *env);
 
+bool validateCanUseHwBinder(const sp<hardware::IBinder>& binder);
+
 }  // namespace android
 
 #endif  // _ANDROID_OS_HW_BINDER_H
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 7221ca1..f437a78 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -883,8 +883,12 @@
 
     sp<hardware::IBinder> binder = parcel->readStrongBinder();
 
-    if (binder == NULL) {
-        return NULL;
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    if (!validateCanUseHwBinder(binder)) {
+        return nullptr;
     }
 
     return JHwRemoteBinder::NewObject(env, binder);
diff --git a/core/jni/android_util_StatsLog.cpp b/core/jni/android_util_StatsLog.cpp
new file mode 100644
index 0000000..e749d34
--- /dev/null
+++ b/core/jni/android_util_StatsLog.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define LOG_NAMESPACE "StatsLog.tag."
+#define LOG_TAG "StatsLog_println"
+
+#include <assert.h>
+#include <cutils/properties.h>
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include "utils/misc.h"
+#include "core_jni_helpers.h"
+#include "stats_event_list.h"
+
+namespace android {
+
+static void android_util_StatsLog_writeRaw(JNIEnv* env, jobject clazz, jbyteArray buf, jint size)
+{
+    if (buf == NULL) {
+        return;
+    }
+    jint actualSize = env->GetArrayLength(buf);
+    if (actualSize < size) {
+        return;
+    }
+
+    jbyte* bufferArray = env->GetByteArrayElements(buf, NULL);
+    if (bufferArray == NULL) {
+        return;
+    }
+    const uint32_t statsEventTag = 1937006964;
+    struct iovec vec[2];
+    vec[0].iov_base = (void*) &statsEventTag;
+    vec[0].iov_len = sizeof(statsEventTag);
+    vec[1].iov_base = (void*) bufferArray;
+    vec[1].iov_len = size;
+    write_to_statsd(vec, 2);
+
+    env->ReleaseByteArrayElements(buf, bufferArray, 0);
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "writeRaw", "([BI)V", (void*) android_util_StatsLog_writeRaw },
+};
+
+int register_android_util_StatsLog(JNIEnv* env)
+{
+    return RegisterMethodsOrDie(env, "android/util/StatsLog", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 0e5f53b..04d2706 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -72,6 +72,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic_malloc.h>
 #include <cutils/ashmem.h>
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
@@ -476,12 +477,9 @@
   }
 }
 
-// The debug malloc library needs to know whether it's the zygote or a child.
-extern "C" int gMallocLeakZygoteChild;
-
 static void PreApplicationInit() {
   // The child process sets this to indicate it's not the zygote.
-  gMallocLeakZygoteChild = 1;
+  android_mallopt(M_SET_ZYGOTE_CHILD, nullptr, 0);
 
   // Set the jemalloc decay time to 1.
   mallopt(M_DECAY_TIME, 1);
diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index 8bf3772..973fa5a 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -460,7 +460,9 @@
         optional int32  vts_coverage = 43;
         optional string zygote = 44;
 
-        // Next Tag: 45
+        optional string gfx_driver_whitelist_0 = 45;
+
+        // Next Tag: 46
     }
     optional Ro ro = 21;
 
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 99f3034..5aa3992 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -384,6 +384,21 @@
         // App allowed to load GPU debug layers.
         optional SettingProto debug_app = 1;
         optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Game Driver - global preference for all Apps
+        // 0 = Default
+        // 1 = All Apps use Game Driver
+        // 2 = All Apps use system graphics driver
+        optional SettingProto game_driver_all_apps = 8;
+        // Game Driver - List of Apps selected to use Game Driver
+        // i.e. <pkg1>,<pkg2>,...,<pkgN>
+        optional SettingProto game_driver_opt_in_apps = 9;
+        // Game Driver - List of Apps selected not to use Game Driver
+        // i.e. <pkg1>,<pkg2>,...,<pkgN>
+        optional SettingProto game_driver_opt_out_apps = 10;
+        // Game Driver - List of Apps that are forbidden to use Game Driver
+        optional SettingProto game_driver_blacklist = 11;
+        // Game Driver - List of Apps that are allowed to use Game Driver
+        optional SettingProto game_driver_whitelist = 12;
     }
     optional Gpu gpu = 59;
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3fe8689..e074db6 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3691,7 +3691,7 @@
              the settings for this service. -->
         <attr name="settingsActivity"/>
         <!-- Secure Element which the AIDs should be routed to -->
-        <attr name="secureElementName"/>
+        <attr name="secureElementName" format="string"/>
     </declare-styleable>
 
     <!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8e383a5..c166408 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -444,6 +444,11 @@
                     Settings.Global.ENABLE_GPU_DEBUG_LAYERS,
                     Settings.Global.GPU_DEBUG_APP,
                     Settings.Global.GPU_DEBUG_LAYERS,
+                    Settings.Global.GAME_DRIVER_ALL_APPS,
+                    Settings.Global.GAME_DRIVER_OPT_IN_APPS,
+                    Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
+                    Settings.Global.GAME_DRIVER_BLACKLIST,
+                    Settings.Global.GAME_DRIVER_WHITELIST,
                     Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
                     Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
                     Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
diff --git a/graphics/proto/Android.bp b/graphics/proto/Android.bp
new file mode 100644
index 0000000..1d06348
--- /dev/null
+++ b/graphics/proto/Android.bp
@@ -0,0 +1,11 @@
+java_library_static {
+    name: "game-driver-protos",
+    host_supported: true,
+    proto: {
+        type: "lite",
+    },
+    srcs: ["game_driver.proto"],
+    no_framework_libs: true,
+    jarjar_rules: "jarjar-rules.txt",
+    sdk_version: "28",
+}
diff --git a/graphics/proto/game_driver.proto b/graphics/proto/game_driver.proto
new file mode 100644
index 0000000..fd7ffcc
--- /dev/null
+++ b/graphics/proto/game_driver.proto
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 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.
+ */
+
+syntax = "proto2";
+
+package android.gamedriver;
+
+option java_package = "android.gamedriver";
+option java_outer_classname = "GameDriverProto";
+
+message Blacklist {
+    optional int64 version_code = 1;
+    repeated string package_names = 2;
+}
+
+message Blacklists {
+    repeated Blacklist blacklists = 1;
+}
diff --git a/graphics/proto/jarjar-rules.txt b/graphics/proto/jarjar-rules.txt
new file mode 100644
index 0000000..4e40637
--- /dev/null
+++ b/graphics/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.** com.android.framework.protobuf.@1
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 31549fa..9d7e562 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -52,6 +52,7 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.TrafficStatsConstants;
 
 import java.io.IOException;
 import java.lang.reflect.Field;
@@ -250,7 +251,8 @@
                 if (isFinishing() || isDestroyed()) return;
                 HttpURLConnection urlConnection = null;
                 int httpResponseCode = 500;
-                int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+                int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                        TrafficStatsConstants.TAG_SYSTEM_PROBE);
                 try {
                     urlConnection = (HttpURLConnection) mNetwork.openConnection(
                             new URL(mCm.getCaptivePortalServerUrl()));
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 5817118..e0bb862 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -37,6 +37,7 @@
         "src/**/*.java",
         ":framework-networkstack-shared-srcs",
         ":services-networkstack-shared-srcs",
+        ":statslog-networkstack-java-gen",
     ],
     static_libs: [
         "androidx.annotation_annotation",
@@ -104,3 +105,11 @@
     certificate: "networkstack",
     manifest: "AndroidManifest.xml",
 }
+
+genrule {
+    name: "statslog-networkstack-java-gen",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --java $(out) --module network_stack" +
+         " --javaPackage com.android.networkstack.metrics --javaClass NetworkStackStatsLog",
+    out: ["com/android/networkstack/metrics/NetworkStackStatsLog.java"],
+}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
index be44519..ca6c17a 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -66,6 +66,7 @@
 import com.android.internal.util.MessageUtils;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.internal.util.TrafficStatsConstants;
 import com.android.internal.util.WakeupMessage;
 import com.android.networkstack.R;
 
@@ -331,7 +332,8 @@
     }
 
     private boolean initUdpSocket() {
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_DHCP);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                TrafficStatsConstants.TAG_SYSTEM_DHCP);
         try {
             mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
             SocketUtils.bindSocketToInterface(mUdpSock, mIfaceName);
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
index 8832eaa..d21b5f7 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
@@ -16,7 +16,6 @@
 
 package android.net.dhcp;
 
-import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
 import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
 import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
 import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
@@ -33,6 +32,7 @@
 import static android.system.OsConstants.SO_BROADCAST;
 import static android.system.OsConstants.SO_REUSEADDR;
 
+import static com.android.internal.util.TrafficStatsConstants.TAG_SYSTEM_DHCP_SERVER;
 import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
 import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
 import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index 547f04d..fb03c54 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -34,6 +34,34 @@
     // TODO: Refer to DeviceConfig definition.
     public static final String NAMESPACE_CONNECTIVITY = "connectivity";
 
+    /**
+     * A list of captive portal detection specifications used in addition to the fallback URLs.
+     * Each spec has the format url@@/@@statusCodeRegex@@/@@contentRegex. Specs are separated
+     * by "@@,@@".
+     */
+    public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
+            "captive_portal_fallback_probe_specs";
+
+    /**
+     * A comma separated list of URLs used for captive portal detection in addition to the
+     * fallback HTTP url associated with the CAPTIVE_PORTAL_FALLBACK_URL settings.
+     */
+    public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS =
+            "captive_portal_other_fallback_urls";
+
+    /**
+     * Which User-Agent string to use in the header of the captive portal detection probes.
+     * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
+     */
+    public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
+
+    /**
+     * Whether to use HTTPS for network validation. This is enabled by default and the setting
+     * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
+     * don't actually use HTTPS, but it's consistent with the other settings.
+     */
+    public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
+
     static {
         System.loadLibrary("networkstackutilsjni");
     }
diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallDetectionStats.java
similarity index 99%
rename from packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java
rename to packages/NetworkStack/src/com/android/networkstack/metrics/DataStallDetectionStats.java
index 225dc0f..2523ecd 100644
--- a/packages/NetworkStack/src/android/net/metrics/DataStallDetectionStats.java
+++ b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallDetectionStats.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.metrics;
+package com.android.networkstack.metrics;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallStatsUtils.java
similarity index 87%
rename from packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
rename to packages/NetworkStack/src/com/android/networkstack/metrics/DataStallStatsUtils.java
index c96411e..9308901 100644
--- a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
+++ b/packages/NetworkStack/src/com/android/networkstack/metrics/DataStallStatsUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net.metrics;
+package com.android.networkstack.metrics;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -41,7 +41,6 @@
     private static int probeResultToEnum(@Nullable final CaptivePortalProbeResult result) {
         if (result == null) return DataStallEventProto.INVALID;
 
-        // TODO: Add partial connectivity support.
         if (result.isSuccessful()) {
             return DataStallEventProto.VALID;
         } else if (result.isPortal()) {
@@ -63,6 +62,12 @@
             Log.d(TAG, "write: " + stats + " with result: " + validationResult
                     + ", dns: " + HexDump.toHexString(stats.mDns));
         }
-        // TODO(b/124613085): Send to Statsd once the public StatsLog API is ready.
+        NetworkStackStatsLog.write(NetworkStackStatsLog.DATA_STALL_EVENT,
+                stats.mEvaluationType,
+                validationResult,
+                stats.mNetworkType,
+                stats.mWifiInfo,
+                stats.mCellularInfo,
+                stats.mDns);
     }
 }
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 588dcf2..093235e 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -43,6 +43,10 @@
 import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS;
 import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS;
 import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USER_AGENT;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
 import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY;
 import static android.net.util.NetworkStackUtils.isEmpty;
 
@@ -65,8 +69,6 @@
 import android.net.Uri;
 import android.net.captiveportal.CaptivePortalProbeResult;
 import android.net.captiveportal.CaptivePortalProbeSpec;
-import android.net.metrics.DataStallDetectionStats;
-import android.net.metrics.DataStallStatsUtils;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
 import android.net.metrics.ValidationProbeEvent;
@@ -100,7 +102,10 @@
 import com.android.internal.util.RingBufferIndices;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.internal.util.TrafficStatsConstants;
 import com.android.networkstack.R;
+import com.android.networkstack.metrics.DataStallDetectionStats;
+import com.android.networkstack.metrics.DataStallStatsUtils;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
@@ -1170,7 +1175,8 @@
     }
 
     private boolean getUseHttpsValidation() {
-        return mDependencies.getSetting(mContext, Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
     }
 
     private String getCaptivePortalServerHttpsUrl() {
@@ -1223,8 +1229,8 @@
 
             final URL[] settingProviderUrls;
             if (!TextUtils.isEmpty(firstUrl)) {
-                final String otherUrls = mDependencies.getSetting(mContext,
-                        Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
+                final String otherUrls = mDependencies.getDeviceConfigProperty(
+                        NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
                 // otherUrls may be empty, but .split() ignores trailing empty strings
                 final String separator = ",";
                 final String[] urls = (firstUrl + separator + otherUrls).split(separator);
@@ -1244,8 +1250,9 @@
 
     private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
         try {
-            final String settingsValue = mDependencies.getSetting(
-                    mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+            final String settingsValue = mDependencies.getDeviceConfigProperty(
+                    NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+
             final CaptivePortalProbeSpec[] emptySpecs = new CaptivePortalProbeSpec[0];
             final CaptivePortalProbeSpec[] providerValue = TextUtils.isEmpty(settingsValue)
                     ? emptySpecs
@@ -1339,8 +1346,8 @@
     }
 
     private String getCaptivePortalUserAgent() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
+        return mDependencies.getDeviceConfigProperty(NAMESPACE_CONNECTIVITY,
+                CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
     }
 
     private URL nextFallbackUrl() {
@@ -1478,7 +1485,8 @@
         int httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
         String redirectUrl = null;
         final Stopwatch probeTimer = new Stopwatch().start();
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                TrafficStatsConstants.TAG_SYSTEM_PROBE);
         try {
             urlConnection = (HttpURLConnection) mNetwork.openConnection(url);
             urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index fa41284..594f2ca 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -26,6 +26,9 @@
 import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
 import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
 import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -59,8 +62,6 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.captiveportal.CaptivePortalProbeResult;
-import android.net.metrics.DataStallDetectionStats;
-import android.net.metrics.DataStallStatsUtils;
 import android.net.metrics.IpConnectivityLog;
 import android.net.util.SharedLog;
 import android.net.wifi.WifiInfo;
@@ -78,6 +79,9 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.networkstack.metrics.DataStallDetectionStats;
+import com.android.networkstack.metrics.DataStallStatsUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -159,7 +163,7 @@
         when(mDependencies.getRandom()).thenReturn(mRandom);
         when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
                 .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
-        when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
+        when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CAPTIVE_PORTAL_USE_HTTPS),
                 anyInt())).thenReturn(1);
         when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
                 .thenReturn(TEST_HTTP_URL);
@@ -682,13 +686,13 @@
     }
 
     private void setOtherFallbackUrls(String urls) {
-        when(mDependencies.getSetting(any(),
-                eq(Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
+        when(mDependencies.getDeviceConfigProperty(any(),
+                eq(CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
     }
 
     private void setFallbackSpecs(String specs) {
-        when(mDependencies.getSetting(any(),
-                eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
+        when(mDependencies.getDeviceConfigProperty(any(),
+                eq(CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
     }
 
     private void setCaptivePortalMode(int mode) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d5efcb5..43c1a26 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -647,6 +647,21 @@
         dumpSetting(s, p,
                 Settings.Global.GPU_DEBUG_LAYERS,
                 GlobalSettingsProto.Gpu.DEBUG_LAYERS);
+        dumpSetting(s, p,
+                Settings.Global.GAME_DRIVER_ALL_APPS,
+                GlobalSettingsProto.Gpu.GAME_DRIVER_ALL_APPS);
+        dumpSetting(s, p,
+                Settings.Global.GAME_DRIVER_OPT_IN_APPS,
+                GlobalSettingsProto.Gpu.GAME_DRIVER_OPT_IN_APPS);
+        dumpSetting(s, p,
+                Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
+                GlobalSettingsProto.Gpu.GAME_DRIVER_OPT_OUT_APPS);
+        dumpSetting(s, p,
+                Settings.Global.GAME_DRIVER_BLACKLIST,
+                GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLIST);
+        dumpSetting(s, p,
+                Settings.Global.GAME_DRIVER_WHITELIST,
+                GlobalSettingsProto.Gpu.GAME_DRIVER_WHITELIST);
         p.end(gpuToken);
 
         final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d79d833..6902a70 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -6492,6 +6492,11 @@
     // OS: Q
     ACTION_EMERGENCY_DIALER_FROM_POWER_MENU = 1569;
 
+    // OPEN: Settings > Developer Options > Game Driver Preference
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_GAME_DRIVER_DASHBOARD = 1613;
+
     // ---- End Q Constants, all Q constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 85787f2..a172fde 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2283,6 +2283,7 @@
                         .setCallingPid(r.callerPid)
                         .setCallingUid(r.callerUid)
                         .setMethod("TelephonyRegistry push")
+                        .setLogAsInfo(true) // we don't need to log an error every time we push
                         .setMinSdkVersionForFine(minSdk)
                         .build();
 
@@ -2300,6 +2301,7 @@
                         .setCallingPid(r.callerPid)
                         .setCallingUid(r.callerUid)
                         .setMethod("TelephonyRegistry push")
+                        .setLogAsInfo(true) // we don't need to log an error every time we push
                         .setMinSdkVersionForCoarse(minSdk)
                         .build();
 
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 160c753..75da9b5 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -55,6 +55,11 @@
         // add other system settings here...
 
         sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_ALL_APPS, int.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_IN_APPS, String.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_OUT_APPS, String.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLIST, String.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_WHITELIST, String.class);
         // add other global settings here...
     }
 
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 1913635..e33392d 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -34,6 +34,7 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkUtils;
+import android.net.ResolverParamsParcel;
 import android.net.Uri;
 import android.net.shared.PrivateDnsConfig;
 import android.os.Binder;
@@ -311,11 +312,9 @@
 
     public void setDnsConfigurationForNetwork(
             int netId, LinkProperties lp, boolean isDefaultNetwork) {
-        final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers());
-        final String[] domainStrs = getDomainStrings(lp.getDomains());
 
         updateParametersSettings();
-        final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples };
+        final ResolverParamsParcel paramsParcel = new ResolverParamsParcel();
 
         // We only use the PrivateDnsConfig data pushed to this class instance
         // from ConnectivityService because it works in coordination with
@@ -329,34 +328,44 @@
 
         final boolean useTls = privateDnsCfg.useTls;
         final boolean strictMode = privateDnsCfg.inStrictMode();
-        final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
-        final String[] tlsServers =
+        paramsParcel.netId = netId;
+        paramsParcel.sampleValiditySeconds = mSampleValidity;
+        paramsParcel.successThreshold = mSuccessThreshold;
+        paramsParcel.minSamples = mMinSamples;
+        paramsParcel.maxSamples = mMaxSamples;
+        paramsParcel.servers = NetworkUtils.makeStrings(lp.getDnsServers());
+        paramsParcel.domains = getDomainStrings(lp.getDomains());
+        paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : "";
+        paramsParcel.tlsServers =
                 strictMode ? NetworkUtils.makeStrings(
                         Arrays.stream(privateDnsCfg.ips)
                               .filter((ip) -> lp.isReachable(ip))
                               .collect(Collectors.toList()))
-                : useTls ? assignedServers  // Opportunistic
+                : useTls ? paramsParcel.servers  // Opportunistic
                 : new String[0];            // Off
-
+        paramsParcel.tlsFingerprints = new String[0];
         // Prepare to track the validation status of the DNS servers in the
         // resolver config when private DNS is in opportunistic or strict mode.
         if (useTls) {
             if (!mPrivateDnsValidationMap.containsKey(netId)) {
                 mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses());
             }
-            mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname);
+            mPrivateDnsValidationMap.get(netId).updateTrackedDnses(paramsParcel.tlsServers,
+                    paramsParcel.tlsName);
         } else {
             mPrivateDnsValidationMap.remove(netId);
         }
 
-        Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
-                netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
-                Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
-        final String[] tlsFingerprints = new String[0];
+        Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
+                + "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers),
+                Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds,
+                paramsParcel.successThreshold, paramsParcel.minSamples,
+                paramsParcel.maxSamples, paramsParcel.baseTimeoutMsec,
+                paramsParcel.retryCount, paramsParcel.tlsName,
+                Arrays.toString(paramsParcel.tlsServers)));
+
         try {
-            mDnsResolver.setResolverConfiguration(
-                    netId, assignedServers, domainStrs, params,
-                    tlsHostname, tlsServers, tlsFingerprints);
+            mDnsResolver.setResolverConfiguration(paramsParcel);
         } catch (RemoteException | ServiceSpecificException e) {
             Slog.e(TAG, "Error setting DNS configuration: " + e);
             return;
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 35f7ea3..77a18e2 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -191,6 +191,7 @@
                 case NOT_STARTED : return "NOT_STARTED";
                 case STARTING : return "STARTING";
                 case STARTED : return "STARTED";
+                case STOPPING : return "STOPPING";
             }
             throw new IllegalArgumentException("Unknown state");
         }
@@ -314,18 +315,27 @@
                     Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
                 }
             }
-            if (NOT_STARTED != mStartedState) {
-                mStartedState = STOPPING;
-                Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
-                if (mType == TYPE_NATT) {
-                    mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
-                } else if (mType == TYPE_TCP) {
-                    mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
-                    mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot);
-                    mTcpController.stopSocketMonitor(mSlot);
-                } else {
-                    Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
-                }
+            Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name() + ": " + reason);
+            switch (mStartedState) {
+                case NOT_STARTED:
+                    // Remove the reference of the keepalive that meet error before starting,
+                    // e.g. invalid parameter.
+                    cleanupStoppedKeepalive(mNai, mSlot);
+                    break;
+                case STOPPING:
+                    // Keepalive is already in stopping state, ignore.
+                    return;
+                default:
+                    mStartedState = STOPPING;
+                    if (mType == TYPE_NATT) {
+                        mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
+                    } else if (mType == TYPE_TCP) {
+                        mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
+                        mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot);
+                        mTcpController.stopSocketMonitor(mSlot);
+                    } else {
+                        Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
+                    }
             }
 
             // Close the duplicated fd that maintains the lifecycle of socket whenever
@@ -405,9 +415,9 @@
             for (KeepaliveInfo ki : networkKeepalives.values()) {
                 ki.stop(reason);
             }
-            networkKeepalives.clear();
-            mKeepalives.remove(nai);
         }
+        // Clean up keepalives will be done as a result of calling ki.stop() after the slots are
+        // freed.
     }
 
     public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) {
@@ -423,8 +433,24 @@
             return;
         }
         ki.stop(reason);
+        // Clean up keepalives will be done as a result of calling ki.stop() after the slots are
+        // freed.
+    }
+
+    private void cleanupStoppedKeepalive(NetworkAgentInfo nai, int slot) {
+        String networkName = (nai == null) ? "(null)" : nai.name();
+        HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
+        if (networkKeepalives == null) {
+            Log.e(TAG, "Attempt to remove keepalive on nonexistent network " + networkName);
+            return;
+        }
+        KeepaliveInfo ki = networkKeepalives.get(slot);
+        if (ki == null) {
+            Log.e(TAG, "Attempt to remove nonexistent keepalive " + slot + " on " + networkName);
+            return;
+        }
         networkKeepalives.remove(slot);
-        Log.d(TAG, "Stopped keepalive " + slot + " on " + networkName + ", "
+        Log.d(TAG, "Remove keepalive " + slot + " on " + networkName + ", "
                 + networkKeepalives.size() + " remains.");
         if (networkKeepalives.isEmpty()) {
             mKeepalives.remove(nai);
@@ -495,10 +521,11 @@
                 handleStopKeepalive(nai, slot, reason);
             }
         } else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
-            // The message indicated result of stopping : don't call handleStopKeepalive.
+            // The message indicated result of stopping : clean up keepalive slots.
             Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.name()
                     + " stopped: " + reason);
             ki.mStartedState = KeepaliveInfo.NOT_STARTED;
+            cleanupStoppedKeepalive(nai, slot);
         } else {
             Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason
                     + " for keepalive in wrong state: " + ki.toString());
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 948c690..a1a8e35 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -33,6 +33,7 @@
 import android.util.Pair;
 
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.TrafficStatsConstants;
 
 import libcore.io.IoUtils;
 
@@ -381,7 +382,8 @@
         protected void setupSocket(
                 int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
                 throws ErrnoException, IOException {
-            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                    TrafficStatsConstants.TAG_SYSTEM_PROBE);
             try {
                 mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
             } finally {
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 1ac09ad..f6ce2dc 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -39,6 +39,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.TrafficStatsConstants;
 import com.android.net.IProxyCallback;
 import com.android.net.IProxyPortListener;
 import com.android.net.IProxyService;
@@ -111,7 +112,8 @@
             String file;
             final Uri pacUrl = mPacUrl;
             if (Uri.EMPTY.equals(pacUrl)) return;
-            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PAC);
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                    TrafficStatsConstants.TAG_SYSTEM_PAC);
             try {
                 file = get(pacUrl);
             } catch (IOException ioe) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index b140c1b..33c84d1 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -237,13 +237,17 @@
             mLog.log("OBSERVED UiEnitlementFailed");
             stopTethering(downstream);
         });
+        mEntitlementMgr.setTetheringConfigurationFetcher(() -> {
+            maybeDefaultDataSubChanged();
+            return mConfig;
+        });
 
         mCarrierConfigChange = new VersionedBroadcastListener(
                 "CarrierConfigChangeListener", mContext, mHandler, filter,
                 (Intent ignored) -> {
                     mLog.log("OBSERVED carrier config change");
                     updateConfiguration();
-                    mEntitlementMgr.reevaluateSimCardProvisioning();
+                    mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
                 });
 
         filter = new IntentFilter();
@@ -252,12 +256,12 @@
                 "DefaultSubscriptionChangeListener", mContext, mHandler, filter,
                 (Intent ignored) -> {
                     mLog.log("OBSERVED default data subscription change");
-                    updateConfiguration();
+                    maybeDefaultDataSubChanged();
                     // To avoid launch unexpected provisioning checks, ignore re-provisioning when
                     // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be
                     // triggered again when CarrierConfig is loaded.
-                    if (mEntitlementMgr.getCarrierConfig() != null) {
-                        mEntitlementMgr.reevaluateSimCardProvisioning();
+                    if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
+                        mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
                     } else {
                         mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded");
                     }
@@ -301,17 +305,26 @@
     // NOTE: This is always invoked on the mLooper thread.
     private void updateConfiguration() {
         final int subId = mDeps.getDefaultDataSubscriptionId();
-        mConfig = new TetheringConfiguration(mContext, mLog, subId);
-        mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
-        mEntitlementMgr.updateConfiguration(mConfig);
+        updateConfiguration(subId);
     }
 
-    private void maybeUpdateConfiguration() {
+    private void updateConfiguration(final int subId) {
+        mConfig = new TetheringConfiguration(mContext, mLog, subId);
+        mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
+    }
+
+    private void maybeDunSettingChanged() {
         final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext);
         if (isDunRequired == mConfig.isDunRequired) return;
         updateConfiguration();
     }
 
+    private void maybeDefaultDataSubChanged() {
+        final int subId = mDeps.getDefaultDataSubscriptionId();
+        if (subId == mConfig.subId) return;
+        updateConfiguration(subId);
+    }
+
     @Override
     public void interfaceStatusChanged(String iface, boolean up) {
         // Never called directly: only called from interfaceLinkStateChanged.
@@ -1183,7 +1196,7 @@
         protected void chooseUpstreamType(boolean tryCell) {
             // We rebuild configuration on ACTION_CONFIGURATION_CHANGED, but we
             // do not currently know how to watch for changes in DUN settings.
-            maybeUpdateConfiguration();
+            maybeDunSettingChanged();
 
             final TetheringConfiguration config = mConfig;
             final NetworkState ns = (config.chooseUpstreamAutomatically)
diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
index b0bbd72..836f1e6 100644
--- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -29,7 +29,6 @@
 
 import static com.android.internal.R.string.config_wifi_tether_enable;
 
-import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -76,6 +75,7 @@
     protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
     private static final String ACTION_PROVISIONING_ALARM =
             "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM";
+    private static final String EXTRA_SUBID = "subId";
 
     // {@link ComponentName} of the Service used to run tether provisioning.
     private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(
@@ -99,7 +99,6 @@
     private final SharedLog mLog;
     private final SparseIntArray mEntitlementCacheValue;
     private final EntitlementHandler mHandler;
-    private @Nullable TetheringConfiguration mConfig;
     private final StateMachine mTetherMasterSM;
     // Key: ConnectivityManager.TETHERING_*(downstream).
     // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
@@ -109,6 +108,7 @@
     private boolean mUsingCellularAsUpstream = false;
     private boolean mNeedReRunProvisioningUi = false;
     private OnUiEntitlementFailedListener mListener;
+    private TetheringConfigurationFetcher mFetcher;
 
     public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
             int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
@@ -143,12 +143,18 @@
         void onUiEntitlementFailed(int downstream);
     }
 
-    /**
-     * Pass a new TetheringConfiguration instance each time when
-     * Tethering#updateConfiguration() is called.
-     */
-    public void updateConfiguration(TetheringConfiguration conf) {
-        mConfig = conf;
+    public void setTetheringConfigurationFetcher(final TetheringConfigurationFetcher fetcher) {
+        mFetcher = fetcher;
+    }
+
+    /** Interface to fetch TetheringConfiguration. */
+    public interface TetheringConfigurationFetcher {
+        /**
+         * Fetch current tethering configuration. This will be called to ensure whether entitlement
+         * check is needed.
+         * @return TetheringConfiguration instance.
+         */
+        TetheringConfiguration fetchTetheringConfiguration();
     }
 
     /**
@@ -176,7 +182,8 @@
 
         if (!mCurrentTethers.contains(type)) mCurrentTethers.add(type);
 
-        if (isTetherProvisioningRequired()) {
+        final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+        if (isTetherProvisioningRequired(config)) {
             // If provisioning is required and the result is not available yet,
             // cellular upstream should not be allowed.
             if (mCellularPermitted.size() == 0) {
@@ -186,9 +193,9 @@
             // till upstream change to cellular.
             if (mUsingCellularAsUpstream) {
                 if (showProvisioningUi) {
-                    runUiTetherProvisioning(type);
+                    runUiTetherProvisioning(type, config.subId);
                 } else {
-                    runSilentTetherProvisioning(type);
+                    runSilentTetherProvisioning(type, config.subId);
                 }
                 mNeedReRunProvisioningUi = false;
             } else {
@@ -237,7 +244,8 @@
         mUsingCellularAsUpstream = isCellular;
 
         if (mUsingCellularAsUpstream) {
-            handleMaybeRunProvisioning();
+            final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+            handleMaybeRunProvisioning(config);
         }
     }
 
@@ -246,8 +254,8 @@
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_MAYBE_RUN_PROVISIONING));
     }
 
-    private void handleMaybeRunProvisioning() {
-        if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired()) {
+    private void handleMaybeRunProvisioning(final TetheringConfiguration config) {
+        if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired(config)) {
             return;
         }
 
@@ -259,9 +267,9 @@
             if (mCellularPermitted.indexOfKey(downstream) < 0) {
                 if (mNeedReRunProvisioningUi) {
                     mNeedReRunProvisioningUi = false;
-                    runUiTetherProvisioning(downstream);
+                    runUiTetherProvisioning(downstream, config.subId);
                 } else {
-                    runSilentTetherProvisioning(downstream);
+                    runSilentTetherProvisioning(downstream, config.subId);
                 }
             }
         }
@@ -270,29 +278,31 @@
     /**
      * Check if the device requires a provisioning check in order to enable tethering.
      *
+     * @param config an object that encapsulates the various tethering configuration elements.
      * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
      */
     @VisibleForTesting
-    public boolean isTetherProvisioningRequired() {
+    protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) {
         if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
-                || mConfig.provisioningApp.length == 0) {
+                || config.provisioningApp.length == 0) {
             return false;
         }
-        if (carrierConfigAffirmsEntitlementCheckNotRequired()) {
+        if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
             return false;
         }
-        return (mConfig.provisioningApp.length == 2);
+        return (config.provisioningApp.length == 2);
     }
 
     /**
      * Re-check tethering provisioning for all enabled tether types.
      * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
      *
+     * @param config an object that encapsulates the various tethering configuration elements.
      * Note: this method is only called from TetherMaster on the handler thread.
      * If there are new callers from different threads, the logic should move to
      * masterHandler to avoid race conditions.
      */
-    public void reevaluateSimCardProvisioning() {
+    public void reevaluateSimCardProvisioning(final TetheringConfiguration config) {
         if (DBG) mLog.i("reevaluateSimCardProvisioning");
 
         if (!mHandler.getLooper().isCurrentThread()) {
@@ -303,24 +313,27 @@
         mCellularPermitted.clear();
 
         // TODO: refine provisioning check to isTetherProvisioningRequired() ??
-        if (!mConfig.hasMobileHotspotProvisionApp()
-                || carrierConfigAffirmsEntitlementCheckNotRequired()) {
-            evaluateCellularPermission();
+        if (!config.hasMobileHotspotProvisionApp()
+                || carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
+            evaluateCellularPermission(config);
             return;
         }
 
         if (mUsingCellularAsUpstream) {
-            handleMaybeRunProvisioning();
+            handleMaybeRunProvisioning(config);
         }
     }
 
-    /** Get carrier configuration bundle. */
-    public PersistableBundle getCarrierConfig() {
+    /**
+     * Get carrier configuration bundle.
+     * @param config an object that encapsulates the various tethering configuration elements.
+     * */
+    public PersistableBundle getCarrierConfig(final TetheringConfiguration config) {
         final CarrierConfigManager configManager = (CarrierConfigManager) mContext
                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (configManager == null) return null;
 
-        final PersistableBundle carrierConfig = configManager.getConfig();
+        final PersistableBundle carrierConfig = configManager.getConfigForSubId(config.subId);
 
         if (CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) {
             return carrierConfig;
@@ -334,9 +347,10 @@
     //
     // TODO: find a better way to express this, or alter the checking process
     // entirely so that this is more intuitive.
-    private boolean carrierConfigAffirmsEntitlementCheckNotRequired() {
+    private boolean carrierConfigAffirmsEntitlementCheckNotRequired(
+            final TetheringConfiguration config) {
         // Check carrier config for entitlement checks
-        final PersistableBundle carrierConfig = getCarrierConfig();
+        final PersistableBundle carrierConfig = getCarrierConfig(config);
         if (carrierConfig == null) return false;
 
         // A CarrierConfigManager was found and it has a config.
@@ -348,17 +362,19 @@
     /**
      * Run no UI tethering provisioning check.
      * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+     * @param subId default data subscription ID.
      */
-    protected void runSilentTetherProvisioning(int type) {
+    @VisibleForTesting
+    protected void runSilentTetherProvisioning(int type, int subId) {
         if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
         // For silent provisioning, settings would stop tethering when entitlement fail.
-        ResultReceiver receiver = buildProxyReceiver(type,
-                false/* notifyFail */, null);
+        ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null);
 
         Intent intent = new Intent();
         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
         intent.putExtra(EXTRA_RUN_PROVISION, true);
         intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
+        intent.putExtra(EXTRA_SUBID, subId);
         intent.setComponent(TETHER_SERVICE);
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -368,24 +384,25 @@
         }
     }
 
+    private void runUiTetherProvisioning(int type, int subId) {
+        ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null);
+        runUiTetherProvisioning(type, subId, receiver);
+    }
+
     /**
      * Run the UI-enabled tethering provisioning check.
      * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+     * @param subId default data subscription ID.
+     * @param receiver to receive entitlement check result.
      */
     @VisibleForTesting
-    protected void runUiTetherProvisioning(int type) {
-        ResultReceiver receiver = buildProxyReceiver(type,
-                true/* notifyFail */, null);
-        runUiTetherProvisioning(type, receiver);
-    }
-
-    @VisibleForTesting
-    protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
+    protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
         if (DBG) mLog.i("runUiTetherProvisioning: " + type);
 
         Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
         intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
+        intent.putExtra(EXTRA_SUBID, subId);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -396,9 +413,9 @@
     }
 
     // Not needed to check if this don't run on the handler thread because it's private.
-    private void scheduleProvisioningRechecks() {
+    private void scheduleProvisioningRechecks(final TetheringConfiguration config) {
         if (mProvisioningRecheckAlarm == null) {
-            final int period = mConfig.provisioningCheckPeriod;
+            final int period = config.provisioningCheckPeriod;
             if (period <= 0) return;
 
             Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
@@ -421,9 +438,9 @@
         }
     }
 
-    private void evaluateCellularPermission() {
+    private void evaluateCellularPermission(final TetheringConfiguration config) {
         final boolean oldPermitted = mCellularUpstreamPermitted;
-        mCellularUpstreamPermitted = (!isTetherProvisioningRequired()
+        mCellularUpstreamPermitted = (!isTetherProvisioningRequired(config)
                 || mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1);
 
         if (DBG) {
@@ -438,7 +455,7 @@
         // Only schedule periodic re-check when tether is provisioned
         // and the result is ok.
         if (mCellularUpstreamPermitted && mCellularPermitted.size() > 0) {
-            scheduleProvisioningRechecks();
+            scheduleProvisioningRechecks(config);
         } else {
             cancelTetherProvisioningRechecks();
         }
@@ -457,7 +474,8 @@
         if (!mCurrentTethers.contains(type)) return;
 
         mCellularPermitted.put(type, resultCode);
-        evaluateCellularPermission();
+        final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+        evaluateCellularPermission(config);
     }
 
     /**
@@ -467,7 +485,8 @@
     protected void removeDownstreamMapping(int type) {
         mLog.i("removeDownstreamMapping: " + type);
         mCellularPermitted.delete(type);
-        evaluateCellularPermission();
+        final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+        evaluateCellularPermission(config);
     }
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -475,7 +494,8 @@
         public void onReceive(Context context, Intent intent) {
             if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) {
                 mLog.log("Received provisioning alarm");
-                reevaluateSimCardProvisioning();
+                final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+                reevaluateSimCardProvisioning(config);
             }
         }
     };
@@ -498,7 +518,8 @@
                     handleNotifyUpstream(toBool(msg.arg1));
                     break;
                 case EVENT_MAYBE_RUN_PROVISIONING:
-                    handleMaybeRunProvisioning();
+                    final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+                    handleMaybeRunProvisioning(config);
                     break;
                 case EVENT_GET_ENTITLEMENT_VALUE:
                     handleGetLatestTetheringEntitlementValue(msg.arg1, (ResultReceiver) msg.obj,
@@ -636,7 +657,8 @@
     private void handleGetLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver,
             boolean showEntitlementUi) {
 
-        if (!isTetherProvisioningRequired()) {
+        final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+        if (!isTetherProvisioningRequired(config)) {
             receiver.send(TETHER_ERROR_NO_ERROR, null);
             return;
         }
@@ -647,7 +669,7 @@
             receiver.send(cacheValue, null);
         } else {
             ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
-            runUiTetherProvisioning(downstream, proxy);
+            runUiTetherProvisioning(downstream, config.subId, proxy);
         }
     }
 }
diff --git a/services/core/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java
index c012ee4..7dffcb4 100644
--- a/services/core/java/com/android/server/location/GpsXtraDownloader.java
+++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java
@@ -20,6 +20,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.util.TrafficStatsConstants;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -92,7 +94,8 @@
 
         // load balance our requests among the available servers
         while (result == null) {
-            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_GPS);
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                    TrafficStatsConstants.TAG_SYSTEM_GPS);
             try {
                 result = doDownload(mXtraServers[mNextServerIndex]);
             } finally {
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index af9b12a..4baf70b 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -38,7 +38,7 @@
 per-file KeySetManagerService.java = cbrubaker@google.com
 per-file PackageKeySetData.java = cbrubaker@google.com
 per-file PackageSignatures.java = cbrubaker@google.com
-per-file SELinuxMMAC.java = cbrubaker@google.com
+per-file SELinuxMMAC.java = cbrubaker@google.com, jeffv@google.com, jgalenson@google.com, nnk@google.com
 
 # shortcuts
 per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 54a7e2a..ba2b37f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10722,7 +10722,7 @@
             sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged();
 
         pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
-                pkg.applicationInfo.targetSandboxVersion, targetSdkVersion);
+                targetSdkVersion);
         pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
                 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId));
 
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index b4154c7..b94047e 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -69,9 +69,6 @@
     // Append privapp to existing seinfo label
     private static final String PRIVILEGED_APP_STR = ":privapp";
 
-    // Append v2 to existing seinfo label
-    private static final String SANDBOX_V2_STR = ":v2";
-
     // Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion
     private static final String TARGETSDKVERSION_STR = ":targetSdkVersion=";
 
@@ -323,14 +320,13 @@
      *
      * @param pkg object representing the package to be labeled.
      * @param isPrivileged boolean.
-     * @param targetSandboxVersion int.
      * @param targetSdkVersion int. If this pkg runs as a sharedUser, targetSdkVersion is the
      *        greater of: lowest targetSdk for all pkgs in the sharedUser, or
      *        MINIMUM_TARGETSDKVERSION.
      * @return String representing the resulting seinfo.
      */
     public static String getSeInfo(PackageParser.Package pkg, boolean isPrivileged,
-            int targetSandboxVersion, int targetSdkVersion) {
+            int targetSdkVersion) {
         String seInfo = null;
         synchronized (sPolicies) {
             if (!sPolicyRead) {
@@ -351,10 +347,6 @@
             seInfo = DEFAULT_SEINFO;
         }
 
-        if (targetSandboxVersion == 2) {
-            seInfo += SANDBOX_V2_STR;
-        }
-
         if (isPrivileged) {
             seInfo += PRIVILEGED_APP_STR;
         }
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index ca08415..cd7ded5 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -139,7 +139,7 @@
         for (PackageParser.Package pkg : pkgList) {
             final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
             pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
-                pkg.applicationInfo.targetSandboxVersion, seInfoTargetSdkVersion);
+                seInfoTargetSdkVersion);
         }
     }
 
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 339607b..59aea21 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.TrafficStatsConstants;
 
 import libcore.io.IoBridge;
 
@@ -586,7 +587,8 @@
     private boolean createSocket() {
         final int SEND_TIMEOUT_MS = 300;
 
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NEIGHBOR);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                TrafficStatsConstants.TAG_SYSTEM_NEIGHBOR);
         try {
             mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
             // Setting SNDTIMEO is purely for defensive purposes.
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 6382acf..6000b56 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -68,6 +68,7 @@
         public void onExtrasRemoved(Conference c, List<String> keys) {}
         public void onConferenceStateChanged(Conference c, boolean isConference) {}
         public void onAddressChanged(Conference c, Uri newAddress, int presentation) {}
+        public void onConnectionEvent(Conference c, String event, Bundle extras) {}
         public void onCallerDisplayNameChanged(
                 Conference c, String callerDisplayName, int presentation) {}
     }
@@ -1024,4 +1025,14 @@
         }
         onExtrasChanged(b);
     }
+
+    /**
+     * See {@link Connection#sendConnectionEvent(String, Bundle)}
+     * @hide
+     */
+    public void sendConnectionEvent(String event, Bundle extras) {
+        for (Listener l : mListeners) {
+            l.onConnectionEvent(this, event, extras);
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 58e80b4..044b387 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1279,6 +1279,14 @@
                 mAdapter.setCallerDisplayName(id, callerDisplayName, presentation);
             }
         }
+
+        @Override
+        public void onConnectionEvent(Conference c, String event, Bundle extras) {
+            String id = mIdByConference.get(c);
+            if (id != null) {
+                mAdapter.onConnectionEvent(id, event, extras);
+            }
+        }
     };
 
     private final Connection.Listener mConnectionListener = new Connection.Listener() {
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 6dd683a..ecb0daf 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3330,6 +3330,7 @@
          * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
          * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
          */
+        @NonNull
         public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers");
 
         /**
@@ -3342,6 +3343,7 @@
          * {@link SubscriptionManager#getDefaultSubscriptionId()}. To specify subId for MSIM,
          * use {@link Uri#withAppendedPath(Uri, String)} to append with subscription id.
          */
+        @NonNull
         public static final Uri SIM_APN_URI = Uri.parse(
                 "content://telephony/carriers/sim_apn_list");
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index bd528b8..51cff8f 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3048,17 +3048,21 @@
     /**
      * Overrides the carrier config of the provided subscription ID with the provided values.
      *
-     * Any further queries to carrier config from any process will return
-     * the overriden values after this method returns. The overrides are effective for the lifetime
-     * of the phone process.
+     * Any further queries to carrier config from any process will return the overridden values
+     * after this method returns. The overrides are effective for the lifetime of the phone process
+     * until the user passes in {@code null} for {@code overrideValues}. This removes all previous
+     * overrides and sets the carrier config back to production values.
      *
      * May throw an {@link IllegalArgumentException} if {@code overrideValues} contains invalid
      * values for the specified config keys.
      *
+     * NOTE: This API is meant for testing purposes only and may only be accessed from the shell UID
+     * during instrumentation testing.
+     *
      * @param subscriptionId The subscription ID for which the override should be done.
-     * @param overrideValues Key-value pairs of the values that are to be overriden. If null,
-     *                       all previous overrides will be disabled and the config reset back to
-     *                       its initial state.
+     * @param overrideValues Key-value pairs of the values that are to be overridden. If set to
+     *                       {@code null}, this will remove all previous overrides and set the
+     *                       carrier configuration back to production values.
      * @hide
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index d829309..b704d62 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -58,15 +58,15 @@
     @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
     private int mSignalStrength; // To be removed
     private int mRssi;
-    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
     private int mRsrp;
-    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
     private int mRsrq;
-    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
     private int mRssnr;
-    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
     private int mCqi;
-    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.O)
+    @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
     private int mTimingAdvance;
     private int mLevel;
 
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index b9d8eb6..eb744f6 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -63,15 +63,18 @@
         public final int callingPid;
         public final int minSdkVersionForCoarse;
         public final int minSdkVersionForFine;
+        public final boolean logAsInfo;
         public final String method;
 
         private LocationPermissionQuery(String callingPackage, int callingUid, int callingPid,
-                int minSdkVersionForCoarse, int minSdkVersionForFine, String method) {
+                int minSdkVersionForCoarse, int minSdkVersionForFine, boolean logAsInfo,
+                String method) {
             this.callingPackage = callingPackage;
             this.callingUid = callingUid;
             this.callingPid = callingPid;
             this.minSdkVersionForCoarse = minSdkVersionForCoarse;
             this.minSdkVersionForFine = minSdkVersionForFine;
+            this.logAsInfo = logAsInfo;
             this.method = method;
         }
 
@@ -81,6 +84,7 @@
             private int mCallingPid;
             private int mMinSdkVersionForCoarse = Integer.MAX_VALUE;
             private int mMinSdkVersionForFine = Integer.MAX_VALUE;
+            private boolean mLogAsInfo = false;
             private String mMethod;
 
             /**
@@ -135,14 +139,27 @@
                 return this;
             }
 
+            /**
+             * If called with {@code true}, log messages will only be printed at the info level.
+             */
+            public Builder setLogAsInfo(boolean logAsInfo) {
+                mLogAsInfo = logAsInfo;
+                return this;
+            }
+
             public LocationPermissionQuery build() {
                 return new LocationPermissionQuery(mCallingPackage, mCallingUid,
-                        mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine, mMethod);
+                        mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine,
+                        mLogAsInfo, mMethod);
             }
         }
     }
 
-    private static void logError(Context context, String errorMsg) {
+    private static void logError(Context context, LocationPermissionQuery query, String errorMsg) {
+        if (query.logAsInfo) {
+            Log.i(TAG, errorMsg);
+            return;
+        }
         Log.e(TAG, errorMsg);
         try {
             if (Build.IS_DEBUGGABLE) {
@@ -201,13 +218,13 @@
                     + " because we're not enforcing API " + minSdkVersion + " yet."
                     + " Please fix this app because it will break in the future. Called from "
                     + query.method;
-            logError(context, errorMsg);
+            logError(context, query, errorMsg);
             return null;
         } else if (!isAppAtLeastSdkVersion(context, query.callingPackage, minSdkVersion)) {
             String errorMsg = "Allowing " + query.callingPackage + " " + locationTypeForLog
                     + " because it doesn't target API " + minSdkVersion + " yet."
                     + " Please fix this app. Called from " + query.method;
-            logError(context, errorMsg);
+            logError(context, query, errorMsg);
             return null;
         } else {
             // If we're not allowing it due to the above two conditions, this means that the app
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 2ce3caf..770f780 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -39,6 +39,7 @@
 import android.util.Log;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
@@ -123,6 +124,16 @@
     private String mMnc;
 
     /**
+     * EHPLMNs associated with the subscription
+     */
+    private String[] mEhplmns;
+
+    /**
+     * HPLMNs associated with the subscription
+     */
+    private String[] mHplmns;
+
+    /**
      * ISO Country code for the subscription's provider
      */
     private String mCountryIso;
@@ -316,6 +327,14 @@
     }
 
     /**
+     * @hide
+     */
+    public void setAssociatedPlmns(String[] ehplmns, String[] hplmns) {
+        mEhplmns = ehplmns;
+        mHplmns = hplmns;
+    }
+
+    /**
      * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a
      * user interface.
      *
@@ -467,6 +486,20 @@
     }
 
     /**
+     * @hide
+     */
+    public List<String> getEhplmns() {
+        return mEhplmns == null ? Collections.emptyList() : Arrays.asList(mEhplmns);
+    }
+
+    /**
+     * @hide
+     */
+    public List<String> getHplmns() {
+        return mHplmns == null ? Collections.emptyList() : Arrays.asList(mHplmns);
+    }
+
+    /**
      * @return the profile class of this subscription.
      * @hide
      */
@@ -599,7 +632,7 @@
             String mcc = source.readString();
             String mnc = source.readString();
             String countryIso = source.readString();
-            Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
+            Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader());
             boolean isEmbedded = source.readBoolean();
             UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR);
             String cardString = source.readString();
@@ -610,11 +643,15 @@
             int carrierid = source.readInt();
             int profileClass = source.readInt();
             int subType = source.readInt();
+            String[] ehplmns = source.readStringArray();
+            String[] hplmns = source.readStringArray();
 
-            return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
-                    nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
-                    isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
-                    isGroupDisabled, carrierid, profileClass, subType);
+            SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName,
+                    carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc,
+                    countryIso, isEmbedded, accessRules, cardString, cardId, isOpportunistic,
+                    groupUUID, isGroupDisabled, carrierid, profileClass, subType);
+            info.setAssociatedPlmns(ehplmns, hplmns);
+            return info;
         }
 
         @Override
@@ -637,7 +674,7 @@
         dest.writeString(mMcc);
         dest.writeString(mMnc);
         dest.writeString(mCountryIso);
-        mIconBitmap.writeToParcel(dest, flags);
+        dest.writeParcelable(mIconBitmap, flags);
         dest.writeBoolean(mIsEmbedded);
         dest.writeTypedArray(mAccessRules, flags);
         dest.writeString(mCardString);
@@ -648,6 +685,8 @@
         dest.writeInt(mCarrierId);
         dest.writeInt(mProfileClass);
         dest.writeInt(mSubscriptionType);
+        dest.writeStringArray(mEhplmns);
+        dest.writeStringArray(mHplmns);
     }
 
     @Override
@@ -685,6 +724,8 @@
                 + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
                 + " mIsGroupDisabled=" + mIsGroupDisabled
                 + " profileClass=" + mProfileClass
+                + " ehplmns = " + Arrays.toString(mEhplmns)
+                + " hplmns = " + Arrays.toString(mHplmns)
                 + " subscriptionType=" + mSubscriptionType + "}";
     }
 
@@ -728,6 +769,8 @@
                 && TextUtils.equals(mDisplayName, toCompare.mDisplayName)
                 && TextUtils.equals(mCarrierName, toCompare.mCarrierName)
                 && Arrays.equals(mAccessRules, toCompare.mAccessRules)
-                && mProfileClass == toCompare.mProfileClass;
+                && mProfileClass == toCompare.mProfileClass
+                && Arrays.equals(mEhplmns, toCompare.mEhplmns)
+                && Arrays.equals(mHplmns, toCompare.mHplmns);
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index b0fa9d5..586c815 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -458,6 +458,18 @@
     public static final String CARRIER_ID = "carrier_id";
 
     /**
+     * @hide A comma-separated list of EHPLMNs associated with the subscription
+     * <P>Type: TEXT (String)</P>
+     */
+    public static final String EHPLMNS = "ehplmns";
+
+    /**
+     * @hide A comma-separated list of HPLMNs associated with the subscription
+     * <P>Type: TEXT (String)</P>
+     */
+    public static final String HPLMNS = "hplmns";
+
+    /**
      * TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
      * <P>Type: TEXT (String)</P>
      * @hide
@@ -2733,6 +2745,8 @@
      *
      * @throws SecurityException if the caller doesn't meet the requirements
      *             outlined above.
+     * @throws IllegalArgumentException if any of the subscriptions in the list doesn't exist.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that will be in the same group
      * @return groupUUID a UUID assigned to the subscription group.
@@ -2781,6 +2795,7 @@
      *             outlined above.
      * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist,
      *             or the groupUuid doesn't exist.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that need adding into the group
      * @param groupUuid the groupUuid the subscriptions are being added to.
@@ -2833,6 +2848,7 @@
      *             outlined above.
      * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong
      *             the specified group.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that need removing from their groups.
      *
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 12acf9d..e1425b9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10321,10 +10321,10 @@
      * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
      * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * @return Map including the key as the active subscription ID (Note: if there is no active
+     * @return Map including the keys as the active subscription IDs (Note: if there is no active
      * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value
-     * as the list of {@link EmergencyNumber}; null if this information is not available; or throw
-     * a SecurityException if the caller does not have the permission.
+     * as the list of {@link EmergencyNumber}; empty Map if this information is not available;
+     * or throw a SecurityException if the caller does not have the permission.
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     @NonNull
@@ -10374,10 +10374,10 @@
      * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MIEC} </li>
      * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li>
      * </ol>
-     * @return Map including the key as the active subscription ID (Note: if there is no active
+     * @return Map including the keys as the active subscription IDs (Note: if there is no active
      * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value
-     * as the list of {@link EmergencyNumber}; null if this information is not available; or throw
-     * a SecurityException if the caller does not have the permission.
+     * as the list of {@link EmergencyNumber}; empty Map if this information is not available;
+     * or throw a SecurityException if the caller does not have the permission.
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     @NonNull
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e9aede7..be58723 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -781,8 +781,13 @@
     }
 
     /**
-     * Change the user's setting for RTT capability of this device.
-     * @param isEnabled if true RTT will be enabled during calls.
+     * Sets the capability of RTT for IMS calls placed on this subscription.
+     *
+     * Note: This does not affect the value of
+     * {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting
+     * for RTT. That value is enabled/disabled separately by the user through the Accessibility
+     * settings.
+     * @param isEnabled if true RTT should be enabled during calls made on this subscription.
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setRttCapabilitySetting(boolean isEnabled) {
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index c008711..e6777c17 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -40,8 +40,6 @@
 import com.android.ims.internal.IImsFeatureStatusCallback;
 import com.android.internal.annotations.VisibleForTesting;
 
-import static android.Manifest.permission.MODIFY_PHONE_STATE;
-
 /**
  * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
  * ImsService must register the service in their AndroidManifest to be detected by the framework.
@@ -229,8 +227,8 @@
 
     private void setupFeature(ImsFeature f, int slotId, int featureType,
             IImsFeatureStatusCallback c) {
-        f.addImsFeatureStatusCallback(c);
         f.initialize(this, slotId);
+        f.addImsFeatureStatusCallback(c);
         addImsFeature(slotId, featureType, f);
     }
 
diff --git a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java
index e8fcac1..de4f174 100644
--- a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.Intent;
 import android.os.IInterface;
 import android.os.RemoteException;
 import android.telephony.SubscriptionManager;
@@ -42,32 +41,6 @@
 
     private static final String LOG_TAG = "ImsFeature";
 
-    /**
-     * Action to broadcast when ImsService is up.
-     * Internal use only.
-     * Only defined here separately compatibility purposes with the old ImsService.
-     * @hide
-     */
-    public static final String ACTION_IMS_SERVICE_UP =
-            "com.android.ims.IMS_SERVICE_UP";
-
-    /**
-     * Action to broadcast when ImsService is down.
-     * Internal use only.
-     * Only defined here separately for compatibility purposes with the old ImsService.
-     * @hide
-     */
-    public static final String ACTION_IMS_SERVICE_DOWN =
-            "com.android.ims.IMS_SERVICE_DOWN";
-
-    /**
-     * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
-     * A long value; the phone ID corresponding to the IMS service coming up or down.
-     * Only defined here separately for compatibility purposes with the old ImsService.
-     * @hide
-     */
-    public static final String EXTRA_PHONE_ID = "android:phone_id";
-
     // Invalid feature value
     public static final int INVALID = -1;
     // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
@@ -162,30 +135,6 @@
                 }
             }
         }
-        sendImsServiceIntent(state);
-    }
-
-    /**
-     * Provide backwards compatibility using deprecated service UP/DOWN intents.
-     */
-    private void sendImsServiceIntent(@ImsState int state) {
-        if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-            return;
-        }
-        Intent intent;
-        switch (state) {
-            case ImsFeature.STATE_NOT_AVAILABLE:
-            case ImsFeature.STATE_INITIALIZING:
-                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-                break;
-            case ImsFeature.STATE_READY:
-                intent = new Intent(ACTION_IMS_SERVICE_UP);
-                break;
-            default:
-                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-        }
-        intent.putExtra(EXTRA_PHONE_ID, mSlotId);
-        mContext.sendBroadcast(intent);
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 5e3f398..74af6bf 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.content.Intent;
 import android.os.IInterface;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -395,30 +394,6 @@
                 }
             }
         }
-        sendImsServiceIntent(state);
-    }
-
-    /**
-     * Provide backwards compatibility using deprecated service UP/DOWN intents.
-     */
-    private void sendImsServiceIntent(@ImsState int state) {
-        if (mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-            return;
-        }
-        Intent intent;
-        switch (state) {
-            case ImsFeature.STATE_UNAVAILABLE:
-            case ImsFeature.STATE_INITIALIZING:
-                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-                break;
-            case ImsFeature.STATE_READY:
-                intent = new Intent(ACTION_IMS_SERVICE_UP);
-                break;
-            default:
-                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-        }
-        intent.putExtra(EXTRA_PHONE_ID, mSlotId);
-        mContext.sendBroadcast(intent);
     }
 
     /**
diff --git a/test-base/api/TEST_MAPPING b/test-base/api/TEST_MAPPING
index 3535954..86e8f76 100644
--- a/test-base/api/TEST_MAPPING
+++ b/test-base/api/TEST_MAPPING
@@ -1,7 +1,7 @@
 {
   "presubmit": [
     {
-      "name": "CtsAndroidTestBase27ApiSignatureTestCases"
+      "name": "CtsAndroidTestBase28ApiSignatureTestCases"
     }
   ]
 }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ed93da1..e3c6c41 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -138,6 +138,7 @@
 import android.net.NetworkState;
 import android.net.NetworkUtils;
 import android.net.ProxyInfo;
+import android.net.ResolverParamsParcel;
 import android.net.RouteInfo;
 import android.net.SocketKeepalive;
 import android.net.UidRange;
@@ -273,7 +274,8 @@
     @Mock NetworkStackClient mNetworkStack;
     @Mock UserManager mUserManager;
 
-    private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class);
+    private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
+            ArgumentCaptor.forClass(ResolverParamsParcel.class);
 
     // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
     // do not go through ConnectivityService but talk to netd directly, so they don't automatically
@@ -4292,8 +4294,9 @@
         }
 
         // Check that there is no port leaked after all keepalives and sockets are closed.
-        assertFalse(isUdpPortInUse(srcPort));
-        assertFalse(isUdpPortInUse(srcPort2));
+        // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7.
+        // assertFalse(isUdpPortInUse(srcPort));
+        // assertFalse(isUdpPortInUse(srcPort2));
 
         mWiFiNetworkAgent.disconnect();
         waitFor(mWiFiNetworkAgent.getDisconnectedCV());
@@ -4421,7 +4424,8 @@
         assertEquals(anyIPv4, sa.getAddress());
 
         testPfd.close();
-        assertFalse(isUdpPortInUse(srcPort));
+        // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7.
+        // assertFalse(isUdpPortInUse(srcPort));
 
         mWiFiNetworkAgent.disconnect();
         waitFor(mWiFiNetworkAgent.getDisconnectedCV());
@@ -4841,16 +4845,13 @@
     @Test
     public void testBasicDnsConfigurationPushed() throws Exception {
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-        ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
 
         // Clear any interactions that occur as a result of CS starting up.
         reset(mMockDnsResolver);
 
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         waitForIdle();
-        verify(mMockDnsResolver, never()).setResolverConfiguration(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
-                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        verify(mMockDnsResolver, never()).setResolverConfiguration(any());
         verifyNoMoreInteractions(mMockDnsResolver);
 
         final LinkProperties cellLp = new LinkProperties();
@@ -4868,35 +4869,33 @@
         mCellNetworkAgent.connect(false);
         waitForIdle();
         // CS tells netd about the empty DNS config for this network.
-        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
-                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
         reset(mMockDnsResolver);
 
         cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
-                anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
-        assertEquals(1, mStringArrayCaptor.getValue().length);
-        assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
+                mResolverParamsParcelCaptor.capture());
+        ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
+        assertEquals(1, resolvrParams.servers.length);
+        assertTrue(ArrayUtils.contains(resolvrParams.servers, "2001:db8::1"));
         // Opportunistic mode.
-        assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1"));
+        assertTrue(ArrayUtils.contains(resolvrParams.tlsServers, "2001:db8::1"));
         reset(mMockDnsResolver);
 
         cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
-                anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
-        assertEquals(2, mStringArrayCaptor.getValue().length);
-        assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
+                mResolverParamsParcelCaptor.capture());
+        resolvrParams = mResolverParamsParcelCaptor.getValue();
+        assertEquals(2, resolvrParams.servers.length);
+        assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         // Opportunistic mode.
-        assertEquals(2, tlsServers.getValue().length);
-        assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
+        assertEquals(2, resolvrParams.tlsServers.length);
+        assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         reset(mMockDnsResolver);
 
@@ -4909,18 +4908,16 @@
 
         waitForIdle();
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
-                anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(TLS_SPECIFIER), eq(TLS_SERVERS), eq(EMPTY_STRING_ARRAY));
-        assertEquals(2, mStringArrayCaptor.getValue().length);
-        assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
+                mResolverParamsParcelCaptor.capture());
+        resolvrParams = mResolverParamsParcelCaptor.getValue();
+        assertEquals(2, resolvrParams.servers.length);
+        assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         reset(mMockDnsResolver);
     }
 
     @Test
     public void testPrivateDnsSettingsChange() throws Exception {
-        ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
-
         // Clear any interactions that occur as a result of CS starting up.
         reset(mMockDnsResolver);
 
@@ -4935,9 +4932,7 @@
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         waitForIdle();
         // CS tells netd about the empty DNS config for this network.
-        verify(mMockDnsResolver, never()).setResolverConfiguration(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
-                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        verify(mMockDnsResolver, never()).setResolverConfiguration(any());
         verifyNoMoreInteractions(mMockDnsResolver);
 
         final LinkProperties cellLp = new LinkProperties();
@@ -4958,14 +4953,14 @@
         mCellNetworkAgent.connect(false);
         waitForIdle();
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
-                anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
-        assertEquals(2, mStringArrayCaptor.getValue().length);
-        assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
+                mResolverParamsParcelCaptor.capture());
+        ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
+        assertEquals(2, resolvrParams.tlsServers.length);
+        assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         // Opportunistic mode.
-        assertEquals(2, tlsServers.getValue().length);
-        assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
+        assertEquals(2, resolvrParams.tlsServers.length);
+        assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         reset(mMockDnsResolver);
         cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
@@ -4980,23 +4975,23 @@
 
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
         verify(mMockDnsResolver, times(1)).setResolverConfiguration(
-                anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
-        assertEquals(2, mStringArrayCaptor.getValue().length);
-        assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
+                mResolverParamsParcelCaptor.capture());
+        resolvrParams = mResolverParamsParcelCaptor.getValue();
+        assertEquals(2, resolvrParams.servers.length);
+        assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         reset(mMockDnsResolver);
         cellNetworkCallback.assertNoCallback();
 
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
-                anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
-        assertEquals(2, mStringArrayCaptor.getValue().length);
-        assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
+                mResolverParamsParcelCaptor.capture());
+        resolvrParams = mResolverParamsParcelCaptor.getValue();
+        assertEquals(2, resolvrParams.servers.length);
+        assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        assertEquals(2, tlsServers.getValue().length);
-        assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
+        assertEquals(2, resolvrParams.tlsServers.length);
+        assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         reset(mMockDnsResolver);
         cellNetworkCallback.assertNoCallback();
@@ -5848,9 +5843,7 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
         verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
-        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
-                eq(cellNetId), eq(EMPTY_STRING_ARRAY), any(), any(),
-                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
@@ -5893,10 +5886,10 @@
         assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
 
         verify(mMockDnsResolver, times(1)).setResolverConfiguration(
-                eq(cellNetId), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
-        assertEquals(1, mStringArrayCaptor.getValue().length);
-        assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "8.8.8.8"));
+                mResolverParamsParcelCaptor.capture());
+        ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
+        assertEquals(1, resolvrParams.servers.length);
+        assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
 
         // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
         // linkproperties are cleaned up.
diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index d28ab70..2b2e8a7 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -29,6 +29,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.times;
@@ -93,6 +94,7 @@
 
     private TestStateMachine mSM;
     private WrappedEntitlementManager mEnMgr;
+    private TetheringConfiguration mConfig;
 
     private class MockContext extends BroadcastInterceptingContext {
         MockContext(Context base) {
@@ -127,13 +129,13 @@
         }
 
         @Override
-        protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
+        protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
             uiProvisionCount++;
             receiver.send(fakeEntitlementResult, null);
         }
 
         @Override
-        protected void runSilentTetherProvisioning(int type) {
+        protected void runSilentTetherProvisioning(int type, int subId) {
             silentProvisionCount++;
             addDownstreamMapping(type, fakeEntitlementResult);
         }
@@ -162,8 +164,10 @@
         mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
                 mSystemProperties);
         mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
-        mEnMgr.updateConfiguration(
-                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
+        mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        mEnMgr.setTetheringConfigurationFetcher(() -> {
+            return mConfig;
+        });
     }
 
     @After
@@ -186,17 +190,16 @@
         // Act like the CarrierConfigManager is present and ready unless told otherwise.
         when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
                 .thenReturn(mCarrierConfigManager);
-        when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mCarrierConfig);
         mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
         mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
+        mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
     }
 
     @Test
     public void canRequireProvisioning() {
         setupForRequiredProvisioning();
-        mEnMgr.updateConfiguration(
-                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
-        assertTrue(mEnMgr.isTetherProvisioningRequired());
+        assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig));
     }
 
     @Test
@@ -204,31 +207,27 @@
         setupForRequiredProvisioning();
         when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
             .thenReturn(null);
-        mEnMgr.updateConfiguration(
-                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
+        mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
         // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
         // Therefore provisioning still be required.
-        assertTrue(mEnMgr.isTetherProvisioningRequired());
+        assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig));
     }
 
     @Test
     public void toleratesCarrierConfigMissing() {
         setupForRequiredProvisioning();
         when(mCarrierConfigManager.getConfig()).thenReturn(null);
-        mEnMgr.updateConfiguration(
-                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
+        mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
         // We still have a provisioning app configured, so still require provisioning.
-        assertTrue(mEnMgr.isTetherProvisioningRequired());
+        assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig));
     }
 
     @Test
     public void toleratesCarrierConfigNotLoaded() {
         setupForRequiredProvisioning();
         mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
-        mEnMgr.updateConfiguration(
-                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
         // We still have a provisioning app configured, so still require provisioning.
-        assertTrue(mEnMgr.isTetherProvisioningRequired());
+        assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig));
     }
 
     @Test
@@ -236,14 +235,12 @@
         setupForRequiredProvisioning();
         when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
             .thenReturn(null);
-        mEnMgr.updateConfiguration(
-                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
-        assertFalse(mEnMgr.isTetherProvisioningRequired());
+        mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        assertFalse(mEnMgr.isTetherProvisioningRequired(mConfig));
         when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
             .thenReturn(new String[] {"malformedApp"});
-        mEnMgr.updateConfiguration(
-                new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
-        assertFalse(mEnMgr.isTetherProvisioningRequired());
+        mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+        assertFalse(mEnMgr.isTetherProvisioningRequired(mConfig));
     }
 
     @Test
@@ -265,8 +262,6 @@
         mEnMgr.reset();
 
         setupForRequiredProvisioning();
-        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
-                  INVALID_SUBSCRIPTION_ID));
         // 2. No cache value and don't need to run entitlement check.
         receiver = new ResultReceiver(null) {
             @Override
@@ -361,8 +356,6 @@
     public void verifyPermissionResult() {
         setupForRequiredProvisioning();
         mEnMgr.notifyUpstream(true);
-        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
-                  INVALID_SUBSCRIPTION_ID));
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
@@ -379,8 +372,6 @@
     public void verifyPermissionIfAllNotApproved() {
         setupForRequiredProvisioning();
         mEnMgr.notifyUpstream(true);
-        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
-                  INVALID_SUBSCRIPTION_ID));
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
@@ -399,8 +390,6 @@
     public void verifyPermissionIfAnyApproved() {
         setupForRequiredProvisioning();
         mEnMgr.notifyUpstream(true);
-        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
-                  INVALID_SUBSCRIPTION_ID));
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
@@ -419,8 +408,6 @@
     @Test
     public void testRunTetherProvisioning() {
         setupForRequiredProvisioning();
-        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
-                INVALID_SUBSCRIPTION_ID));
         // 1. start ui provisioning, upstream is mobile
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.notifyUpstream(true);
@@ -458,7 +445,7 @@
         // 5. tear down mobile, then switch SIM
         mEnMgr.notifyUpstream(false);
         mLooper.dispatchAll();
-        mEnMgr.reevaluateSimCardProvisioning();
+        mEnMgr.reevaluateSimCardProvisioning(mConfig);
         assertEquals(0, mEnMgr.uiProvisionCount);
         assertEquals(0, mEnMgr.silentProvisionCount);
         mEnMgr.reset();
@@ -474,8 +461,6 @@
     @Test
     public void testCallStopTetheringWhenUiProvisioningFail() {
         setupForRequiredProvisioning();
-        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
-                INVALID_SUBSCRIPTION_ID));
         verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.notifyUpstream(true);
@@ -486,7 +471,6 @@
         verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
     }
 
-
     public class TestStateMachine extends StateMachine {
         public final ArrayList<Message> messages = new ArrayList<>();
         private final State
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/Main.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/Main.java
index edb9a49..828cce7 100644
--- a/tools/locked_region_code_injection/src/lockedregioncodeinjection/Main.java
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/Main.java
@@ -13,6 +13,9 @@
  */
 package lockedregioncodeinjection;
 
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
 import java.io.BufferedInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -24,8 +27,6 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassWriter;
 
 public class Main {
     public static void main(String[] args) throws IOException {
@@ -74,6 +75,7 @@
         while (srcEntries.hasMoreElements()) {
             ZipEntry entry = srcEntries.nextElement();
             ZipEntry newEntry = new ZipEntry(entry.getName());
+            newEntry.setTime(entry.getTime());
             zos.putNextEntry(newEntry);
             BufferedInputStream bis = new BufferedInputStream(zipSrc.getInputStream(entry));
 
diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp
index c84567b..2488341 100644
--- a/tools/preload-check/Android.bp
+++ b/tools/preload-check/Android.bp
@@ -15,6 +15,7 @@
 java_test_host {
     name: "PreloadCheck",
     srcs: ["src/**/*.java"],
+    java_resources: [":preloaded-classes-blacklist"],
     libs: ["tradefed"],
     test_suites: ["general-tests"],
     required: ["preload-check-device"],
diff --git a/tools/preload-check/device/src/com/android/preload/check/Initialized.java b/tools/preload-check/device/src/com/android/preload/check/Initialized.java
index b21b5f6..81c074c 100644
--- a/tools/preload-check/device/src/com/android/preload/check/Initialized.java
+++ b/tools/preload-check/device/src/com/android/preload/check/Initialized.java
@@ -16,6 +16,9 @@
 
 package com.android.preload.check;
 
+/**
+ * Test that the given boot classpath class is initialized.
+ */
 public class Initialized {
     public static void main(String[] args) throws Exception {
         Util.assertInitialized(args[0], null);
diff --git a/tools/preload-check/device/src/com/android/preload/check/IntegrityCheck.java b/tools/preload-check/device/src/com/android/preload/check/IntegrityCheck.java
index 6cc3946..1c1e927 100644
--- a/tools/preload-check/device/src/com/android/preload/check/IntegrityCheck.java
+++ b/tools/preload-check/device/src/com/android/preload/check/IntegrityCheck.java
@@ -16,13 +16,16 @@
 
 package com.android.preload.check;
 
+/**
+ * Test that a helper class is first seen as uninitialized, then initialized after forced.
+ */
 public class IntegrityCheck {
     public static void main(String[] args) throws Exception {
         ClassLoader loader = IntegrityCheck.class.getClassLoader();
 
         Util.assertNotInitialized("com.android.preload.check.IntegrityCheck$StatusHelper", loader);
 
-        Class<?> klass = Class.forName("com.android.preload.check.IntegrityCheck$StatusHelper",
+        Class.forName("com.android.preload.check.IntegrityCheck$StatusHelper",
                 /* initialize */ true, loader);
 
         Util.assertInitialized("com.android.preload.check.IntegrityCheck$StatusHelper", loader);
@@ -30,6 +33,7 @@
         System.out.println("OK");
     }
 
+    @SuppressWarnings("unused")
     private static class StatusHelper {
         private final static Object defer = new Object();
     }
diff --git a/tools/preload-check/device/src/com/android/preload/check/NotInitialized.java b/tools/preload-check/device/src/com/android/preload/check/NotInitialized.java
index d2e98fe..c3d2c77 100644
--- a/tools/preload-check/device/src/com/android/preload/check/NotInitialized.java
+++ b/tools/preload-check/device/src/com/android/preload/check/NotInitialized.java
@@ -16,6 +16,9 @@
 
 package com.android.preload.check;
 
+/**
+ * Test that the given boot classpath class is not initialized.
+ */
 public class NotInitialized {
     public static void main(String[] args) throws Exception {
         Util.assertNotInitialized(args[0], null);
diff --git a/tools/preload-check/device/src/com/android/preload/check/NotInitializedRegex.java b/tools/preload-check/device/src/com/android/preload/check/NotInitializedRegex.java
new file mode 100644
index 0000000..d942bad
--- /dev/null
+++ b/tools/preload-check/device/src/com/android/preload/check/NotInitializedRegex.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.preload.check;
+
+import dalvik.system.DexFile;
+
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Test boot classpath classes that satisfy a given regular expression to be not initialized.
+ * Optionally check that at least one class was matched.
+ */
+public class NotInitializedRegex {
+    /**
+     * First arg (mandatory): regular exception. Second arg (optional): boolean to denote a
+     * required match.
+     */
+    public static void main(String[] args) throws Exception {
+        Matcher m = Pattern.compile(args[0]).matcher("");
+        boolean requiresMatch = args.length > 1 ? Boolean.parseBoolean(args[1]) : false;
+
+        Collection<DexFile> dexFiles = Util.getBootDexFiles();
+        int matched = 0, notMatched = 0;
+        for (DexFile dexFile : dexFiles) {
+            Enumeration<String> entries = dexFile.entries();
+            while (entries.hasMoreElements()) {
+                String entry = entries.nextElement();
+                m.reset(entry);
+                if (m.matches()) {
+                    System.out.println(entry + ": match");
+                    matched++;
+                    check(entry);
+                } else {
+                    System.out.println(entry + ": no match");
+                    notMatched++;
+                }
+            }
+        }
+        System.out.println("Matched: " + matched + " Not-Matched: " + notMatched);
+        if (requiresMatch && matched == 0) {
+            throw new RuntimeException("Did not find match");
+        }
+        System.out.println("OK");
+    }
+
+    private static void check(String name) {
+        Util.assertNotInitialized(name, null);
+    }
+}
diff --git a/tools/preload-check/device/src/com/android/preload/check/Util.java b/tools/preload-check/device/src/com/android/preload/check/Util.java
index 662f67a..fccea0a 100644
--- a/tools/preload-check/device/src/com/android/preload/check/Util.java
+++ b/tools/preload-check/device/src/com/android/preload/check/Util.java
@@ -16,7 +16,18 @@
 
 package com.android.preload.check;
 
+import dalvik.system.DexFile;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
 
 public class Util {
     private static Field statusField;
@@ -29,6 +40,51 @@
         } catch (Throwable t) {
             throw new RuntimeException(t);
         }
+        // Reset the framework's kill handler.
+        Thread.setDefaultUncaughtExceptionHandler(null);
+    }
+
+    public static Collection<DexFile> getBootDexFiles() throws Exception {
+        Class<?> vmClassLoaderClass = Class.forName("java.lang.VMClassLoader");
+        Method getResources = vmClassLoaderClass.getDeclaredMethod("getResources", String.class);
+        getResources.setAccessible(true);
+        LinkedList<DexFile> res = new LinkedList<>();
+        for (int i = 1;; i++) {
+            try {
+                String name = "classes" + (i > 1 ? String.valueOf(i) : "") + ".dex";
+                @SuppressWarnings("unchecked")
+                List<URL> urls = (List<URL>) getResources.invoke(null, name);
+                if (urls.isEmpty()) {
+                    break;
+                }
+                for (URL url : urls) {
+                    // Make temp copy, so we can use public API. Would be nice to use in-memory, but
+                    // those are unstable.
+                    String tmp = "/data/local/tmp/tmp.dex";
+                    try (BufferedInputStream in = new BufferedInputStream(url.openStream());
+                            BufferedOutputStream out = new BufferedOutputStream(
+                                    new FileOutputStream(tmp))) {
+                        byte[] buf = new byte[4096];
+                        for (;;) {
+                            int r = in.read(buf);
+                            if (r == -1) {
+                                break;
+                            }
+                            out.write(buf, 0, r);
+                        }
+                    }
+                    try {
+                        res.add(new DexFile(tmp));
+                    } catch (Exception dexError) {
+                        dexError.printStackTrace(System.out);
+                    }
+                    new File(tmp).delete();
+                }
+            } catch (Exception ignored) {
+                break;
+            }
+        }
+        return res;
     }
 
     public static boolean isInitialized(Class<?> klass) throws Exception {
diff --git a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
index dbdecdb..00fd414e3 100644
--- a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
+++ b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
@@ -16,7 +16,7 @@
 
 package com.android.preload.check;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -25,6 +25,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class PreloadCheck implements IDeviceTest {
     private ITestDevice mTestDevice;
@@ -65,6 +68,43 @@
         run("com.android.preload.check.Initialized", "android.animation.Animator");
     }
 
+    /**
+     * Test the classes mentioned in the embedded preloaded-classes blacklist.
+     */
+    @Test
+    public void testBlackList() throws Exception {
+        StringBuilder sb = new StringBuilder();
+        try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass()
+                .getResourceAsStream("/preloaded-classes-blacklist")))) {
+            String s;
+            while ((s = br.readLine()) != null) {
+                s = s.trim();
+                if (s.startsWith("#") || s.isEmpty()) {
+                    continue;
+                }
+                try {
+                    run("com.android.preload.check.NotInitialized", s);
+                } catch (Throwable t) {
+                    if (sb.length() > 0) {
+                        sb.append('\n');
+                    }
+                    sb.append(t.getMessage());
+                }
+            }
+        }
+        if (sb.length() > 0) {
+            throw new RuntimeException(sb.toString());
+        }
+    }
+
+    /**
+     * Test the classes ending in NoPreloadHolder are not initialized.
+     */
+    @Test
+    public void testNoPreloadHolder() throws Exception {
+        run("com.android.preload.check.NotInitializedRegex", ".*NoPreloadHolder$", "true");
+    }
+
     private void run(String cmd, String... args) throws Exception {
         StringBuilder sb = new StringBuilder();
         sb.append("app_process ")
@@ -72,9 +112,16 @@
                 .append(" /system/bin ")
                 .append(cmd);
         for (String arg : args) {
-            sb.append(' ').append(arg);
+            sb.append(' ').append(escape(arg));
         }
         String res = mTestDevice.executeShellCommand(sb.toString());
-        assertEquals(sb.toString(), "OK", res.trim());
+        assertTrue(sb.toString() + "\n===\n" + res, res.trim().endsWith("OK"));
+    }
+
+    private static String escape(String input) {
+        if (input.indexOf('$') == -1) {
+            return input;
+        }
+        return input.replace("$", "\\$");
     }
 }
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 49eee07..dc18b8d 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -219,6 +219,14 @@
       errorCount++;
       continue;
     }
+
+    // Doubles are not supported yet.
+    if (javaType == JAVA_TYPE_DOUBLE) {
+        print_error(field, "Doubles are not supported in atoms. Please change field %s to float\n",
+                    field->name().c_str());
+        errorCount++;
+        continue;
+    }
   }
 
   // Check that if there's an attribution chain, it's at position 1.
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index e0ea2077..8e4cb9f 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -48,6 +48,7 @@
   JAVA_TYPE_DOUBLE = 6,
   JAVA_TYPE_STRING = 7,
   JAVA_TYPE_ENUM = 8,
+  JAVA_TYPE_KEY_VALUE_PAIR = 9,
 
   JAVA_TYPE_OBJECT = -1,
   JAVA_TYPE_BYTE_ARRAY = -2,
@@ -118,4 +119,4 @@
 }  // namespace android
 
 
-#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
\ No newline at end of file
+#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 73a0fe1..43b79cc 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -27,6 +27,11 @@
 const string DEFAULT_MODULE_NAME = "DEFAULT";
 const string DEFAULT_CPP_NAMESPACE = "android,util";
 const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+const string DEFAULT_JAVA_PACKAGE = "android.util";
+const string DEFAULT_JAVA_CLASS = "StatsLogInternal";
+
+const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
+const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
 
 using android::os::statsd::Atom;
 
@@ -807,11 +812,350 @@
     }
 }
 
+static void write_java_helpers_for_module(
+        FILE * out,
+        const AtomDecl &attributionDecl,
+        const int requiredHelpers) {
+    fprintf(out, "    private static void copyInt(byte[] buff, int pos, int val) {\n");
+    fprintf(out, "        buff[pos] = (byte) (val);\n");
+    fprintf(out, "        buff[pos + 1] = (byte) (val >> 8);\n");
+    fprintf(out, "        buff[pos + 2] = (byte) (val >> 16);\n");
+    fprintf(out, "        buff[pos + 3] = (byte) (val >> 24);\n");
+    fprintf(out, "        return;\n");
+    fprintf(out, "    }\n");
+    fprintf(out, "\n");
+
+    fprintf(out, "    private static void copyLong(byte[] buff, int pos, long val) {\n");
+    fprintf(out, "        buff[pos] = (byte) (val);\n");
+    fprintf(out, "        buff[pos + 1] = (byte) (val >> 8);\n");
+    fprintf(out, "        buff[pos + 2] = (byte) (val >> 16);\n");
+    fprintf(out, "        buff[pos + 3] = (byte) (val >> 24);\n");
+    fprintf(out, "        buff[pos + 4] = (byte) (val >> 32);\n");
+    fprintf(out, "        buff[pos + 5] = (byte) (val >> 40);\n");
+    fprintf(out, "        buff[pos + 6] = (byte) (val >> 48);\n");
+    fprintf(out, "        buff[pos + 7] = (byte) (val >> 56);\n");
+    fprintf(out, "        return;\n");
+    fprintf(out, "    }\n");
+    fprintf(out, "\n");
+
+    if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) {
+        fprintf(out, "    private static void copyFloat(byte[] buff, int pos, float val) {\n");
+        fprintf(out, "        copyInt(buff, pos, Float.floatToIntBits(val));\n");
+        fprintf(out, "        return;\n");
+        fprintf(out, "    }\n");
+        fprintf(out, "\n");
+    }
+
+    if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) {
+        fprintf(out, "    private static void writeAttributionChain(byte[] buff, int pos");
+        for (auto chainField : attributionDecl.fields) {
+            fprintf(out, ", %s[] %s",
+                java_type_name(chainField.javaType), chainField.name.c_str());
+        }
+        fprintf(out, ") {\n");
+
+        const char* uidName = attributionDecl.fields.front().name.c_str();
+        const char* tagName = attributionDecl.fields.back().name.c_str();
+
+        // Write the first list begin.
+        fprintf(out, "        buff[pos] = LIST_TYPE;\n");
+        fprintf(out, "        buff[pos + 1] = (byte) (%s.length);\n", tagName);
+        fprintf(out, "        pos += LIST_TYPE_OVERHEAD;\n");
+
+        // Iterate through the attribution chain and write the nodes.
+        fprintf(out, "        for (int i = 0; i < %s.length; i++) {\n", tagName);
+        // Write the list begin.
+        fprintf(out, "            buff[pos] = LIST_TYPE;\n");
+        fprintf(out, "            buff[pos + 1] = %lu;\n", attributionDecl.fields.size());
+        fprintf(out, "            pos += LIST_TYPE_OVERHEAD;\n");
+
+        // Write the uid.
+        fprintf(out, "            buff[pos] = INT_TYPE;\n");
+        fprintf(out, "            copyInt(buff, pos + 1, %s[i]);\n", uidName);
+        fprintf(out, "            pos += INT_TYPE_SIZE;\n");
+
+        // Write the tag.
+        fprintf(out, "            String %sStr = (%s[i] == null) ? \"\" : %s[i];\n",
+                tagName, tagName, tagName);
+        fprintf(out, "            byte[] %sByte = %sStr.getBytes(UTF_8);\n", tagName, tagName);
+        fprintf(out, "            buff[pos] = STRING_TYPE;\n");
+        fprintf(out, "            copyInt(buff, pos + 1, %sByte.length);\n", tagName);
+        fprintf(out, "            System.arraycopy("
+                "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n",
+                tagName, tagName);
+        fprintf(out, "            pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", tagName);
+        fprintf(out, "        }\n");
+        fprintf(out, "    }\n");
+        fprintf(out, "\n");
+    }
+}
+
+
+static int write_java_non_chained_method_for_module(
+        FILE* out,
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const string& moduleName
+        ) {
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        // Skip if this signature is not needed for the module.
+        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+            continue;
+        }
+
+        // Print method signature.
+        vector<java_type_t> signature = signature_to_modules_it->first;
+        fprintf(out, "    public static void write_non_chained(int code");
+        int argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
+            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+                // Non chained signatures should not have attribution chains.
+                return 1;
+            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+                // Module logging does not yet support key value pair.
+                return 1;
+            } else {
+                fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+            }
+            argIndex++;
+        }
+        fprintf(out, ") {\n");
+
+        fprintf(out, "        write(code");
+        argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
+            // First two args are uid and tag of attribution chain.
+            if (argIndex == 1) {
+                fprintf(out, ", new int[] {arg%d}", argIndex);
+            } else if (argIndex == 2) {
+                fprintf(out, ", new java.lang.String[] {arg%d}", argIndex);
+            } else {
+                fprintf(out, ", arg%d", argIndex);
+            }
+            argIndex++;
+        }
+        fprintf(out, ");\n");
+        fprintf(out, "    }\n");
+        fprintf(out, "\n");
+    }
+    return 0;
+}
+
+static int write_java_method_for_module(
+        FILE* out,
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const AtomDecl &attributionDecl,
+        const string& moduleName,
+        int* requiredHelpers
+        ) {
+
+    for (auto signature_to_modules_it = signatures_to_modules.begin();
+            signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        // Skip if this signature is not needed for the module.
+        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+            continue;
+        }
+
+        // Print method signature.
+        vector<java_type_t> signature = signature_to_modules_it->first;
+        fprintf(out, "    public static void write(int code");
+        int argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
+            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+                for (auto chainField : attributionDecl.fields) {
+                    fprintf(out, ", %s[] %s",
+                        java_type_name(chainField.javaType), chainField.name.c_str());
+                }
+            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+                // Module logging does not yet support key value pair.
+                return 1;
+            } else {
+                fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+            }
+            argIndex++;
+        }
+        fprintf(out, ") {\n");
+
+        // Calculate the size of the buffer.
+        fprintf(out, "        // Initial overhead of the list, timestamp, and atom tag.\n");
+        fprintf(out, "        int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n");
+        argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
+            switch (*arg) {
+            case JAVA_TYPE_BOOLEAN:
+            case JAVA_TYPE_INT:
+            case JAVA_TYPE_FLOAT:
+            case JAVA_TYPE_ENUM:
+                fprintf(out, "        needed += INT_TYPE_SIZE;\n");
+                break;
+            case JAVA_TYPE_LONG:
+                // Longs take 9 bytes, 1 for the type and 8 for the value.
+                fprintf(out, "        needed += LONG_TYPE_SIZE;\n");
+                break;
+            case JAVA_TYPE_STRING:
+                // Strings take 5 metadata bytes + length of byte encoded string.
+                fprintf(out, "        if (arg%d == null) {\n", argIndex);
+                fprintf(out, "            arg%d = \"\";\n", argIndex);
+                fprintf(out, "        }\n");
+                fprintf(out, "        byte[] arg%dBytes= arg%d.getBytes(UTF_8);\n",
+                        argIndex, argIndex);
+                fprintf(out, "        needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
+                        argIndex);
+                break;
+            case JAVA_TYPE_BYTE_ARRAY:
+                // Byte arrays take 5 metadata bytes + length of byte array.
+                fprintf(out, "        if (arg%d == null) {\n", argIndex);
+                fprintf(out, "            arg%d = new byte[0];\n", argIndex);
+                fprintf(out, "        }\n");
+                fprintf(out, "        needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex);
+                break;
+            case JAVA_TYPE_ATTRIBUTION_CHAIN:
+            {
+                const char* uidName = attributionDecl.fields.front().name.c_str();
+                const char* tagName = attributionDecl.fields.back().name.c_str();
+                // Null checks on the params.
+                fprintf(out, "        if (%s == null) {\n", uidName);
+                fprintf(out, "            %s = new %s[0];\n", uidName,
+                        java_type_name(attributionDecl.fields.front().javaType));
+                fprintf(out, "        }\n");
+                fprintf(out, "        if (%s == null) {\n", tagName);
+                fprintf(out, "            %s = new %s[0];\n", tagName,
+                        java_type_name(attributionDecl.fields.back().javaType));
+                fprintf(out, "        }\n");
+
+                // First check that the lengths of the uid and tag arrays are the same.
+                fprintf(out, "        if (%s.length != %s.length) {\n", uidName, tagName);
+                fprintf(out, "            return;\n");
+                fprintf(out, "        }\n");
+                fprintf(out, "        int attrSize = LIST_TYPE_OVERHEAD;\n");
+                fprintf(out, "        for (int i = 0; i < %s.length; i++) {\n", tagName);
+                fprintf(out, "            String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
+                        argIndex, tagName, tagName);
+                fprintf(out, "            int str%dlen = str%d.getBytes(UTF_8).length;\n",
+                        argIndex, argIndex);
+                fprintf(out,
+                        "            attrSize += "
+                        "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n",
+                        argIndex);
+                fprintf(out, "        }\n");
+                fprintf(out, "        needed += attrSize;\n");
+                break;
+            }
+            default:
+                // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR.
+                return 1;
+            }
+            argIndex++;
+        }
+
+        // Now we have the size that is needed. Check for overflow and return if needed.
+        fprintf(out, "        if (needed > MAX_EVENT_PAYLOAD) {\n");
+        fprintf(out, "            return;\n");
+        fprintf(out, "        }\n");
+
+        // Create new buffer, and associated data types.
+        fprintf(out, "        byte[] buff = new byte[needed];\n");
+        fprintf(out, "        int pos = 0;\n");
+
+        // Initialize the buffer with list data type.
+        fprintf(out, "        buff[pos] = LIST_TYPE;\n");
+        fprintf(out, "        buff[pos + 1] = %lu;\n", signature.size() + 2);
+        fprintf(out, "        pos += LIST_TYPE_OVERHEAD;\n");
+
+        // Write timestamp.
+        fprintf(out, "        long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n");
+        fprintf(out, "        buff[pos] = LONG_TYPE;\n");
+        fprintf(out, "        copyLong(buff, pos + 1, elapsedRealtime);\n");
+        fprintf(out, "        pos += LONG_TYPE_SIZE;\n");
+
+        // Write atom code.
+        fprintf(out, "        buff[pos] = INT_TYPE;\n");
+        fprintf(out, "        copyInt(buff, pos + 1, code);\n");
+        fprintf(out, "        pos += INT_TYPE_SIZE;\n");
+
+        // Write the args.
+        argIndex = 1;
+        for (vector<java_type_t>::const_iterator arg = signature.begin();
+                arg != signature.end(); arg++) {
+            switch (*arg) {
+            case JAVA_TYPE_BOOLEAN:
+                fprintf(out, "        buff[pos] = INT_TYPE;\n");
+                fprintf(out, "        copyInt(buff, pos + 1, arg%d? 1 : 0);\n", argIndex);
+                fprintf(out, "        pos += INT_TYPE_SIZE;\n");
+                break;
+            case JAVA_TYPE_INT:
+            case JAVA_TYPE_ENUM:
+                fprintf(out, "        buff[pos] = INT_TYPE;\n");
+                fprintf(out, "        copyInt(buff, pos + 1, arg%d);\n", argIndex);
+                fprintf(out, "        pos += INT_TYPE_SIZE;\n");
+                break;
+            case JAVA_TYPE_FLOAT:
+                *requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
+                fprintf(out, "        buff[pos] = FLOAT_TYPE;\n");
+                fprintf(out, "        copyFloat(buff, pos + 1, arg%d);\n", argIndex);
+                fprintf(out, "        pos += FLOAT_TYPE_SIZE;\n");
+                break;
+            case JAVA_TYPE_LONG:
+                fprintf(out, "        buff[pos] = LONG_TYPE;\n");
+                fprintf(out, "        copyLong(buff, pos + 1, arg%d);\n", argIndex);
+                fprintf(out, "        pos += LONG_TYPE_SIZE;\n");
+                break;
+            case JAVA_TYPE_STRING:
+                fprintf(out, "        buff[pos] = STRING_TYPE;\n");
+                fprintf(out, "        copyInt(buff, pos + 1, arg%dBytes.length);\n", argIndex);
+                fprintf(out, "        System.arraycopy("
+                        "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n",
+                        argIndex, argIndex);
+                fprintf(out, "        pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
+                        argIndex);
+                break;
+            case JAVA_TYPE_BYTE_ARRAY:
+                fprintf(out, "        buff[pos] = STRING_TYPE;\n");
+                fprintf(out, "        copyInt(buff, pos + 1, arg%d.length);\n", argIndex);
+                fprintf(out, "        System.arraycopy("
+                        "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
+                        argIndex, argIndex);
+                fprintf(out, "        pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex);
+                break;
+            case JAVA_TYPE_ATTRIBUTION_CHAIN:
+            {
+                *requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
+                const char* uidName = attributionDecl.fields.front().name.c_str();
+                const char* tagName = attributionDecl.fields.back().name.c_str();
+
+                fprintf(out, "        writeAttributionChain(buff, pos, %s, %s);\n",
+                        uidName, tagName);
+                fprintf(out, "        pos += attrSize;\n");
+                break;
+            }
+            default:
+                // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR.
+                return 1;
+            }
+            argIndex++;
+        }
+
+        fprintf(out, "        StatsLog.writeRaw(buff, pos);\n");
+        fprintf(out, "    }\n");
+        fprintf(out, "\n");
+    }
+    return 0;
+}
+
 static void write_java_work_source_method(FILE* out,
-        const map<vector<java_type_t>, set<string>>& signatures_to_modules) {
+        const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+        const string& moduleName) {
     fprintf(out, "\n    // WorkSource methods.\n");
     for (auto signature_to_modules_it = signatures_to_modules.begin();
             signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+        // Skip if this signature is not needed for the module.
+        if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+            continue;
+        }
         vector<java_type_t> signature = signature_to_modules_it->first;
         // Determine if there is Attribution in this signature.
         int attributionArg = -1;
@@ -834,7 +1178,9 @@
         }
 
         // Method header (signature)
-        fprintf(out, "    /** @hide */\n");
+        if (moduleName == DEFAULT_MODULE_NAME) {
+            fprintf(out, "    /** @hide */\n");
+        }
         fprintf(out, "    public static void write(int code");
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature.begin();
@@ -859,7 +1205,7 @@
             }
         }
         fprintf(out, ");\n");
-        fprintf(out, "        }\n"); // close flor-loop
+        fprintf(out, "        }\n"); // close for-loop
 
         // write() component.
         fprintf(out, "        ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
@@ -880,23 +1226,7 @@
     }
 }
 
-static int
-write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
-{
-    // Print prelude
-    fprintf(out, "// This file is autogenerated\n");
-    fprintf(out, "\n");
-    fprintf(out, "package android.util;\n");
-    fprintf(out, "\n");
-    fprintf(out, "import android.os.WorkSource;\n");
-    fprintf(out, "import java.util.ArrayList;\n");
-    fprintf(out, "\n");
-    fprintf(out, "\n");
-    fprintf(out, "/**\n");
-    fprintf(out, " * API For logging statistics events.\n");
-    fprintf(out, " * @hide\n");
-    fprintf(out, " */\n");
-    fprintf(out, "public class StatsLogInternal {\n");
+static void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) {
     fprintf(out, "    // Constants for atom codes.\n");
 
     std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
@@ -905,6 +1235,10 @@
     // Print constants for the atom codes.
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
             atom != atoms.decls.end(); atom++) {
+        // Skip if the atom is not needed for the module.
+        if (!atom_needed_for_module(*atom, moduleName)) {
+            continue;
+        }
         string constant = make_constant_name(atom->name);
         fprintf(out, "\n");
         fprintf(out, "    /**\n");
@@ -914,16 +1248,23 @@
         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
             write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
         }
-        fprintf(out, "     * @hide\n");
+        if (moduleName == DEFAULT_MODULE_NAME) {
+            fprintf(out, "     * @hide\n");
+        }
         fprintf(out, "     */\n");
         fprintf(out, "    public static final int %s = %d;\n", constant.c_str(), atom->code);
     }
     fprintf(out, "\n");
+}
 
-    // Print constants for the enum values.
+static void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName) {
     fprintf(out, "    // Constants for enum values.\n\n");
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
         atom != atoms.decls.end(); atom++) {
+        // Skip if the atom is not needed for the module.
+        if (!atom_needed_for_module(*atom, moduleName)) {
+            continue;
+        }
         for (vector<AtomField>::const_iterator field = atom->fields.begin();
             field != atom->fields.end(); field++) {
             if (field->javaType == JAVA_TYPE_ENUM) {
@@ -931,7 +1272,9 @@
                     field->name.c_str());
                 for (map<int, string>::const_iterator value = field->enumValues.begin();
                     value != field->enumValues.end(); value++) {
-                    fprintf(out, "    /** @hide */\n");
+                    if (moduleName == DEFAULT_MODULE_NAME) {
+                        fprintf(out, "    /** @hide */\n");
+                    }
                     fprintf(out, "    public static final int %s__%s__%s = %d;\n",
                         make_constant_name(atom->message).c_str(),
                         make_constant_name(field->name).c_str(),
@@ -942,19 +1285,107 @@
             }
         }
     }
+}
+
+static int
+write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
+{
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+    fprintf(out, "package android.util;\n");
+    fprintf(out, "\n");
+    fprintf(out, "import android.os.WorkSource;\n");
+    fprintf(out, "import android.util.SparseArray;\n");
+    fprintf(out, "import java.util.ArrayList;\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "/**\n");
+    fprintf(out, " * API For logging statistics events.\n");
+    fprintf(out, " * @hide\n");
+    fprintf(out, " */\n");
+    fprintf(out, "public class StatsLogInternal {\n");
+    write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME);
+
+    write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME);
 
     // Print write methods
     fprintf(out, "    // Write methods\n");
     write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
     write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
             attributionDecl);
-    write_java_work_source_method(out, atoms.signatures_to_modules);
+    write_java_work_source_method(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
 
     fprintf(out, "}\n");
 
     return 0;
 }
 
+// TODO: Merge this with write_stats_log_java so that we can get rid of StatsLogInternal JNI.
+static int
+write_stats_log_java_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+                     const string& moduleName, const string& javaClass, const string& javaPackage)
+{
+    // Print prelude
+    fprintf(out, "// This file is autogenerated\n");
+    fprintf(out, "\n");
+    fprintf(out, "package %s;\n", javaPackage.c_str());
+    fprintf(out, "\n");
+    fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
+    fprintf(out, "\n");
+    fprintf(out, "import android.util.StatsLog;\n");
+    fprintf(out, "import android.os.SystemClock;\n");
+    fprintf(out, "\n");
+    fprintf(out, "import java.util.ArrayList;\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "/**\n");
+    fprintf(out, " * Utility class for logging statistics events.\n");
+    fprintf(out, " */\n");
+    fprintf(out, "public class %s {\n", javaClass.c_str());
+
+    // TODO: ideally these match with the native values (and automatically change if they change).
+    fprintf(out, "    private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n");
+    fprintf(out,
+            "    private static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n");
+    // Value types. Must match with EventLog.java and log.h.
+    fprintf(out, "    private static final byte INT_TYPE = 0;\n");
+    fprintf(out, "    private static final byte LONG_TYPE = 1;\n");
+    fprintf(out, "    private static final byte STRING_TYPE = 2;\n");
+    fprintf(out, "    private static final byte LIST_TYPE = 3;\n");
+    fprintf(out, "    private static final byte FLOAT_TYPE = 4;\n");
+
+    // Size of each value type.
+    // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value.
+    fprintf(out, "    private static final int INT_TYPE_SIZE = 5;\n");
+    fprintf(out, "    private static final int FLOAT_TYPE_SIZE = 5;\n");
+    // Longs take 9 bytes, 1 for the type and 8 for the value.
+    fprintf(out, "    private static final int LONG_TYPE_SIZE = 9;\n");
+    // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length.
+    fprintf(out, "    private static final int STRING_TYPE_OVERHEAD = 5;\n");
+    fprintf(out, "    private static final int LIST_TYPE_OVERHEAD = 2;\n");
+
+    write_java_atom_codes(out, atoms, moduleName);
+
+    write_java_enum_values(out, atoms, moduleName);
+
+    int errors = 0;
+    int requiredHelpers = 0;
+    // Print write methods
+    fprintf(out, "    // Write methods\n");
+    errors += write_java_method_for_module(out, atoms.signatures_to_modules, attributionDecl,
+            moduleName, &requiredHelpers);
+    errors += write_java_non_chained_method_for_module(out, atoms.non_chained_signatures_to_modules,
+            moduleName);
+
+    fprintf(out, "    // Helper methods for copying primitives\n");
+    write_java_helpers_for_module(out, attributionDecl, requiredHelpers);
+
+    fprintf(out, "}\n");
+
+    return errors;
+}
+
 static const char*
 jni_type_name(java_type_t type)
 {
@@ -1319,10 +1750,10 @@
     fprintf(out, "\n");
 
     // Print registration function
-    fprintf(out, "int register_android_util_StatsLog(JNIEnv* env) {\n");
+    fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n");
     fprintf(out, "    return RegisterMethodsOrDie(\n");
     fprintf(out, "            env,\n");
-    fprintf(out, "            \"android/util/StatsLog\",\n");
+    fprintf(out, "            \"android/util/StatsLogInternal\",\n");
     fprintf(out, "            gRegisterMethods, NELEM(gRegisterMethods));\n");
     fprintf(out, "}\n");
 
@@ -1346,7 +1777,11 @@
     fprintf(stderr, "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with module\n");
     fprintf(stderr, "                                    comma separated namespace of the files\n");
     fprintf(stderr, "  --importHeader NAME  required for cpp/jni to say which header to import\n");
-}
+    fprintf(stderr, "  --javaPackage PACKAGE             the package for the java file.\n");
+    fprintf(stderr, "                                    required for java with module\n");
+    fprintf(stderr, "  --javaClass CLASS    the class name of the java class.\n");
+    fprintf(stderr, "                       Optional for Java with module.\n");
+    fprintf(stderr, "                       Default is \"StatsLogInternal\"\n");}
 
 /**
  * Do the argument parsing and execute the tasks.
@@ -1362,6 +1797,8 @@
     string moduleName = DEFAULT_MODULE_NAME;
     string cppNamespace = DEFAULT_CPP_NAMESPACE;
     string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
+    string javaPackage = DEFAULT_JAVA_PACKAGE;
+    string javaClass = DEFAULT_JAVA_CLASS;
 
     int index = 1;
     while (index < argc) {
@@ -1417,6 +1854,20 @@
                 return 1;
             }
             cppHeaderImport = argv[index];
+        } else if (0 == strcmp("--javaPackage", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            javaPackage = argv[index];
+        } else if (0 == strcmp("--javaClass", argv[index])) {
+            index++;
+            if (index >= argc) {
+                print_usage();
+                return 1;
+            }
+            javaClass = argv[index];
         }
         index++;
     }
@@ -1486,8 +1937,18 @@
             fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
             return 1;
         }
-        errorCount = android::stats_log_api_gen::write_stats_log_java(
-            out, atoms, attributionDecl);
+        // If this is for a specific module, the java package must also be provided.
+        if (moduleName != DEFAULT_MODULE_NAME && javaPackage== DEFAULT_JAVA_PACKAGE) {
+            fprintf(stderr, "Must supply --javaPackage if supplying a specific module\n");
+            return 1;
+        }
+        if (moduleName == DEFAULT_MODULE_NAME) {
+            errorCount = android::stats_log_api_gen::write_stats_log_java(
+                    out, atoms, attributionDecl);
+        } else {
+            errorCount = android::stats_log_api_gen::write_stats_log_java_for_module(
+                    out, atoms, attributionDecl, moduleName, javaClass, javaPackage);
+        }
         fclose(out);
     }
 
@@ -1503,7 +1964,7 @@
         fclose(out);
     }
 
-    return 0;
+    return errorCount;
 }
 
 }