Merge "Set dist_group: "android" for frameworks/base java_sdk_libraries"
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index 1bd90a8..80317e4 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7396576"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShimPriv.apk"
   }
@@ -9,4 +9,5 @@
   version_group: ""
   git_project: "platform/frameworks/base"
   git_branch: "sc-dev"
+  transform: TRANSFORM_NONE
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index 544bca02..3605b6d 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7396576"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShim.apk"
   }
@@ -9,4 +9,5 @@
   version_group: ""
   git_project: "platform/frameworks/base"
   git_branch: "sc-dev"
+  transform: TRANSFORM_NONE
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 72386bb..025ec3a 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7396576"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShimPriv.apk"
   }
@@ -9,4 +9,5 @@
   version_group: ""
   git_project: "platform/frameworks/base"
   git_branch: "sc-dev"
+  transform: TRANSFORM_NONE
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index 893eac2..e19235a 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7396576"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShim.apk"
   }
@@ -9,4 +9,5 @@
   version_group: ""
   git_project: "platform/frameworks/base"
   git_branch: "sc-dev"
+  transform: TRANSFORM_NONE
 }
diff --git a/Android.bp b/Android.bp
index 6e7940c..05c852ee 100644
--- a/Android.bp
+++ b/Android.bp
@@ -254,6 +254,14 @@
     installable: false,
 }
 
+// NOTE: This filegroup is exposed for vendor libraries to depend on and is referenced in
+// documentation. Do not remove without consulting the treble/hidl teams.
+filegroup {
+    name: "framework-jarjar-rules",
+    srcs: ["framework-jarjar-rules.txt"],
+    visibility: ["//visibility:public"],
+}
+
 java_library {
     name: "framework-minus-apex",
     defaults: ["framework-aidl-export-defaults"],
@@ -270,7 +278,7 @@
         "--multi-dex",
     ],
     installable: true,
-    jarjar_rules: "framework-jarjar-rules.txt",
+    jarjar_rules: ":framework-jarjar-rules",
     javac_shard_size: 150,
     plugins: [
         "view-inspector-annotation-processor",
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 71cc11b..b087054 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1123,7 +1123,7 @@
             InetAddress.clearDnsCache();
             // Allow libcore to perform the necessary actions as it sees fit upon a network
             // configuration change.
-            NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
+            NetworkEventDispatcher.getInstance().dispatchNetworkConfigurationChange();
         }
 
         public void updateHttpProxy() {
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 352f2e9..68917a8 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -514,6 +514,10 @@
         return mSubscriberIdMatchRule;
     }
 
+    public int getMeteredness() {
+        return mMetered;
+    }
+
     /**
      * Test if given {@link NetworkIdentity} matches this template.
      */
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index 848b6d5..53843fe 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -40,4 +40,5 @@
     boolean unsetPreferredService();
     boolean supportsAidPrefixRegistration();
     ApduServiceInfo getPreferredPaymentService(int userHandle);
