Merge "Migrates additional Assistant logging to Westworld"
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d976997..448bf6c 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -470,6 +470,14 @@
         NetworkDhcpRenewReported network_dhcp_renew_reported = 291 [(module) = "network_stack"];
         NetworkValidationReported network_validation_reported = 292 [(module) = "network_stack"];
         NetworkStackQuirkReported network_stack_quirk_reported = 293 [(module) = "network_stack"];
+        MediametricsAudioRecordDeviceUsageReported mediametrics_audiorecorddeviceusage_reported =
+            294;
+        MediametricsAudioThreadDeviceUsageReported mediametrics_audiothreaddeviceusage_reported =
+            295;
+        MediametricsAudioTrackDeviceUsageReported mediametrics_audiotrackdeviceusage_reported =
+            296;
+        MediametricsAudioDeviceConnectionReported mediametrics_audiodeviceconnection_reported =
+            297;
 
         // StatsdStats tracks platform atoms with ids upto 500.
         // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -10562,3 +10570,237 @@
     // Whether the Assistant handles were showing at the time of invocation.
     optional bool assistant_handles_showing = 6;
 }
+
+/**
+ * Logs when an AudioRecord finishes running on an audio device
+ *
+ * Logged from:
+ *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
+ */
+message MediametricsAudioRecordDeviceUsageReported {
+    // The devices connected to this AudioRecord.
+    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
+    // See lookup<INPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string devices = 1;
+
+    // The name of the remote device attached to the device, typically available for USB or BT.
+    // This may be empty for a fixed device, or separated by "|" if more than one.
+    optional string device_names = 2;
+
+    // The amount of time spent in the device as measured by the active track in AudioFlinger.
+    optional int64 device_time_nanos = 3;
+
+    // The audio data format used for encoding.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
+    optional string encoding = 4;
+
+    // The client-server buffer framecount.
+    // The framecount is generally between 960 - 48000 for PCM encoding.
+    // The framecount represents raw buffer size in bytes for non-PCM encoding.
+    optional int32 frame_count = 5;
+
+    // The number of audio intervals (contiguous, continuous playbacks).
+    optional int32 interval_count = 6;
+
+    // The sample rate of the AudioRecord.
+    // A number generally between 8000-96000 (frames per second).
+    optional int32 sample_rate = 7;
+
+    // The audio input flags used to construct the AudioRecord.
+    // A string OR from system/media/audio/include/system/audio-base.h audio_input_flags_t
+    optional string flags = 8;
+
+    // The santized package name of the audio client associated with the AudioRecord.
+    // See getSanitizedPackageNameAndVersionCode() in
+    // frameworks/av/services/mediametrics/MediaMetricsService.cpp
+    optional string package_name = 9;
+
+    // The selected device id (nonzero if a non-default device is selected)
+    optional int32 selected_device_id = 10;
+
+    // The caller of the AudioRecord.
+    // See lookup<CALLER_NAME>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    optional string caller = 11;
+
+    // The audio source for AudioRecord.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_source_t
+    optional string source = 12;
+}
+
+/**
+ * Logs when an AudioThread finishes running on an audio device
+ *
+ * Logged from:
+ *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
+ */
+message MediametricsAudioThreadDeviceUsageReported {
+    // The devices connected to this audio thread.
+    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
+    // (for record threads):
+    // See lookup<INPUT_DEVICE> in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // (for playback threads):
+    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string devices = 1;
+
+    // The name of the remote device attached to the device, typically available for USB or BT.
+    // This may be empty for a fixed device, or separated by "|" if more than one.
+    optional string device_names = 2;
+
+    // The amount of time spent in the device as measured by the active track in AudioFlinger.
+    optional int64 device_time_nanos = 3;
+
+    // The audio data format used for encoding.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
+    optional string encoding = 4;
+
+    // The framecount of the buffer delivered to (or from) the HAL.
+    // The framecount is generally ~960 for PCM encoding.
+    // The framecount represents raw buffer size in bytes for non-PCM encoding.
+    optional int32 frame_count = 5;
+
+    // The number of audio intervals (contiguous, continuous playbacks).
+    optional int32 interval_count = 6;
+
+    // The sample rate of the audio thread.
+    // A number generally between 8000-96000 (frames per second).
+    optional int32 sample_rate = 7;
+
+    // The audio flags used to construct the thread
+    // (for record threads):
+    // A string OR from system/media/audio/include/system/audio-base.h audio_input_flags_t
+    // (for playback threads):
+    // A string OR from system/media/audio/include/system/audio-base.h audio_output_flags_t
+    optional string flags = 8;
+
+    // The number of underruns encountered for a playback thread or the
+    // number of overruns encountered for a capture thread.
+    optional int32 xruns = 9;
+
+    // The type of thread
+    // A thread type enumeration from
+    // frameworks/av/mediametrics/services/Translate.h
+    optional string type = 10;
+}
+
+/**
+ * Logs when an AudioTrack finishes running on an audio device
+ *
+ * Logged from:
+ *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
+ */
+message MediametricsAudioTrackDeviceUsageReported {
+    // The output devices connected to this AudioTrack.
+    // A string OR of various output device categories, e.g. "DEVICE1|DEVICE2".
+    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string devices = 1;
+
+    // The name of the remote device attached to the device, typically available for USB or BT.
+    // This may be empty for a fixed device, or separated by "|" if more than one.
+    optional string device_names = 2;
+
+    // The amount of time spent in the device as measured by the active track in AudioFlinger.
+    optional int64 device_time_nanos = 3;
+
+    // The audio data format used for encoding.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
+    optional string encoding = 4;
+
+    // The client-server buffer framecount.
+    // The framecount is generally between 960 - 48000 for PCM encoding.
+    // The framecount represents raw buffer size in bytes for non-PCM encoding.
+    // A static track (see traits) may have a very large framecount.
+    optional int32 frame_count = 5;
+
+    // The number of audio intervals (contiguous, continuous playbacks).
+    optional int32 interval_count = 6;
+
+    // The sample rate of the AudioTrack.
+    // A number generally between 8000-96000 (frames per second).
+    optional int32 sample_rate = 7;
+
+    // The audio flags used to construct the AudioTrack.
+    // A string OR from system/media/audio/include/system/audio-base.h audio_output_flags_t
+    optional string flags = 8;
+
+    // The number of underruns encountered.
+    optional int32 xruns = 9;
+
+    // The santized package name of the audio client associated with the AudioTrack.
+    // See getSanitizedPackageNameAndVersionCode() in
+    // frameworks/av/services/mediametrics/MediaMetricsService.cpp
+    optional string package_name = 10;
+
+    // The latency of the last sample in the buffer in milliseconds.
+    optional float device_latency_millis = 11;
+
+    // The startup time in milliseconds from start() to sample played.
+    optional float device_startup_millis = 12;
+
+    // The average volume of the track on the device [ 0.f - 1.f ]
+    optional float device_volume = 13;
+
+    // The selected device id (nonzero if a non-default device is selected)
+    optional int32 selected_device_id = 14;
+
+    // The stream_type category for the AudioTrack.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_stream_type_t
+    optional string stream_type = 15;
+
+    // The usage for the AudioTrack.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_usage_t
+    optional string usage = 16;
+
+    // The content type of the AudioTrack.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_content_type_t
+    optional string content_type = 17;
+
+    // The caller of the AudioTrack.
+    // See lookup<CALLER_NAME>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    optional string caller = 18;
+
+    // The traits of the AudioTrack.
+    // A string OR of different traits, may be empty string.
+    // Only "static" is supported for R.
+    // See lookup<TRACK_TRAITS>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    optional string traits = 19;
+}
+
+/**
+ * Logs the status of an audio device connection attempt.
+ *
+ * Logged from:
+ *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
+ */
+message MediametricsAudioDeviceConnectionReported {
+    // The input devices represented by this report.
+    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
+    // See lookup<INPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string input_devices = 1;
+
+    // The output devices represented by this report.
+    // A string OR of various output device categories.
+    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string output_devices = 2;
+
+    // The name of the remote device attached to the device, typically available for USB or BT.
+    // This may be empty for a fixed device, or separated by "|" if more than one.
+    optional string device_names = 3;
+
+    // The result of the audio device connection.
+    // 0 indicates success: connection verified.
+    // 1 indicates unknown: connection not verified or not known if diverted properly.
+    // Other values indicate specific status.
+    // See DeviceConnectionResult in frameworks/av/services/mediametrics/AudioTypes.h
+    optional int32 result = 4;
+
+    // Average milliseconds of time to connect
+    optional float time_to_connect_millis = 5;
+
+    // Number of connections if aggregated statistics, otherwise 1.
+    optional int32 connection_count = 6;
+}
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index d0052ab..9bf0513 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -316,7 +316,7 @@
             };
             msg.replyTo = new Messenger(h);
 