+    boolean isDefaultPaymentRegistered();
 }
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index b138a3f..d498535 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -294,9 +294,23 @@
      */
     public int getSelectionModeForCategory(String category) {
         if (CATEGORY_PAYMENT.equals(category)) {
-            String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(),
-                    Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
-            if (defaultComponent != null) {
+            boolean paymentRegistered = false;
+            try {
+                paymentRegistered = sService.isDefaultPaymentRegistered();
+            } catch (RemoteException e) {
+                recoverService();
+                if (sService == null) {
+                    Log.e(TAG, "Failed to recover CardEmulationService.");
+                    return SELECTION_MODE_ALWAYS_ASK;
+                }
+                try {
+                    paymentRegistered = sService.isDefaultPaymentRegistered();
+                } catch (RemoteException ee) {
+                    Log.e(TAG, "Failed to reach CardEmulationService.");
+                    return SELECTION_MODE_ALWAYS_ASK;
+                }
+            }
+            if (paymentRegistered) {
                 return SELECTION_MODE_PREFER_DEFAULT;
             } else {
                 return SELECTION_MODE_ALWAYS_ASK;
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 097b672..75bc8af 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -228,6 +228,8 @@
     /**
      * Vibrate constantly for the specified period of time.
      *
+     * <p>The app should be in foreground for the vibration to happen.</p>
+     *
      * @param milliseconds The number of milliseconds to vibrate.
      * @deprecated Use {@link #vibrate(VibrationEffect)} instead.
      */
@@ -240,6 +242,9 @@
     /**
      * Vibrate constantly for the specified period of time.
      *
+     * <p>The app should be in foreground for the vibration to happen. Background apps should
+     * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+     *
      * @param milliseconds The number of milliseconds to vibrate.
      * @param attributes   {@link AudioAttributes} corresponding to the vibration. For example,
      *                     specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
@@ -274,6 +279,8 @@
      * to start the repeat, or -1 to disable repeating.
      * </p>
      *
+     * <p>The app should be in foreground for the vibration to happen.</p>
+     *
      * @param pattern an array of longs of times for which to turn the vibrator on or off.
      * @param repeat  the index into pattern at which to repeat, or -1 if
      *                you don't want to repeat.
@@ -299,6 +306,9 @@
      * to start the repeat, or -1 to disable repeating.
      * </p>
      *
+     * <p>The app should be in foreground for the vibration to happen. Background apps should
+     * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+     *
      * @param pattern    an array of longs of times for which to turn the vibrator on or off.
      * @param repeat     the index into pattern at which to repeat, or -1 if
      *                   you don't want to repeat.
@@ -326,11 +336,30 @@
         }
     }
 
+    /**
+     * Vibrate with a given effect.
+     *
+     * <p>The app should be in foreground for the vibration to happen.</p>
+     *
+     * @param vibe {@link VibrationEffect} describing the vibration to be performed.
+     */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
     public void vibrate(VibrationEffect vibe) {
         vibrate(vibe, null);
     }
 
+    /**
+     * Vibrate with a given effect.
+     *
+     * <p>The app should be in foreground for the vibration to happen. Background apps should
+     * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+     *
+     * @param vibe       {@link VibrationEffect} describing the vibration to be performed.
+     * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
+     *                   specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
+     *                   {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
+     *                   vibrations associated with incoming calls.
+     */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
     public void vibrate(VibrationEffect vibe, AudioAttributes attributes) {
         vibrate(Process.myUid(), mPackageName, vibe, null, attributes);
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index 64570a8..e1d6012 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -8,6 +8,6 @@
 mount@google.com
 njawad@google.com
 
-per-file TextView.java, EditText.java, Editor.java = siyamed@google.com, nona@google.com, clarabayarri@google.com
+per-file TextView*, EditText.java, Editor.java = siyamed@google.com, nona@google.com, clarabayarri@google.com
 
 per-file SpellChecker.java = file:../view/inputmethod/OWNERS
diff --git a/core/java/com/android/internal/content/OWNERS b/core/java/com/android/internal/content/OWNERS
new file mode 100644
index 0000000..c42bee6
--- /dev/null
+++ b/core/java/com/android/internal/content/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 36137
+include /core/java/android/content/pm/OWNERS
+
+per-file ReferrerIntent.aidl = file:/services/core/java/com/android/server/am/OWNERS
+per-file ReferrerIntent.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/com/android/internal/content/om/OWNERS b/core/java/com/android/internal/content/om/OWNERS
new file mode 100644
index 0000000..44fd9fd
--- /dev/null
+++ b/core/java/com/android/internal/content/om/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 568631
+include /core/java/android/content/om/OWNERS
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 0c91c5d..0ab2a90 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -933,11 +933,10 @@
         private final int mProcessSource;
 
         public SettingsObserver(Context context, BinderCallsStats binderCallsStats,
-                    int processSource, int userHandle) {
+                    int processSource) {
             super(BackgroundThread.getHandler());
             mContext = context;
-            context.getContentResolver().registerContentObserver(mUri, false, this,
-                    userHandle);
+            context.getContentResolver().registerContentObserver(mUri, false, this);
             mBinderCallsStats = binderCallsStats;
             mProcessSource = processSource;
             // Always kick once to ensure that we match current state
diff --git a/core/java/com/android/internal/os/BinderDeathDispatcher.java b/core/java/com/android/internal/os/BinderDeathDispatcher.java
index 038707e..0c93f7f 100644
--- a/core/java/com/android/internal/os/BinderDeathDispatcher.java
+++ b/core/java/com/android/internal/os/BinderDeathDispatcher.java
@@ -63,10 +63,6 @@
 
         @Override
         public void binderDied() {
-        }
-
-        @Override
-        public void binderDied(IBinder who) {
             final ArraySet<DeathRecipient> copy;
             synchronized (mLock) {
                 copy = mRecipients;
@@ -81,7 +77,7 @@
             // Let's call it without holding the lock.
             final int size = copy.size();
             for (int i = 0; i < size; i++) {
-                copy.valueAt(i).binderDied(who);
+                copy.valueAt(i).binderDied();
             }
         }
     }
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index fdc3a9ee..f44b9fb 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -1,16 +1,6 @@
 {
   "presubmit": [
     {
-      "file_patterns": [
-        "BinderDeathDispatcher\\.java"
-      ],
-      "name": "FrameworksCoreTests",
-      "options": [
-        { "include-filter": "com.android.internal.os.BinderDeathDispatcherTest" },
-        { "exclude-annotation": "com.android.internal.os.SkipPresubmit" }
-      ]
-    },
-    {
       "name": "FrameworksCoreTests",
       "options": [
         {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 382acc0..b236385 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -227,6 +227,7 @@
             shared_libs: [
                 "android.hardware.memtrack-V1-ndk_platform",
                 "libandroidicu",
+                "libandroid_net",
                 "libbpf_android",
                 "libnetdbpf",
                 "libnetdutils",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 96fc086..6ac43bd3 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -93,10 +93,6 @@
 
 #include "nativebridge/native_bridge.h"
 
-#if defined(__BIONIC__)
-extern "C" void android_reset_stack_guards();
-#endif
-
 namespace {
 
 // TODO (chriswailes): Add a function to initialize native Zygote data.
@@ -393,7 +389,6 @@
 }
 
 // This signal handler is for zygote mode, since the zygote must reap its children
-NO_STACK_PROTECTOR
 static void SigChldHandler(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
     pid_t pid;
     int status;
@@ -1970,7 +1965,6 @@
 }
 
 // Utility routine to fork a process from the zygote.
-NO_STACK_PROTECTOR
 pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
                          const std::vector<int>& fds_to_close,
                          const std::vector<int>& fds_to_ignore,
@@ -2024,11 +2018,6 @@
       setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
     }
 
-#if defined(__BIONIC__)
-    // Reset the stack guard for the new process.
-    android_reset_stack_guards();
-#endif
-
     // The child process.
     PreApplicationInit();
 
@@ -2061,7 +2050,6 @@
   PreApplicationInit();
 }
 
-NO_STACK_PROTECTOR
 static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
         JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
         jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
@@ -2111,7 +2099,6 @@
     return pid;
 }
 
-NO_STACK_PROTECTOR
 static jint com_android_internal_os_Zygote_nativeForkSystemServer(
         JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
@@ -2183,7 +2170,6 @@
  * @param is_priority_fork  Controls the nice level assigned to the newly created process
  * @return child pid in the parent, 0 in the child
  */
-NO_STACK_PROTECTOR
 static jint com_android_internal_os_Zygote_nativeForkApp(JNIEnv* env,
                                                          jclass,
                                                          jint read_pipe_fd,
@@ -2198,7 +2184,6 @@
                             args_known == JNI_TRUE, is_priority_fork == JNI_TRUE, true);
 }
 
-NO_STACK_PROTECTOR
 int zygote::forkApp(JNIEnv* env,
                     int read_pipe_fd,
                     int write_pipe_fd,
diff --git a/core/jni/com_android_internal_os_Zygote.h b/core/jni/com_android_internal_os_Zygote.h
index 15f53e0..b87396c 100644
--- a/core/jni/com_android_internal_os_Zygote.h
+++ b/core/jni/com_android_internal_os_Zygote.h
@@ -20,14 +20,6 @@
 #define LOG_TAG "Zygote"
 #define ATRACE_TAG ATRACE_TAG_DALVIK
 
-/*
- * All functions that lead to ForkCommon must be marked with the
- * no_stack_protector attributed.  Because ForkCommon changes the stack
- * protector cookie, all of the guard checks on the frames above ForkCommon
- * would fail when they are popped.
- */
-#define NO_STACK_PROTECTOR __attribute__((no_stack_protector))
-
 #include <jni.h>
 #include <vector>
 #include <android-base/stringprintf.h>
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 1b4b9bd..5fe96ed 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -365,7 +365,6 @@
 // We only process fork commands if the peer uid matches expected_uid.
 // For every fork command after the first, we check that the requested uid is at
 // least minUid.
-NO_STACK_PROTECTOR
 jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
             JNIEnv* env,
             jclass,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4a57448..8db1bbf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -575,8 +575,6 @@
 
     <protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
 
-    <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
-
     <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
     <protected-broadcast android:name="android.accounts.action.ACCOUNT_REMOVED" />
     <protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 2650d9f..2be5c47 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -245,6 +245,9 @@
     <!-- Slovakia: 4 digits (premium), plus EU: http://www.cmtelecom.com/premium-sms/slovakia -->
     <shortcode country="sk" premium="\\d{4}" free="116\\d{3}|8000" />
 
+    <!-- Taiwan -->
+    <shortcode country="tw" pattern="\\d{4}" free="1922" />
+
     <!-- Thailand: 4186001 used by AIS_TH_DCB -->
     <shortcode country="th" pattern="\\d{1,5}" premium="4\\d{6}" free="4186001" />
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index 8310333..942045c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -17,7 +17,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
@@ -32,14 +31,14 @@
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.FileDescriptor;
 
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BinderDeathDispatcherTest {
@@ -121,7 +120,7 @@
         public void die() {
             isAlive = false;
             if (mRecipient != null) {
-                mRecipient.binderDied(this);
+                mRecipient.binderDied();
             }
             mRecipient = null;
         }
@@ -228,33 +227,33 @@
         // Kill the targets.
 
         t1.die();
-        verify(r1, times(1)).binderDied(t1);
-        verify(r2, times(1)).binderDied(t1);
-        verify(r3, times(1)).binderDied(t1);
-        verify(r4, times(0)).binderDied(any());
-        verify(r5, times(0)).binderDied(any());
+        verify(r1, times(1)).binderDied();
+        verify(r2, times(1)).binderDied();
+        verify(r3, times(1)).binderDied();
+        verify(r4, times(0)).binderDied();
+        verify(r5, times(0)).binderDied();
 
         assertThat(d.getTargetsForTest().size()).isEqualTo(2);
 
         reset(r1, r2, r3, r4, r5);
 
         t2.die();
-        verify(r1, times(1)).binderDied(t2);
-        verify(r2, times(0)).binderDied(any());
-        verify(r3, times(0)).binderDied(any());
-        verify(r4, times(0)).binderDied(any());
-        verify(r5, times(0)).binderDied(any());
+        verify(r1, times(1)).binderDied();
+        verify(r2, times(0)).binderDied();
+        verify(r3, times(0)).binderDied();
+        verify(r4, times(0)).binderDied();
+        verify(r5, times(0)).binderDied();
 
         assertThat(d.getTargetsForTest().size()).isEqualTo(1);
 
         reset(r1, r2, r3, r4, r5);
 
         t3.die();
-        verify(r1, times(0)).binderDied(any());
-        verify(r2, times(0)).binderDied(any());
-        verify(r3, times(1)).binderDied(t3);
-        verify(r4, times(0)).binderDied(any());
-        verify(r5, times(1)).binderDied(t3);
+        verify(r1, times(0)).binderDied();
+        verify(r2, times(0)).binderDied();
+        verify(r3, times(1)).binderDied();
+        verify(r4, times(0)).binderDied();
+        verify(r5, times(1)).binderDied();
 
         assertThat(d.getTargetsForTest().size()).isEqualTo(0);
 
@@ -263,27 +262,4 @@
 
         assertThat(d.getTargetsForTest().size()).isEqualTo(0);
     }
-
-    @Test
-    public void duplicateRegistrations() {
-        BinderDeathDispatcher<MyTarget> d = new BinderDeathDispatcher<>();
-
-        MyTarget t1 = new MyTarget();
-
-        DeathRecipient r1 = mock(DeathRecipient.class);
-        DeathRecipient r2 = mock(DeathRecipient.class);
-
-        for (int i = 0; i < 5; i++) {
-            assertThat(d.linkToDeath(t1, r1)).isEqualTo(1);
-        }
-        assertThat(d.linkToDeath(t1, r2)).isEqualTo(2);
-
-        t1.die();
-        verify(r1, times(1)).binderDied(t1);
-        verify(r2, times(1)).binderDied(t1);
-
-        d.unlinkToDeath(t1, r1);
-        d.unlinkToDeath(t1, r2);
-        assertThat(d.getTargetsForTest()).isEmpty();
-    }
 }
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index d0e2474..e7c8f9d 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -119,6 +119,20 @@
 }
 
 prebuilt_etc {
+    name: "privapp_whitelist_com.android.networkstack",
+    sub_dir: "permissions",
+    src: "com.android.networkstack.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
+    name: "privapp_whitelist_com.android.networkstack.tethering",
+    sub_dir: "permissions",
+    src: "com.android.networkstack.tethering.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "privapp_whitelist_com.android.provision",
     system_ext_specific: true,
     sub_dir: "permissions",
diff --git a/data/etc/com.android.networkstack.tethering.xml b/data/etc/com.android.networkstack.tethering.xml
new file mode 100644
index 0000000..f26a961
--- /dev/null
+++ b/data/etc/com.android.networkstack.tethering.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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
+-->
+
+<permissions>
+    <privapp-permissions package="com.android.networkstack.tethering">
+        <permission name="android.permission.BLUETOOTH_PRIVILEGED" />
+        <permission name="android.permission.MANAGE_USB"/>
+        <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+        <permission name="android.permission.TETHER_PRIVILEGED"/>
+        <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+        <permission name="android.permission.UPDATE_DEVICE_STATS"/>
+      </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.networkstack.xml b/data/etc/com.android.networkstack.xml
new file mode 100644
index 0000000..06fec1c
--- /dev/null
+++ b/data/etc/com.android.networkstack.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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
+-->
+
+<permissions>
+    <privapp-permissions package="com.android.networkstack">
+        <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
+        <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+        <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
+        <permission name="android.permission.CONTROL_VPN"/>
+        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
+        <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/>
+        <permission name="android.permission.MANAGE_USB"/>
+        <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
+        <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
+        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+        <permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+        <permission name="android.permission.READ_WIFI_CREDENTIAL"/>
+        <permission name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"/>
+        <permission name="android.permission.TETHER_PRIVILEGED"/>
+        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+    </privapp-permissions>
+</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ee2387b..4731a8e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -254,36 +254,6 @@
         <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.networkstack">
-        <permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
-        <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
-        <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
-        <permission name="android.permission.CONTROL_VPN"/>
-        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
-        <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
-        <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/>
-        <permission name="android.permission.MANAGE_USB"/>
-        <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
-        <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
-        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
-        <permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
-        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
-        <permission name="android.permission.READ_WIFI_CREDENTIAL"/>
-        <permission name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"/>
-        <permission name="android.permission.TETHER_PRIVILEGED"/>
-        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
-    </privapp-permissions>
-
-    <privapp-permissions package="com.android.networkstack.tethering">
-        <permission name="android.permission.BLUETOOTH_PRIVILEGED" />
-        <permission name="android.permission.MANAGE_USB"/>
-        <permission name="android.permission.MODIFY_PHONE_STATE"/>
-        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
-        <permission name="android.permission.TETHER_PRIVILEGED"/>
-        <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
-        <permission name="android.permission.UPDATE_DEVICE_STATS"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.server.telecom">
         <permission name="android.permission.BIND_CONNECTION_SERVICE"/>
         <permission name="android.permission.BIND_INCALL_SERVICE"/>
@@ -472,6 +442,9 @@
         <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
         <!-- Permission required for CTS test - CtsAlarmManagerTestCases -->
         <permission name="android.permission.UPDATE_DEVICE_STATS" />
+        <!-- Permission required for hotword detection service CTS tests -->
+        <permission name="android.permission.MANAGE_HOTWORD_DETECTION" />
+        <permission name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/framework-jarjar-rules.txt b/framework-jarjar-rules.txt
index 52ee63a..be21f4e 100644
--- a/framework-jarjar-rules.txt
+++ b/framework-jarjar-rules.txt
@@ -1,3 +1,7 @@
+# This rule is meant to be reused across libraries in the bootclasspath that depend
+# on the HIDL libraries.
 rule android.hidl.** android.internal.hidl.@1
+
+# Framework-specific renames.
 rule android.net.wifi.WifiAnnotations* android.internal.wifi.WifiAnnotations@1
 rule com.android.server.vcn.util.** com.android.server.vcn.repackaged.util.@1
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 49ef504..f7b0fb5 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -3094,7 +3094,7 @@
         r = iFilterSp->setDataSource(NULL);
     } else {
         sp<IFilter> srcSp = getFilter(env, srcFilter)->getIFilter();
-        if (iFilterSp == NULL) {
+        if (srcSp == NULL) {
             ALOGD("Failed to set filter data source: src filter not found");
             return (jint) Result::INVALID_ARGUMENT;
         }
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index d56aa86..919fd81 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -274,6 +274,7 @@
     ATrace_endAsyncSection; # introduced=29
     ATrace_setCounter; # introduced=29
     android_getaddrinfofornetwork; # introduced=23
+    android_getprocnetwork; # introduced=31
     android_setprocnetwork; # introduced=23
     android_setsocknetwork; # introduced=23
     android_res_cancel; # introduced=29
diff --git a/native/android/libandroid_net.map.txt b/native/android/libandroid_net.map.txt
index 8d4e900..cc8dd72 100644
--- a/native/android/libandroid_net.map.txt
+++ b/native/android/libandroid_net.map.txt
@@ -14,6 +14,8 @@
     android_res_nquery; # llndk
     android_res_nresult; # llndk
     android_res_nsend; # llndk
+    # These functions have been part of the NDK since API 31.
+    android_getprocnetwork; # llndk
   local:
     *;
 };
diff --git a/native/android/net.c b/native/android/net.c
index a8104fc..d4b8888 100644
--- a/native/android/net.c
+++ b/native/android/net.c
@@ -22,12 +22,13 @@
 #include <stdlib.h>
 #include <sys/limits.h>
 
+// This value MUST be kept in sync with the corresponding value in
+// the android.net.Network#getNetworkHandle() implementation.
+static const uint32_t kHandleMagic = 0xcafed00d;
+static const uint32_t kHandleMagicSize = 32;
 
 static int getnetidfromhandle(net_handle_t handle, unsigned *netid) {
     static const uint32_t k32BitMask = 0xffffffff;
-    // This value MUST be kept in sync with the corresponding value in
-    // the android.net.Network#getNetworkHandle() implementation.
-    static const uint32_t kHandleMagic = 0xcafed00d;
 
     // Check for minimum acceptable version of the API in the low bits.
     if (handle != NETWORK_UNSPECIFIED &&
@@ -41,6 +42,12 @@
     return 1;
 }
 
+static net_handle_t gethandlefromnetid(unsigned netid) {
+    if (netid == NETID_UNSET) {
+        return NETWORK_UNSPECIFIED;
+    }
+    return (((net_handle_t) netid) << kHandleMagicSize) | kHandleMagic;
+}
 
 int android_setsocknetwork(net_handle_t network, int fd) {
     unsigned netid;
@@ -72,6 +79,17 @@
     return rval;
 }
 
+int android_getprocnetwork(net_handle_t *network) {
+    if (network == NULL) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    unsigned netid = getNetworkForProcess();
+    *network = gethandlefromnetid(netid);
+    return 0;
+}
+
 int android_getaddrinfofornetwork(net_handle_t network,
         const char *node, const char *service,
         const struct addrinfo *hints, struct addrinfo **res) {
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index 784a747..bb6dfa3 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index 5b7bda4..2835d57 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index 784a747..bb6dfa3 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 780cb8a..2e1a789 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
index b1234f2..51e533a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
@@ -73,6 +73,7 @@
 
     private static NetworkTemplate getMobileTemplateForSubId(
             TelephonyManager telephonyManager, int subId) {
-        return NetworkTemplate.buildTemplateMobileAll(telephonyManager.getSubscriberId(subId));
+        return NetworkTemplate.buildTemplateCarrierMetered(
+                telephonyManager.getSubscriberId(subId));
     }
 }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java
index 37f2600..7e389a1 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/NetworkPolicyEditorTest.java
@@ -44,7 +44,7 @@
 
     @Before
     public void setUp() {
-        mNetworkTemplate = NetworkTemplate.buildTemplateMobileAll("123456789123456");
+        mNetworkTemplate = NetworkTemplate.buildTemplateCarrierMetered("123456789123456");
         NetworkPolicyManager policyManager = NetworkPolicyManager.from(InstrumentationRegistry
                 .getContext());
         mNetworkPolicyEditor = new NetworkPolicyEditor(policyManager);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
index 27d877d..9be783d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageControllerTest.java
@@ -87,8 +87,8 @@
         ShadowSubscriptionManager.setDefaultDataSubscriptionId(mDefaultSubscriptionId);
         doReturn(SUB_ID).when(mTelephonyManager).getSubscriberId();
 
-        mNetworkTemplate = NetworkTemplate.buildTemplateMobileAll(SUB_ID);
-        mNetworkTemplate2 = NetworkTemplate.buildTemplateMobileAll(SUB_ID_2);
+        mNetworkTemplate = NetworkTemplate.buildTemplateCarrierMetered(SUB_ID);
+        mNetworkTemplate2 = NetworkTemplate.buildTemplateCarrierMetered(SUB_ID_2);
         mWifiNetworkTemplate = NetworkTemplate.buildTemplateWifi(
                 NetworkTemplate.WIFI_NETWORKID_ALL, null);
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java
index 877eb61..e8d5844 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/NetworkCycleDataForUidLoaderTest.java
@@ -62,7 +62,7 @@
         when(mContext.getSystemService(Context.NETWORK_POLICY_SERVICE))
                 .thenReturn(mNetworkPolicyManager);
         when(mNetworkPolicyManager.getNetworkPolicies()).thenReturn(new NetworkPolicy[0]);
-        mNetworkTemplate = NetworkTemplate.buildTemplateMobileAll(SUB_ID);
+        mNetworkTemplate = NetworkTemplate.buildTemplateCarrierMetered(SUB_ID);
     }
 
     @Test
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 133a839..af995f9 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -471,6 +471,10 @@
     <!-- Permission required for CTS test - GlobalSearchSessionPlatformCtsTests -->
     <uses-permission android:name="android.permission.READ_GLOBAL_APP_SEARCH_DATA" />
 
+    <!-- Permission required for hotword detection service CTS tests -->
+    <uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
+    <uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index 8472b1b..4a5d142 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -39,6 +39,7 @@
 import android.content.res.Resources;
 import android.hardware.SensorManager;
 import android.hardware.SensorPrivacyManager;
+import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.DisplayManager;
 import android.media.AudioManager;
 import android.media.MediaRouter2Manager;
@@ -107,6 +108,12 @@
 
     @Provides
     @Singleton
+    static ColorDisplayManager provideColorDisplayManager(Context context) {
+        return context.getSystemService(ColorDisplayManager.class);
+    }
+
+    @Provides
+    @Singleton
     static ConnectivityManager provideConnectivityManagager(Context context) {
         return context.getSystemService(ConnectivityManager.class);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index 1e8c4d8..290ab85 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -20,7 +20,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.external.TileServices;
-import com.android.systemui.qs.logging.QSLogger;
 
 import java.util.Collection;
 
@@ -31,7 +30,6 @@
     void openPanels();
     Context getContext();
     Context getUserContext();
-    QSLogger getQSLogger();
     UiEventLogger getUiEventLogger();
     Collection<QSTile> getTiles();
     void addCallback(Callback callback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 1f3967c..3b16a4e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -179,10 +179,6 @@
         onTuningChanged(TILES_SETTING, value);
     }
 
-    public QSLogger getQSLogger() {
-        return mQSLogger;
-    }
-
     @Override
     public UiEventLogger getUiEventLogger() {
         return mUiEventLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 30e0a76..19c7b6ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -29,7 +29,9 @@
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.service.quicksettings.IQSTileService;
@@ -42,16 +44,27 @@
 import android.view.WindowManagerGlobal;
 import android.widget.Switch;
 
+import androidx.annotation.NonNull;
+
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
 import java.util.Objects;
 
+import javax.inject.Inject;
+
+import dagger.Lazy;
+
 public class CustomTile extends QSTileImpl<State> implements TileChangeListener {
     public static final String PREFIX = "custom(";
 
@@ -79,8 +92,19 @@
     private boolean mIsTokenGranted;
     private boolean mIsShowingDialog;
 
-    private CustomTile(QSHost host, String action, Context userContext) {
-        super(host);
+    private CustomTile(
+            QSHost host,
+            Looper backgroundLooper,
+            Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            String action,
+            Context userContext
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
         mComponent = ComponentName.unflattenFromString(action);
         mTile = new Tile();
@@ -397,7 +421,7 @@
         return ComponentName.unflattenFromString(action);
     }
 
-    public static CustomTile create(QSHost host, String spec, Context userContext) {
+    private static String getAction(String spec) {
         if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) {
             throw new IllegalArgumentException("Bad custom tile spec: " + spec);
         }
@@ -405,6 +429,81 @@
         if (action.isEmpty()) {
             throw new IllegalArgumentException("Empty custom tile spec action");
         }
-        return new CustomTile(host, action, userContext);
+        return action;
+    }
+
+    /**
+     * Create a {@link CustomTile} for a given spec and user.
+     *
+     * @param builder including injected common dependencies.
+     * @param spec as provided by {@link CustomTile#toSpec}
+     * @param userContext context for the user that is creating this tile.
+     * @return a new {@link CustomTile}
+     */
+    public static CustomTile create(Builder builder, String spec, Context userContext) {
+        return builder
+                .setSpec(spec)
+                .setUserContext(userContext)
+                .build();
+    }
+
+    public static class Builder {
+        final Lazy<QSHost> mQSHostLazy;
+        final Looper mBackgroundLooper;
+        final Handler mMainHandler;
+        final MetricsLogger mMetricsLogger;
+        final StatusBarStateController mStatusBarStateController;
+        final ActivityStarter mActivityStarter;
+        final QSLogger mQSLogger;
+
+        Context mUserContext;
+        String mSpec = "";
+
+        @Inject
+        public Builder(
+                Lazy<QSHost> hostLazy,
+                @Background Looper backgroundLooper,
+                @Main Handler mainHandler,
+                MetricsLogger metricsLogger,
+                StatusBarStateController statusBarStateController,
+                ActivityStarter activityStarter,
+                QSLogger qsLogger
+        ) {
+            mQSHostLazy = hostLazy;
+            mBackgroundLooper = backgroundLooper;
+            mMainHandler = mainHandler;
+            mMetricsLogger = metricsLogger;
+            mStatusBarStateController = statusBarStateController;
+            mActivityStarter = activityStarter;
+            mQSLogger = qsLogger;
+        }
+
+        Builder setSpec(@NonNull String spec) {
+            mSpec = spec;
+            return this;
+        }
+
+        Builder setUserContext(@NonNull Context userContext) {
+            mUserContext = userContext;
+            return this;
+        }
+
+        CustomTile build() {
+            if (mUserContext == null) {
+                throw new NullPointerException("UserContext cannot be null");
+            }
+            String action = getAction(mSpec);
+            return new CustomTile(
+                    mQSHostLazy.get(),
+                    mBackgroundLooper,
+                    mMainHandler,
+                    mMetricsLogger,
+                    mStatusBarStateController,
+                    mActivityStarter,
+                    mQSLogger,
+                    action,
+                    mUserContext
+            );
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index c182a58..69a6fe1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -80,9 +80,12 @@
     private final Provider<ScreenRecordTile> mScreenRecordTileProvider;
 
     private final Lazy<QSHost> mQsHostLazy;
+    private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
 
     @Inject
-    public QSFactoryImpl(Lazy<QSHost> qsHostLazy,
+    public QSFactoryImpl(
+            Lazy<QSHost> qsHostLazy,
+            Provider<CustomTile.Builder> customTileBuilderProvider,
             Provider<WifiTile> wifiTileProvider,
             Provider<BluetoothTile> bluetoothTileProvider,
             Provider<CellularTile> cellularTileProvider,
@@ -104,6 +107,8 @@
             Provider<UiModeNightTile> uiModeNightTileProvider,
             Provider<ScreenRecordTile> screenRecordTileProvider) {
         mQsHostLazy = qsHostLazy;
+        mCustomTileBuilderProvider = customTileBuilderProvider;
+
         mWifiTileProvider = wifiTileProvider;
         mBluetoothTileProvider = bluetoothTileProvider;
         mCellularTileProvider = cellularTileProvider;
@@ -179,8 +184,8 @@
 
         // Custom tiles
         if (tileSpec.startsWith(CustomTile.PREFIX)) {
-            return CustomTile.create(mQsHostLazy.get(), tileSpec,
-                    mQsHostLazy.get().getUserContext());
+            return CustomTile.create(
+                    mCustomTileBuilderProvider.get(), tileSpec, mQsHostLazy.get().getUserContext());
         }
 
         // Debug tiles.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 795d062..255513a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.qs.tileimpl;
 
+import static androidx.lifecycle.Lifecycle.State.CREATED;
+import static androidx.lifecycle.Lifecycle.State.DESTROYED;
 import static androidx.lifecycle.Lifecycle.State.RESUMED;
 import static androidx.lifecycle.Lifecycle.State.STARTED;
 
@@ -54,7 +56,6 @@
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.Prefs;
 import com.android.systemui.plugins.ActivityStarter;
@@ -92,12 +93,12 @@
     protected final QSHost mHost;
     protected final Context mContext;
     // @NonFinalForTesting
-    protected H mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
-    protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
+    protected final H mHandler;
+    protected final Handler mUiHandler;
     private final ArraySet<Object> mListeners = new ArraySet<>();
-    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
-    private final StatusBarStateController
-            mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+    private final MetricsLogger mMetricsLogger;
+    private final StatusBarStateController mStatusBarStateController;
+    protected final ActivityStarter mActivityStarter;
     private final UiEventLogger mUiEventLogger;
     private final QSLogger mQSLogger;
 
@@ -150,14 +151,30 @@
      */
     abstract public int getMetricsCategory();
 
-    protected QSTileImpl(QSHost host) {
+    protected QSTileImpl(
+            QSHost host,
+            Looper backgroundLooper,
+            Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger
+    ) {
         mHost = host;
         mContext = host.getContext();
         mInstanceId = host.getNewInstanceId();
+        mUiEventLogger = host.getUiEventLogger();
+
+        mUiHandler = mainHandler;
+        mHandler = new H(backgroundLooper);
+        mQSLogger = qsLogger;
+        mMetricsLogger = metricsLogger;
+        mStatusBarStateController = statusBarStateController;
+        mActivityStarter = activityStarter;
+
         mState = newTileState();
         mTmpState = newTileState();
-        mQSLogger = host.getQSLogger();
-        mUiEventLogger = host.getUiEventLogger();
+        mUiHandler.post(() -> mLifecycle.setCurrentState(CREATED));
     }
 
     protected final void resetStates() {
@@ -357,8 +374,7 @@
      * {@link QSTileImpl#getLongClickIntent}
      */
     protected void handleLongClick() {
-        Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
-                getLongClickIntent(), 0);
+        mActivityStarter.postStartActivityDismissingKeyguard(getLongClickIntent(), 0);
     }
 
     /**
@@ -437,15 +453,24 @@
         if (listening) {
             if (mListeners.add(listener) && mListeners.size() == 1) {
                 if (DEBUG) Log.d(TAG, "handleSetListening true");
-                mLifecycle.setCurrentState(RESUMED);
                 handleSetListening(listening);
-                refreshState(); // Ensure we get at least one refresh after listening.
+                mUiHandler.post(() -> {
+                    // This tile has been destroyed, the state should not change anymore and we
+                    // should not refresh it anymore.
+                    if (mLifecycle.getCurrentState().equals(DESTROYED)) return;
+                    mLifecycle.setCurrentState(RESUMED);
+                    refreshState(); // Ensure we get at least one refresh after listening.
+                });
             }
         } else {
             if (mListeners.remove(listener) && mListeners.size() == 0) {
                 if (DEBUG) Log.d(TAG, "handleSetListening false");
-                mLifecycle.setCurrentState(STARTED);
                 handleSetListening(listening);
+                mUiHandler.post(() -> {
+                    // This tile has been destroyed, the state should not change anymore.
+                    if (mLifecycle.getCurrentState().equals(DESTROYED)) return;
+                    mLifecycle.setCurrentState(STARTED);
+                });
             }
         }
         updateIsFullQs();
@@ -472,9 +497,14 @@
         mQSLogger.logTileDestroyed(mTileSpec, "Handle destroy");
         if (mListeners.size() != 0) {
             handleSetListening(false);
+            mListeners.clear();
         }
         mCallbacks.clear();
         mHandler.removeCallbacksAndMessages(null);
+        // This will force it to be removed from all controllers that may have it registered.
+        mUiHandler.post(() -> {
+            mLifecycle.setCurrentState(DESTROYED);
+        });
     }
 
     protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
@@ -530,7 +560,8 @@
         private static final int REMOVE_CALLBACKS = 11;
         private static final int REMOVE_CALLBACK = 12;
         private static final int SET_LISTENING = 13;
-        private static final int STALE = 14;
+        @VisibleForTesting
+        protected static final int STALE = 14;
 
         @VisibleForTesting
         protected H(Looper looper) {
@@ -555,8 +586,7 @@
                     if (mState.disabledByPolicy) {
                         Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
                                 mContext, mEnforcedAdmin);
-                        Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
-                                intent, 0);
+                        mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
                     } else {
                         handleClick();
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index b24fdbf..b848590 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -21,6 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
@@ -33,33 +35,50 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
 import javax.inject.Inject;
 
+import dagger.Lazy;
+
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTileImpl<BooleanState> {
     private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_airplane);
     private final GlobalSetting mSetting;
-    private final ActivityStarter mActivityStarter;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final Lazy<ConnectivityManager> mLazyConnectivityManager;
 
     private boolean mListening;
 
     @Inject
-    public AirplaneModeTile(QSHost host, ActivityStarter activityStarter,
-            BroadcastDispatcher broadcastDispatcher) {
-        super(host);
-        mActivityStarter = activityStarter;
+    public AirplaneModeTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            BroadcastDispatcher broadcastDispatcher,
+            Lazy<ConnectivityManager> lazyConnectivityManager
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mBroadcastDispatcher = broadcastDispatcher;
+        mLazyConnectivityManager = lazyConnectivityManager;
 
         mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
             @Override
             protected void handleValueChanged(int value) {
+                // mHandler is the background handler so calling this is OK
                 handleRefreshState(value);
             }
         };
@@ -83,9 +102,7 @@
     }
 
     private void setEnabled(boolean enabled) {
-        final ConnectivityManager mgr =
-                (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mgr.setAirplaneMode(enabled);
+        mLazyConnectivityManager.get().setAirplaneMode(enabled);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 7150e43..c64fc50 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -16,16 +16,24 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings.Secure;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.BatteryController;
 
@@ -46,8 +54,18 @@
     private Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_battery_saver);
 
     @Inject
-    public BatterySaverTile(QSHost host, BatteryController batteryController) {
-        super(host);
+    public BatterySaverTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            BatteryController batteryController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mBatteryController = batteryController;
         mBatteryController.observe(getLifecycle(), this);
         int currentUser = host.getUserContext().getUserId();
@@ -55,6 +73,7 @@
                 currentUser) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
+                // mHandler is the background handler so calling this is OK
                 handleRefreshState(null);
             }
         };
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 888c7ab..56083c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -24,6 +24,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
@@ -37,12 +39,16 @@
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.BluetoothController;
 
@@ -58,15 +64,21 @@
 
     private final BluetoothController mController;
     private final BluetoothDetailAdapter mDetailAdapter;
-    private final ActivityStarter mActivityStarter;
 
     @Inject
-    public BluetoothTile(QSHost host,
-            BluetoothController bluetoothController,
-            ActivityStarter activityStarter) {
-        super(host);
+    public BluetoothTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            BluetoothController bluetoothController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mController = bluetoothController;
-        mActivityStarter = activityStarter;
         mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter();
         mController.observe(getLifecycle(), mCallback);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 4b53ae2..56b939d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -22,6 +22,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.MediaRouter.RouteInfo;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.util.Log;
@@ -35,12 +37,16 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.CastController;
@@ -64,20 +70,28 @@
     private final KeyguardStateController mKeyguard;
     private final NetworkController mNetworkController;
     private final Callback mCallback = new Callback();
-    private final ActivityStarter mActivityStarter;
     private Dialog mDialog;
     private boolean mWifiConnected;
 
     @Inject
-    public CastTile(QSHost host, CastController castController,
-            KeyguardStateController keyguardStateController, NetworkController networkController,
-            ActivityStarter activityStarter) {
-        super(host);
+    public CastTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            CastController castController,
+            KeyguardStateController keyguardStateController,
+            NetworkController networkController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mController = castController;
         mDetailAdapter = new CastDetailAdapter();
         mKeyguard = keyguardStateController;
         mNetworkController = networkController;
-        mActivityStarter = activityStarter;
         mController.observe(this, mCallback);
         mKeyguard.observe(this, mCallback);
         mNetworkController.observe(this, mSignalCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 33e98d8..f742752 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -23,6 +23,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
@@ -40,12 +42,16 @@
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.NetworkController;
@@ -63,14 +69,21 @@
     private final CellularDetailAdapter mDetailAdapter;
 
     private final CellSignalCallback mSignalCallback = new CellSignalCallback();
-    private final ActivityStarter mActivityStarter;
 
     @Inject
-    public CellularTile(QSHost host, NetworkController networkController,
-            ActivityStarter activityStarter) {
-        super(host);
+    public CellularTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            NetworkController networkController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mController = networkController;
-        mActivityStarter = activityStarter;
         mDataController = mController.getMobileDataController();
         mDetailAdapter = new CellularDetailAdapter();
         mController.observe(getLifecycle(), mSignalCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 9c0030d..131e285 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -17,17 +17,25 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.R.drawable;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
 import javax.inject.Inject;
@@ -41,13 +49,23 @@
     private boolean mListening;
 
     @Inject
-    public ColorInversionTile(QSHost host) {
-        super(host);
+    public ColorInversionTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
 
-        mSetting = new SecureSetting(mContext, mHandler,
+        mSetting = new SecureSetting(mContext, mainHandler,
                 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
+                // mHandler is the background handler so calling this is OK
                 handleRefreshState(value);
             }
         };
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 7ae8fbc..85f1245 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -16,19 +16,26 @@
 
 import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.systemui.statusbar.policy.NetworkController;
 
 import javax.inject.Inject;
 
@@ -38,9 +45,19 @@
     private final DataSaverController mDataSaverController;
 
     @Inject
-    public DataSaverTile(QSHost host, NetworkController networkController) {
-        super(host);
-        mDataSaverController = networkController.getDataSaverController();
+    public DataSaverTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            DataSaverController dataSaverController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
+        mDataSaverController = dataSaverController;
         mDataSaverController.observe(getLifecycle(), this);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 9f7b84a..ec8b143 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -30,6 +30,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
@@ -53,11 +55,14 @@
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -79,7 +84,6 @@
 
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
-    private final ActivityStarter mActivityStarter;
     private final SharedPreferences mSharedPreferences;
     private final BroadcastDispatcher mBroadcastDispatcher;
 
@@ -88,12 +92,21 @@
     private boolean mReceiverRegistered;
 
     @Inject
-    public DndTile(QSHost host, ZenModeController zenModeController,
-            ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher,
-            @Main SharedPreferences sharedPreferences) {
-        super(host);
+    public DndTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            ZenModeController zenModeController,
+            BroadcastDispatcher broadcastDispatcher,
+            @Main SharedPreferences sharedPreferences
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mController = zenModeController;
-        mActivityStarter = activityStarter;
         mSharedPreferences = sharedPreferences;
         mDetailAdapter = new DndDetailAdapter();
         mBroadcastDispatcher = broadcastDispatcher;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 27ccd7c..cd45082 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -18,14 +18,22 @@
 
 import android.app.ActivityManager;
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.MediaStore;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.FlashlightController;
 
@@ -39,8 +47,18 @@
     private final FlashlightController mFlashlightController;
 
     @Inject
-    public FlashlightTile(QSHost host, FlashlightController flashlightController) {
-        super(host);
+    public FlashlightTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            FlashlightController flashlightController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mFlashlightController = flashlightController;
         mFlashlightController.observe(getLifecycle(), this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 1ab77f3..a45d94a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -18,16 +18,24 @@
 
 import android.annotation.Nullable;
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.util.Log;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -45,9 +53,19 @@
     private boolean mListening;
 
     @Inject
-    public HotspotTile(QSHost host, HotspotController hotspotController,
-            DataSaverController dataSaverController) {
-        super(host);
+    public HotspotTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            HotspotController hotspotController,
+            DataSaverController dataSaverController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mHotspotController = hotspotController;
         mDataSaverController = dataSaverController;
         mHotspotController.observe(this, mCallbacks);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 02f364b..d502d06 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -17,16 +17,23 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -41,16 +48,24 @@
 
     private final LocationController mController;
     private final KeyguardStateController mKeyguard;
-    private final ActivityStarter mActivityStarter;
     private final Callback mCallback = new Callback();
 
     @Inject
-    public LocationTile(QSHost host, LocationController locationController,
-            KeyguardStateController keyguardStateController, ActivityStarter activityStarter) {
-        super(host);
+    public LocationTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            LocationController locationController,
+            KeyguardStateController keyguardStateController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mController = locationController;
         mKeyguard = keyguardStateController;
-        mActivityStarter = activityStarter;
         mController.observe(this, mCallback);
         mKeyguard.observe(this, mCallback);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 7da9135..fb281169 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -23,15 +23,23 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.nfc.NfcAdapter;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
 import javax.inject.Inject;
@@ -47,8 +55,18 @@
     private boolean mListening;
 
     @Inject
-    public NfcTile(QSHost host, BroadcastDispatcher broadcastDispatcher) {
-        super(host);
+    public NfcTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            BroadcastDispatcher broadcastDispatcher
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mBroadcastDispatcher = broadcastDispatcher;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index acd2846..f628f7b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -33,10 +33,16 @@
 
 import androidx.annotation.StringRes;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.LocationController;
 
@@ -66,11 +72,22 @@
     private boolean mIsListening;
 
     @Inject
-    public NightDisplayTile(QSHost host, LocationController locationController) {
-        super(host);
+    public NightDisplayTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            LocationController locationController,
+            ColorDisplayManager colorDisplayManager
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mLocationController = locationController;
-        mManager = mContext.getSystemService(ColorDisplayManager.class);
-        mListener = new NightDisplayListener(mContext, new Handler(Looper.myLooper()));
+        mManager = colorDisplayManager;
+        mListener = new NightDisplayListener(mContext, mainHandler);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 5dcb4e3..4bf27e2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -19,14 +19,22 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
@@ -40,8 +48,18 @@
     private final RotationLockController mController;
 
     @Inject
-    public RotationLockTile(QSHost host, RotationLockController rotationLockController) {
-        super(host);
+    public RotationLockTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            RotationLockController rotationLockController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mController = rotationLockController;
         mController.observe(this, mCallback);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index 0c34b27..d7a2975 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -17,15 +17,22 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.util.Log;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
@@ -44,9 +51,19 @@
     private Callback mCallback = new Callback();
 
     @Inject
-    public ScreenRecordTile(QSHost host, RecordingController controller,
-            KeyguardDismissUtil keyguardDismissUtil) {
-        super(host);
+    public ScreenRecordTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            RecordingController controller,
+            KeyguardDismissUtil keyguardDismissUtil
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mController = controller;
         mController.observe(this, mCallback);
         mKeyguardDismissUtil = keyguardDismissUtil;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index f777553..78975a47 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -19,15 +19,23 @@
 import android.app.UiModeManager;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -54,9 +62,20 @@
     private final BatteryController mBatteryController;
     private final LocationController mLocationController;
     @Inject
-    public UiModeNightTile(QSHost host, ConfigurationController configurationController,
-            BatteryController batteryController, LocationController locationController) {
-        super(host);
+    public UiModeNightTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            ConfigurationController configurationController,
+            BatteryController batteryController,
+            LocationController locationController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mBatteryController = batteryController;
         mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
         mLocationController = locationController;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index aab30d4..26adfdc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -18,14 +18,22 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.util.Pair;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -39,9 +47,19 @@
     private Pair<String, Drawable> mLastUpdate;
 
     @Inject
-    public UserTile(QSHost host, UserSwitcherController userSwitcherController,
-            UserInfoController userInfoController) {
-        super(host);
+    public UserTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            UserSwitcherController userSwitcherController,
+            UserInfoController userInfoController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mUserSwitcherController = userSwitcherController;
         mUserInfoController = userInfoController;
         mUserInfoController.observe(getLifecycle(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 1279d42..4d89dea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -20,6 +20,8 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
@@ -32,15 +34,19 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.AlphaControlledSignalTileView;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSIconViewImpl;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.NetworkController;
@@ -63,17 +69,24 @@
     private final QSTile.SignalState mStateBeforeClick = newTileState();
 
     protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
-    private final ActivityStarter mActivityStarter;
     private boolean mExpectDisabled;
 
     @Inject
-    public WifiTile(QSHost host, NetworkController networkController,
-            ActivityStarter activityStarter) {
-        super(host);
+    public WifiTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            NetworkController networkController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mController = networkController;
         mWifiController = mController.getAccessPointController();
         mDetailAdapter = (WifiDetailAdapter) createDetailAdapter();
-        mActivityStarter = activityStarter;
         mController.observe(getLifecycle(), mSignalCallback);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 318c0c4..5235b6d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -17,14 +17,22 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 
@@ -38,8 +46,18 @@
     private final ManagedProfileController mProfileController;
 
     @Inject
-    public WorkModeTile(QSHost host, ManagedProfileController managedProfileController) {
-        super(host);
+    public WorkModeTile(
+            QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            ManagedProfileController managedProfileController
+    ) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
         mProfileController = managedProfileController;
         mProfileController.observe(getLifecycle(), this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index b12224b..d1805af 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -44,13 +44,17 @@
 import android.util.Log;
 import android.util.LongSparseArray;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
 import java.io.FileDescriptor;
@@ -396,15 +400,23 @@
         public static final String TILE_SPEC = "dbg:mem";
 
         private final GarbageMonitor gm;
-        private final ActivityStarter mActivityStarter;
         private ProcessMemInfo pmi;
         private boolean dumpInProgress;
 
         @Inject
-        public MemoryTile(QSHost host, GarbageMonitor monitor, ActivityStarter starter) {
-            super(host);
+        public MemoryTile(
+                QSHost host,
+                @Background Looper backgroundLooper,
+                @Main Handler mainHandler,
+                MetricsLogger metricsLogger,
+                StatusBarStateController statusBarStateController,
+                ActivityStarter activityStarter,
+                QSLogger qsLogger,
+                GarbageMonitor monitor
+        ) {
+            super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                    activityStarter, qsLogger);
             gm = monitor;
-            mActivityStarter = starter;
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 5d4ef55..c8e1a74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -41,14 +41,17 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.CollectionUtils;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -75,7 +78,7 @@
 
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 public class QSTileHostTest extends SysuiTestCase {
 
     private static String MOCK_STATE_STRING = "MockState";
@@ -331,7 +334,15 @@
     private class TestTile extends QSTileImpl<QSTile.State> {
 
         protected TestTile(QSHost host) {
-            super(host);
+            super(
+                    host,
+                    mLooper.getLooper(),
+                    new Handler(mLooper.getLooper()),
+                    mock(MetricsLogger.class),
+                    mock(StatusBarStateController.class),
+                    mock(ActivityStarter.class),
+                    mQSLogger
+            );
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 953198c..3aa40de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -23,17 +23,23 @@
 import android.content.pm.ServiceInfo
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.Icon
+import android.os.Handler
 import android.service.quicksettings.IQSTileService
 import android.service.quicksettings.Tile
 import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
 import android.view.IWindowManager
-import androidx.test.runner.AndroidJUnit4
+import com.android.internal.logging.MetricsLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
-import junit.framework.Assert.assertFalse
-import junit.framework.Assert.assertTrue
+import com.android.systemui.qs.logging.QSLogger
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -46,7 +52,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 class CustomTileTest : SysuiTestCase() {
 
     companion object {
@@ -56,36 +63,53 @@
         val TILE_SPEC = CustomTile.toSpec(componentName)
     }
 
-    @Mock private lateinit var mTileHost: QSHost
-    @Mock private lateinit var mTileService: IQSTileService
-    @Mock private lateinit var mTileServices: TileServices
-    @Mock private lateinit var mTileServiceManager: TileServiceManager
-    @Mock private lateinit var mWindowService: IWindowManager
-    @Mock private lateinit var mPackageManager: PackageManager
-    @Mock private lateinit var mApplicationInfo: ApplicationInfo
-    @Mock private lateinit var mServiceInfo: ServiceInfo
+    @Mock private lateinit var tileHost: QSHost
+    @Mock private lateinit var metricsLogger: MetricsLogger
+    @Mock private lateinit var statusBarStateController: StatusBarStateController
+    @Mock private lateinit var activityStarter: ActivityStarter
+    @Mock private lateinit var qsLogger: QSLogger
+    @Mock private lateinit var tileService: IQSTileService
+    @Mock private lateinit var tileServices: TileServices
+    @Mock private lateinit var tileServiceManager: TileServiceManager
+    @Mock private lateinit var windowService: IWindowManager
+    @Mock private lateinit var packageManager: PackageManager
+    @Mock private lateinit var applicationInfo: ApplicationInfo
+    @Mock private lateinit var serviceInfo: ServiceInfo
 
     private lateinit var customTile: CustomTile
+    private lateinit var testableLooper: TestableLooper
+    private lateinit var customTileBuilder: CustomTile.Builder
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        testableLooper = TestableLooper.get(this)
 
-        mContext.addMockSystemService("window", mWindowService)
-        mContext.setMockPackageManager(mPackageManager)
-        `when`(mTileHost.tileServices).thenReturn(mTileServices)
-        `when`(mTileHost.context).thenReturn(mContext)
-        `when`(mTileServices.getTileWrapper(any(CustomTile::class.java)))
-                .thenReturn(mTileServiceManager)
-        `when`(mTileServiceManager.tileService).thenReturn(mTileService)
-        `when`(mPackageManager.getApplicationInfo(anyString(), anyInt()))
-                .thenReturn(mApplicationInfo)
+        mContext.addMockSystemService("window", windowService)
+        mContext.setMockPackageManager(packageManager)
+        `when`(tileHost.tileServices).thenReturn(tileServices)
+        `when`(tileHost.context).thenReturn(mContext)
+        `when`(tileServices.getTileWrapper(any(CustomTile::class.java)))
+                .thenReturn(tileServiceManager)
+        `when`(tileServiceManager.tileService).thenReturn(tileService)
+        `when`(packageManager.getApplicationInfo(anyString(), anyInt()))
+                .thenReturn(applicationInfo)
 
-        `when`(mPackageManager.getServiceInfo(any(ComponentName::class.java), anyInt()))
-                .thenReturn(mServiceInfo)
-        mServiceInfo.applicationInfo = mApplicationInfo
+        `when`(packageManager.getServiceInfo(any(ComponentName::class.java), anyInt()))
+                .thenReturn(serviceInfo)
+        serviceInfo.applicationInfo = applicationInfo
 
-        customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext)
+        customTileBuilder = CustomTile.Builder(
+                { tileHost },
+                testableLooper.looper,
+                Handler(testableLooper.looper),
+                metricsLogger,
+                statusBarStateController,
+                activityStarter,
+                qsLogger
+        )
+
+        customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
     }
 
     @Test
@@ -93,18 +117,18 @@
         assertEquals(0, customTile.user)
 
         val userContext = mock(Context::class.java)
-        `when`(userContext.packageManager).thenReturn(mPackageManager)
+        `when`(userContext.packageManager).thenReturn(packageManager)
         `when`(userContext.userId).thenReturn(10)
 
-        val tile = CustomTile.create(mTileHost, TILE_SPEC, userContext)
+        val tile = CustomTile.create(customTileBuilder, TILE_SPEC, userContext)
 
         assertEquals(10, tile.user)
     }
 
     @Test
     fun testToggleableTileHasBooleanState() {
-        `when`(mTileServiceManager.isToggleableTile).thenReturn(true)
-        customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext)
+        `when`(tileServiceManager.isToggleableTile).thenReturn(true)
+        customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
 
         assertTrue(customTile.state is QSTile.BooleanState)
         assertTrue(customTile.newTileState() is QSTile.BooleanState)
@@ -118,8 +142,8 @@
 
     @Test
     fun testValueUpdatedInBooleanTile() {
-        `when`(mTileServiceManager.isToggleableTile).thenReturn(true)
-        customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext)
+        `when`(tileServiceManager.isToggleableTile).thenReturn(true)
+        customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
         customTile.qsTile.icon = mock(Icon::class.java)
         `when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java)))
                 .thenReturn(mock(Drawable::class.java))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 438de99..7f74f9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -35,17 +35,14 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import static java.lang.Thread.sleep;
-
 import android.content.Intent;
 import android.metrics.LogMaker;
+import android.os.Handler;
+import android.os.Looper;
 import android.service.quicksettings.Tile;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -57,7 +54,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.UiEventLoggerFake;
-import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile;
@@ -69,7 +65,6 @@
 import com.android.systemui.statusbar.StatusBarState;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -91,9 +86,14 @@
 
     private TestableLooper mTestableLooper;
     private TileImpl mTile;
+    @Mock
     private QSTileHost mHost;
+    @Mock
     private MetricsLogger mMetricsLogger;
+    @Mock
     private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private ActivityStarter mActivityStarter;
     private UiEventLoggerFake mUiEventLoggerFake;
     private InstanceId mInstanceId = InstanceId.fakeInstanceId(5);
 
@@ -104,21 +104,16 @@
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
         mTestableLooper = TestableLooper.get(this);
-        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
-        mDependency.injectMockDependency(ActivityStarter.class);
-        mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
         mUiEventLoggerFake = new UiEventLoggerFake();
-        mStatusBarStateController =
-            mDependency.injectMockDependency(StatusBarStateController.class);
-        mHost = mock(QSTileHost.class);
         when(mHost.indexOf(SPEC)).thenReturn(POSITION);
         when(mHost.getContext()).thenReturn(mContext.getBaseContext());
-        when(mHost.getQSLogger()).thenReturn(mQsLogger);
         when(mHost.getUiEventLogger()).thenReturn(mUiEventLoggerFake);
         when(mHost.getNewInstanceId()).thenReturn(mInstanceId);
 
-        mTile = spy(new TileImpl(mHost));
-        mTile.mHandler = mTile.new H(mTestableLooper.getLooper());
+        Handler mainHandler = new Handler(mTestableLooper.getLooper());
+
+        mTile = new TileImpl(mHost, mTestableLooper.getLooper(), mainHandler,
+                mMetricsLogger, mStatusBarStateController, mActivityStarter, mQsLogger);
         mTile.setTileSpec(SPEC);
     }
 
@@ -223,40 +218,35 @@
         verify(maker).addTaggedData(eq(FIELD_QS_POSITION), eq(POSITION));
     }
 
-    @Test
-    @Ignore("flaky")
-    public void testStaleTimeout() throws InterruptedException {
-        when(mTile.getStaleTimeout()).thenReturn(5l);
-        clearInvocations(mTile);
-
-        mTile.handleRefreshState(null);
-        mTestableLooper.processAllMessages();
-        verify(mTile, never()).handleStale();
-
-        sleep(10);
-        mTestableLooper.processAllMessages();
-        verify(mTile).handleStale();
-    }
+    //TODO(b/161799397) Bring back testStaleTimeout when we can use FakeExecutor
 
     @Test
     public void testStaleListening() {
         mTile.handleStale();
         mTestableLooper.processAllMessages();
-        verify(mTile).handleSetListening(eq(true));
+        verify(mQsLogger).logTileChangeListening(SPEC, true);
 
         mTile.handleRefreshState(null);
         mTestableLooper.processAllMessages();
-        verify(mTile).handleSetListening(eq(false));
+        verify(mQsLogger).logTileChangeListening(SPEC, false);
     }
 
     @Test
     public void testHandleDestroyClearsHandlerQueue() {
-        when(mTile.getStaleTimeout()).thenReturn(0L);
         mTile.handleRefreshState(null); // this will add a delayed H.STALE message
         mTile.handleDestroy();
 
+        assertFalse(mTile.mHandler.hasMessages(QSTileImpl.H.STALE));
+    }
+
+    @Test
+    public void testHandleDestroyLifecycle() {
+        assertNotEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
+        mTile.handleDestroy();
+
         mTestableLooper.processAllMessages();
-        verify(mTile, never()).handleStale();
+
+        assertEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
     }
 
     @Test
@@ -310,6 +300,25 @@
         assertNotEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
     }
 
+    @Test
+    public void testRefreshStateAfterDestroyedDoesNotCrash() {
+        mTile.destroy();
+        mTile.refreshState();
+
+        mTestableLooper.processAllMessages();
+    }
+
+    @Test
+    public void testSetListeningAfterDestroyedDoesNotCrash() {
+        Object o = new Object();
+        mTile.destroy();
+
+        mTile.setListening(o, true);
+        mTile.setListening(o, false);
+
+        mTestableLooper.processAllMessages();
+    }
+
     private void assertEvent(UiEventLogger.UiEventEnum eventType,
             UiEventLoggerFake.FakeUiEvent fakeEvent) {
         assertEquals(eventType.getId(), fakeEvent.eventId);
@@ -351,8 +360,17 @@
     }
 
     private static class TileImpl extends QSTileImpl<QSTile.BooleanState> {
-        protected TileImpl(QSHost host) {
-            super(host);
+        protected TileImpl(
+                QSHost host,
+                Looper backgroundLooper,
+                Handler mainHandler,
+                MetricsLogger metricsLogger,
+                StatusBarStateController statusBarStateController,
+                ActivityStarter activityStarter,
+                QSLogger qsLogger
+        ) {
+            super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                    activityStarter, qsLogger);
             getState().state = Tile.STATE_ACTIVE;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
index 3199287..2006a75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
@@ -17,13 +17,17 @@
 package com.android.systemui.qs.tiles
 
 import android.content.Context
+import android.os.Handler
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
-import com.android.systemui.Dependency
+import com.android.internal.logging.MetricsLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.qs.QSHost
+import com.android.systemui.qs.logging.QSLogger
 import com.android.systemui.statusbar.policy.BatteryController
 import org.junit.Assert.assertEquals
 import org.junit.Before
@@ -34,7 +38,7 @@
 import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class BatterySaverTileTest : SysuiTestCase() {
 
@@ -47,6 +51,14 @@
     @Mock
     private lateinit var qsHost: QSHost
     @Mock
+    private lateinit var metricsLogger: MetricsLogger
+    @Mock
+    private lateinit var statusBarStateController: StatusBarStateController
+    @Mock
+    private lateinit var activityStarter: ActivityStarter
+    @Mock
+    private lateinit var qsLogger: QSLogger
+    @Mock
     private lateinit var batteryController: BatteryController
     private lateinit var testableLooper: TestableLooper
     private lateinit var tile: BatterySaverTile
@@ -55,11 +67,18 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         testableLooper = TestableLooper.get(this)
-        mDependency.injectTestDependency(Dependency.BG_LOOPER, testableLooper.looper)
         `when`(qsHost.userContext).thenReturn(userContext)
         `when`(userContext.userId).thenReturn(USER)
 
-        tile = BatterySaverTile(qsHost, batteryController)
+        tile = BatterySaverTile(
+                qsHost,
+                testableLooper.looper,
+                Handler(testableLooper.looper),
+                metricsLogger,
+                statusBarStateController,
+                activityStarter,
+                qsLogger,
+                batteryController)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index 853b2db..5d14898 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -27,6 +27,7 @@
 import android.media.MediaRouter;
 import android.media.MediaRouter.RouteInfo;
 import android.media.projection.MediaProjectionInfo;
+import android.os.Handler;
 import android.service.quicksettings.Tile;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -34,10 +35,12 @@
 import androidx.lifecycle.LifecycleOwner;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.Dependency;
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -55,7 +58,7 @@
 
 
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 public class CastTileTest extends SysuiTestCase {
 
@@ -71,6 +74,12 @@
     private QSTileHost mHost;
     @Mock
     NetworkController.SignalCallback mCallback;
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private QSLogger mQSLogger;
 
     private TestableLooper mTestableLooper;
     private CastTile mCastTile;
@@ -80,16 +89,20 @@
         MockitoAnnotations.initMocks(this);
         mTestableLooper = TestableLooper.get(this);
 
-        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
-        mController = mDependency.injectMockDependency(CastController.class);
-        mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
-        mKeyguard = mDependency.injectMockDependency(KeyguardStateController.class);
-        mNetworkController = mDependency.injectMockDependency(NetworkController.class);
-
         when(mHost.getContext()).thenReturn(mContext);
 
-        mCastTile = new CastTile(mHost, mController, mKeyguard, mNetworkController,
-                mActivityStarter);
+        mCastTile = new CastTile(
+                mHost,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mController,
+                mKeyguard,
+                mNetworkController
+        );
 
         // We are not setting the mocks to listening, so we trigger a first refresh state to
         // set the initial state
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 5a68238..2d276bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -23,16 +23,20 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.os.Handler;
 import android.service.quicksettings.Tile;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.Dependency;
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 
@@ -43,7 +47,7 @@
 import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper()
 @SmallTest
 public class ScreenRecordTileTest extends SysuiTestCase {
 
@@ -53,6 +57,14 @@
     private QSTileHost mHost;
     @Mock
     private KeyguardDismissUtil mKeyguardDismissUtil;
+    @Mock
+    private MetricsLogger mMetricsLogger;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private QSLogger mQSLogger;
 
     private TestableLooper mTestableLooper;
     private ScreenRecordTile mTile;
@@ -62,12 +74,20 @@
         MockitoAnnotations.initMocks(this);
 
         mTestableLooper = TestableLooper.get(this);
-        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
-        mController = mDependency.injectMockDependency(RecordingController.class);
 
         when(mHost.getContext()).thenReturn(mContext);
 
-        mTile = new ScreenRecordTile(mHost, mController, mKeyguardDismissUtil);
+        mTile = new ScreenRecordTile(
+                mHost,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mController,
+                mKeyguardDismissUtil
+        );
     }
 
     // Test that the tile is inactive and labeled correctly when the controller is neither starting
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
index fa711f1..a16fb5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
@@ -23,10 +23,12 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.annotation.NonNull;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.Lifecycle.Event;
 import androidx.lifecycle.LifecycleEventObserver;
 import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -76,6 +78,34 @@
         verify(controller).removeCallback(eq(callback));
     }
 
+    @Test
+    public void testCallbackIsRemovedOnDestroy() {
+        SimpleLifecycleOwner owner = new SimpleLifecycleOwner();
+
+        Object callback = new Object();
+        Controller controller = mock(Controller.class);
+        controller.observe(owner, callback);
+
+        owner.setState(Lifecycle.State.RESUMED);
+        verify(controller).addCallback(callback);
+
+        owner.setState(Lifecycle.State.DESTROYED);
+        verify(controller).removeCallback(callback);
+    }
+
+    private static class SimpleLifecycleOwner implements LifecycleOwner {
+        LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+        @NonNull
+        @Override
+        public Lifecycle getLifecycle() {
+            return mLifecycle;
+        }
+
+        public void setState(Lifecycle.State state) {
+            mLifecycle.setCurrentState(state);
+        }
+    }
+
     private static class Controller implements CallbackController<Object> {
         @Override
         public void addCallback(Object listener) {
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 781c354..7cdcc01 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -91,7 +91,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BinderDeathDispatcher;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
@@ -177,8 +176,6 @@
                     .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                             | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
 
-    private static final BinderDeathDispatcher<IAlarmListener> sListenerDeathDispatcher =
-            new BinderDeathDispatcher<>();
     final LocalLog mLog = new LocalLog(TAG);
 
     AppOpsManager mAppOps;
@@ -1704,8 +1701,9 @@
         }
 
         if (directReceiver != null) {
-            if (sListenerDeathDispatcher.linkToDeath(directReceiver, mListenerDeathRecipient)
-                    <= 0) {
+            try {
+                directReceiver.asBinder().linkToDeath(mListenerDeathRecipient, 0);
+            } catch (RemoteException e) {
                 Slog.w(TAG, "Dropping unreachable alarm listener " + listenerTag);
                 return;
             }
@@ -2466,10 +2464,6 @@
             pw.println("]");
             pw.println();
 
-            pw.println("Listener death dispatcher state:");
-            sListenerDeathDispatcher.dump(pw, "  ");
-            pw.println();
-
             if (mLog.dump(pw, "  Recent problems", "    ")) {
                 pw.println();
             }
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index bcbd692..7fb164a 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -64,6 +64,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
+import android.util.LocalLog;
 import android.util.Log;
 import android.util.Slog;
 
@@ -148,6 +149,11 @@
 // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity
 public class VcnManagementService extends IVcnManagementService.Stub {
     @NonNull private static final String TAG = VcnManagementService.class.getSimpleName();
+    private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
+    private static final int LOCAL_LOG_LINE_COUNT = 128;
+
+    // Public for use in all other VCN classes
+    @NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT);
 
     public static final boolean VDBG = false; // STOPSHIP: if true
 
@@ -241,13 +247,13 @@
             try {
                 configBundle = mConfigDiskRwHelper.readFromDisk();
             } catch (IOException e1) {
-                Slog.e(TAG, "Failed to read configs from disk; retrying", e1);
+                logErr("Failed to read configs from disk; retrying", e1);
 
                 // Retry immediately. The IOException may have been transient.
                 try {
                     configBundle = mConfigDiskRwHelper.readFromDisk();
                 } catch (IOException e2) {
-                    Slog.wtf(TAG, "Failed to read configs from disk", e2);
+                    logWtf("Failed to read configs from disk", e2);
                     return;
                 }
             }
@@ -441,7 +447,7 @@
             synchronized (mLock) {
                 final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot;
                 mLastSnapshot = snapshot;
-                Slog.d(TAG, "new snapshot: " + mLastSnapshot);
+                logDbg("new snapshot: " + mLastSnapshot);
 
                 // Start any VCN instances as necessary
                 for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
@@ -544,7 +550,7 @@
 
     @GuardedBy("mLock")
     private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
-        Slog.d(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
+        logDbg("Starting VCN config for subGrp: " + subscriptionGroup);
 
         // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
         //                    VCN.
@@ -569,7 +575,7 @@
     @GuardedBy("mLock")
     private void startOrUpdateVcnLocked(
             @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
-        Slog.d(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup);
+        logDbg("Starting or updating VCN config for subGrp: " + subscriptionGroup);
 
         if (mVcns.containsKey(subscriptionGroup)) {
             final Vcn vcn = mVcns.get(subscriptionGroup);
@@ -595,7 +601,7 @@
         if (!config.getProvisioningPackageName().equals(opPkgName)) {
             throw new IllegalArgumentException("Mismatched caller and VcnConfig creator");
         }
-        Slog.d(TAG, "VCN config updated for subGrp: " + subscriptionGroup);
+        logDbg("VCN config updated for subGrp: " + subscriptionGroup);
 
         mContext.getSystemService(AppOpsManager.class)
                 .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName());
@@ -621,7 +627,7 @@
     public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) {
         requireNonNull(subscriptionGroup, "subscriptionGroup was null");
         requireNonNull(opPkgName, "opPkgName was null");
-        Slog.d(TAG, "VCN config cleared for subGrp: " + subscriptionGroup);
+        logDbg("VCN config cleared for subGrp: " + subscriptionGroup);
 
         mContext.getSystemService(AppOpsManager.class)
                 .checkPackage(mDeps.getBinderCallingUid(), opPkgName);
@@ -684,7 +690,7 @@
                             VcnConfig::toPersistableBundle);
             mConfigDiskRwHelper.writeToDisk(bundle);
         } catch (IOException e) {
-            Slog.e(TAG, "Failed to save configs to disk", e);
+            logErr("Failed to save configs to disk", e);
             throw new ServiceSpecificException(0, "Failed to save configs");
         }
     }
@@ -794,7 +800,7 @@
         for (int subId : networkCapabilities.getSubscriptionIds()) {
             // Verify that all subscriptions point to the same group
             if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) {
-                Slog.wtf(TAG, "Got multiple subscription groups for a single network");
+                logWtf("Got multiple subscription groups for a single network");
             }
 
             subGrp = snapshot.getGroupForSubId(subId);
@@ -860,10 +866,8 @@
             final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy(
                     mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
 
-            if (VDBG) {
-                Slog.d(TAG, "getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
+            logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
                         + "; and lp: " + linkProperties + "; result = " + policy);
-            }
             return policy;
         });
     }
@@ -955,14 +959,14 @@
                         || vcnStatus == VCN_STATUS_CODE_SAFE_MODE) {
                     resultStatus = vcnStatus;
                 } else {
-                    Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus);
+                    logWtf("Unknown VCN status: " + vcnStatus);
                     resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED;
                 }
 
                 try {
                     cbInfo.mCallback.onVcnStatusChanged(resultStatus);
                 } catch (RemoteException e) {
-                    Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e);
+                    logDbg("VcnStatusCallback threw on VCN status change", e);
                 }
             }
         } finally {
@@ -990,6 +994,43 @@
         }
     }
 
+    private void logVdbg(String msg) {
+        if (VDBG) {
+            Slog.v(TAG, msg);
+            LOCAL_LOG.log(TAG + " VDBG: " + msg);
+        }
+    }
+
+    private void logDbg(String msg) {
+        Slog.d(TAG, msg);
+        LOCAL_LOG.log(TAG + " DBG: " + msg);
+    }
+
+    private void logDbg(String msg, Throwable tr) {
+        Slog.d(TAG, msg, tr);
+        LOCAL_LOG.log(TAG + " DBG: " + msg + tr);
+    }
+
+    private void logErr(String msg) {
+        Slog.e(TAG, msg);
+        LOCAL_LOG.log(TAG + " ERR: " + msg);
+    }
+
+    private void logErr(String msg, Throwable tr) {
+        Slog.e(TAG, msg, tr);
+        LOCAL_LOG.log(TAG + " ERR: " + msg + tr);
+    }
+
+    private void logWtf(String msg) {
+        Slog.wtf(TAG, msg);
+        LOCAL_LOG.log(TAG + " WTF: " + msg);
+    }
+
+    private void logWtf(String msg, Throwable tr) {
+        Slog.wtf(TAG, msg, tr);
+        LOCAL_LOG.log(TAG + " WTF: " + msg + tr);
+    }
+
     /**
      * Dumps the state of the VcnManagementService for logging and debugging purposes.
      *
@@ -999,48 +1040,44 @@
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
 
-        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| ");
 
-        pw.println("VcnManagementService dump:");
-        pw.increaseIndent();
-
-        pw.println("mNetworkProvider:");
-        pw.increaseIndent();
-        mNetworkProvider.dump(pw);
-        pw.decreaseIndent();
-        pw.println();
-
-        pw.println("mTrackingNetworkCallback:");
-        pw.increaseIndent();
-        mTrackingNetworkCallback.dump(pw);
-        pw.decreaseIndent();
-        pw.println();
-
-        synchronized (mLock) {
-            pw.println("mLastSnapshot:");
-            pw.increaseIndent();
-            mLastSnapshot.dump(pw);
-            pw.decreaseIndent();
+        // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell.
+        mHandler.runWithScissors(() -> {
+            mNetworkProvider.dump(pw);
             pw.println();
 
-            pw.println("mConfigs:");
-            pw.increaseIndent();
-            for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
-                pw.println(entry.getKey() + ": " + entry.getValue().getProvisioningPackageName());
+            mTrackingNetworkCallback.dump(pw);
+            pw.println();
+
+            synchronized (mLock) {
+                mLastSnapshot.dump(pw);
+                pw.println();
+
+                pw.println("mConfigs:");
+                pw.increaseIndent();
+                for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
+                    pw.println(entry.getKey() + ": "
+                            + entry.getValue().getProvisioningPackageName());
+                }
+                pw.decreaseIndent();
+                pw.println();
+
+                pw.println("mVcns:");
+                pw.increaseIndent();
+                for (Vcn vcn : mVcns.values()) {
+                    vcn.dump(pw);
+                }
+                pw.decreaseIndent();
+                pw.println();
             }
-            pw.decreaseIndent();
-            pw.println();
 
-            pw.println("mVcns:");
+            pw.println("Local log:");
             pw.increaseIndent();
-            for (Vcn vcn : mVcns.values()) {
-                vcn.dump(pw);
-            }
+            LOCAL_LOG.dump(pw);
             pw.decreaseIndent();
             pw.println();
-        }
-
-        pw.decreaseIndent();
+        }, DUMP_TIMEOUT_MILLIS);
     }
 
     // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
diff --git a/services/core/java/com/android/server/connectivity/PacProxyService.java b/services/core/java/com/android/server/connectivity/PacProxyService.java
index d23b488..0070339 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyService.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyService.java
@@ -345,7 +345,14 @@
                     if (mProxyService == null) {
                         Log.e(TAG, "No proxy service");
                     } else {
-                        mNetThreadHandler.post(mPacDownloader);
+                        // If mCurrentPac is not null, then the PacService might have
+                        // crashed and restarted. The download task will not actually
+                        // call setCurrentProxyScript, so call setCurrentProxyScript here.
+                        if (mCurrentPac != null) {
+                            setCurrentProxyScript(mCurrentPac);
+                        } else {
+                            mNetThreadHandler.post(mPacDownloader);
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 07ac14f..aba9615 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -105,6 +105,7 @@
 import android.security.keystore2.AndroidKeyStoreProvider;
 import android.service.gatekeeper.GateKeeperResponse;
 import android.service.gatekeeper.IGateKeeperService;
+import android.system.keystore2.Domain;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -253,8 +254,7 @@
      * The UIDs that are used for system credential storage in keystore.
      */
     private static final int[] SYSTEM_CREDENTIAL_UIDS = {
-            Process.WIFI_UID, Process.VPN_UID,
-            Process.ROOT_UID, Process.SYSTEM_UID };
+            Process.VPN_UID, Process.ROOT_UID, Process.SYSTEM_UID};
 
     // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
     // devices. The most basic of these is to show/hide notifications about missing features until
@@ -1987,9 +1987,14 @@
             // Clear all the users credentials could have been installed in for this user.
             for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
                 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
-                    mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
+                    AndroidKeyStoreMaintenance.clearNamespace(Domain.APP,
+                            UserHandle.getUid(profileId, uid));
                 }
             }
+            if (mUserManager.getUserInfo(userId).isPrimary()) {
+                AndroidKeyStoreMaintenance.clearNamespace(Domain.SELINUX,
+                        KeyProperties.NAMESPACE_WIFI);
+            }
         } finally {
             if (managedUserId != -1 && managedUserDecryptedPassword != null) {
                 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 3f2b8ff..b714c6d7 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -33,6 +33,9 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.SystemProperties;
@@ -126,6 +129,7 @@
             ERROR_UNLOCK_ALL_USERS,
             ERROR_PROVIDER_MISMATCH,
             ERROR_KEYSTORE_FAILURE,
+            ERROR_NO_NETWORK,
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface RebootEscrowErrorCode {
@@ -139,6 +143,7 @@
     static final int ERROR_UNLOCK_ALL_USERS = 5;
     static final int ERROR_PROVIDER_MISMATCH = 6;
     static final int ERROR_KEYSTORE_FAILURE = 7;
+    static final int ERROR_NO_NETWORK = 8;
 
     private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
 
@@ -235,6 +240,23 @@
                     "server_based_ror_enabled", false);
         }
 
+        public boolean isNetworkConnected() {
+            final ConnectivityManager connectivityManager =
+                    mContext.getSystemService(ConnectivityManager.class);
+            if (connectivityManager == null) {
+                return false;
+            }
+
+            Network activeNetwork = connectivityManager.getActiveNetwork();
+            NetworkCapabilities networkCapabilities =
+                    connectivityManager.getNetworkCapabilities(activeNetwork);
+            return networkCapabilities != null
+                    && networkCapabilities.hasCapability(
+                            NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                    && networkCapabilities.hasCapability(
+                            NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+        }
+
         public Context getContext() {
             return mContext;
         }
@@ -363,7 +385,11 @@
         }
 
         Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
-        mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
+        if (mInjector.serverBasedResumeOnReboot() && !mInjector.isNetworkConnected()) {
+            mLoadEscrowDataErrorCode = ERROR_NO_NETWORK;
+        } else {
+            mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
+        }
         onGetRebootEscrowKeyFailed(users, attemptNumber);
     }
 
@@ -471,6 +497,8 @@
             mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
         }
 
+        Slog.i(TAG, "Reporting RoR recovery metrics, success: " + success + ", service type: "
+                + serviceType + ", error code: " + mLoadEscrowDataErrorCode);
         // TODO(179105110) report the duration since boot complete.
         mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount,
                 escrowDurationInSeconds, vbmetaDigestStatus, -1);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index d0da912..9fb5f04 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -97,8 +97,12 @@
 import static android.net.NetworkPolicyManager.uidPoliciesToString;
 import static android.net.NetworkPolicyManager.uidRulesToString;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
+import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_YES;
+import static android.net.NetworkTemplate.MATCH_CARRIER;
 import static android.net.NetworkTemplate.MATCH_MOBILE;
 import static android.net.NetworkTemplate.MATCH_WIFI;
+import static android.net.NetworkTemplate.buildTemplateCarrierMetered;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
@@ -350,7 +354,8 @@
     private static final int VERSION_SWITCH_UID = 10;
     private static final int VERSION_ADDED_CYCLE = 11;
     private static final int VERSION_ADDED_NETWORK_TYPES = 12;
-    private static final int VERSION_LATEST = VERSION_ADDED_NETWORK_TYPES;
+    private static final int VERSION_SUPPORTED_CARRIER_USAGE = 13;
+    private static final int VERSION_LATEST = VERSION_SUPPORTED_CARRIER_USAGE;
 
     @VisibleForTesting
     public static final int TYPE_WARNING = SystemMessage.NOTE_NET_WARNING;
@@ -375,7 +380,9 @@
     private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
     private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
     private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
+    private static final String ATTR_SUBSCRIBER_ID_MATCH_RULE = "subscriberIdMatchRule";
     private static final String ATTR_NETWORK_ID = "networkId";
+    private static final String ATTR_TEMPLATE_METERED = "templateMetered";
     @Deprecated private static final String ATTR_CYCLE_DAY = "cycleDay";
     @Deprecated private static final String ATTR_CYCLE_TIMEZONE = "cycleTimezone";
     private static final String ATTR_CYCLE_START = "cycleStart";
@@ -1430,7 +1437,7 @@
      */
     @GuardedBy("mNetworkPoliciesSecondLock")
     private int findRelevantSubIdNL(NetworkTemplate template) {
-        // Mobile template is relevant when any active subscriber matches
+        // Carrier template is relevant when any active subscriber matches
         for (int i = 0; i < mSubIdToSubscriberId.size(); i++) {
             final int subId = mSubIdToSubscriberId.keyAt(i);
             final String subscriberId = mSubIdToSubscriberId.valueAt(i);
@@ -1508,6 +1515,7 @@
             }
             case TYPE_LIMIT: {
                 switch (policy.template.getMatchRule()) {
+                    case MATCH_CARRIER:
                     case MATCH_MOBILE:
                         title = res.getText(R.string.data_usage_mobile_limit_title);
                         break;
@@ -1536,6 +1544,7 @@
             }
             case TYPE_LIMIT_SNOOZED: {
                 switch (policy.template.getMatchRule()) {
+                    case MATCH_CARRIER:
                     case MATCH_MOBILE:
                         title = res.getText(R.string.data_usage_mobile_limit_snoozed_title);
                         break;
@@ -1632,7 +1641,7 @@
 
         synchronized (mUidRulesFirstLock) {
             synchronized (mNetworkPoliciesSecondLock) {
-                ensureActiveMobilePolicyAL();
+                ensureActiveCarrierPolicyAL();
                 normalizePoliciesNL();
                 updateNetworkEnabledNL();
                 updateNetworkRulesNL();
@@ -1657,17 +1666,17 @@
     }
 
     /**
-     * Update mobile policies with data cycle information from {@link CarrierConfigManager}
+     * Update carrier policies with data cycle information from {@link CarrierConfigManager}
      * if necessary.
      *
      * @param subId that has its associated NetworkPolicy updated if necessary
      * @return if any policies were updated
      */
     @GuardedBy("mNetworkPoliciesSecondLock")
-    private boolean maybeUpdateMobilePolicyCycleAL(int subId, String subscriberId) {
-        if (LOGV) Slog.v(TAG, "maybeUpdateMobilePolicyCycleAL()");
+    private boolean maybeUpdateCarrierPolicyCycleAL(int subId, String subscriberId) {
+        if (LOGV) Slog.v(TAG, "maybeUpdateCarrierPolicyCycleAL()");
 
-        // find and update the mobile NetworkPolicy for this subscriber id
+        // find and update the carrier NetworkPolicy for this subscriber id
         boolean policyUpdated = false;
         final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true,
@@ -1676,21 +1685,21 @@
             final NetworkTemplate template = mNetworkPolicy.keyAt(i);
             if (template.matches(probeIdent)) {
                 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
-                policyUpdated |= updateDefaultMobilePolicyAL(subId, policy);
+                policyUpdated |= updateDefaultCarrierPolicyAL(subId, policy);
             }
         }
         return policyUpdated;
     }
 
     /**
-     * Returns the cycle day that should be used for a mobile NetworkPolicy.
+     * Returns the cycle day that should be used for a carrier NetworkPolicy.
      *
      * It attempts to get an appropriate cycle day from the passed in CarrierConfig. If it's unable
      * to do so, it returns the fallback value.
      *
      * @param config The CarrierConfig to read the value from.
      * @param fallbackCycleDay to return if the CarrierConfig can't be read.
-     * @return cycleDay to use in the mobile NetworkPolicy.
+     * @return cycleDay to use in the carrier NetworkPolicy.
      */
     @VisibleForTesting
     int getCycleDayFromCarrierConfig(@Nullable PersistableBundle config,
@@ -1715,14 +1724,14 @@
     }
 
     /**
-     * Returns the warning bytes that should be used for a mobile NetworkPolicy.
+     * Returns the warning bytes that should be used for a carrier NetworkPolicy.
      *
      * It attempts to get an appropriate value from the passed in CarrierConfig. If it's unable
      * to do so, it returns the fallback value.
      *
      * @param config The CarrierConfig to read the value from.
      * @param fallbackWarningBytes to return if the CarrierConfig can't be read.
-     * @return warningBytes to use in the mobile NetworkPolicy.
+     * @return warningBytes to use in the carrier NetworkPolicy.
      */
     @VisibleForTesting
     long getWarningBytesFromCarrierConfig(@Nullable PersistableBundle config,
@@ -1748,14 +1757,14 @@
     }
 
     /**
-     * Returns the limit bytes that should be used for a mobile NetworkPolicy.
+     * Returns the limit bytes that should be used for a carrier NetworkPolicy.
      *
      * It attempts to get an appropriate value from the passed in CarrierConfig. If it's unable
      * to do so, it returns the fallback value.
      *
      * @param config The CarrierConfig to read the value from.
      * @param fallbackLimitBytes to return if the CarrierConfig can't be read.
-     * @return limitBytes to use in the mobile NetworkPolicy.
+     * @return limitBytes to use in the carrier NetworkPolicy.
      */
     @VisibleForTesting
     long getLimitBytesFromCarrierConfig(@Nullable PersistableBundle config,
@@ -1801,8 +1810,8 @@
                 synchronized (mNetworkPoliciesSecondLock) {
                     final String subscriberId = mSubIdToSubscriberId.get(subId, null);
                     if (subscriberId != null) {
-                        ensureActiveMobilePolicyAL(subId, subscriberId);
-                        maybeUpdateMobilePolicyCycleAL(subId, subscriberId);
+                        ensureActiveCarrierPolicyAL(subId, subscriberId);
+                        maybeUpdateCarrierPolicyCycleAL(subId, subscriberId);
                     } else {
                         Slog.wtf(TAG, "Missing subscriberId for subId " + subId);
                     }
@@ -1888,10 +1897,12 @@
         // TODO: reach into ConnectivityManager to proactively disable bringing
         // up this network, since we know that traffic will be blocked.
 
-        if (template.getMatchRule() == MATCH_MOBILE) {
-            // If mobile data usage hits the limit or if the user resumes the data, we need to
+        if (template.getMatchRule() == MATCH_MOBILE
+                || template.getMatchRule() == MATCH_CARRIER) {
+            // If carrier data usage hits the limit or if the user resumes the data, we need to
             // notify telephony.
 
+            // TODO: It needs to check if it matches the merged WIFI and notify to wifi module.
             final IntArray matchingSubIds = new IntArray();
             synchronized (mNetworkPoliciesSecondLock) {
                 for (int i = 0; i < mSubIdToSubscriberId.size(); i++) {
@@ -2151,7 +2162,7 @@
                         .truncatedTo(ChronoUnit.DAYS)
                         .toInstant().toEpochMilli();
                 final long totalBytes = getTotalBytes(
-                        NetworkTemplate.buildTemplateMobileAll(snapshot.getSubscriberId()),
+                        buildTemplateCarrierMetered(snapshot.getSubscriberId()),
                         start, startOfDay);
                 final long remainingBytes = limitBytes - totalBytes;
                 // Number of remaining days including current day
@@ -2177,31 +2188,31 @@
 
     /**
      * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
-     * have at least a default mobile policy defined.
+     * have at least a default carrier policy defined.
      */
     @GuardedBy("mNetworkPoliciesSecondLock")
-    private void ensureActiveMobilePolicyAL() {
-        if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyAL()");
+    private void ensureActiveCarrierPolicyAL() {
+        if (LOGV) Slog.v(TAG, "ensureActiveCarrierPolicyAL()");
         if (mSuppressDefaultPolicy) return;
 
         for (int i = 0; i < mSubIdToSubscriberId.size(); i++) {
             final int subId = mSubIdToSubscriberId.keyAt(i);
             final String subscriberId = mSubIdToSubscriberId.valueAt(i);
 
-            ensureActiveMobilePolicyAL(subId, subscriberId);
+            ensureActiveCarrierPolicyAL(subId, subscriberId);
         }
     }
 
     /**
      * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
-     * have at least a default mobile policy defined.
+     * have at least a default carrier policy defined.
      *
      * @param subId to build a default policy for
      * @param subscriberId that we check for an existing policy
-     * @return true if a mobile network policy was added, or false one already existed.
+     * @return true if a carrier network policy was added, or false one already existed.
      */
     @GuardedBy("mNetworkPoliciesSecondLock")
-    private boolean ensureActiveMobilePolicyAL(int subId, String subscriberId) {
+    private boolean ensureActiveCarrierPolicyAL(int subId, String subscriberId) {
         // Poke around to see if we already have a policy
         final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
                 TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true,
@@ -2220,7 +2231,7 @@
         Slog.i(TAG, "No policy for subscriber "
                 + NetworkIdentityUtils.scrubSubscriberId(subscriberId)
                 + "; generating default policy");
-        final NetworkPolicy policy = buildDefaultMobilePolicy(subId, subscriberId);
+        final NetworkPolicy policy = buildDefaultCarrierPolicy(subId, subscriberId);
         addNetworkPolicyAL(policy);
         return true;
     }
@@ -2240,8 +2251,8 @@
     }
 
     @VisibleForTesting
-    NetworkPolicy buildDefaultMobilePolicy(int subId, String subscriberId) {
-        final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
+    NetworkPolicy buildDefaultCarrierPolicy(int subId, String subscriberId) {
+        final NetworkTemplate template = buildTemplateCarrierMetered(subscriberId);
         final RecurrenceRule cycleRule = NetworkPolicy
                 .buildRule(ZonedDateTime.now().getDayOfMonth(), ZoneId.systemDefault());
         final NetworkPolicy policy = new NetworkPolicy(template, cycleRule,
@@ -2249,7 +2260,7 @@
                 SNOOZE_NEVER, SNOOZE_NEVER, true, true);
         synchronized (mUidRulesFirstLock) {
             synchronized (mNetworkPoliciesSecondLock) {
-                updateDefaultMobilePolicyAL(subId, policy);
+                updateDefaultCarrierPolicyAL(subId, policy);
             }
         }
         return policy;
@@ -2263,7 +2274,7 @@
      * @return if the policy was modified
      */
     @GuardedBy("mNetworkPoliciesSecondLock")
-    private boolean updateDefaultMobilePolicyAL(int subId, NetworkPolicy policy) {
+    private boolean updateDefaultCarrierPolicyAL(int subId, NetworkPolicy policy) {
         if (!policy.inferred) {
             if (LOGD) Slog.d(TAG, "Ignoring user-defined policy " + policy);
             return false;
@@ -2350,14 +2361,33 @@
                         mLoadedRestrictBackground = (version >= VERSION_ADDED_RESTRICT_BACKGROUND)
                                 && readBooleanAttribute(in, ATTR_RESTRICT_BACKGROUND);
                     } else if (TAG_NETWORK_POLICY.equals(tag)) {
-                        final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
+                        int templateType = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
                         final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
                         final String networkId;
+                        final int subscriberIdMatchRule;
+                        final int templateMeteredness;
                         if (version >= VERSION_ADDED_NETWORK_ID) {
                             networkId = in.getAttributeValue(null, ATTR_NETWORK_ID);
                         } else {
                             networkId = null;
                         }
+
+                        if (version >= VERSION_SUPPORTED_CARRIER_USAGE) {
+                            subscriberIdMatchRule = readIntAttribute(in,
+                                    ATTR_SUBSCRIBER_ID_MATCH_RULE);
+                            templateMeteredness = readIntAttribute(in, ATTR_TEMPLATE_METERED);
+
+                        } else {
+                            subscriberIdMatchRule = NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
+                            if (templateType == MATCH_MOBILE) {
+                                Log.d(TAG, "Update template match rule from mobile to carrier and"
+                                        + " force to metered");
+                                templateType = MATCH_CARRIER;
+                                templateMeteredness = METERED_YES;
+                            } else {
+                                templateMeteredness = METERED_ALL;
+                            }
+                        }
                         final RecurrenceRule cycleRule;
                         if (version >= VERSION_ADDED_CYCLE) {
                             final String start = readStringAttribute(in, ATTR_CYCLE_START);
@@ -2391,7 +2421,7 @@
                         if (version >= VERSION_ADDED_METERED) {
                             metered = readBooleanAttribute(in, ATTR_METERED);
                         } else {
-                            switch (networkTemplate) {
+                            switch (templateType) {
                                 case MATCH_MOBILE:
                                     metered = true;
                                     break;
@@ -2411,9 +2441,11 @@
                         } else {
                             inferred = false;
                         }
-
-                        final NetworkTemplate template = new NetworkTemplate(networkTemplate,
-                                subscriberId, networkId);
+                        final NetworkTemplate template = new NetworkTemplate(templateType,
+                                subscriberId, new String[] { subscriberId },
+                                networkId, templateMeteredness, NetworkStats.ROAMING_ALL,
+                                NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL,
+                                NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule);
                         if (template.isPersistable()) {
                             mNetworkPolicy.put(template, new NetworkPolicy(template, cycleRule,
                                     warningBytes, limitBytes, lastWarningSnooze,
@@ -2621,10 +2653,14 @@
                 if (subscriberId != null) {
                     out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
                 }
+                writeIntAttribute(out, ATTR_SUBSCRIBER_ID_MATCH_RULE,
+                        template.getSubscriberIdMatchRule());
                 final String networkId = template.getNetworkId();
                 if (networkId != null) {
                     out.attribute(null, ATTR_NETWORK_ID, networkId);
                 }
+                writeIntAttribute(out, ATTR_TEMPLATE_METERED,
+                        template.getMeteredness());
                 writeStringAttribute(out, ATTR_CYCLE_START,
                         RecurrenceRule.convertZonedDateTime(policy.cycleRule.start));
                 writeStringAttribute(out, ATTR_CYCLE_END,
@@ -3492,8 +3528,8 @@
 
                     final String subscriberId = mSubIdToSubscriberId.get(subId, null);
                     if (subscriberId != null) {
-                        ensureActiveMobilePolicyAL(subId, subscriberId);
-                        maybeUpdateMobilePolicyCycleAL(subId, subscriberId);
+                        ensureActiveCarrierPolicyAL(subId, subscriberId);
+                        maybeUpdateCarrierPolicyCycleAL(subId, subscriberId);
                     } else {
                         Slog.wtf(TAG, "Missing subscriberId for subId " + subId);
                     }
@@ -5534,11 +5570,15 @@
             return;
         }
 
-        // Turn mobile data limit off
+        // Turn carrier/mobile data limit off
         NetworkPolicy[] policies = getNetworkPolicies(mContext.getOpPackageName());
-        NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(subscriber);
+        NetworkTemplate templateCarrier = buildTemplateCarrierMetered(subscriber);
+        NetworkTemplate templateMobile = buildTemplateMobileAll(subscriber);
         for (NetworkPolicy policy : policies) {
-            if (policy.template.equals(template)) {
+            //  All policies loaded from disk will be carrier templates, and setting will also only
+            //  set carrier templates, but we clear mobile templates just in case one is set by
+            //  some other caller
+            if (policy.template.equals(templateCarrier) || policy.template.equals(templateMobile)) {
                 policy.limitBytes = NetworkPolicy.LIMIT_DISABLED;
                 policy.inferred = false;
                 policy.clearSnooze();
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index 18da33c..fdb93a8 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -103,7 +103,7 @@
 
         IntentFilter deletionFilter = new IntentFilter(ACTION_HISTORY_DELETION);
         deletionFilter.addDataScheme(SCHEME_DELETION);
-        mContext.registerReceiver(mFileCleaupReceiver, deletionFilter);
+        mContext.registerReceiver(mFileCleanupReceiver, deletionFilter);
     }
 
     public void init() {
@@ -329,6 +329,12 @@
         }
     }
 
+    public void unregisterFileCleanupReceiver() {
+        if(mContext != null) {
+            mContext.unregisterReceiver(mFileCleanupReceiver);
+        }
+    }
+
     private static long safeParseLong(String fileName) {
         // AtomicFile will create copies of the numeric files with ".new" and ".bak"
         // over the course of its processing. If these files still exist on boot we need to clean
@@ -340,7 +346,7 @@
         }
     }
 
-    private final BroadcastReceiver mFileCleaupReceiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mFileCleanupReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
index 69a7ce90..1aae6c3 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
@@ -272,6 +272,7 @@
 
     private void disableHistory(NotificationHistoryDatabase userHistory, @UserIdInt int userId) {
         userHistory.disableHistory();
+        userHistory.unregisterFileCleanupReceiver();
 
         mUserPendingHistoryDisables.put(userId, false);
         mHistoryEnabled.put(userId, false);
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index 5b48abb..5e4c801 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -135,7 +135,7 @@
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
-        context.registerReceiver(mBroadcastReceiver, filter);
+        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
 
         mHasTelephony =
                 context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 5565ccb..fca706b 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -39,7 +39,6 @@
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -222,12 +221,10 @@
         if (SubscriptionManager.isValidSubscriptionId(subId)) {
             final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
             if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) {
-                Slog.v(TAG, String.format("SubId %s ready for SlotId %s", subId, slotId));
                 mReadySubIdsBySlotId.put(slotId, subId);
                 handleSubscriptionsChanged();
             }
         } else {
-            Slog.v(TAG, "Slot unloaded: " + slotId);
             mReadySubIdsBySlotId.remove(slotId);
             handleSubscriptionsChanged();
         }
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index b05662e..ee7bf5f 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -20,6 +20,8 @@
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
 
+import static com.android.server.VcnManagementService.LOCAL_LOG;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.ConnectivityManager;
@@ -40,6 +42,7 @@
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -106,6 +109,17 @@
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     static final int PRIORITY_ANY = Integer.MAX_VALUE;
 
+    private static final SparseArray<String> PRIORITY_TO_STRING_MAP = new SparseArray<>();
+
+    static {
+        PRIORITY_TO_STRING_MAP.put(
+                PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR");
+        PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE");
+        PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE");
+        PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR");
+        PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY");
+    }
+
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
     @NonNull private final UnderlyingNetworkTrackerCallback mCb;
@@ -395,12 +409,12 @@
     }
 
     private void reevaluateNetworks() {
-        TreeSet<UnderlyingNetworkRecord> sorted =
-                new TreeSet<>(
-                        UnderlyingNetworkRecord.getComparator(
-                                mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig));
-        sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks());
+        if (mRouteSelectionCallback == null) {
+            return; // UnderlyingNetworkTracker has quit.
+        }
 
+        TreeSet<UnderlyingNetworkRecord> sorted =
+                mRouteSelectionCallback.getSortedUnderlyingNetworks();
         UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first();
         if (Objects.equals(mCurrentRecord, candidate)) {
             return;
@@ -413,7 +427,7 @@
     private static boolean isOpportunistic(
             @NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) {
         if (snapshot == null) {
-            Slog.wtf(TAG, "Got null snapshot");
+            logWtf("Got null snapshot");
             return false;
         }
 
@@ -446,17 +460,23 @@
         private final Map<Network, UnderlyingNetworkRecord.Builder>
                 mUnderlyingNetworkRecordBuilders = new ArrayMap<>();
 
-        private List<UnderlyingNetworkRecord> getUnderlyingNetworks() {
-            final List<UnderlyingNetworkRecord> records = new ArrayList<>();
+        private TreeSet<UnderlyingNetworkRecord> getSortedUnderlyingNetworks() {
+            TreeSet<UnderlyingNetworkRecord> sorted =
+                    new TreeSet<>(
+                            UnderlyingNetworkRecord.getComparator(
+                                    mSubscriptionGroup,
+                                    mLastSnapshot,
+                                    mCurrentRecord,
+                                    mCarrierConfig));
 
             for (UnderlyingNetworkRecord.Builder builder :
                     mUnderlyingNetworkRecordBuilders.values()) {
                 if (builder.isValid()) {
-                    records.add(builder.build());
+                    sorted.add(builder.build());
                 }
             }
 
-            return records;
+            return sorted;
         }
 
         @Override
@@ -478,7 +498,7 @@
             final UnderlyingNetworkRecord.Builder builder =
                     mUnderlyingNetworkRecordBuilders.get(network);
             if (builder == null) {
-                Slog.wtf(TAG, "Got capabilities change for unknown key: " + network);
+                logWtf("Got capabilities change for unknown key: " + network);
                 return;
             }
 
@@ -494,7 +514,7 @@
             final UnderlyingNetworkRecord.Builder builder =
                     mUnderlyingNetworkRecordBuilders.get(network);
             if (builder == null) {
-                Slog.wtf(TAG, "Got link properties change for unknown key: " + network);
+                logWtf("Got link properties change for unknown key: " + network);
                 return;
             }
 
@@ -509,7 +529,7 @@
             final UnderlyingNetworkRecord.Builder builder =
                     mUnderlyingNetworkRecordBuilders.get(network);
             if (builder == null) {
-                Slog.wtf(TAG, "Got blocked status change for unknown key: " + network);
+                logWtf("Got blocked status change for unknown key: " + network);
                 return;
             }
 
@@ -597,7 +617,7 @@
             // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED
 
             if (isBlocked) {
-                Slog.wtf(TAG, "Network blocked for System Server: " + network);
+                logWtf("Network blocked for System Server: " + network);
                 return PRIORITY_ANY;
             }
 
@@ -660,10 +680,21 @@
         }
 
         /** Dumps the state of this record for logging and debugging purposes. */
-        public void dump(IndentingPrintWriter pw) {
+        private void dump(
+                IndentingPrintWriter pw,
+                ParcelUuid subscriptionGroup,
+                TelephonySubscriptionSnapshot snapshot,
+                UnderlyingNetworkRecord currentlySelected,
+                PersistableBundle carrierConfig) {
             pw.println("UnderlyingNetworkRecord:");
             pw.increaseIndent();
 
+            final int priorityClass =
+                    calculatePriorityClass(
+                            subscriptionGroup, snapshot, currentlySelected, carrierConfig);
+            pw.println(
+                    "Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " ("
+                            + priorityClass + ")");
             pw.println("mNetwork: " + network);
             pw.println("mNetworkCapabilities: " + networkCapabilities);
             pw.println("mLinkProperties: " + linkProperties);
@@ -733,6 +764,40 @@
         }
     }
 
+    private static void logWtf(String msg) {
+        Slog.wtf(TAG, msg);
+        LOCAL_LOG.log(TAG + " WTF: " + msg);
+    }
+
+    private static void logWtf(String msg, Throwable tr) {
+        Slog.wtf(TAG, msg, tr);
+        LOCAL_LOG.log(TAG + " WTF: " + msg + tr);
+    }
+
+    /** Dumps the state of this record for logging and debugging purposes. */
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("UnderlyingNetworkTracker:");
+        pw.increaseIndent();
+
+        pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig));
+        pw.println("Carrier WiFi Exit Threshold: " + getWifiExitRssiThreshold(mCarrierConfig));
+        pw.println(
+                "Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network));
+
+        pw.println("Underlying networks:");
+        pw.increaseIndent();
+        if (mRouteSelectionCallback != null) {
+            for (UnderlyingNetworkRecord record :
+                    mRouteSelectionCallback.getSortedUnderlyingNetworks()) {
+                record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig);
+            }
+        }
+        pw.decreaseIndent();
+        pw.println();
+
+        pw.decreaseIndent();
+    }
+
     private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback
             implements ActiveDataSubscriptionIdListener {
         @Override
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index f918827..f7d6136 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -24,6 +24,7 @@
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
 import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
 
+import static com.android.server.VcnManagementService.LOCAL_LOG;
 import static com.android.server.VcnManagementService.VDBG;
 
 import android.annotation.NonNull;
@@ -513,37 +514,44 @@
     }
 
     private String getLogPrefix() {
-        return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "]: ";
+        return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "] ";
     }
 
     private void logVdbg(String msg) {
         if (VDBG) {
             Slog.v(TAG, getLogPrefix() + msg);
+            LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg);
         }
     }
 
     private void logDbg(String msg) {
         Slog.d(TAG, getLogPrefix() + msg);
+        LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg);
     }
 
     private void logDbg(String msg, Throwable tr) {
         Slog.d(TAG, getLogPrefix() + msg, tr);
+        LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr);
     }
 
     private void logErr(String msg) {
         Slog.e(TAG, getLogPrefix() + msg);
+        LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg);
     }
 
     private void logErr(String msg, Throwable tr) {
         Slog.e(TAG, getLogPrefix() + msg, tr);
+        LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr);
     }
 
     private void logWtf(String msg) {
         Slog.wtf(TAG, getLogPrefix() + msg);
+        LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg);
     }
 
     private void logWtf(String msg, Throwable tr) {
         Slog.wtf(TAG, getLogPrefix() + msg, tr);
+        LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr);
     }
 
     /**
@@ -557,11 +565,14 @@
 
         pw.println("mCurrentStatus: " + mCurrentStatus);
         pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled);
+        pw.println();
 
         pw.println("mVcnGatewayConnections:");
+        pw.increaseIndent();
         for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) {
             gw.dump(pw);
         }
+        pw.decreaseIndent();
         pw.println();
 
         pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index dff04bf..4936970 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -30,6 +30,7 @@
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR;
 import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
 
+import static com.android.server.VcnManagementService.LOCAL_LOG;
 import static com.android.server.VcnManagementService.VDBG;
 
 import android.annotation.NonNull;
@@ -1644,7 +1645,7 @@
                 @NonNull IpSecTransform transform,
                 int direction) {
             if (direction != IpSecManager.DIRECTION_IN && direction != IpSecManager.DIRECTION_OUT) {
-                Slog.wtf(TAG, "Applying transform for unexpected direction: " + direction);
+                logWtf("Applying transform for unexpected direction: " + direction);
             }
 
             try {
@@ -1969,6 +1970,9 @@
             }
             builder.setAdministratorUids(adminUids);
 
+            builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps());
+            builder.setLinkDownstreamBandwidthKbps(underlyingCaps.getLinkDownstreamBandwidthKbps());
+
             // Set TransportInfo for SysUI use (never parcelled out of SystemServer).
             if (underlyingCaps.hasTransport(TRANSPORT_WIFI)
                     && underlyingCaps.getTransportInfo() instanceof WifiInfo) {
@@ -1985,6 +1989,11 @@
                         "Unknown transport type or missing TransportInfo/NetworkSpecifier for"
                                 + " non-null underlying network");
             }
+        } else {
+            Slog.wtf(
+                    TAG,
+                    "No underlying network while building network capabilities",
+                    new IllegalStateException());
         }
 
         return builder.build();
@@ -2012,7 +2021,18 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
                 null /*iface*/, RouteInfo.RTN_UNICAST));
 
-        final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu();
+        int underlyingMtu = 0;
+        if (underlying != null) {
+            final LinkProperties underlyingLp = underlying.linkProperties;
+
+            lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes());
+            underlyingMtu = underlyingLp.getMtu();
+        } else {
+            Slog.wtf(
+                    TAG,
+                    "No underlying network while building link properties",
+                    new IllegalStateException());
+        }
         lp.setMtu(
                 MtuUtils.getMtu(
                         ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(),
@@ -2114,37 +2134,44 @@
                 + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup)
                 + "-"
                 + mConnectionConfig.getGatewayConnectionName()
-                + "]: ";
+                + "] ";
     }
 
     private void logVdbg(String msg) {
         if (VDBG) {
             Slog.v(TAG, getLogPrefix() + msg);
+            LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg);
         }
     }
 
     private void logDbg(String msg) {
         Slog.d(TAG, getLogPrefix() + msg);
+        LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg);
     }
 
     private void logDbg(String msg, Throwable tr) {
         Slog.d(TAG, getLogPrefix() + msg, tr);
+        LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr);
     }
 
     private void logErr(String msg) {
         Slog.e(TAG, getLogPrefix() + msg);
+        LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg);
     }
 
     private void logErr(String msg, Throwable tr) {
         Slog.e(TAG, getLogPrefix() + msg, tr);
+        LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr);
     }
 
     private void logWtf(String msg) {
         Slog.wtf(TAG, getLogPrefix() + msg);
+        LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg);
     }
 
     private void logWtf(String msg, Throwable tr) {
         Slog.wtf(TAG, getLogPrefix() + msg, tr);
+        LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr);
     }
 
     /**
@@ -2168,15 +2195,9 @@
         pw.println(
                 "mNetworkAgent.getNetwork(): "
                         + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
+        pw.println();
 
-        pw.println("mUnderlying:");
-        pw.increaseIndent();
-        if (mUnderlying != null) {
-            mUnderlying.dump(pw);
-        } else {
-            pw.println("null");
-        }
-        pw.decreaseIndent();
+        mUnderlyingNetworkTracker.dump(pw);
         pw.println();
 
         pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index 8adcf95..ebabe2a 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -105,6 +105,10 @@
 
     @Override
     public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
+        if (VDBG) {
+            Slog.v(TAG, "Network request withdrawn: Request = " + request);
+        }
+
         mRequests.remove(request);
     }
 
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/network-policy-mobile.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/network-policy-mobile.xml
new file mode 100644
index 0000000..d1357e7
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/network-policy-mobile.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="12" restrictBackground="false">
+  <network-policy networkTemplate="1" subscriberId="466977604504520" cycleStart="2020-01-09T00:00+08:00[Asia/Taipei]" cyclePeriod="P1M" warningBytes="2147483648" limitBytes="-1" lastWarningSnooze="-1" lastLimitSnooze="-1" metered="true" inferred="true" />
+</policy-list>
+<whitelist />
+
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/network-policy-wifi-with-subscriberId-match-rule-all-and-templateMetered-no.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/network-policy-wifi-with-subscriberId-match-rule-all-and-templateMetered-no.xml
new file mode 100644
index 0000000..60d7d25
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/network-policy-wifi-with-subscriberId-match-rule-all-and-templateMetered-no.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policy-list version="13" restrictBackground="false">
+<network-policy networkTemplate="4" subscriberIdMatchRule="1" networkId="TEST_SSID" templateMetered="0" cycleStart="2020-01-09T00:00+08:00[Asia/Taipei]" cyclePeriod="P1M" warningBytes="2147483648" limitBytes="-1" lastWarningSnooze="-1" lastLimitSnooze="-1" metered="true" inferred="true" />
+</policy-list>
+<whitelist />
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index aecc794..b01c1c8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -165,7 +165,17 @@
             mRebootEscrow = null;
             mServerBased = true;
             RebootEscrowProviderServerBasedImpl.Injector injector =
-                    new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection);
+                    new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) {
+                        @Override
+                        long getServiceTimeoutInSeconds() {
+                            return 30;
+                        }
+
+                        @Override
+                        long getServerBlobLifetimeInMillis() {
+                            return 600_000;
+                        }
+                    };
             mDefaultRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(
                     storage, injector);
             mUserManager = userManager;
@@ -189,6 +199,11 @@
         }
 
         @Override
+        public boolean isNetworkConnected() {
+            return false;
+        }
+
+        @Override
         public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
             mRebootEscrowProviderInUse = mDefaultRebootEscrowProvider;
             return mRebootEscrowProviderInUse;
@@ -602,7 +617,7 @@
         // Sleep 5s for the retry to complete
         Thread.sleep(5 * 1000);
         assertFalse(metricsSuccessCaptor.getValue());
-        assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_RETRY_COUNT_EXHAUSTED),
+        assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
                 metricsErrorCodeCaptor.getValue());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index d041eec..fa65b07 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -50,10 +50,12 @@
 import static android.net.NetworkPolicyManager.uidRulesToString;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
 import static android.net.NetworkStats.SET_ALL;
 import static android.net.NetworkStats.TAG_ALL;
 import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateCarrierMetered;
 import static android.net.NetworkTemplate.buildTemplateWifi;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
@@ -229,7 +231,8 @@
     private static final int TEST_NET_ID = 24;
 
     private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
-    private static NetworkTemplate sTemplateMobileAll = buildTemplateMobileAll(TEST_IMSI);
+    private static NetworkTemplate sTemplateCarrierMetered =
+            buildTemplateCarrierMetered(TEST_IMSI);
 
     /**
      * Path on assets where files used by {@link NetPolicyXml} are located.
@@ -450,7 +453,7 @@
         verify(mNetworkManager).registerObserver(networkObserver.capture());
         mNetworkObserver = networkObserver.getValue();
 
-        NetworkPolicy defaultPolicy = mService.buildDefaultMobilePolicy(0, "");
+        NetworkPolicy defaultPolicy = mService.buildDefaultCarrierPolicy(0, "");
         mDefaultWarningBytes = defaultPolicy.warningBytes;
         mDefaultLimitBytes = defaultPolicy.limitBytes;
     }
@@ -1229,7 +1232,7 @@
             reset(mTelephonyManager, mNetworkManager, mNotifManager);
             TelephonyManager tmSub = expectMobileDefaults();
 
-            mService.snoozeLimit(NetworkTemplate.buildTemplateMobileAll(TEST_IMSI));
+            mService.snoozeLimit(NetworkTemplate.buildTemplateCarrierMetered(TEST_IMSI));
             mService.updateNetworks();
 
             verify(tmSub, atLeastOnce()).setPolicyDataEnabled(true);
@@ -1482,7 +1485,7 @@
         assertEquals(mDefaultLimitBytes, actualLimitBytes);
     }
 
-    private PersistableBundle setupUpdateMobilePolicyCycleTests() throws RemoteException {
+    private PersistableBundle setupUpdateCarrierPolicyCycleTests() throws RemoteException {
         when(mConnManager.getAllNetworkStateSnapshots())
                 .thenReturn(new ArrayList<NetworkStateSnapshot>());
 
@@ -1490,19 +1493,19 @@
 
         PersistableBundle bundle = CarrierConfigManager.getDefaultConfig();
         when(mCarrierConfigManager.getConfigForSubId(FAKE_SUB_ID)).thenReturn(bundle);
-        setNetworkPolicies(buildDefaultFakeMobilePolicy());
+        setNetworkPolicies(buildDefaultFakeCarrierPolicy());
         return bundle;
     }
 
     @Test
-    public void testUpdateMobilePolicyCycleWithNullConfig() throws RemoteException {
+    public void testUpdateCarrierPolicyCycleWithNullConfig() throws RemoteException {
         when(mConnManager.getAllNetworkStateSnapshots())
                 .thenReturn(new ArrayList<NetworkStateSnapshot>());
 
         setupTelephonySubscriptionManagers(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID);
 
         when(mCarrierConfigManager.getConfigForSubId(FAKE_SUB_ID)).thenReturn(null);
-        setNetworkPolicies(buildDefaultFakeMobilePolicy());
+        setNetworkPolicies(buildDefaultFakeCarrierPolicy());
         // smoke test to make sure no errors are raised
         mServiceContext.sendBroadcast(
                 new Intent(ACTION_CARRIER_CONFIG_CHANGED)
@@ -1513,8 +1516,8 @@
     }
 
     @Test
-    public void testUpdateMobilePolicyCycleWithInvalidConfig() throws RemoteException {
-        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+    public void testUpdateCarrierPolicyCycleWithInvalidConfig() throws RemoteException {
+        PersistableBundle bundle = setupUpdateCarrierPolicyCycleTests();
         // Test with an invalid CarrierConfig, there should be no changes or crashes.
         bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, -100);
         bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, -100);
@@ -1529,8 +1532,8 @@
     }
 
     @Test
-    public void testUpdateMobilePolicyCycleWithDefaultConfig() throws RemoteException {
-        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+    public void testUpdateCarrierPolicyCycleWithDefaultConfig() throws RemoteException {
+        PersistableBundle bundle = setupUpdateCarrierPolicyCycleTests();
         // Test that we respect the platform values when told to
         bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT,
                 DATA_CYCLE_USE_PLATFORM_DEFAULT);
@@ -1548,11 +1551,11 @@
     }
 
     @Test
-    public void testUpdateMobilePolicyCycleWithUserOverrides() throws RemoteException {
-        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+    public void testUpdateCarrierPolicyCycleWithUserOverrides() throws RemoteException {
+        PersistableBundle bundle = setupUpdateCarrierPolicyCycleTests();
 
         // inferred = false implies that a user manually modified this policy.
-        NetworkPolicy policy = buildDefaultFakeMobilePolicy();
+        NetworkPolicy policy = buildDefaultFakeCarrierPolicy();
         policy.inferred = false;
         setNetworkPolicies(policy);
 
@@ -1571,8 +1574,8 @@
     }
 
     @Test
-    public void testUpdateMobilePolicyCycleUpdatesDataCycle() throws RemoteException {
-        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+    public void testUpdateCarrierPolicyCycleUpdatesDataCycle() throws RemoteException {
+        PersistableBundle bundle = setupUpdateCarrierPolicyCycleTests();
 
         bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
         bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG, 9999);
@@ -1586,8 +1589,8 @@
     }
 
     @Test
-    public void testUpdateMobilePolicyCycleDisableThresholds() throws RemoteException {
-        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+    public void testUpdateCarrierPolicyCycleDisableThresholds() throws RemoteException {
+        PersistableBundle bundle = setupUpdateCarrierPolicyCycleTests();
 
         bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
         bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
@@ -1603,8 +1606,8 @@
     }
 
     @Test
-    public void testUpdateMobilePolicyCycleRevertsToDefault() throws RemoteException {
-        PersistableBundle bundle = setupUpdateMobilePolicyCycleTests();
+    public void testUpdateCarrierPolicyCycleRevertsToDefault() throws RemoteException {
+        PersistableBundle bundle = setupUpdateCarrierPolicyCycleTests();
 
         bundle.putInt(CarrierConfigManager.KEY_MONTHLY_DATA_CYCLE_DAY_INT, 31);
         bundle.putLong(CarrierConfigManager.KEY_DATA_WARNING_THRESHOLD_BYTES_LONG,
@@ -1774,7 +1777,7 @@
     @Test
     public void testSetNetworkPolicies_withNullPolicies_doesNotThrow() {
         NetworkPolicy[] policies = new NetworkPolicy[3];
-        policies[1] = buildDefaultFakeMobilePolicy();
+        policies[1] = buildDefaultFakeCarrierPolicy();
         setNetworkPolicies(policies);
 
         assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
@@ -1820,7 +1823,8 @@
 
         // Set warning to 7KB and limit to 10KB.
         setNetworkPolicies(new NetworkPolicy(
-                sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, 7000L, 10000L, true));
+                sTemplateCarrierMetered, CYCLE_DAY, TIMEZONE_UTC, 7000L, 10000L,
+                true));
         postMsgAndWaitForCompletion();
 
         // Verifies that remaining quotas are set to providers.
@@ -1971,6 +1975,40 @@
         }
     }
 
+    @Test
+    @NetPolicyXml("network-policy-mobile.xml")
+    public void testStartToSupportCarrierUsagePolicy() throws Exception {
+        NetworkPolicy[] policies = mService.getNetworkPolicies(
+                mServiceContext.getOpPackageName());
+        assertEquals("Unexpected number of network policies", 1, policies.length);
+        NetworkPolicy actualPolicy = policies[0];
+        assertEquals("Unexpected template match rule in network policies",
+                NetworkTemplate.MATCH_CARRIER,
+                actualPolicy.template.getMatchRule());
+        assertEquals("Unexpected subscriberId match rule in network policies",
+                NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT,
+                actualPolicy.template.getSubscriberIdMatchRule());
+        assertEquals("Unexpected template meteredness in network policies",
+                METERED_YES, actualPolicy.template.getMeteredness());
+    }
+
+    @Test
+    @NetPolicyXml("network-policy-wifi-with-subscriberId-match-rule-all-and-templateMetered-no.xml")
+    public void testSupportedCarrierUsagePolicy() throws Exception {
+        NetworkPolicy[] policies = mService.getNetworkPolicies(
+                mServiceContext.getOpPackageName());
+        assertEquals("Unexpected number of network policies", 1, policies.length);
+        NetworkPolicy actualPolicy = policies[0];
+        assertEquals("Unexpected template match rule in network policies",
+                NetworkTemplate.MATCH_WIFI,
+                actualPolicy.template.getMatchRule());
+        assertEquals("Unexpected subscriberId match rule in network policies",
+                NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_ALL,
+                actualPolicy.template.getSubscriberIdMatchRule());
+        assertEquals("Unexpected template meteredness in network policies",
+                METERED_NO, actualPolicy.template.getMeteredness());
+    }
+
     private String formatBlockedStateError(int uid, int rule, boolean metered,
             boolean backgroundRestricted) {
         return String.format(
@@ -2023,8 +2061,8 @@
         return nc;
     }
 
-    private NetworkPolicy buildDefaultFakeMobilePolicy() {
-        NetworkPolicy p = mService.buildDefaultMobilePolicy(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID);
+    private NetworkPolicy buildDefaultFakeCarrierPolicy() {
+        NetworkPolicy p = mService.buildDefaultCarrierPolicy(FAKE_SUB_ID, FAKE_SUBSCRIBER_ID);
         // set a deterministic cycle date
         p.cycleRule = new RecurrenceRule(
                 p.cycleRule.start.withDayOfMonth(DEFAULT_CYCLE_DAY),
@@ -2032,9 +2070,9 @@
         return p;
     }
 
-    private static NetworkPolicy buildFakeMobilePolicy(int cycleDay, long warningBytes,
+    private static NetworkPolicy buildFakeCarrierPolicy(int cycleDay, long warningBytes,
             long limitBytes, boolean inferred) {
-        final NetworkTemplate template = buildTemplateMobileAll(FAKE_SUBSCRIBER_ID);
+        final NetworkTemplate template = buildTemplateCarrierMetered(FAKE_SUBSCRIBER_ID);
         return new NetworkPolicy(template, cycleDay, TimeZone.getDefault().getID(), warningBytes,
                 limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, true, inferred);
     }
@@ -2045,8 +2083,8 @@
                 mServiceContext.getOpPackageName());
         assertEquals("Unexpected number of network policies", 1, policies.length);
         NetworkPolicy actualPolicy = policies[0];
-        NetworkPolicy expectedPolicy = buildFakeMobilePolicy(expectedCycleDay, expectedWarningBytes,
-                expectedLimitBytes, expectedInferred);
+        NetworkPolicy expectedPolicy = buildFakeCarrierPolicy(expectedCycleDay,
+                expectedWarningBytes, expectedLimitBytes, expectedInferred);
         assertEquals(expectedPolicy, actualPolicy);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 3c55b7c..d7299fd 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2404,6 +2404,12 @@
     boolean removeUceRequestDisallowedStatus(int subId);
 
     /**
+     * Set the timeout for contact capabilities request.
+     * Note: This is designed for a SHELL command only.
+     */
+    boolean setCapabilitiesRequestTimeout(int subId, long timeoutAfterMs);
+
+    /**
      * Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
      * specified thresholds.
      */
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 39f7386..9c93f81 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -200,6 +200,9 @@
     public void testMigration() throws Exception {
         triggerChildOpened();
 
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
         getChildSessionCallback()
                 .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
         mTestLooper.dispatchAll();
@@ -207,7 +210,7 @@
         verify(mIpSecSvc, times(2))
                 .setNetworkForTunnelInterface(
                         eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
-                        eq(TEST_UNDERLYING_NETWORK_RECORD_1.network),
+                        eq(TEST_UNDERLYING_NETWORK_RECORD_2.network),
                         any());
 
         for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
@@ -226,8 +229,10 @@
                 MtuUtils.getMtu(
                         saProposals,
                         mConfig.getMaxMtu(),
-                        TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu());
-        verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu()));
+                        TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu());
+        verify(mNetworkAgent).sendLinkProperties(
+                argThat(lp -> expectedMtu == lp.getMtu()
+                        && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes())));
     }
 
     private void triggerChildOpened() {
@@ -297,6 +302,7 @@
         final LinkProperties lp = lpCaptor.getValue();
         assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
         assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
+        assertEquals(TEST_TCP_BUFFER_SIZES_1, lp.getTcpBufferSizes());
 
         final NetworkCapabilities nc = ncCaptor.getValue();
         assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 9705f0f..a4f95e0 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -74,6 +74,9 @@
     private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
     private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
 
+    private static final int TEST_UPSTREAM_BANDWIDTH = 1234;
+    private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345;
+
     static {
         final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
         subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
@@ -106,6 +109,8 @@
             capBuilder.setNetworkSpecifier(
                     new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1));
         }
+        capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH);
+        capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH);
         capBuilder.setAdministratorUids(new int[] {TEST_UID});
         UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
                 mock(Network.class, CALLS_REAL_METHODS),
@@ -130,6 +135,8 @@
 
         assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
         assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
+        assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps());
+        assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps());
 
         final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo();
         if (transportType == TRANSPORT_WIFI) {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 860a919..b97023a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -99,6 +99,7 @@
     protected static final long ELAPSED_REAL_TIME = 123456789L;
     protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
 
+    protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4";
     protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
             new UnderlyingNetworkRecord(
                     mock(Network.class, CALLS_REAL_METHODS),
@@ -108,8 +109,10 @@
 
     static {
         TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500);
+        TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_1);
     }
 
+    protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5";
     protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
             new UnderlyingNetworkRecord(
                     mock(Network.class, CALLS_REAL_METHODS),
@@ -119,6 +122,7 @@
 
     static {
         TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460);
+        TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_2);
     }
 
     protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index e8873bf..7546e41 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -27,7 +27,7 @@
 
 static ApiVersion sDevelopmentSdkLevel = 10000;
 static const auto sDevelopmentSdkCodeNames = std::unordered_set<StringPiece>({
-    "Q", "R", "S"
+    "Q", "R", "S", "T"
 });
 
 static const std::vector<std::pair<uint16_t, ApiVersion>> sAttrIdMap = {
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 514f17a0..3960856f 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -4,6 +4,9 @@
 if git branch -vv | grep -q -P "^\*[^\[]+\[aosp/"; then
     # Change appears to be in AOSP
     exit 0
+elif git log -n 1 --format='%B' $1 | grep -q -E "^Ignore-AOSP-First: .+" ; then
+    # Change is explicitly marked as ok to skip AOSP
+    exit 0
 else
     # Change appears to be non-AOSP.