-            if (mScreenshotConnection == null) {
+            if (mScreenshotConnection == null || mScreenshotService == null) {
                 final ComponentName serviceComponent = ComponentName.unflattenFromString(
                         mContext.getResources().getString(
                                 com.android.internal.R.string.config_screenshotServiceComponent));
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
index 775ef81..8aa7b63 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
@@ -23,9 +23,12 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.util.Log;
+import android.view.IWindowManager;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -44,13 +47,14 @@
  */
 @Singleton
 public class UserSwitchTransitionViewController extends OverlayViewController {
-    private static final String TAG = "UserSwitchTransitionViewController";
+    private static final String TAG = "UserSwitchTransition";
     private static final String ENABLE_DEVELOPER_MESSAGE_TRUE = "true";
 
     private final Context mContext;
     private final Handler mHandler;
     private final Resources mResources;
     private final UserManager mUserManager;
+    private final IWindowManager mWindowManagerService;
 
     @GuardedBy("this")
     private boolean mShowing;
@@ -62,6 +66,7 @@
             @Main Handler handler,
             @Main Resources resources,
             UserManager userManager,
+            IWindowManager windowManagerService,
             OverlayViewGlobalStateController overlayViewGlobalStateController) {
 
         super(R.id.user_switching_dialog_stub, overlayViewGlobalStateController);
@@ -70,6 +75,7 @@
         mHandler = handler;
         mResources = resources;
         mUserManager = userManager;
+        mWindowManagerService = windowManagerService;
     }
 
     /**
@@ -81,6 +87,13 @@
         if (mPreviousUserId == newUserId || mShowing) return;
         mShowing = true;
         mHandler.post(() -> {
+            try {
+                mWindowManagerService.setSwitchingUser(true);
+                mWindowManagerService.lockNow(null);
+            } catch (RemoteException e) {
+                Log.e(TAG, "unable to notify window manager service regarding user switch");
+            }
+
             start();
             populateDialog(mPreviousUserId, newUserId);
             // next time a new user is selected, this current new user will be the previous user.
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
index eab381c..65c5562 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
@@ -28,6 +28,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableResources;
+import android.view.IWindowManager;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 
@@ -52,6 +53,8 @@
     private TestableResources mTestableResources;
     @Mock
     private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+    @Mock
+    private IWindowManager mWindowManagerService;
 
     @Before
     public void setUp() {
@@ -62,6 +65,7 @@
                 Handler.getMain(),
                 mTestableResources.getResources(),
                 (UserManager) mContext.getSystemService(Context.USER_SERVICE),
+                mWindowManagerService,
                 mOverlayViewGlobalStateController
         );
 
@@ -125,8 +129,10 @@
 
         TestableUserSwitchTransitionViewController(Context context, Handler handler,
                 Resources resources, UserManager userManager,
+                IWindowManager windowManagerService,
                 OverlayViewGlobalStateController overlayViewGlobalStateController) {
-            super(context, handler, resources, userManager, overlayViewGlobalStateController);
+            super(context, handler, resources, userManager, windowManagerService,
+                    overlayViewGlobalStateController);
             mHandler = handler;
         }
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9d7833a..9faa2cf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2640,7 +2640,7 @@
     <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
     <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
     <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
-    <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=20] -->
+    <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] -->
     <string name="bubble_dismiss_text">Dismiss bubble</string>
     <!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]-->
     <string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string>
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 5d36dd6..0fa7bf9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -163,6 +163,11 @@
                             Log.d(TAG, "onActivityViewReady: calling startActivity, "
                                     + "bubble=" + getBubbleKey());
                         }
+                        if (mActivityView == null) {
+                            mBubbleController.removeBubble(getBubbleKey(),
+                                    BubbleController.DISMISS_INVALID_INTENT);
+                            return;
+                        }
                         try {
                             if (!mIsOverflow && mBubble.usingShortcutInfo()) {
                                 options.setApplyActivityFlagsForBubbles(true);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 6ea36ab..5fe3995 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -109,6 +109,24 @@
         }
     }
 
+    private val appChangeReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent) {
+            when (intent.action) {
+                Intent.ACTION_PACKAGES_SUSPENDED -> {
+                    val packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+                    packages?.forEach {
+                        removeAllForPackage(it)
+                    }
+                }
+                Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_RESTARTED -> {
+                    intent.data?.encodedSchemeSpecificPart?.let {
+                        removeAllForPackage(it)
+                    }
+                }
+            }
+        }
+    }
+
     init {
         mediaTimeoutListener.timeoutCallback = { token: String, timedOut: Boolean ->
             setTimedOut(token, timedOut) }
@@ -129,6 +147,17 @@
 
         val userFilter = IntentFilter(Intent.ACTION_USER_SWITCHED)
         broadcastDispatcher.registerReceiver(userChangeReceiver, userFilter, null, UserHandle.ALL)
+
+        val suspendFilter = IntentFilter(Intent.ACTION_PACKAGES_SUSPENDED)
+        broadcastDispatcher.registerReceiver(appChangeReceiver, suspendFilter, null, UserHandle.ALL)
+
+        val uninstallFilter = IntentFilter().apply {
+            addAction(Intent.ACTION_PACKAGE_REMOVED)
+            addAction(Intent.ACTION_PACKAGE_RESTARTED)
+            addDataScheme("package")
+        }
+        // BroadcastDispatcher does not allow filters with data schemes
+        context.registerReceiver(appChangeReceiver, uninstallFilter)
     }
 
     fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
@@ -160,6 +189,18 @@
         mediaEntries.clear()
     }
 
+    private fun removeAllForPackage(packageName: String) {
+        Assert.isMainThread()
+        val listenersCopy = listeners.toSet()
+        val toRemove = mediaEntries.filter { it.value.packageName == packageName }
+        toRemove.forEach {
+            mediaEntries.remove(it.key)
+            listenersCopy.forEach { listener ->
+                listener.onMediaDataRemoved(it.key)
+            }
+        }
+    }
+
     private fun addResumptionControls(
         desc: MediaDescription,
         action: Runnable,
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index 1e9a303..6462f07 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -135,12 +135,16 @@
          */
         @Override
         public void onConnected() {
+            Log.d(TAG, "Service connected for " + mComponentName);
             if (mMediaBrowser.isConnected()) {
-                mCallback.onConnected();
-                Log.d(TAG, "Service connected for " + mComponentName);
                 String root = mMediaBrowser.getRoot();
-                mMediaBrowser.subscribe(root, mSubscriptionCallback);
+                if (!TextUtils.isEmpty(root)) {
+                    mCallback.onConnected();
+                    mMediaBrowser.subscribe(root, mSubscriptionCallback);
+                    return;
+                }
             }
+            mCallback.onError();
         }
 
         /**
@@ -193,6 +197,10 @@
                     @Override
                     public void onConnected() {
                         Log.d(TAG, "Connected for restart " + mMediaBrowser.isConnected());
+                        if (!mMediaBrowser.isConnected()) {
+                            mCallback.onError();
+                            return;
+                        }
                         MediaSession.Token token = mMediaBrowser.getSessionToken();
                         MediaController controller = new MediaController(mContext, token);
                         controller.getTransportControls();
@@ -251,7 +259,8 @@
                     @Override
                     public void onConnected() {
                         Log.d(TAG, "connected");
-                        if (TextUtils.isEmpty(mMediaBrowser.getRoot())) {
+                        if (!mMediaBrowser.isConnected()
+                                || TextUtils.isEmpty(mMediaBrowser.getRoot())) {
                             mCallback.onError();
                         } else {
                             mCallback.onConnected();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index daefef5..c211de0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -16,14 +16,19 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.content.Intent.ACTION_OVERLAY_CHANGED;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.om.IOverlayManager;
 import android.content.om.OverlayInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ApkAssets;
+import android.os.PatternMatcher;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -79,6 +84,19 @@
                 }
             };
 
+    // The primary user SysUI process doesn't get AppInfo changes from overlay package changes for
+    // the secondary user (b/158613864), so we need to update the interaction mode here as well
+    // as a fallback if we don't receive the configuration change
+    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Log.d(TAG, "ACTION_OVERLAY_CHANGED");
+            }
+            updateCurrentInteractionMode(true /* notify */);
+        }
+    };
+
 
     @Inject
     public NavigationModeController(Context context,
@@ -92,6 +110,11 @@
         mUiBgExecutor = uiBgExecutor;
         deviceProvisionedController.addCallback(mDeviceProvisionedCallback);
 
+        IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
+        overlayFilter.addDataScheme("package");
+        overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
+        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);
+
         configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
             @Override
             public void onOverlayChanged() {
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 2ef5895..3df0ba2 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -56,8 +56,8 @@
 
 /**
  * Maintains a binding to the best service that matches the given intent information. Bind and
- * unbind callbacks, as well as all binder operations, will all be run on the {@link FgThread}
- * handler.
+ * unbind callbacks, as well as all binder operations, will all be run on a single thread, but the
+ * exact thread is left undefined.
  */
 public class ServiceWatcher implements ServiceConnection {
 
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index b694fc3..92fce8a 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -103,6 +103,13 @@
     @Override
     public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
         checkCompatChangeReadAndLogPermission();
+        return isChangeEnabledInternal(changeId, appInfo);
+    }
+
+    /**
+     * Internal version of the above method. Does not perform costly permission check.
+     */
+    public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
         if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
             reportChange(changeId, appInfo.uid,
                     ChangeReporter.STATE_ENABLED);
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 4b6ee71..5b9db64 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -32,7 +32,6 @@
 import android.content.pm.parsing.component.ParsedIntentInfo;
 import android.content.pm.parsing.component.ParsedMainComponent;
 import android.content.pm.parsing.component.ParsedProvider;
-import android.os.Binder;
 import android.os.Process;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -239,20 +238,13 @@
         }
 
         private void updateEnabledState(AndroidPackage pkg) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // TODO(b/135203078): Do not use toAppInfo
-                final boolean enabled =
-                        mInjector.getCompatibility().isChangeEnabled(
-                                PackageManager.FILTER_APPLICATION_QUERY,
-                                pkg.toAppInfoWithoutState());
-                if (enabled) {
-                    mDisabledPackages.remove(pkg.getPackageName());
-                } else {
-                    mDisabledPackages.add(pkg.getPackageName());
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
+            // TODO(b/135203078): Do not use toAppInfo
+            final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternal(
+                    PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
+            if (enabled) {
+                mDisabledPackages.remove(pkg.getPackageName());
+            } else {
+                mDisabledPackages.add(pkg.getPackageName());
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 67e1994..fdd9636 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -349,7 +349,8 @@
         if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) {
             return sharedUserSetting.seInfoTargetSdkVersion;
         }
-        if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.toAppInfoWithoutState())) {
+        if (compatibility.isChangeEnabledInternal(SELINUX_LATEST_CHANGES,
+                pkg.toAppInfoWithoutState())) {
             return android.os.Build.VERSION_CODES.R;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index efc1c05..a550b27 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -52,7 +52,7 @@
     @Test
     public void getSeInfoOptInToLatest() {
         AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
-        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
                 argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
                 .thenReturn(true);
         assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
@@ -62,7 +62,7 @@
     @Test
     public void getSeInfoNoOptIn() {
         AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
-        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
                 argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
                 .thenReturn(false);
         assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
@@ -72,7 +72,7 @@
     @Test
     public void getSeInfoNoOptInButAlreadyR() {
         AndroidPackage pkg = makePackage(OPT_IN_VERSION);
-        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
                 argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
                 .thenReturn(false);
         assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),