Merge "Add more javadocs to SyncFence" into tm-dev
diff --git a/core/api/current.txt b/core/api/current.txt
index 5b1f59a..56415ec 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -16870,6 +16870,7 @@
     field public static final long USAGE_SENSOR_DIRECT_DATA = 8388608L; // 0x800000L
     field public static final long USAGE_VIDEO_ENCODE = 65536L; // 0x10000L
     field public static final int YCBCR_420_888 = 35; // 0x23
+    field public static final int YCBCR_P010 = 54; // 0x36
   }
 
   public final class Sensor {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ed7fc66..2c29343 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -205,7 +205,6 @@
     field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
     field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
     field public static final String MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE = "android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE";
-    field public static final String MODIFY_TOUCH_MODE_STATE = "android.permission.MODIFY_TOUCH_MODE_STATE";
     field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
     field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE";
     field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
@@ -6789,7 +6788,8 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.TIS_EXTENSION_INTERFACE) public java.util.List<java.lang.String> getAvailableExtensionInterfaceNames(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
     method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public int getClientPid(@NonNull String);
-    method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public int getClientPriority(int, @Nullable String);
+    method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public int getClientPriority(int, @NonNull String);
+    method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public int getClientPriority(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TUNED_INFO) public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
     method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
     method @Nullable @RequiresPermission(android.Manifest.permission.TIS_EXTENSION_INTERFACE) public android.os.IBinder getExtensionInterface(@NonNull String, @NonNull String);
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index ac1bcf3..1e4c9501 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -63,6 +63,7 @@
             D_FP32,
             DS_FP32UI8,
             S_UI8,
+            YCBCR_P010,
     })
     public @interface Format {
     }
@@ -96,6 +97,14 @@
     public static final int DS_FP32UI8   = 0x34;
     /** Format: 8 bits stencil */
     public static final int S_UI8        = 0x35;
+    /**
+     * <p>Android YUV P010 format.</p>
+     *
+     * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+     * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
+     * little-endian value, with the lower 6 bits set to zero.
+     */
+    public static final int YCBCR_P010 = 0x36;
 
     // Note: do not rename, this field is used by native code
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -422,6 +431,7 @@
             case D_FP32:
             case DS_FP32UI8:
             case S_UI8:
+            case YCBCR_P010:
                 return true;
         }
         return false;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2359d8d..2717463 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2031,14 +2031,20 @@
      * @param inputConnection the connection to be invalidated.
      * @param textSnapshot {@link TextSnapshot} to be used to update {@link EditorInfo}.
      * @param sessionId the session ID to be sent.
+     * @return {@code true} if the operation is done. {@code false} if the caller needs to fall back
+     *         to {@link InputMethodManager#restartInput(View)}.
      * @hide
      */
-    public void doInvalidateInput(@NonNull RemoteInputConnectionImpl inputConnection,
+    public boolean doInvalidateInput(@NonNull RemoteInputConnectionImpl inputConnection,
             @NonNull TextSnapshot textSnapshot, int sessionId) {
         synchronized (mH) {
             if (mServedInputConnection != inputConnection || mCurrentTextBoxAttribute == null) {
                 // OK to ignore because the calling InputConnection is already abandoned.
-                return;
+                return true;
+            }
+            if (mCurrentInputMethodSession == null) {
+                // IME is not yet bound to the client.  Need to fall back to the restartInput().
+                return false;
             }
             final EditorInfo editorInfo = mCurrentTextBoxAttribute.createCopyInternal();
             editorInfo.initialSelStart = mCursorSelStart = textSnapshot.getSelectionStart();
@@ -2051,6 +2057,7 @@
                     sessionId);
             forAccessibilitySessions(wrapper -> wrapper.invalidateInput(editorInfo,
                     mServedInputConnection, sessionId));
+            return true;
         }
     }
 
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
index 5bcfa8b..1da2af4 100644
--- a/core/java/android/webkit/UserPackage.java
+++ b/core/java/android/webkit/UserPackage.java
@@ -34,7 +34,7 @@
     private final UserInfo mUserInfo;
     private final PackageInfo mPackageInfo;
 
-    public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.S;
+    public static final int MINIMUM_SUPPORTED_SDK = Build.VERSION_CODES.TIRAMISU;
 
     public UserPackage(UserInfo user, PackageInfo packageInfo) {
         this.mUserInfo = user;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index cf6807e..0ef37d1 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -51,7 +51,7 @@
     // visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
     /** @hide */
     private static final String CHROMIUM_WEBVIEW_FACTORY =
-            "com.android.webview.chromium.WebViewChromiumFactoryProviderForS";
+            "com.android.webview.chromium.WebViewChromiumFactoryProviderForT";
 
     private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
 
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index d1942ac..780de0e 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -282,9 +282,8 @@
 
                     if (!alwaysTrueEndBatchEditDetected) {
                         final TextSnapshot textSnapshot = ic.takeSnapshot();
-                        if (textSnapshot != null) {
-                            mParentInputMethodManager.doInvalidateInput(this, textSnapshot,
-                                    nextSessionId);
+                        if (textSnapshot != null && mParentInputMethodManager.doInvalidateInput(
+                                this, textSnapshot, nextSessionId)) {
                             return;
                         }
                     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3b2a248..d4c03e4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4718,10 +4718,10 @@
     <permission android:name="android.permission.READ_FRAME_BUFFER"
         android:protectionLevel="signature|recents" />
 
-      <!-- @SystemApi Allows an application to change the touch mode state.
+      <!-- Allows an application to change the touch mode state.
            Without this permission, an app can only change the touch mode
            if it currently has focus.
-         @hide -->
+           @hide -->
     <permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE"
         android:protectionLevel="signature" />
 
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 9feb619..b341a4e 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -428,7 +428,7 @@
 
     /**
      * <p>Private raw camera sensor image format, a single channel image with
-     * implementation depedent pixel layout.</p>
+     * implementation dependent pixel layout.</p>
      *
      * <p>RAW_PRIVATE is a format for unprocessed raw image buffers coming from an
      * image sensor. The actual structure of buffers of this format is
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 101295d..11ecc91 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -35,6 +35,9 @@
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.ClipDescription;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -54,6 +57,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -205,6 +209,7 @@
                 break;
             case ACTION_DRAG_ENTERED:
                 pd.dragLayout.show();
+                pd.dragLayout.update(event);
                 break;
             case ACTION_DRAG_LOCATION:
                 pd.dragLayout.update(event);
@@ -250,10 +255,6 @@
                 // Hide the window if another drag hasn't been started while animating the drop
                 setDropTargetWindowVisibility(pd, View.INVISIBLE);
             }
-
-            // Clean up the drag surface
-            mTransaction.reparent(dragSurface, null);
-            mTransaction.apply();
         });
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index e8bae0f..7568310 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -123,6 +123,13 @@
     }
 
     /**
+     * Returns the number of targets.
+     */
+    int getNumTargets() {
+        return mTargets.size();
+    }
+
+    /**
      * Returns the target's regions based on the current state of the device and display.
      */
     @NonNull
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index d395f95..25fe8b9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -17,6 +17,7 @@
 package com.android.wm.shell.draganddrop;
 
 import static android.app.StatusBarManager.DISABLE_NONE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -24,6 +25,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.StatusBarManager;
@@ -44,6 +46,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -135,6 +138,12 @@
         }
     }
 
+    private void updateContainerMarginsForSingleTask() {
+        mDropZoneView1.setContainerMargin(
+                mDisplayMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin);
+        mDropZoneView2.setContainerMargin(0, 0, 0, 0);
+    }
+
     private void updateContainerMargins(int orientation) {
         final float halfMargin = mDisplayMargin / 2f;
         if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
@@ -165,11 +174,20 @@
         if (!alreadyInSplit) {
             ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
             if (taskInfo1 != null) {
-                Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
-                int bgColor1 = getResizingBackgroundColor(taskInfo1);
-                mDropZoneView1.setAppInfo(bgColor1, icon1);
-                mDropZoneView2.setAppInfo(bgColor1, icon1);
-                updateDropZoneSizes(null, null); // passing null splits the views evenly
+                final int activityType = taskInfo1.getActivityType();
+                if (activityType == ACTIVITY_TYPE_STANDARD) {
+                    Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
+                    int bgColor1 = getResizingBackgroundColor(taskInfo1);
+                    mDropZoneView1.setAppInfo(bgColor1, icon1);
+                    mDropZoneView2.setAppInfo(bgColor1, icon1);
+                    updateDropZoneSizes(null, null); // passing null splits the views evenly
+                } else {
+                    // We use the first drop zone to show the fullscreen highlight, and don't need
+                    // to set additional info
+                    mDropZoneView1.setForceIgnoreBottomMargin(true);
+                    updateDropZoneSizesForSingleTask();
+                    updateContainerMarginsForSingleTask();
+                }
             }
         } else {
             // We're already in split so get taskInfo from the controller to populate icon / color.
@@ -195,6 +213,21 @@
         }
     }
 
+    private void updateDropZoneSizesForSingleTask() {
+        final LinearLayout.LayoutParams dropZoneView1 =
+                (LayoutParams) mDropZoneView1.getLayoutParams();
+        final LinearLayout.LayoutParams dropZoneView2 =
+                (LayoutParams) mDropZoneView2.getLayoutParams();
+        dropZoneView1.width = MATCH_PARENT;
+        dropZoneView1.height = MATCH_PARENT;
+        dropZoneView2.width = 0;
+        dropZoneView2.height = 0;
+        dropZoneView1.weight = 1;
+        dropZoneView2.weight = 0;
+        mDropZoneView1.setLayoutParams(dropZoneView1);
+        mDropZoneView2.setLayoutParams(dropZoneView2);
+    }
+
     /**
      * Sets the size of the two drop zones based on the provided bounds. The divider sits between
      * the views and its size is included in the calculations.
@@ -265,9 +298,12 @@
                 // Animating to no target
                 animateSplitContainers(false, null /* animCompleteCallback */);
             } else if (mCurrentTarget == null) {
-                // Animating to first target
-                animateSplitContainers(true, null /* animCompleteCallback */);
-                animateHighlight(target);
+                if (mPolicy.getNumTargets() == 1) {
+                    animateFullscreenContainer(true);
+                } else {
+                    animateSplitContainers(true, null /* animCompleteCallback */);
+                    animateHighlight(target);
+                }
             } else {
                 // Switching between targets
                 mDropZoneView1.animateSwitch();
@@ -283,6 +319,10 @@
     public void hide(DragEvent event, Runnable hideCompleteCallback) {
         mIsShowing = false;
         animateSplitContainers(false, hideCompleteCallback);
+        // Reset the state if we previously force-ignore the bottom margin
+        mDropZoneView1.setForceIgnoreBottomMargin(false);
+        mDropZoneView2.setForceIgnoreBottomMargin(false);
+        updateContainerMargins(getResources().getConfiguration().orientation);
         mCurrentTarget = null;
     }
 
@@ -297,11 +337,63 @@
         // Process the drop
         mPolicy.handleDrop(mCurrentTarget, event.getClipData());
 
-        // TODO(b/169894807): Coordinate with dragSurface
+        // Start animating the drop UI out with the drag surface
         hide(event, dropCompleteCallback);
+        hideDragSurface(dragSurface);
         return handledDrop;
     }
 
+    private void hideDragSurface(SurfaceControl dragSurface) {
+        final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+        final ValueAnimator dragSurfaceAnimator = ValueAnimator.ofFloat(0f, 1f);
+        // Currently the splash icon animation runs with the default ValueAnimator duration of
+        // 300ms
+        dragSurfaceAnimator.setDuration(300);
+        dragSurfaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        dragSurfaceAnimator.addUpdateListener(animation -> {
+            float t = animation.getAnimatedFraction();
+            float alpha = 1f - t;
+            // TODO: Scale the drag surface as well once we make all the source surfaces
+            //       consistent
+            tx.setAlpha(dragSurface, alpha);
+            tx.apply();
+        });
+        dragSurfaceAnimator.addListener(new AnimatorListenerAdapter() {
+            private boolean mCanceled = false;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                cleanUpSurface();
+                mCanceled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (mCanceled) {
+                    // Already handled above
+                    return;
+                }
+                cleanUpSurface();
+            }
+
+            private void cleanUpSurface() {
+                // Clean up the drag surface
+                tx.remove(dragSurface);
+                tx.apply();
+            }
+        });
+        dragSurfaceAnimator.start();
+    }
+
+    private void animateFullscreenContainer(boolean visible) {
+        mStatusBarManager.disable(visible
+                ? HIDE_STATUS_BAR_FLAGS
+                : DISABLE_NONE);
+        // We're only using the first drop zone if there is one fullscreen target
+        mDropZoneView1.setShowingMargin(visible);
+        mDropZoneView1.setShowingHighlight(visible);
+    }
+
     private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) {
         mStatusBarManager.disable(visible
                 ? HIDE_STATUS_BAR_FLAGS
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index a3ee8ae..38870bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -65,6 +65,7 @@
     private final float[] mContainerMargin = new float[4];
     private float mCornerRadius;
     private float mBottomInset;
+    private boolean mIgnoreBottomMargin;
     private int mMarginColor; // i.e. color used for negative space like the container insets
 
     private boolean mShowingHighlight;
@@ -141,6 +142,14 @@
         }
     }
 
+    /** Ignores the bottom margin provided by the insets. */
+    public void setForceIgnoreBottomMargin(boolean ignoreBottomMargin) {
+        mIgnoreBottomMargin = ignoreBottomMargin;
+        if (mMarginPercent > 0) {
+            mMarginView.invalidate();
+        }
+    }
+
     /** Sets the bottom inset so the drop zones are above bottom navigation. */
     public void setBottomInset(float bottom) {
         mBottomInset = bottom;
@@ -257,7 +266,8 @@
             mPath.addRoundRect(mContainerMargin[0] * mMarginPercent,
                     mContainerMargin[1] * mMarginPercent,
                     getWidth() - (mContainerMargin[2] * mMarginPercent),
-                    getHeight() - (mContainerMargin[3] * mMarginPercent) - mBottomInset,
+                    getHeight() - (mContainerMargin[3] * mMarginPercent)
+                            - (mIgnoreBottomMargin ? 0 : mBottomInset),
                     mCornerRadius * mMarginPercent,
                     mCornerRadius * mMarginPercent,
                     Path.Direction.CW);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 96809bd..69fe5ee 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1863,12 +1863,9 @@
      * Returns a priority for the given use case type and the client's foreground or background
      * status.
      *
-     * @param useCase the use case type of the client. When the given use case type is invalid,
-     *        the default use case type will be used. {@see TvInputService#PriorityHintUseCaseType}.
-     * @param sessionId the unique id of the session owned by the client. When {@code null},
-     *        the caller will be used as a client. When the session is invalid, background status
-     *        will be used as a client's status. Otherwise, TV app corresponding to the given
-     *        session id will be used as a client.
+     * @param useCase the use case type of the client.
+     *        {@see TvInputService#PriorityHintUseCaseType}.
+     * @param sessionId the unique id of the session owned by the client.
      *        {@see TvInputService#onCreateSession(String, String)}.
      *
      * @return the use case priority value for the given use case type and the client's foreground
@@ -1879,11 +1876,35 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
     public int getClientPriority(@TvInputService.PriorityHintUseCaseType int useCase,
-            @Nullable String sessionId) {
+            @NonNull String sessionId) {
+        Preconditions.checkNotNull(sessionId);
+        if (!isValidUseCase(useCase)) {
+            throw new IllegalArgumentException("Invalid use case: " + useCase);
+        }
         return getClientPriorityInternal(useCase, sessionId);
     };
 
     /**
+     * Returns a priority for the given use case type and the caller's foreground or background
+     * status.
+     *
+     * @param useCase the use case type of the caller.
+     *        {@see TvInputService#PriorityHintUseCaseType}.
+     *
+     * @return the use case priority value for the given use case type and the caller's foreground
+     *         or background status.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS)
+    public int getClientPriority(@TvInputService.PriorityHintUseCaseType int useCase) {
+        if (!isValidUseCase(useCase)) {
+            throw new IllegalArgumentException("Invalid use case: " + useCase);
+        }
+        return getClientPriorityInternal(useCase, null);
+    };
+    /**
      * Creates a recording {@link Session} for a given TV input.
      *
      * <p>The number of sessions that can be created at the same time is limited by the capability
@@ -1935,6 +1956,14 @@
         }
     }
 
+    private boolean isValidUseCase(int useCase) {
+        return useCase == TvInputService.PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND
+            || useCase == TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN
+            || useCase == TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK
+            || useCase == TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE
+            || useCase == TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD;
+    }
+
     /**
      * Returns the TvStreamConfig list of the given TV input.
      *
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index d0acc53..397c704 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1839,7 +1839,7 @@
     if (mDemuxClient == nullptr) {
         return nullptr;
     }
-    long time = mDemuxClient->getAvSyncTime((int)id);
+    int64_t time = mDemuxClient->getAvSyncTime((int)id);
     if (time >= 0) {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         jclass longClazz = env->FindClass("java/lang/Long");
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3f80647..23b2529 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2407,4 +2407,7 @@
     <string name="add_user_supervised" translatable="false">@*android:string/supervised_user_creation_label</string>
     <!-- Manage users - For system user management [CHAR LIMIT=40]  -->
     <string name="manage_users">Manage users</string>
+
+    <!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] -->
+    <string name="drag_split_not_supported">This notification does not support dragging to Splitscreen.</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index 06b739b..c2c40d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -17,6 +17,11 @@
 
 package com.android.systemui.statusbar.notification.row;
 
+import static android.widget.Toast.LENGTH_SHORT;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.app.Notification;
 import android.app.PendingIntent;
@@ -33,13 +38,15 @@
 import android.util.Log;
 import android.view.DragEvent;
 import android.view.HapticFeedbackConstants;
+import android.view.SurfaceControl;
 import android.view.View;
 import android.widget.ImageView;
+import android.widget.Toast;
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -55,12 +62,15 @@
 
     private final Context mContext;
     private final HeadsUpManager mHeadsUpManager;
+    private final ShadeController mShadeController;
 
     @Inject
     public ExpandableNotificationRowDragController(Context context,
-            HeadsUpManager headsUpManager) {
+            HeadsUpManager headsUpManager,
+            ShadeController shadeController) {
         mContext = context;
         mHeadsUpManager = headsUpManager;
+        mShadeController = shadeController;
 
         init();
     }
@@ -87,6 +97,16 @@
         final PendingIntent contentIntent = notification.contentIntent != null
                 ? notification.contentIntent
                 : notification.fullScreenIntent;
+        if (contentIntent == null) {
+            if (!enr.isPinned()) {
+                // We dismiss the shade for consistency, but also because toasts currently don't
+                // show above the shade
+                dismissShade();
+            }
+            Toast.makeText(mContext, R.string.drag_split_not_supported, LENGTH_SHORT)
+                 .show();
+            return;
+        }
         Bitmap iconBitmap = getBitmapFromDrawable(
                 getPkgIcon(enr.getEntry().getSbn().getPackageName()));
 
@@ -97,15 +117,30 @@
         ClipDescription clipDescription = new ClipDescription("Drag And Drop",
                 new String[]{ClipDescription.MIMETYPE_APPLICATION_ACTIVITY});
         Intent dragIntent = new Intent();
-        dragIntent.putExtra("android.intent.extra.PENDING_INTENT", contentIntent);
+        dragIntent.putExtra(ClipDescription.EXTRA_PENDING_INTENT, contentIntent);
         dragIntent.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
         ClipData.Item item = new ClipData.Item(dragIntent);
         ClipData dragData = new ClipData(clipDescription, item);
         View.DragShadowBuilder myShadow = new View.DragShadowBuilder(snapshot);
         view.setOnDragListener(getDraggedViewDragListener());
-        view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL);
+        boolean result = view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL
+                | View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
+        if (result) {
+            view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+            if (enr.isPinned()) {
+                mHeadsUpManager.releaseAllImmediately();
+            } else {
+                dismissShade();
+            }
+        }
     }
 
+    private void dismissShade() {
+        // Speed up dismissing the shade since the drag needs to be handled by
+        // the shell layer underneath
+        mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */,
+                false /* delayed */, 1.1f /* speedUpFactor */);
+    }
 
     private Drawable getPkgIcon(String pkgName) {
         Drawable pkgicon = null;
@@ -145,16 +180,6 @@
         return (view, dragEvent) -> {
             switch (dragEvent.getAction()) {
                 case DragEvent.ACTION_DRAG_STARTED:
-                    view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                    if (view instanceof ExpandableNotificationRow) {
-                        ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
-                        if (enr.isPinned()) {
-                            mHeadsUpManager.releaseAllImmediately();
-                        } else {
-                            Dependency.get(ShadeController.class).animateCollapsePanels(
-                                    CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
-                        }
-                    }
                     return true;
                 case DragEvent.ACTION_DRAG_ENDED:
                     if (dragEvent.getResult()) {
@@ -162,10 +187,55 @@
                             ExpandableNotificationRow enr = (ExpandableNotificationRow) view;
                             enr.dragAndDropSuccess();
                         }
+                    } else {
+                        // Fade out the drag surface in place instead of animating back to the
+                        // start position now that the shade is closed
+                        fadeOutAndRemoveDragSurface(dragEvent);
                     }
+                    // Clear the drag listener set above
+                    view.setOnDragListener(null);
                     return true;
             }
             return false;
         };
     }
+
+    private void fadeOutAndRemoveDragSurface(DragEvent dragEvent) {
+        SurfaceControl dragSurface = dragEvent.getDragSurface();
+        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+        ValueAnimator returnAnimator = ValueAnimator.ofFloat(0f, 1f);
+        returnAnimator.setDuration(200);
+        returnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        returnAnimator.addUpdateListener(animation -> {
+            float t = animation.getAnimatedFraction();
+            float alpha = 1f - t;
+            tx.setAlpha(dragSurface, alpha);
+            tx.apply();
+        });
+        returnAnimator.addListener(new AnimatorListenerAdapter() {
+            private boolean mCanceled = false;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                cleanUpSurface();
+                mCanceled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (mCanceled) {
+                    // Already handled above
+                    return;
+                }
+                cleanUpSurface();
+            }
+
+            private void cleanUpSurface() {
+                tx.remove(dragSurface);
+                tx.apply();
+                tx.close();
+            }
+        });
+        returnAnimator.start();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index 24a0ad3..bc54bf8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -18,6 +18,8 @@
 
 import static android.view.DragEvent.ACTION_DRAG_STARTED;
 
+import android.app.Notification;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -36,7 +38,12 @@
 import org.junit.runner.RunWith;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -58,6 +65,7 @@
     private NotificationMenuRow mMenuRow = mock(NotificationMenuRow.class);
     private NotificationMenuRowPlugin.MenuItem mMenuItem =
             mock(NotificationMenuRowPlugin.MenuItem.class);
+    private ShadeController mShadeController = mock(ShadeController.class);
 
     @Before
     public void setUp() throws Exception {
@@ -69,11 +77,15 @@
                 mContext,
                 mDependency,
                 TestableLooper.get(this));
-        mRow = mNotificationTestHelper.createRow();
+        mRow = spy(mNotificationTestHelper.createRow());
+        Notification notification = mRow.getEntry().getSbn().getNotification();
+        notification.contentIntent = mock(PendingIntent.class);
+        doReturn(true).when(mRow).startDragAndDrop(any(), any(), any(), anyInt());
         mGroupRow = mNotificationTestHelper.createGroup(4);
         when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
 
-        mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager);
+        mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager,
+                mShadeController);
     }
 
     @Test
@@ -86,10 +98,6 @@
         mRow.doLongClickCallback(0, 0);
         mRow.doDragCallback(0, 0);
         verify(controller).startDragAndDrop(mRow);
-
-        // Simulate the drag start
-        mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
-                null, null, false));
         verify(mHeadsUpManager, times(1)).releaseAllImmediately();
     }
 
@@ -98,14 +106,27 @@
         ExpandableNotificationRowDragController controller = createSpyController();
         mRow.setDragController(controller);
 
-        mDependency.get(ShadeController.class).instantExpandNotificationsPanel();
+        mRow.doDragCallback(0, 0);
+        verify(controller).startDragAndDrop(mRow);
+        verify(mShadeController).animateCollapsePanels(eq(0), eq(true),
+                eq(false), anyFloat());
+    }
+
+    @Test
+    public void testDoStartDrag_noLaunchIntent() throws Exception {
+        ExpandableNotificationRowDragController controller = createSpyController();
+        mRow.setDragController(controller);
+
+        // Clear the intents
+        Notification notification = mRow.getEntry().getSbn().getNotification();
+        notification.contentIntent = null;
+        notification.fullScreenIntent = null;
+
         mRow.doDragCallback(0, 0);
         verify(controller).startDragAndDrop(mRow);
 
-        // Simulate the drag start
-        mRow.dispatchDragEvent(DragEvent.obtain(ACTION_DRAG_STARTED, 0, 0, 0, 0, null, null, null,
-                null, null, false));
-        verify(mDependency.get(ShadeController.class)).animateCollapsePanels(0, true);
+        // Verify that we never start the actual drag since there is no content
+        verify(mRow, never()).startDragAndDrop(any(), any(), any(), anyInt());
     }
 
     private ExpandableNotificationRowDragController createSpyController() {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 09ef03c..111bd34 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -67,7 +67,7 @@
  *
  * @hide Only for use within the system server.
  */
-public abstract class PackageManagerInternal implements PackageSettingsSnapshotProvider {
+public abstract class PackageManagerInternal {
     @IntDef(prefix = "PACKAGE_", value = {
             PACKAGE_SYSTEM,
             PACKAGE_SETUP_WIZARD,
diff --git a/services/core/java/android/content/pm/PackageSettingsSnapshotProvider.java b/services/core/java/android/content/pm/PackageSettingsSnapshotProvider.java
deleted file mode 100644
index 221f172..0000000
--- a/services/core/java/android/content/pm/PackageSettingsSnapshotProvider.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.
- */
-
-package android.content.pm;
-
-import android.annotation.NonNull;
-
-import com.android.internal.util.FunctionalUtils;
-import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.PackageSetting;
-import com.android.server.pm.pkg.PackageStateInternal;
-
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-/** @hide */
-public interface PackageSettingsSnapshotProvider {
-
-    /**
-     * Run a function block that requires access to {@link PackageStateInternal} data. This will
-     * ensure the {@link PackageManagerService} lock is taken before any caller's internal lock
-     * to avoid deadlock. Note that this method may or may not lock. If a snapshot is available
-     * and valid, it will iterate the snapshot set of data.
-     */
-    void withPackageSettingsSnapshot(
-            @NonNull Consumer<Function<String, PackageStateInternal>> block);
-
-    /**
-     * Variant which returns a value to the caller.
-     * @see #withPackageSettingsSnapshot(Consumer)
-     */
-    <Output> Output withPackageSettingsSnapshotReturning(
-            @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>,
-                    Output> block);
-
-    /**
-     * Variant which throws.
-     * @see #withPackageSettingsSnapshot(Consumer)
-     */
-    <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
-            @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String, PackageStateInternal>,
-                    ExceptionType> block) throws ExceptionType;
-
-    /**
-     * Variant which throws 2 exceptions.
-     * @see #withPackageSettingsSnapshot(Consumer)
-     */
-    <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
-            withPackageSettingsSnapshotThrowing2(
-                    @NonNull FunctionalUtils.ThrowingChecked2Consumer<
-                            Function<String, PackageStateInternal>,
-                            ExceptionOne, ExceptionTwo> block)
-            throws ExceptionOne, ExceptionTwo;
-
-    /**
-     * Variant which returns a value to the caller and throws.
-     * @see #withPackageSettingsSnapshot(Consumer)
-     */
-    <Output, ExceptionType extends Exception> Output
-            withPackageSettingsSnapshotReturningThrowing(
-                    @NonNull FunctionalUtils.ThrowingCheckedFunction<
-                            Function<String, PackageStateInternal>, Output, ExceptionType> block)
-            throws ExceptionType;
-}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 9ba9d78..b813bc4 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -159,7 +159,7 @@
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
             mGameServiceController = new GameServiceController(
-                    BackgroundThread.getExecutor(),
+                    context, BackgroundThread.getExecutor(),
                     new GameServiceProviderSelectorImpl(
                             context.getResources(),
                             context.getPackageManager()),
@@ -376,9 +376,10 @@
 
     /**
      * Called by games to communicate the current state to the platform.
+     *
      * @param packageName The client package name.
-     * @param gameState An object set to the current state.
-     * @param userId The user associated with this state.
+     * @param gameState   An object set to the current state.
+     * @param userId      The user associated with this state.
      */
     public void setGameState(String packageName, @NonNull GameState gameState,
             @UserIdInt int userId) {
@@ -1373,7 +1374,7 @@
      * @hide
      */
     @VisibleForTesting
-    void updateConfigsForUser(@UserIdInt int userId, String ...packageNames) {
+    void updateConfigsForUser(@UserIdInt int userId, String... packageNames) {
         try {
             synchronized (mDeviceConfigLock) {
                 for (final String packageName : packageNames) {
@@ -1442,7 +1443,7 @@
         final List<PackageInfo> packages =
                 mPackageManager.getInstalledPackagesAsUser(0, userId);
         return packages.stream().filter(e -> e.applicationInfo != null && e.applicationInfo.category
-                == ApplicationInfo.CATEGORY_GAME)
+                        == ApplicationInfo.CATEGORY_GAME)
                 .map(e -> e.packageName)
                 .toArray(String[]::new);
     }
diff --git a/services/core/java/com/android/server/app/GameServiceConfiguration.java b/services/core/java/com/android/server/app/GameServiceConfiguration.java
new file mode 100644
index 0000000..1f31a87
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameServiceConfiguration.java
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+package com.android.server.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.UserHandle;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+/**
+ * Representation of a {@link android.service.games.GameService} provider configuration.
+ */
+final class GameServiceConfiguration {
+    private final String mPackageName;
+    @Nullable
+    private final GameServiceComponentConfiguration mGameServiceComponentConfiguration;
+
+    GameServiceConfiguration(
+            @NonNull String packageName,
+            @Nullable GameServiceComponentConfiguration gameServiceComponentConfiguration) {
+        Objects.requireNonNull(packageName);
+
+        mPackageName = packageName;
+        mGameServiceComponentConfiguration = gameServiceComponentConfiguration;
+    }
+
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    @Nullable
+    public GameServiceComponentConfiguration getGameServiceComponentConfiguration() {
+        return mGameServiceComponentConfiguration;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof GameServiceConfiguration)) {
+            return false;
+        }
+
+        GameServiceConfiguration that = (GameServiceConfiguration) o;
+        return TextUtils.equals(mPackageName, that.mPackageName)
+                && Objects.equals(mGameServiceComponentConfiguration,
+                that.mGameServiceComponentConfiguration);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPackageName, mGameServiceComponentConfiguration);
+    }
+
+    @Override
+    public String toString() {
+        return "GameServiceConfiguration{"
+                + "packageName="
+                + mPackageName
+                + ", gameServiceComponentConfiguration="
+                + mGameServiceComponentConfiguration
+                + '}';
+    }
+
+    static final class GameServiceComponentConfiguration {
+        private final UserHandle mUserHandle;
+        private final ComponentName mGameServiceComponentName;
+        private final ComponentName mGameSessionServiceComponentName;
+
+        GameServiceComponentConfiguration(
+                @NonNull UserHandle userHandle, @NonNull ComponentName gameServiceComponentName,
+                @NonNull ComponentName gameSessionServiceComponentName) {
+            Objects.requireNonNull(userHandle);
+            Objects.requireNonNull(gameServiceComponentName);
+            Objects.requireNonNull(gameSessionServiceComponentName);
+
+            mUserHandle = userHandle;
+            mGameServiceComponentName = gameServiceComponentName;
+            mGameSessionServiceComponentName = gameSessionServiceComponentName;
+        }
+
+        @NonNull
+        public UserHandle getUserHandle() {
+            return mUserHandle;
+        }
+
+        @NonNull
+        public ComponentName getGameServiceComponentName() {
+            return mGameServiceComponentName;
+        }
+
+        @NonNull
+        public ComponentName getGameSessionServiceComponentName() {
+            return mGameSessionServiceComponentName;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+
+            if (!(o instanceof GameServiceComponentConfiguration)) {
+                return false;
+            }
+
+            GameServiceComponentConfiguration that =
+                    (GameServiceComponentConfiguration) o;
+            return mUserHandle.equals(that.mUserHandle) && mGameServiceComponentName.equals(
+                    that.mGameServiceComponentName)
+                    && mGameSessionServiceComponentName.equals(
+                    that.mGameSessionServiceComponentName);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mUserHandle,
+                    mGameServiceComponentName,
+                    mGameSessionServiceComponentName);
+        }
+
+        @Override
+        public String toString() {
+            return "GameServiceComponentConfiguration{"
+                    + "userHandle="
+                    + mUserHandle
+                    + ", gameServiceComponentName="
+                    + mGameServiceComponentName
+                    + ", gameSessionServiceComponentName="
+                    + mGameSessionServiceComponentName
+                    + "}";
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/app/GameServiceController.java b/services/core/java/com/android/server/app/GameServiceController.java
index 397439a..db1ca97 100644
--- a/services/core/java/com/android/server/app/GameServiceController.java
+++ b/services/core/java/com/android/server/app/GameServiceController.java
@@ -19,10 +19,17 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PatternMatcher;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.SystemService;
+import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
 
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -36,8 +43,8 @@
 final class GameServiceController {
     private static final String TAG = "GameServiceController";
 
-
     private final Object mLock = new Object();
+    private final Context mContext;
     private final Executor mBackgroundExecutor;
     private final GameServiceProviderSelector mGameServiceProviderSelector;
     private final GameServiceProviderInstanceFactory mGameServiceProviderInstanceFactory;
@@ -46,18 +53,24 @@
     @Nullable
     private volatile String mGameServiceProviderOverride;
     @Nullable
+    private BroadcastReceiver mGameServicePackageChangedReceiver;
+    @Nullable
     private volatile SystemService.TargetUser mCurrentForegroundUser;
     @GuardedBy("mLock")
     @Nullable
-    private volatile GameServiceProviderConfiguration mActiveGameServiceProviderConfiguration;
+    private volatile GameServiceComponentConfiguration mActiveGameServiceComponentConfiguration;
     @GuardedBy("mLock")
     @Nullable
     private volatile GameServiceProviderInstance mGameServiceProviderInstance;
+    @GuardedBy("mLock")
+    @Nullable
+    private volatile String mActiveGameServiceProviderPackage;
 
     GameServiceController(
-            @NonNull Executor backgroundExecutor,
+            @NonNull Context context, @NonNull Executor backgroundExecutor,
             @NonNull GameServiceProviderSelector gameServiceProviderSelector,
             @NonNull GameServiceProviderInstanceFactory gameServiceProviderInstanceFactory) {
+        mContext = context;
         mGameServiceProviderInstanceFactory = gameServiceProviderInstanceFactory;
         mBackgroundExecutor = backgroundExecutor;
         mGameServiceProviderSelector = gameServiceProviderSelector;
@@ -139,35 +152,92 @@
         }
 
         synchronized (mLock) {
-            GameServiceProviderConfiguration selectedGameServiceProviderConfiguration =
+            final GameServiceConfiguration selectedGameServiceConfiguration =
                     mGameServiceProviderSelector.get(mCurrentForegroundUser,
                             mGameServiceProviderOverride);
+            final String gameServicePackage =
+                    selectedGameServiceConfiguration == null ? null :
+                            selectedGameServiceConfiguration.getPackageName();
+            final GameServiceComponentConfiguration gameServiceComponentConfiguration =
+                    selectedGameServiceConfiguration == null ? null
+                            : selectedGameServiceConfiguration
+                                    .getGameServiceComponentConfiguration();
 
-            boolean didActiveGameServiceProviderChanged =
-                    !Objects.equals(selectedGameServiceProviderConfiguration,
-                            mActiveGameServiceProviderConfiguration);
-            if (!didActiveGameServiceProviderChanged) {
+            evaluateGameServiceProviderPackageChangedListenerLocked(gameServicePackage);
+
+            boolean didActiveGameServiceProviderChange =
+                    !Objects.equals(gameServiceComponentConfiguration,
+                            mActiveGameServiceComponentConfiguration);
+            if (!didActiveGameServiceProviderChange) {
                 return;
             }
 
             if (mGameServiceProviderInstance != null) {
                 Slog.i(TAG, "Stopping Game Service provider: "
-                        + mActiveGameServiceProviderConfiguration);
+                        + mActiveGameServiceComponentConfiguration);
                 mGameServiceProviderInstance.stop();
+                mGameServiceProviderInstance = null;
             }
 
-            mActiveGameServiceProviderConfiguration = selectedGameServiceProviderConfiguration;
-
-            if (mActiveGameServiceProviderConfiguration == null) {
+            mActiveGameServiceComponentConfiguration = gameServiceComponentConfiguration;
+            if (mActiveGameServiceComponentConfiguration == null) {
                 return;
             }
 
             Slog.i(TAG,
-                    "Starting Game Service provider: " + mActiveGameServiceProviderConfiguration);
+                    "Starting Game Service provider: " + mActiveGameServiceComponentConfiguration);
             mGameServiceProviderInstance =
                     mGameServiceProviderInstanceFactory.create(
-                            mActiveGameServiceProviderConfiguration);
+                            mActiveGameServiceComponentConfiguration);
             mGameServiceProviderInstance.start();
         }
     }
+
+    @GuardedBy("mLock")
+    private void evaluateGameServiceProviderPackageChangedListenerLocked(
+            @Nullable String gameServicePackage) {
+        if (TextUtils.equals(mActiveGameServiceProviderPackage, gameServicePackage)) {
+            return;
+        }
+
+        if (mGameServicePackageChangedReceiver != null) {
+            mContext.unregisterReceiver(mGameServicePackageChangedReceiver);
+            mGameServicePackageChangedReceiver = null;
+        }
+
+        mActiveGameServiceProviderPackage = gameServicePackage;
+
+        if (TextUtils.isEmpty(mActiveGameServiceProviderPackage)) {
+            return;
+        }
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        intentFilter.addDataScheme("package");
+        intentFilter.addDataSchemeSpecificPart(gameServicePackage, PatternMatcher.PATTERN_LITERAL);
+        mGameServicePackageChangedReceiver = new PackageChangedBroadcastReceiver(
+                gameServicePackage);
+        mContext.registerReceiver(
+                mGameServicePackageChangedReceiver,
+                intentFilter);
+    }
+
+    private final class PackageChangedBroadcastReceiver extends BroadcastReceiver {
+        private final String mPackageName;
+
+        PackageChangedBroadcastReceiver(String packageName) {
+            mPackageName = packageName;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!TextUtils.equals(intent.getData().getSchemeSpecificPart(), mPackageName)) {
+                return;
+            }
+            mBackgroundExecutor.execute(
+                    GameServiceController.this::evaluateActiveGameServiceProvider);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java b/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java
deleted file mode 100644
index 7c8f251..0000000
--- a/services/core/java/com/android/server/app/GameServiceProviderConfiguration.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server.app;
-
-import android.annotation.NonNull;
-import android.content.ComponentName;
-import android.os.UserHandle;
-
-import java.util.Objects;
-
-/**
- * Representation of a {@link android.service.games.GameService} provider configuration.
- */
-final class GameServiceProviderConfiguration {
-    private final UserHandle mUserHandle;
-    private final ComponentName mGameServiceComponentName;
-    private final ComponentName mGameSessionServiceComponentName;
-
-    GameServiceProviderConfiguration(
-            @NonNull UserHandle userHandle,
-            @NonNull ComponentName gameServiceComponentName,
-            @NonNull ComponentName gameSessionServiceComponentName) {
-        Objects.requireNonNull(userHandle);
-        Objects.requireNonNull(gameServiceComponentName);
-        Objects.requireNonNull(gameSessionServiceComponentName);
-
-        this.mUserHandle = userHandle;
-        this.mGameServiceComponentName = gameServiceComponentName;
-        this.mGameSessionServiceComponentName = gameSessionServiceComponentName;
-    }
-
-    @NonNull
-    public UserHandle getUserHandle() {
-        return mUserHandle;
-    }
-
-    @NonNull
-    public ComponentName getGameServiceComponentName() {
-        return mGameServiceComponentName;
-    }
-
-    @NonNull
-    public ComponentName getGameSessionServiceComponentName() {
-        return mGameSessionServiceComponentName;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-
-        if (!(o instanceof GameServiceProviderConfiguration)) {
-            return false;
-        }
-
-        GameServiceProviderConfiguration that = (GameServiceProviderConfiguration) o;
-        return mUserHandle.equals(that.mUserHandle)
-                && mGameServiceComponentName.equals(that.mGameServiceComponentName)
-                && mGameSessionServiceComponentName.equals(that.mGameSessionServiceComponentName);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mUserHandle, mGameServiceComponentName,
-                mGameSessionServiceComponentName);
-    }
-
-    @Override
-    public String toString() {
-        return "GameServiceProviderConfiguration{"
-                + "mUserHandle="
-                + mUserHandle
-                + ", gameServiceComponentName="
-                + mGameServiceComponentName
-                + ", gameSessionServiceComponentName="
-                + mGameSessionServiceComponentName
-                + '}';
-    }
-}
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java
index 7640cc5..7dfaec0 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactory.java
@@ -18,12 +18,13 @@
 
 import android.annotation.NonNull;
 
+import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
+
 /**
  * Factory for creating {@link GameServiceProviderInstance}.
  */
 interface GameServiceProviderInstanceFactory {
 
     @NonNull
-    GameServiceProviderInstance create(@NonNull
-            GameServiceProviderConfiguration gameServiceProviderConfiguration);
+    GameServiceProviderInstance create(@NonNull GameServiceComponentConfiguration configuration);
 }
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
index 73278e4..0abab6a 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
@@ -30,6 +30,7 @@
 import com.android.internal.infra.ServiceConnector;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
+import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
 import com.android.server.wm.WindowManagerInternal;
 import com.android.server.wm.WindowManagerService;
 
@@ -43,9 +44,9 @@
     @NonNull
     @Override
     public GameServiceProviderInstance create(
-            @NonNull GameServiceProviderConfiguration gameServiceProviderConfiguration) {
+            @NonNull GameServiceComponentConfiguration configuration) {
         return new GameServiceProviderInstanceImpl(
-                gameServiceProviderConfiguration.getUserHandle(),
+                configuration.getUserHandle(),
                 BackgroundThread.getExecutor(),
                 mContext,
                 new GameClassifierImpl(mContext.getPackageManager()),
@@ -53,8 +54,8 @@
                 ActivityTaskManager.getService(),
                 (WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
                 LocalServices.getService(WindowManagerInternal.class),
-                new GameServiceConnector(mContext, gameServiceProviderConfiguration),
-                new GameSessionServiceConnector(mContext, gameServiceProviderConfiguration));
+                new GameServiceConnector(mContext, configuration),
+                new GameSessionServiceConnector(mContext, configuration));
     }
 
     private static final class GameServiceConnector extends ServiceConnector.Impl<IGameService> {
@@ -63,7 +64,7 @@
 
         GameServiceConnector(
                 @NonNull Context context,
-                @NonNull GameServiceProviderConfiguration configuration) {
+                @NonNull GameServiceComponentConfiguration configuration) {
             super(context, new Intent(GameService.ACTION_GAME_SERVICE)
                             .setComponent(configuration.getGameServiceComponentName()),
                     BINDING_FLAGS, configuration.getUserHandle().getIdentifier(),
@@ -86,7 +87,7 @@
 
         GameSessionServiceConnector(
                 @NonNull Context context,
-                @NonNull GameServiceProviderConfiguration configuration) {
+                @NonNull GameServiceComponentConfiguration configuration) {
             super(context, new Intent(GameSessionService.ACTION_GAME_SESSION_SERVICE)
                             .setComponent(configuration.getGameSessionServiceComponentName()),
                     BINDING_FLAGS, configuration.getUserHandle().getIdentifier(),
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 4eba771..e8d9dad 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -244,11 +244,11 @@
 
         // TODO(b/204503192): It is possible that the game service is disconnected. In this
         //  case we should avoid rebinding just to shut it down again.
-        AndroidFuture<Void> unusedPostDisconnectedFuture =
-                mGameServiceConnector.post(gameService -> {
-                    gameService.disconnected();
-                });
-        mGameServiceConnector.unbind();
+        mGameServiceConnector.post(gameService -> {
+            gameService.disconnected();
+        }).whenComplete((result, t) -> {
+            mGameServiceConnector.unbind();
+        });
         mGameSessionServiceConnector.unbind();
     }
 
diff --git a/services/core/java/com/android/server/app/GameServiceProviderSelector.java b/services/core/java/com/android/server/app/GameServiceProviderSelector.java
index 0f55b9f..d125f21 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderSelector.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderSelector.java
@@ -26,10 +26,10 @@
 interface GameServiceProviderSelector {
 
     /**
-     * Returns the {@link GameServiceProviderConfiguration} associated with the selected Game
+     * Returns the {@link GameServiceConfiguration} associated with the selected Game
      * Service provider for the given user or {@code null} if none should be used.
      */
     @Nullable
-    GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user,
+    GameServiceConfiguration get(@Nullable SystemService.TargetUser user,
             @Nullable String packageNameOverride);
 }
diff --git a/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java b/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java
index c1ad668..fc85308 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderSelectorImpl.java
@@ -34,6 +34,7 @@
 import android.util.Xml;
 
 import com.android.server.SystemService;
+import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -57,7 +58,7 @@
 
     @Override
     @Nullable
-    public GameServiceProviderConfiguration get(@Nullable SystemService.TargetUser user,
+    public GameServiceConfiguration get(@Nullable SystemService.TargetUser user,
             @Nullable String packageNameOverride) {
         if (user == null) {
             return null;
@@ -98,10 +99,10 @@
 
         if (gameServiceResolveInfos == null || gameServiceResolveInfos.isEmpty()) {
             Slog.w(TAG, "No available game service found for user id: " + userId);
-            return null;
+            return new GameServiceConfiguration(gameServicePackage, null);
         }
 
-        GameServiceProviderConfiguration selectedProvider = null;
+        GameServiceConfiguration selectedProvider = null;
         for (ResolveInfo resolveInfo : gameServiceResolveInfos) {
             if (resolveInfo.serviceInfo == null) {
                 continue;
@@ -115,16 +116,18 @@
             }
 
             selectedProvider =
-                    new GameServiceProviderConfiguration(
-                            new UserHandle(userId),
-                            gameServiceServiceInfo.getComponentName(),
-                            gameSessionServiceComponentName);
+                    new GameServiceConfiguration(
+                            gameServicePackage,
+                            new GameServiceComponentConfiguration(
+                                    new UserHandle(userId),
+                                    gameServiceServiceInfo.getComponentName(),
+                                    gameSessionServiceComponentName));
             break;
         }
 
         if (selectedProvider == null) {
             Slog.w(TAG, "No valid game service found for user id: " + userId);
-            return null;
+            return new GameServiceConfiguration(gameServicePackage, null);
         }
 
         return selectedProvider;
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 9e87898..30ac1b8 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -3134,8 +3134,8 @@
                 writer.println("Domain verification status:");
                 writer.increaseIndent();
                 try {
-                    mDomainVerificationManager.printState(writer, packageName,
-                            UserHandle.USER_ALL, mSettings::getPackage);
+                    mDomainVerificationManager.printState(this, writer, packageName,
+                            UserHandle.USER_ALL);
                 } catch (Exception e) {
                     pw.println("Failure printing domain verification information");
                     Slog.e(TAG, "Failure printing domain verification information", e);
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 3220b31..58f9bb2 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -453,7 +453,8 @@
         }
         for (final int affectedUserId : affectedUserIds) {
             if (hadSuspendAppsPermission.get(affectedUserId)) {
-                mPm.unsuspendForSuspendingPackage(packageName, affectedUserId);
+                mPm.unsuspendForSuspendingPackage(mPm.snapshotComputer(), packageName,
+                        affectedUserId);
                 mPm.removeAllDistractingPackageRestrictions(affectedUserId);
             }
         }
diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
index d24435e..db8c6dc 100644
--- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java
+++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
@@ -26,17 +26,12 @@
 import android.os.Message;
 import android.os.UserHandle;
 
-import com.android.internal.util.FunctionalUtils;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.verify.domain.DomainVerificationService;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV2;
 
-import java.util.function.Consumer;
-import java.util.function.Function;
-
 public final class DomainVerificationConnection implements DomainVerificationService.Connection,
         DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection {
     final PackageManagerService mPm;
@@ -111,42 +106,8 @@
         return mUmInternal.exists(userId);
     }
 
-    @Override
-    public void withPackageSettingsSnapshot(
-            @NonNull Consumer<Function<String, PackageStateInternal>> block) {
-        mPmInternal.withPackageSettingsSnapshot(block);
-    }
-
-    @Override
-    public <Output> Output withPackageSettingsSnapshotReturning(
-            @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>,
-                    Output> block) {
-        return mPmInternal.withPackageSettingsSnapshotReturning(block);
-    }
-
-    @Override
-    public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
-            @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String, PackageStateInternal>,
-                    ExceptionType> block) throws ExceptionType {
-        mPmInternal.withPackageSettingsSnapshotThrowing(block);
-    }
-
-    @Override
-    public <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
-            withPackageSettingsSnapshotThrowing2(
-                    @NonNull FunctionalUtils.ThrowingChecked2Consumer<
-                            Function<String, PackageStateInternal>, ExceptionOne,
-                            ExceptionTwo> block)
-            throws ExceptionOne, ExceptionTwo {
-        mPmInternal.withPackageSettingsSnapshotThrowing2(block);
-    }
-
-    @Override
-    public <Output, ExceptionType extends Exception> Output
-            withPackageSettingsSnapshotReturningThrowing(
-            @NonNull FunctionalUtils.ThrowingCheckedFunction<
-                    Function<String, PackageStateInternal>, Output, ExceptionType> block)
-            throws ExceptionType {
-        return mPmInternal.withPackageSettingsSnapshotReturningThrowing(block);
+    @NonNull
+    public Computer snapshot() {
+        return (Computer) mPmInternal.snapshot();
     }
 }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 234a230..c09c904 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -36,7 +36,6 @@
 import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
-import static android.content.pm.PackageManagerInternal.PACKAGE_SETUP_WIZARD;
 import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
 import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
 import static android.os.PowerExemptionManager.REASON_PACKAGE_REPLACED;
@@ -145,6 +144,7 @@
 import com.android.internal.content.InstallLocationUtils;
 import com.android.internal.security.VerityUtils;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.EventLogTags;
 import com.android.server.pm.dex.ArtManagerService;
@@ -2563,7 +2563,9 @@
         Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
 
         synchronized (mPm.mLock) {
-            size = mPm.mPendingBroadcasts.size();
+            final SparseArray<ArrayMap<String, ArrayList<String>>> userIdToPackagesToComponents =
+                    mPm.mPendingBroadcasts.copiedMap();
+            size = userIdToPackagesToComponents.size();
             if (size <= 0) {
                 // Nothing to be done. Just return
                 return;
@@ -2573,11 +2575,11 @@
             uids = new int[size];
             int i = 0;  // filling out the above arrays
 
-            for (int n = 0; n < mPm.mPendingBroadcasts.userIdCount(); n++) {
-                final int packageUserId = mPm.mPendingBroadcasts.userIdAt(n);
+            for (int n = 0; n < size; n++) {
+                final int packageUserId = userIdToPackagesToComponents.keyAt(n);
                 final ArrayMap<String, ArrayList<String>> componentsToBroadcast =
-                        mPm.mPendingBroadcasts.packagesForUserId(packageUserId);
-                final int numComponents = componentsToBroadcast.size();
+                        userIdToPackagesToComponents.valueAt(n);
+                final int numComponents = CollectionUtils.size(componentsToBroadcast);
                 for (int index = 0; i < size && index < numComponents; index++) {
                     packages[i] = componentsToBroadcast.keyAt(index);
                     components[i] = componentsToBroadcast.valueAt(index);
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index 46e2aa3..b028a2c 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -382,6 +382,7 @@
             case PRUNE_UNUSED_STATIC_SHARED_LIBRARIES: {
                 try {
                     mPm.mInjector.getSharedLibrariesImpl().pruneUnusedStaticSharedLibraries(
+                            mPm.snapshotComputer(),
                             Long.MAX_VALUE,
                             Settings.Global.getLong(mPm.mContext.getContentResolver(),
                                     Settings.Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0b7a6a7..c05faf1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -293,7 +293,6 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * Keep track of all those APKs everywhere.
@@ -1898,7 +1897,8 @@
             t.traceEnd();
 
             t.traceBegin("read user settings");
-            mFirstBoot = !mSettings.readLPw(mInjector.getUserManagerInternal().getUsers(
+            mFirstBoot = !mSettings.readLPw(mLiveComputer,
+                    mInjector.getUserManagerInternal().getUsers(
                     /* excludePartial= */ true,
                     /* excludeDying= */ false,
                     /* excludePreCreated= */ false));
@@ -2841,8 +2841,9 @@
             }
             if (file.getUsableSpace() >= bytes) return;
 
+            Computer computer = snapshotComputer();
             // 5. Consider shared libraries with refcount=0 and age>min cache period
-            if (internalVolume && mSharedLibraries.pruneUnusedStaticSharedLibraries(bytes,
+            if (internalVolume && mSharedLibraries.pruneUnusedStaticSharedLibraries(computer, bytes,
                     android.provider.Settings.Global.getLong(mContext.getContentResolver(),
                             Global.UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD,
                             FREE_STORAGE_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD))) {
@@ -2854,14 +2855,12 @@
 
             // 7. Consider installed instant apps unused longer than min cache period
             if (internalVolume) {
-                if (executeWithConsistentComputerReturning(computer ->
-                        mInstantAppRegistry.pruneInstalledInstantApps(computer, bytes,
-                                android.provider.Settings.Global.getLong(
-                                        mContext.getContentResolver(),
-                                        Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
-                                        InstantAppRegistry
-                                                .DEFAULT_INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD)))
-                ) {
+                if (mInstantAppRegistry.pruneInstalledInstantApps(computer, bytes,
+                        android.provider.Settings.Global.getLong(
+                                mContext.getContentResolver(),
+                                Global.INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
+                                InstantAppRegistry
+                                        .DEFAULT_INSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) {
                     return;
                 }
             }
@@ -2881,14 +2880,12 @@
 
             // 10. Consider instant meta-data (uninstalled apps) older that min cache period
             if (internalVolume) {
-                if (executeWithConsistentComputerReturning(computer ->
-                        mInstantAppRegistry.pruneUninstalledInstantApps(computer, bytes,
-                                android.provider.Settings.Global.getLong(
-                                        mContext.getContentResolver(),
-                                        Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
-                                        InstantAppRegistry
-                                                .DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD)))
-                ) {
+                if (mInstantAppRegistry.pruneUninstalledInstantApps(computer, bytes,
+                        android.provider.Settings.Global.getLong(
+                                mContext.getContentResolver(),
+                                Global.UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD,
+                                InstantAppRegistry
+                                        .DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) {
                     return;
                 }
             }
@@ -3493,8 +3490,8 @@
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */,
                 false /* checkShell */, "getEphemeralApplications");
 
-        List<InstantAppInfo> instantApps = executeWithConsistentComputerReturning(computer ->
-                mInstantAppRegistry.getInstantApps(computer, userId));
+        Computer computer = snapshotComputer();
+        List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(computer, userId);
         if (instantApps != null) {
             return new ParceledListSlice<>(instantApps);
         }
@@ -3710,13 +3707,13 @@
     public void notifyPackageUse(String packageName, int reason) {
         final int callingUid = Binder.getCallingUid();
         final int callingUserId = UserHandle.getUserId(callingUid);
-        boolean notify = executeWithConsistentComputerReturning(computer -> {
-            if (getInstantAppPackageName(callingUid) != null) {
-                return isCallerSameApp(packageName, callingUid);
-            } else {
-                return !isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID);
-            }
-        });
+        Computer computer = snapshotComputer();
+        final boolean notify;
+        if (getInstantAppPackageName(callingUid) != null) {
+            notify = isCallerSameApp(packageName, callingUid);
+        } else {
+            notify = !isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID);
+        }
         if (!notify) {
             return;
         }
@@ -4255,34 +4252,33 @@
         final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
 
         ArraySet<String> changesToCommit = new ArraySet<>();
-        executeWithConsistentComputer(computer -> {
-            final boolean[] canRestrict = (restrictionFlags != 0)
-                    ? mSuspendPackageHelper.canSuspendPackageForUser(computer, packageNames, userId,
-                    callingUid) : null;
-            for (int i = 0; i < packageNames.length; i++) {
-                final String packageName = packageNames[i];
-                final PackageStateInternal packageState =
-                        computer.getPackageStateInternal(packageName);
-                if (packageState == null
-                        || shouldFilterApplication(packageState, callingUid, userId)) {
-                    Slog.w(TAG, "Could not find package setting for package: " + packageName
-                            + ". Skipping...");
-                    unactionedPackages.add(packageName);
-                    continue;
-                }
-                if (canRestrict != null && !canRestrict[i]) {
-                    unactionedPackages.add(packageName);
-                    continue;
-                }
-                final int oldDistractionFlags = packageState.getUserStateOrDefault(userId)
-                        .getDistractionFlags();
-                if (restrictionFlags != oldDistractionFlags) {
-                    changedPackagesList.add(packageName);
-                    changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
-                    changesToCommit.add(packageName);
-                }
+        Computer computer = snapshotComputer();
+        final boolean[] canRestrict = (restrictionFlags != 0)
+                ? mSuspendPackageHelper.canSuspendPackageForUser(computer, packageNames, userId,
+                callingUid) : null;
+        for (int i = 0; i < packageNames.length; i++) {
+            final String packageName = packageNames[i];
+            final PackageStateInternal packageState =
+                    computer.getPackageStateInternal(packageName);
+            if (packageState == null
+                    || computer.shouldFilterApplication(packageState, callingUid, userId)) {
+                Slog.w(TAG, "Could not find package setting for package: " + packageName
+                        + ". Skipping...");
+                unactionedPackages.add(packageName);
+                continue;
             }
-        });
+            if (canRestrict != null && !canRestrict[i]) {
+                unactionedPackages.add(packageName);
+                continue;
+            }
+            final int oldDistractionFlags = packageState.getUserStateOrDefault(userId)
+                    .getDistractionFlags();
+            if (restrictionFlags != oldDistractionFlags) {
+                changedPackagesList.add(packageName);
+                changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+                changesToCommit.add(packageName);
+            }
+        }
 
         commitPackageStateMutation(null, mutator -> {
             final int size = changesToCommit.size();
@@ -4341,8 +4337,9 @@
         final int callingUid = Binder.getCallingUid();
         enforceCanSetPackagesSuspendedAsUser(callingPackage, callingUid, userId,
                 "setPackagesSuspendedAsUser");
-        return mSuspendPackageHelper.setPackagesSuspended(packageNames, suspended, appExtras,
-                launcherExtras, dialogInfo, callingPackage, userId, callingUid);
+        return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
+                suspended, appExtras, launcherExtras, dialogInfo, callingPackage, userId,
+                callingUid);
     }
 
     @Override
@@ -4361,11 +4358,12 @@
         return mComputer.isPackageSuspendedForUser(packageName, userId);
     }
 
-    void unsuspendForSuspendingPackage(String suspendingPackage, int userId) {
+    void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage,
+            @UserIdInt int userId) {
         // TODO: This can be replaced by a special parameter to iterate all packages, rather than
         //  this weird pre-collect of all packages.
-        final String[] allPackages = getPackageStates().keySet().toArray(new String[0]);
-        mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(
+        final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]);
+        mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer,
                 allPackages, suspendingPackage::equals, userId);
     }
 
@@ -4424,7 +4422,7 @@
             throw new SecurityException("Calling uid " + callingUid
                     + " cannot query getUnsuspendablePackagesForUser for user " + userId);
         }
-        return mSuspendPackageHelper.getUnsuspendablePackagesForUser(
+        return mSuspendPackageHelper.getUnsuspendablePackagesForUser(snapshotComputer(),
                 packageNames, userId, callingUid);
     }
 
@@ -4625,7 +4623,7 @@
             return true;
         };
         PackageStateMutator.InitialState initialState = recordInitialState();
-        boolean allowed = executeWithConsistentComputerReturningThrowing(implementation);
+        boolean allowed = implementation.apply(snapshotComputer());
         if (allowed) {
             // TODO: Need to lock around here to handle mSettings.addInstallerPackageNames,
             //  should find an alternative which avoids any race conditions
@@ -4635,7 +4633,7 @@
                         targetPackage, state -> state.setInstaller(installerPackageName));
                 if (result.isPackagesChanged() || result.isStateChanged()) {
                     synchronized (mPackageStateWriteLock) {
-                        allowed = executeWithConsistentComputerReturningThrowing(implementation);
+                        allowed = implementation.apply(snapshotComputer());
                         if (allowed) {
                             commitPackageStateMutation(null, targetPackage,
                                     state -> state.setInstaller(installerPackageName));
@@ -4685,12 +4683,12 @@
             }
         };
 
-        PackageStateMutator.Result result = executeWithConsistentComputerReturning(implementation);
+        PackageStateMutator.Result result = implementation.apply(snapshotComputer());
         if (result != null && result.isStateChanged() && !result.isSpecificPackageNull()) {
             // TODO: Specific return value of what state changed?
             // The installer on record might have changed, retry with lock
             synchronized (mPackageStateWriteLock) {
-                result = executeWithConsistentComputerReturning(implementation);
+                result = implementation.apply(snapshotComputer());
             }
         }
 
@@ -4988,7 +4986,7 @@
                     }
                     if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
                             == PERMISSION_GRANTED) {
-                        unsuspendForSuspendingPackage(packageName, userId);
+                        unsuspendForSuspendingPackage(snapshotComputer(), packageName, userId);
                         removeAllDistractingPackageRestrictions(userId);
                         flushPackageRestrictionsAsUserInternalLocked(userId);
                     }
@@ -5080,17 +5078,7 @@
         updateInstantAppInstallerLocked(packageName);
         scheduleWritePackageRestrictions(userId);
 
-        final ArrayList<String> pendingComponents = mPendingBroadcasts.get(userId, packageName);
-        if (pendingComponents == null) {
-            mPendingBroadcasts.put(userId, packageName, updatedComponents);
-        } else {
-            for (int i = 0; i < updatedComponents.size(); i++) {
-                final String updatedComponent = updatedComponents.get(i);
-                if (!pendingComponents.contains(updatedComponent)) {
-                    pendingComponents.add(updatedComponent);
-                }
-            }
-        }
+        mPendingBroadcasts.addComponents(userId, packageName, updatedComponents);
         if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
             mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
         }
@@ -5278,7 +5266,8 @@
         try {
             try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
                 TypedXmlSerializer serializer = Xml.resolveSerializer(output);
-                mDomainVerificationManager.writeSettings(serializer, true, userId);
+                mDomainVerificationManager.writeSettings(snapshotComputer(), serializer, true,
+                        userId);
                 return output.toByteArray();
             }
         } catch (Exception e) {
@@ -5301,7 +5290,7 @@
 
             // User ID input isn't necessary here as it assumes the user integers match and that
             // the only states inside the backup XML are for the target user.
-            mDomainVerificationManager.restoreSettings(parser);
+            mDomainVerificationManager.restoreSettings(snapshotComputer(), parser);
             input.close();
         } catch (Exception e) {
             if (DEBUG_BACKUP) {
@@ -5689,48 +5678,48 @@
         int callingUid = Binder.getCallingUid();
         String componentPkgName = componentName.getPackageName();
 
-        boolean changed = executeWithConsistentComputerReturning(computer -> {
-            int componentUid = getPackageUid(componentPkgName, 0, userId);
-            if (!UserHandle.isSameApp(callingUid, componentUid)) {
-                throw new SecurityException("The calling UID (" + callingUid + ")"
-                        + " does not match the target UID");
-            }
+        Computer computer = snapshotComputer();
 
-            String allowedCallerPkg =
-                    mContext.getString(R.string.config_overrideComponentUiPackage);
-            if (TextUtils.isEmpty(allowedCallerPkg)) {
-                throw new SecurityException( "There is no package defined as allowed to change a "
-                        + "component's label or icon");
-            }
+        int componentUid = computer.getPackageUid(componentPkgName, 0, userId);
+        if (!UserHandle.isSameApp(callingUid, componentUid)) {
+            throw new SecurityException("The calling UID (" + callingUid + ")"
+                    + " does not match the target UID");
+        }
 
-            int allowedCallerUid = getPackageUid(allowedCallerPkg, PackageManager.MATCH_SYSTEM_ONLY,
-                    userId);
-            if (allowedCallerUid == -1 || !UserHandle.isSameApp(callingUid, allowedCallerUid)) {
-                throw new SecurityException("The calling UID (" + callingUid + ")"
-                        + " is not allowed to change a component's label or icon");
-            }
-            PackageStateInternal packageState = computer.getPackageStateInternal(componentPkgName);
-            if (packageState == null || packageState.getPkg() == null
-                    || (!packageState.isSystem()
-                    && !packageState.getTransientState().isUpdatedSystemApp())) {
-                throw new SecurityException(
-                        "Changing the label is not allowed for " + componentName);
-            }
+        String allowedCallerPkg =
+                mContext.getString(R.string.config_overrideComponentUiPackage);
+        if (TextUtils.isEmpty(allowedCallerPkg)) {
+            throw new SecurityException( "There is no package defined as allowed to change a "
+                    + "component's label or icon");
+        }
 
-            if (!mComponentResolver.componentExists(componentName)) {
-                throw new IllegalArgumentException("Component " + componentName + " not found");
-            }
+        int allowedCallerUid = computer.getPackageUid(allowedCallerPkg,
+                PackageManager.MATCH_SYSTEM_ONLY, userId);
+        if (allowedCallerUid == -1 || !UserHandle.isSameApp(callingUid, allowedCallerUid)) {
+            throw new SecurityException("The calling UID (" + callingUid + ")"
+                    + " is not allowed to change a component's label or icon");
+        }
+        PackageStateInternal packageState = computer.getPackageStateInternal(componentPkgName);
+        if (packageState == null || packageState.getPkg() == null
+                || (!packageState.isSystem()
+                && !packageState.getTransientState().isUpdatedSystemApp())) {
+            throw new SecurityException(
+                    "Changing the label is not allowed for " + componentName);
+        }
 
-            Pair<String, Integer> overrideLabelIcon = packageState.getUserStateOrDefault(userId)
-                    .getOverrideLabelIconForComponent(componentName);
+        if (!computer.getComponentResolver().componentExists(componentName)) {
+            throw new IllegalArgumentException("Component " + componentName + " not found");
+        }
 
-            String existingLabel = overrideLabelIcon == null ? null : overrideLabelIcon.first;
-            Integer existingIcon = overrideLabelIcon == null ? null : overrideLabelIcon.second;
+        Pair<String, Integer> overrideLabelIcon = packageState.getUserStateOrDefault(userId)
+                .getOverrideLabelIconForComponent(componentName);
 
-            return !TextUtils.equals(existingLabel, nonLocalizedLabel)
-                    || !Objects.equals(existingIcon, icon);
-        });
-        if (!changed) {
+        String existingLabel = overrideLabelIcon == null ? null : overrideLabelIcon.first;
+        Integer existingIcon = overrideLabelIcon == null ? null : overrideLabelIcon.second;
+
+        if (TextUtils.equals(existingLabel, nonLocalizedLabel)
+                && Objects.equals(existingIcon, icon)) {
+            // Nothing changed
             return;
         }
 
@@ -5738,16 +5727,7 @@
                 state -> state.userState(userId)
                         .setComponentLabelIcon(componentName, nonLocalizedLabel, icon));
 
-        ArrayList<String> components = mPendingBroadcasts.get(userId, componentPkgName);
-        if (components == null) {
-            components = new ArrayList<>();
-            mPendingBroadcasts.put(userId, componentPkgName, components);
-        }
-
-        String className = componentName.getClassName();
-        if (!components.contains(className)) {
-            components.add(className);
-        }
+        mPendingBroadcasts.addComponent(userId, componentPkgName, componentName.getClassName());
 
         if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
             mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
@@ -5956,6 +5936,7 @@
         // packageName -> list of components to send broadcasts now
         final ArrayMap<String, ArrayList<String>> sendNowBroadcasts = new ArrayMap<>(targetSize);
         synchronized (mLock) {
+            Computer computer = snapshotComputer();
             boolean scheduleBroadcastMessage = false;
             boolean isSynchronous = false;
             boolean anyChanged = false;
@@ -5967,8 +5948,8 @@
                 // update enabled settings
                 final ComponentEnabledSetting setting = settings.get(i);
                 final String packageName = setting.getPackageName();
-                if (!setEnabledSettingInternalLocked(pkgSettings.get(packageName), setting,
-                        userId, callingPackage)) {
+                if (!setEnabledSettingInternalLocked(computer, pkgSettings.get(packageName),
+                        setting, userId, callingPackage)) {
                     continue;
                 }
                 anyChanged = true;
@@ -5979,26 +5960,18 @@
                 // collect broadcast list for the package
                 final String componentName = setting.isComponent()
                         ? setting.getClassName() : packageName;
-                ArrayList<String> componentList = sendNowBroadcasts.get(packageName);
-                if (componentList == null) {
-                    componentList = mPendingBroadcasts.get(userId, packageName);
-                }
-                final boolean newPackage = componentList == null;
-                if (newPackage) {
-                    componentList = new ArrayList<>();
-                }
-                if (!componentList.contains(componentName)) {
-                    componentList.add(componentName);
-                }
                 if ((setting.getEnabledFlags() & PackageManager.DONT_KILL_APP) == 0) {
+                    ArrayList<String> componentList = sendNowBroadcasts.get(packageName);
+                    componentList = componentList == null ? new ArrayList<>() : componentList;
+                    if (!componentList.contains(componentName)) {
+                        componentList.add(componentName);
+                    }
                     sendNowBroadcasts.put(packageName, componentList);
                     // Purge entry from pending broadcast list if another one exists already
                     // since we are sending one right away.
                     mPendingBroadcasts.remove(userId, packageName);
                 } else {
-                    if (newPackage) {
-                        mPendingBroadcasts.put(userId, packageName, componentList);
-                    }
+                    mPendingBroadcasts.addComponent(userId, packageName, componentName);
                     scheduleBroadcastMessage = true;
                 }
             }
@@ -6041,8 +6014,9 @@
         }
     }
 
-    private boolean setEnabledSettingInternalLocked(PackageSetting pkgSetting,
-            ComponentEnabledSetting setting, int userId, String callingPackage) {
+    private boolean setEnabledSettingInternalLocked(@NonNull Computer computer,
+            PackageSetting pkgSetting, ComponentEnabledSetting setting, @UserIdInt int userId,
+            String callingPackage) {
         final int newState = setting.getEnabledState();
         final String packageName = setting.getPackageName();
         boolean success = false;
@@ -6061,7 +6035,7 @@
                 // This app should not generally be allowed to get disabled by the UI, but
                 // if it ever does, we don't want to end up with some of the user's apps
                 // permanently suspended.
-                unsuspendForSuspendingPackage(packageName, userId);
+                unsuspendForSuspendingPackage(computer, packageName, userId);
                 removeAllDistractingPackageRestrictions(userId);
             }
             success = true;
@@ -6152,11 +6126,8 @@
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
         if (!mUserManager.exists(userId)) return;
         final int callingUid = Binder.getCallingUid();
-        Pair<Boolean, String> wasNotLaunchedAndInstallerPackageName =
-                executeWithConsistentComputerReturningThrowing(computer -> {
-            if (computer.getInstantAppPackageName(callingUid) != null) {
-                return null;
-            }
+        final Computer computer = snapshotComputer();
+        if (computer.getInstantAppPackageName(callingUid) == null) {
             final int permission = mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
             final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
@@ -6171,36 +6142,30 @@
                     true /* requireFullPermission */, true /* checkShell */, "stop package");
 
             final PackageStateInternal packageState = computer.getPackageStateInternal(packageName);
-            final PackageUserState PackageUserState = packageState == null
+            final PackageUserState packageUserState = packageState == null
                     ? null : packageState.getUserStateOrDefault(userId);
-            if (packageState == null
-                    || computer.shouldFilterApplication(packageState, callingUid, userId)
-                    || PackageUserState.isStopped() == stopped) {
-                return null;
-            }
+            if (packageState != null
+                    && !computer.shouldFilterApplication(packageState, callingUid, userId)
+                    && packageUserState.isStopped() != stopped) {
+                boolean wasNotLaunched = packageUserState.isNotLaunched();
+                commitPackageStateMutation(null, packageName, state -> {
+                    PackageUserStateWrite userState = state.userState(userId);
+                    userState.setStopped(stopped);
+                    if (wasNotLaunched) {
+                        userState.setNotLaunched(false);
+                    }
+                });
 
-            return Pair.create(PackageUserState.isNotLaunched(),
-                    packageState.getInstallSource().installerPackageName);
-        });
-        if (wasNotLaunchedAndInstallerPackageName != null) {
-            boolean wasNotLaunched = wasNotLaunchedAndInstallerPackageName.first;
-
-            commitPackageStateMutation(null, packageName, packageState -> {
-                PackageUserStateWrite userState = packageState.userState(userId);
-                userState.setStopped(stopped);
                 if (wasNotLaunched) {
-                    userState.setNotLaunched(false);
+                    final String installerPackageName =
+                            packageState.getInstallSource().installerPackageName;
+                    if (installerPackageName != null) {
+                        notifyFirstLaunch(packageName, installerPackageName, userId);
+                    }
                 }
-            });
 
-            if (wasNotLaunched) {
-                final String installerPackageName = wasNotLaunchedAndInstallerPackageName.second;
-                if (installerPackageName != null) {
-                    notifyFirstLaunch(packageName, installerPackageName, userId);
-                }
+                scheduleWritePackageRestrictions(userId);
             }
-
-            scheduleWritePackageRestrictions(userId);
         }
 
         // If this would cause the app to leave force-stop, then also make sure to unhibernate the
@@ -6687,7 +6652,7 @@
                 "Only package verification agents can read the verifier device identity");
 
         synchronized (mLock) {
-            return mSettings.getVerifierDeviceIdentityLPw();
+            return mSettings.getVerifierDeviceIdentityLPw(mLiveComputer);
         }
     }
 
@@ -7026,15 +6991,16 @@
 
         @Override
         public void removeAllNonSystemPackageSuspensions(int userId) {
-            final String[] allPackages = mComputer.getAllAvailablePackageNames();
-            mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(allPackages,
+            final Computer computer = snapshotComputer();
+            final String[] allPackages = computer.getAllAvailablePackageNames();
+            mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
                     (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
                     userId);
         }
 
         @Override
         public void removeNonSystemPackageSuspensions(String packageName, int userId) {
-            mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(
+            mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(snapshotComputer(),
                     new String[]{packageName},
                     (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
                     userId);
@@ -7233,29 +7199,29 @@
         @Override
         public void grantImplicitAccess(int userId, Intent intent,
                 int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
-            boolean accessGranted = executeWithConsistentComputerReturning(computer -> {
-                final AndroidPackage visiblePackage = computer.getPackage(visibleUid);
-                final int recipientUid = UserHandle.getUid(userId, recipientAppId);
-                if (visiblePackage == null || computer.getPackage(recipientUid) == null) {
-                    return false;
-                }
+            Computer computer = snapshotComputer();
+            final AndroidPackage visiblePackage = computer.getPackage(visibleUid);
+            final int recipientUid = UserHandle.getUid(userId, recipientAppId);
+            if (visiblePackage == null || computer.getPackage(recipientUid) == null) {
+                return;
+            }
 
-                final boolean instantApp = computer.isInstantAppInternal(
-                        visiblePackage.getPackageName(), userId, visibleUid);
-                if (instantApp) {
-                    if (!direct) {
-                        // if the interaction that lead to this granting access to an instant app
-                        // was indirect (i.e.: URI permission grant), do not actually execute the
-                        // grant.
-                        return false;
-                    }
-                    return mInstantAppRegistry.grantInstantAccess(userId, intent,
-                            recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
-                } else {
-                    return mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
-                            retainOnUpdate);
+            final boolean instantApp = computer.isInstantAppInternal(
+                    visiblePackage.getPackageName(), userId, visibleUid);
+            final boolean accessGranted;
+            if (instantApp) {
+                if (!direct) {
+                    // if the interaction that lead to this granting access to an instant app
+                    // was indirect (i.e.: URI permission grant), do not actually execute the
+                    // grant.
+                    return;
                 }
-            });
+                accessGranted = mInstantAppRegistry.grantInstantAccess(userId, intent,
+                        recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
+            } else {
+                accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
+                        retainOnUpdate);
+            }
 
             if (accessGranted) {
                 ApplicationPackageManager.invalidateGetPackagesForUidCache();
@@ -7271,8 +7237,7 @@
 
         @Override
         public void pruneInstantApps() {
-            executeWithConsistentComputer(computer ->
-                    mInstantAppRegistry.pruneInstantApps(computer));
+            mInstantAppRegistry.pruneInstantApps(snapshotComputer());
         }
 
         @Override
@@ -7680,7 +7645,8 @@
 
         @Override
         public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
-            PackageManagerService.this.unsuspendForSuspendingPackage(packageName, affectedUser);
+            PackageManagerService.this.unsuspendForSuspendingPackage(snapshotComputer(),
+                    packageName, affectedUser);
         }
 
         @Override
@@ -7744,52 +7710,6 @@
         }
 
         @Override
-        public void withPackageSettingsSnapshot(
-                @NonNull Consumer<Function<String, PackageStateInternal>> block) {
-            executeWithConsistentComputer(computer ->
-                    block.accept(computer::getPackageStateInternal));
-        }
-
-        @Override
-        public <Output> Output withPackageSettingsSnapshotReturning(
-                @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>,
-                        Output> block) {
-            return executeWithConsistentComputerReturning(computer ->
-                    block.apply(computer::getPackageStateInternal));
-        }
-
-        @Override
-        public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
-                @NonNull FunctionalUtils.ThrowingCheckedConsumer<Function<String,
-                        PackageStateInternal>, ExceptionType> block) throws ExceptionType {
-            executeWithConsistentComputerThrowing(computer ->
-                    block.accept(computer::getPackageStateInternal));
-        }
-
-        @Override
-        public <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
-                withPackageSettingsSnapshotThrowing2(
-                        @NonNull FunctionalUtils.ThrowingChecked2Consumer<
-                                Function<String, PackageStateInternal>, ExceptionOne,
-                                ExceptionTwo> block)
-                throws ExceptionOne, ExceptionTwo {
-            executeWithConsistentComputerThrowing2(
-                    (FunctionalUtils.ThrowingChecked2Consumer<Computer, ExceptionOne,
-                            ExceptionTwo>) computer -> block.accept(computer::getPackageStateInternal));
-        }
-
-        @Override
-        public <Output, ExceptionType extends Exception> Output
-                withPackageSettingsSnapshotReturningThrowing(
-                        @NonNull FunctionalUtils.ThrowingCheckedFunction<
-                                Function<String, PackageStateInternal>, Output,
-                                ExceptionType> block)
-                throws ExceptionType {
-            return executeWithConsistentComputerReturningThrowing(computer ->
-                    block.apply(computer::getPackageStateInternal));
-        }
-
-        @Override
         public void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
                 boolean migrateAppsData) {
             PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags,
@@ -7834,70 +7754,59 @@
             @NonNull Set<String> outUpdatedPackageNames) {
         synchronized (mOverlayPathsLock) {
             final ArrayMap<String, ArraySet<String>> libNameToModifiedDependents = new ArrayMap<>();
-            Boolean targetModified = executeWithConsistentComputerReturning(computer -> {
-                final PackageStateInternal packageState = computer.getPackageStateInternal(
-                        targetPackageName);
-                final AndroidPackage targetPkg =
-                        packageState == null ? null : packageState.getPkg();
-                if (targetPackageName == null || targetPkg == null) {
-                    Slog.e(TAG, "failed to find package " + targetPackageName);
-                    return null;
-                }
-
-                if (Objects.equals(packageState.getUserStateOrDefault(userId).getOverlayPaths(),
-                        newOverlayPaths)) {
-                    return false;
-                }
-
-                if (targetPkg.getLibraryNames() != null) {
-                    // Set the overlay paths for dependencies of the shared library.
-                    for (final String libName : targetPkg.getLibraryNames()) {
-                        ArraySet<String> modifiedDependents = null;
-
-                        final SharedLibraryInfo info = computer.getSharedLibraryInfo(libName,
-                                SharedLibraryInfo.VERSION_UNDEFINED);
-                        if (info == null) {
-                            continue;
-                        }
-                        final List<VersionedPackage> dependents = computer
-                                .getPackagesUsingSharedLibrary(info, 0, Process.SYSTEM_UID, userId);
-                        if (dependents == null) {
-                            continue;
-                        }
-                        for (final VersionedPackage dependent : dependents) {
-                            final PackageStateInternal dependentState =
-                                    computer.getPackageStateInternal(dependent.getPackageName());
-                            if (dependentState == null) {
-                                continue;
-                            }
-                            if (!Objects.equals(dependentState.getUserStateOrDefault(userId)
-                                    .getSharedLibraryOverlayPaths()
-                                    .get(libName), newOverlayPaths)) {
-                                String dependentPackageName = dependent.getPackageName();
-                                modifiedDependents = ArrayUtils.add(modifiedDependents,
-                                        dependentPackageName);
-                                outUpdatedPackageNames.add(dependentPackageName);
-                            }
-                        }
-
-                        if (modifiedDependents != null) {
-                            libNameToModifiedDependents.put(libName, modifiedDependents);
-                        }
-                    }
-                }
-
-                outUpdatedPackageNames.add(targetPackageName);
-                return true;
-            });
-
-            if (targetModified == null) {
-                // Null indicates error
+            Computer computer = snapshotComputer();
+            final PackageStateInternal packageState = computer.getPackageStateInternal(
+                    targetPackageName);
+            final AndroidPackage targetPkg = packageState == null ? null : packageState.getPkg();
+            if (targetPackageName == null || targetPkg == null) {
+                Slog.e(TAG, "failed to find package " + targetPackageName);
                 return false;
-            } else if (!targetModified) {
-                // Treat non-modification as a successful commit
+            }
+
+            if (Objects.equals(packageState.getUserStateOrDefault(userId).getOverlayPaths(),
+                    newOverlayPaths)) {
                 return true;
             }
 
+            if (targetPkg.getLibraryNames() != null) {
+                // Set the overlay paths for dependencies of the shared library.
+                for (final String libName : targetPkg.getLibraryNames()) {
+                    ArraySet<String> modifiedDependents = null;
+
+                    final SharedLibraryInfo info = computer.getSharedLibraryInfo(libName,
+                            SharedLibraryInfo.VERSION_UNDEFINED);
+                    if (info == null) {
+                        continue;
+                    }
+                    final List<VersionedPackage> dependents = computer
+                            .getPackagesUsingSharedLibrary(info, 0, Process.SYSTEM_UID, userId);
+                    if (dependents == null) {
+                        continue;
+                    }
+                    for (final VersionedPackage dependent : dependents) {
+                        final PackageStateInternal dependentState =
+                                computer.getPackageStateInternal(dependent.getPackageName());
+                        if (dependentState == null) {
+                            continue;
+                        }
+                        if (!Objects.equals(dependentState.getUserStateOrDefault(userId)
+                                .getSharedLibraryOverlayPaths()
+                                .get(libName), newOverlayPaths)) {
+                            String dependentPackageName = dependent.getPackageName();
+                            modifiedDependents = ArrayUtils.add(modifiedDependents,
+                                    dependentPackageName);
+                            outUpdatedPackageNames.add(dependentPackageName);
+                        }
+                    }
+
+                    if (modifiedDependents != null) {
+                        libNameToModifiedDependents.put(libName, modifiedDependents);
+                    }
+                }
+            }
+
+            outUpdatedPackageNames.add(targetPackageName);
+
             commitPackageStateMutation(null, mutator -> {
                 mutator.forPackage(targetPackageName)
                         .userState(userId)
@@ -8062,36 +7971,6 @@
         forEachPackageState(mComputer.getPackageStates(), actionWrapped);
     }
 
-    // TODO: Make private
-    void executeWithConsistentComputer(
-            @NonNull FunctionalUtils.ThrowingConsumer<Computer> consumer) {
-        consumer.accept(snapshotComputer());
-    }
-
-    private <T> T executeWithConsistentComputerReturning(
-            @NonNull FunctionalUtils.ThrowingFunction<Computer, T> function) {
-        return function.apply(snapshotComputer());
-    }
-
-    private <ExceptionType extends Exception> void executeWithConsistentComputerThrowing(
-            @NonNull FunctionalUtils.ThrowingCheckedConsumer<Computer, ExceptionType> consumer)
-            throws ExceptionType {
-        consumer.accept(snapshotComputer());
-    }
-
-    private <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
-    executeWithConsistentComputerThrowing2(
-            @NonNull FunctionalUtils.ThrowingChecked2Consumer<Computer, ExceptionOne,
-                    ExceptionTwo> consumer) throws ExceptionOne, ExceptionTwo {
-        consumer.accept(snapshotComputer());
-    }
-
-    private <T, ExceptionType extends Exception> T executeWithConsistentComputerReturningThrowing(
-            @NonNull FunctionalUtils.ThrowingCheckedFunction<Computer, T, ExceptionType> function)
-            throws ExceptionType {
-        return function.apply(snapshotComputer());
-    }
-
     boolean isHistoricalPackageUsageAvailable() {
         return mPackageUsage.isHistoricalPackageUsageAvailable();
     }
@@ -8357,7 +8236,7 @@
      */
     void writeSettingsLPrTEMP() {
         mPermissionManager.writeLegacyPermissionsTEMP(mSettings.mPermissions);
-        mSettings.writeLPr();
+        mSettings.writeLPr(mLiveComputer);
     }
 
     @Override
@@ -8856,7 +8735,6 @@
     }
 
     void notifyInstantAppPackageInstalled(String packageName, int[] newUsers) {
-        executeWithConsistentComputer(computer ->
-                mInstantAppRegistry.onPackageInstalled(computer, packageName, newUsers));
+        mInstantAppRegistry.onPackageInstalled(snapshotComputer(), packageName, newUsers);
     }
 }
diff --git a/services/core/java/com/android/server/pm/PendingPackageBroadcasts.java b/services/core/java/com/android/server/pm/PendingPackageBroadcasts.java
index 4e9a06a..6e2f756 100644
--- a/services/core/java/com/android/server/pm/PendingPackageBroadcasts.java
+++ b/services/core/java/com/android/server/pm/PendingPackageBroadcasts.java
@@ -16,12 +16,17 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.util.ArrayMap;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Set of pending broadcasts for aggregating enable/disable of components.
@@ -29,65 +34,111 @@
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
 public final class PendingPackageBroadcasts {
 
+    private final Object mLock = new PackageManagerTracedLock();
+
     // for each user id, a map of <package name -> components within that package>
+    @GuardedBy("mLock")
     final SparseArray<ArrayMap<String, ArrayList<String>>> mUidMap;
 
     public PendingPackageBroadcasts() {
         mUidMap = new SparseArray<>(2);
     }
 
-    public ArrayList<String> get(int userId, String packageName) {
-        ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId);
-        return packages.get(packageName);
+    public boolean hasPackage(@UserIdInt int userId, @NonNull String packageName) {
+        synchronized (mLock) {
+            final ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId);
+            return packages != null && packages.containsKey(packageName);
+        }
     }
 
     public void put(int userId, String packageName, ArrayList<String> components) {
-        ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId);
-        packages.put(packageName, components);
+        synchronized (mLock) {
+            ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId);
+            packages.put(packageName, components);
+        }
+    }
+
+    public void addComponent(@UserIdInt int userId, @NonNull String packageName,
+            @NonNull String componentClassName) {
+        synchronized (mLock) {
+            ArrayList<String> components = getOrAllocate(userId, packageName);
+            if (!components.contains(componentClassName)) {
+                components.add(componentClassName);
+            }
+        }
+    }
+
+    public void addComponents(@UserIdInt int userId, @NonNull String packageName,
+            @NonNull List<String> componentClassNames) {
+        synchronized (mLock) {
+            ArrayList<String> components = getOrAllocate(userId, packageName);
+            for (int index = 0; index < componentClassNames.size(); index++) {
+                String componentClassName = componentClassNames.get(index);
+                if (!components.contains(componentClassName)) {
+                    components.add(componentClassName);
+                }
+            }
+        }
     }
 
     public void remove(int userId, String packageName) {
-        ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId);
-        if (packages != null) {
-            packages.remove(packageName);
+        synchronized (mLock) {
+            ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId);
+            if (packages != null) {
+                packages.remove(packageName);
+            }
         }
     }
 
     public void remove(int userId) {
-        mUidMap.remove(userId);
-    }
-
-    public int userIdCount() {
-        return mUidMap.size();
-    }
-
-    public int userIdAt(int n) {
-        return mUidMap.keyAt(n);
-    }
-
-    public ArrayMap<String, ArrayList<String>> packagesForUserId(int userId) {
-        return mUidMap.get(userId);
-    }
-
-    public int size() {
-        // total number of pending broadcast entries across all userIds
-        int num = 0;
-        for (int i = 0; i < mUidMap.size(); i++) {
-            num += mUidMap.valueAt(i).size();
+        synchronized (mLock) {
+            mUidMap.remove(userId);
         }
-        return num;
+    }
+
+    @Nullable
+    public SparseArray<ArrayMap<String, ArrayList<String>>> copiedMap() {
+        synchronized (mLock) {
+            SparseArray<ArrayMap<String, ArrayList<String>>> copy = new SparseArray<>();
+            for (int userIdIndex = 0; userIdIndex < mUidMap.size(); userIdIndex++) {
+                final ArrayMap<String, ArrayList<String>> packages = mUidMap.valueAt(userIdIndex);
+                ArrayMap<String, ArrayList<String>> packagesCopy = new ArrayMap<>();
+                for (int packagesIndex = 0; packagesIndex < packages.size(); packagesIndex++) {
+                    packagesCopy.put(packages.keyAt(packagesIndex),
+                            new ArrayList<>(packages.valueAt(packagesIndex)));
+                }
+                copy.put(mUidMap.keyAt(userIdIndex), packagesCopy);
+            }
+            return copy;
+        }
     }
 
     public void clear() {
-        mUidMap.clear();
+        synchronized (mLock) {
+            mUidMap.clear();
+        }
     }
 
     private ArrayMap<String, ArrayList<String>> getOrAllocate(int userId) {
-        ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId);
-        if (map == null) {
-            map = new ArrayMap<>();
-            mUidMap.put(userId, map);
+        synchronized (mLock) {
+            ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId);
+            if (map == null) {
+                map = new ArrayMap<>();
+                mUidMap.put(userId, map);
+            }
+            return map;
         }
-        return map;
+    }
+
+    private ArrayList<String> getOrAllocate(int userId, @NonNull String packageName) {
+        synchronized (mLock) {
+            ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId);
+            if (map == null) {
+                map = new ArrayMap<>();
+                mUidMap.put(userId, map);
+            }
+
+            return map.computeIfAbsent(packageName, k -> new ArrayList<>());
+        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 2ad35b7..394c8fb 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2432,7 +2432,7 @@
         }
     }
 
-    void writeLPr() {
+    void writeLPr(@NonNull Computer computer) {
         //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
 
         final long startTime = SystemClock.uptimeMillis();
@@ -2524,8 +2524,8 @@
                 }
             }
 
-            mDomainVerificationManager.writeSettings(serializer, false /* includeSignatures */,
-                    UserHandle.USER_ALL);
+            mDomainVerificationManager.writeSettings(computer, serializer,
+                    false /* includeSignatures */, UserHandle.USER_ALL);
 
             mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
 
@@ -2967,7 +2967,7 @@
         }
     }
 
-    boolean readLPw(@NonNull List<UserInfo> users) {
+    boolean readLPw(@NonNull Computer computer, @NonNull List<UserInfo> users) {
         FileInputStream str = null;
         if (mBackupSettingsFilename.exists()) {
             try {
@@ -3111,7 +3111,7 @@
                     ver.databaseVersion = parser.getAttributeInt(null, ATTR_DATABASE_VERSION);
                     ver.fingerprint = XmlUtils.readStringAttribute(parser, ATTR_FINGERPRINT);
                 } else if (tagName.equals(DomainVerificationPersistence.TAG_DOMAIN_VERIFICATIONS)) {
-                    mDomainVerificationManager.readSettings(parser);
+                    mDomainVerificationManager.readSettings(computer, parser);
                 } else if (tagName.equals(
                         DomainVerificationLegacySettings.TAG_DOMAIN_VERIFICATIONS_LEGACY)) {
                     mDomainVerificationManager.readLegacySettings(parser);
@@ -4287,11 +4287,11 @@
         return Process.FIRST_APPLICATION_UID + size;
     }
 
-    public VerifierDeviceIdentity getVerifierDeviceIdentityLPw() {
+    public VerifierDeviceIdentity getVerifierDeviceIdentityLPw(@NonNull Computer computer) {
         if (mVerifierDeviceIdentity == null) {
             mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();
 
-            writeLPr();
+            writeLPr(computer);
         }
 
         return mVerifierDeviceIdentity;
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 0638d5e..3fe0790 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -321,7 +321,8 @@
      *                       on the device.
      * @return {@code true} if the available storage space is reached.
      */
-    boolean pruneUnusedStaticSharedLibraries(long neededSpace, long maxCachePeriod)
+    boolean pruneUnusedStaticSharedLibraries(@NonNull Computer computer, long neededSpace,
+            long maxCachePeriod)
             throws IOException {
         final StorageManager storage = mInjector.getSystemService(StorageManager.class);
         final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
@@ -332,38 +333,36 @@
         // Important: We skip shared libs used for some user since
         // in such a case we need to keep the APK on the device. The check for
         // a lib being used for any user is performed by the uninstall call.
-        mPm.executeWithConsistentComputer(computer -> {
-            final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
-                    sharedLibraries = computer.getSharedLibraries();
-            final int libCount = sharedLibraries.size();
-            for (int i = 0; i < libCount; i++) {
-                final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
-                        sharedLibraries.valueAt(i);
-                if (versionedLib == null) {
+        final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
+                sharedLibraries = computer.getSharedLibraries();
+        final int libCount = sharedLibraries.size();
+        for (int i = 0; i < libCount; i++) {
+            final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
+                    sharedLibraries.valueAt(i);
+            if (versionedLib == null) {
+                continue;
+            }
+            final int versionCount = versionedLib.size();
+            for (int j = 0; j < versionCount; j++) {
+                SharedLibraryInfo libInfo = versionedLib.valueAt(j);
+                final PackageStateInternal ps = getLibraryPackage(computer, libInfo);
+                if (ps == null) {
                     continue;
                 }
-                final int versionCount = versionedLib.size();
-                for (int j = 0; j < versionCount; j++) {
-                    SharedLibraryInfo libInfo = versionedLib.valueAt(j);
-                    final PackageStateInternal ps = getLibraryPackage(computer, libInfo);
-                    if (ps == null) {
-                        continue;
-                    }
-                    // Skip unused libs cached less than the min period to prevent pruning a lib
-                    // needed by a subsequently installed package.
-                    if (now - ps.getLastUpdateTime() < maxCachePeriod) {
-                        continue;
-                    }
-
-                    if (ps.getPkg().isSystem()) {
-                        continue;
-                    }
-
-                    packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(),
-                            libInfo.getDeclaringPackage().getLongVersionCode()));
+                // Skip unused libs cached less than the min period to prevent pruning a lib
+                // needed by a subsequently installed package.
+                if (now - ps.getLastUpdateTime() < maxCachePeriod) {
+                    continue;
                 }
+
+                if (ps.getPkg().isSystem()) {
+                    continue;
+                }
+
+                packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(),
+                        libInfo.getDeclaringPackage().getLongVersionCode()));
             }
-        });
+        }
 
         final int packageCount = packagesToDelete.size();
         for (int i = 0; i < packageCount; i++) {
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index bd1c9c7..3ef5599 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -27,6 +27,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.content.Intent;
@@ -99,10 +100,10 @@
      * @return The names of failed packages.
      */
     @Nullable
-    String[] setPackagesSuspended(@Nullable String[] packageNames, boolean suspended,
-            @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras,
-            @Nullable SuspendDialogInfo dialogInfo, @NonNull String callingPackage,
-            int userId, int callingUid) {
+    String[] setPackagesSuspended(@NonNull Computer computer, @Nullable String[] packageNames,
+            boolean suspended, @Nullable PersistableBundle appExtras,
+            @Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo,
+            @NonNull String callingPackage, @UserIdInt int userId, int callingUid) {
         if (ArrayUtils.isEmpty(packageNames)) {
             return packageNames;
         }
@@ -121,62 +122,60 @@
 
         ArraySet<String> modifiedPackages = new ArraySet<>();
 
-        mPm.executeWithConsistentComputer(computer -> {
-            final boolean[] canSuspend = suspended
-                    ? canSuspendPackageForUser(computer, packageNames, userId, callingUid) : null;
-            for (int i = 0; i < packageNames.length; i++) {
-                final String packageName = packageNames[i];
-                if (callingPackage.equals(packageName)) {
-                    Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
-                            + (suspended ? "" : "un") + "suspend itself. Ignoring");
-                    unmodifiablePackages.add(packageName);
-                    continue;
-                }
-                final PackageStateInternal packageState =
-                        computer.getPackageStateInternal(packageName);
-                if (packageState == null
-                        || computer.shouldFilterApplication(packageState, callingUid, userId)) {
-                    Slog.w(TAG, "Could not find package setting for package: " + packageName
-                            + ". Skipping suspending/un-suspending.");
-                    unmodifiablePackages.add(packageName);
-                    continue;
-                }
-                if (canSuspend != null && !canSuspend[i]) {
-                    unmodifiablePackages.add(packageName);
-                    continue;
-                }
+        final boolean[] canSuspend = suspended
+                ? canSuspendPackageForUser(computer, packageNames, userId, callingUid) : null;
+        for (int i = 0; i < packageNames.length; i++) {
+            final String packageName = packageNames[i];
+            if (callingPackage.equals(packageName)) {
+                Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+                        + (suspended ? "" : "un") + "suspend itself. Ignoring");
+                unmodifiablePackages.add(packageName);
+                continue;
+            }
+            final PackageStateInternal packageState =
+                    computer.getPackageStateInternal(packageName);
+            if (packageState == null
+                    || computer.shouldFilterApplication(packageState, callingUid, userId)) {
+                Slog.w(TAG, "Could not find package setting for package: " + packageName
+                        + ". Skipping suspending/un-suspending.");
+                unmodifiablePackages.add(packageName);
+                continue;
+            }
+            if (canSuspend != null && !canSuspend[i]) {
+                unmodifiablePackages.add(packageName);
+                continue;
+            }
 
-                final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
-                        packageState.getUserStateOrDefault(userId).getSuspendParams();
-                if (suspended) {
-                    if (suspendParamsMap != null && suspendParamsMap.containsKey(packageName)) {
-                        final SuspendParams suspendParams = suspendParamsMap.get(packageName);
-                        // Skip if there's no changes
-                        if (suspendParams != null
-                                && Objects.equals(suspendParams.getDialogInfo(), dialogInfo)
-                                && Objects.equals(suspendParams.getAppExtras(), appExtras)
-                                && Objects.equals(suspendParams.getLauncherExtras(),
-                                launcherExtras)) {
-                            // Carried over API behavior, must notify change even if no change
-                            changedPackagesList.add(packageName);
-                            changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
-                            continue;
-                        }
+            final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+                    packageState.getUserStateOrDefault(userId).getSuspendParams();
+            if (suspended) {
+                if (suspendParamsMap != null && suspendParamsMap.containsKey(packageName)) {
+                    final SuspendParams suspendParams = suspendParamsMap.get(packageName);
+                    // Skip if there's no changes
+                    if (suspendParams != null
+                            && Objects.equals(suspendParams.getDialogInfo(), dialogInfo)
+                            && Objects.equals(suspendParams.getAppExtras(), appExtras)
+                            && Objects.equals(suspendParams.getLauncherExtras(),
+                            launcherExtras)) {
+                        // Carried over API behavior, must notify change even if no change
+                        changedPackagesList.add(packageName);
+                        changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+                        continue;
                     }
                 }
-
-                // If size one, the package will be unsuspended from this call
-                boolean packageUnsuspended =
-                        !suspended && CollectionUtils.size(suspendParamsMap) <= 1;
-                if (suspended || packageUnsuspended) {
-                    changedPackagesList.add(packageName);
-                    changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
-                }
-
-                modifiedPackages.add(packageName);
-                modifiedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
             }
-        });
+
+            // If size one, the package will be unsuspended from this call
+            boolean packageUnsuspended =
+                    !suspended && CollectionUtils.size(suspendParamsMap) <= 1;
+            if (suspended || packageUnsuspended) {
+                changedPackagesList.add(packageName);
+                changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+            }
+
+            modifiedPackages.add(packageName);
+            modifiedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+        }
 
         mPm.commitPackageStateMutation(null, mutator -> {
             final int size = modifiedPackages.size();
@@ -218,29 +217,27 @@
      * @return The names of packages which are Unsuspendable.
      */
     @NonNull
-    String[] getUnsuspendablePackagesForUser(@NonNull String[] packageNames, int userId,
-            int callingUid) {
+    String[] getUnsuspendablePackagesForUser(@NonNull Computer computer,
+            @NonNull String[] packageNames, @UserIdInt int userId, int callingUid) {
         if (!isSuspendAllowedForUser(userId, callingUid)) {
             Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
             return packageNames;
         }
         final ArraySet<String> unactionablePackages = new ArraySet<>();
-        mPm.executeWithConsistentComputer(computer -> {
-            final boolean[] canSuspend = canSuspendPackageForUser(computer, packageNames, userId,
-                    callingUid);
-            for (int i = 0; i < packageNames.length; i++) {
-                if (!canSuspend[i]) {
-                    unactionablePackages.add(packageNames[i]);
-                    continue;
-                }
-                final PackageStateInternal packageState =
-                        computer.getPackageStateFiltered(packageNames[i], callingUid, userId);
-                if (packageState == null) {
-                    Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
-                    unactionablePackages.add(packageNames[i]);
-                }
+        final boolean[] canSuspend = canSuspendPackageForUser(computer, packageNames, userId,
+                callingUid);
+        for (int i = 0; i < packageNames.length; i++) {
+            if (!canSuspend[i]) {
+                unactionablePackages.add(packageNames[i]);
+                continue;
             }
-        });
+            final PackageStateInternal packageState =
+                    computer.getPackageStateFiltered(packageNames[i], callingUid, userId);
+            if (packageState == null) {
+                Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
+                unactionablePackages.add(packageNames[i]);
+            }
+        }
         return unactionablePackages.toArray(new String[unactionablePackages.size()]);
     }
 
@@ -282,45 +279,44 @@
      *                                   suspensions will be removed.
      * @param userId The user for which the changes are taking place.
      */
-    void removeSuspensionsBySuspendingPackage(@NonNull String[] packagesToChange,
+    void removeSuspensionsBySuspendingPackage(@NonNull Computer computer,
+            @NonNull String[] packagesToChange,
             @NonNull Predicate<String> suspendingPackagePredicate, int userId) {
         final List<String> unsuspendedPackages = new ArrayList<>();
         final IntArray unsuspendedUids = new IntArray();
         final ArrayMap<String, ArraySet<String>> pkgToSuspendingPkgsToCommit = new ArrayMap<>();
-        mPm.executeWithConsistentComputer(computer -> {
-            for (String packageName : packagesToChange) {
-                final PackageStateInternal packageState =
-                        computer.getPackageStateInternal(packageName);
-                final PackageUserStateInternal packageUserState = packageState == null
-                        ? null : packageState.getUserStateOrDefault(userId);
-                if (packageUserState == null || !packageUserState.isSuspended()) {
-                    continue;
-                }
+        for (String packageName : packagesToChange) {
+            final PackageStateInternal packageState =
+                    computer.getPackageStateInternal(packageName);
+            final PackageUserStateInternal packageUserState = packageState == null
+                    ? null : packageState.getUserStateOrDefault(userId);
+            if (packageUserState == null || !packageUserState.isSuspended()) {
+                continue;
+            }
 
-                WatchedArrayMap<String, SuspendParams> suspendParamsMap =
-                        packageUserState.getSuspendParams();
-                int countRemoved = 0;
-                for (int index = 0; index < suspendParamsMap.size(); index++) {
-                    String suspendingPackage = suspendParamsMap.keyAt(index);
-                    if (suspendingPackagePredicate.test(suspendingPackage)) {
-                        ArraySet<String> suspendingPkgsToCommit =
-                                pkgToSuspendingPkgsToCommit.get(packageName);
-                        if (suspendingPkgsToCommit == null) {
-                            suspendingPkgsToCommit = new ArraySet<>();
-                            pkgToSuspendingPkgsToCommit.put(packageName, suspendingPkgsToCommit);
-                        }
-                        suspendingPkgsToCommit.add(suspendingPackage);
-                        countRemoved++;
+            WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+                    packageUserState.getSuspendParams();
+            int countRemoved = 0;
+            for (int index = 0; index < suspendParamsMap.size(); index++) {
+                String suspendingPackage = suspendParamsMap.keyAt(index);
+                if (suspendingPackagePredicate.test(suspendingPackage)) {
+                    ArraySet<String> suspendingPkgsToCommit =
+                            pkgToSuspendingPkgsToCommit.get(packageName);
+                    if (suspendingPkgsToCommit == null) {
+                        suspendingPkgsToCommit = new ArraySet<>();
+                        pkgToSuspendingPkgsToCommit.put(packageName, suspendingPkgsToCommit);
                     }
-                }
-
-                // Everything would be removed and package unsuspended
-                if (countRemoved == suspendParamsMap.size()) {
-                    unsuspendedPackages.add(packageState.getPackageName());
-                    unsuspendedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+                    suspendingPkgsToCommit.add(suspendingPackage);
+                    countRemoved++;
                 }
             }
-        });
+
+            // Everything would be removed and package unsuspended
+            if (countRemoved == suspendParamsMap.size()) {
+                unsuspendedPackages.add(packageState.getPackageName());
+                unsuspendedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+            }
+        }
 
         mPm.commitPackageStateMutation(null, mutator -> {
             for (int mapIndex = 0; mapIndex < pkgToSuspendingPkgsToCommit.size(); mapIndex++) {
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index b730ab2..e06b608 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -30,6 +30,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.util.CollectionUtils;
+import com.android.server.pm.Computer;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
@@ -38,7 +39,6 @@
 
 import java.util.Arrays;
 import java.util.List;
-import java.util.function.Function;
 
 @SuppressWarnings("PointlessBooleanExpression")
 public class DomainVerificationDebug {
@@ -62,8 +62,7 @@
     }
 
     public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
-            @Nullable @UserIdInt Integer userId,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction,
+            @Nullable @UserIdInt Integer userId, @NonNull Computer snapshot,
             @NonNull DomainVerificationStateMap<DomainVerificationPkgState> stateMap)
             throws NameNotFoundException {
         ArrayMap<String, Integer> reusedMap = new ArrayMap<>();
@@ -74,7 +73,7 @@
             for (int index = 0; index < size; index++) {
                 DomainVerificationPkgState pkgState = stateMap.valueAt(index);
                 String pkgName = pkgState.getPackageName();
-                PackageStateInternal pkgSetting = pkgSettingFunction.apply(pkgName);
+                PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName);
                 if (pkgSetting == null || pkgSetting.getPkg() == null) {
                     continue;
                 }
@@ -90,7 +89,7 @@
                 throw DomainVerificationUtils.throwPackageUnavailable(packageName);
             }
 
-            PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName);
+            PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
             if (pkgSetting == null || pkgSetting.getPkg() == null) {
                 throw DomainVerificationUtils.throwPackageUnavailable(packageName);
             }
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 25147d0..1714086 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -25,7 +25,6 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.PackageSettingsSnapshotProvider;
 import android.content.pm.ResolveInfo;
 import android.content.pm.verify.domain.DomainVerificationInfo;
 import android.content.pm.verify.domain.DomainVerificationManager;
@@ -37,7 +36,7 @@
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 
-import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.Computer;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.Settings;
 import com.android.server.pm.pkg.PackageStateInternal;
@@ -227,14 +226,14 @@
      * assumed nothing has changed since the device rebooted.
      * <p>
      * If this is a new install, state will be restored from a previous call to {@link
-     * #restoreSettings(TypedXmlPullParser)}, or a new one will be generated. In either case, a
+     * #restoreSettings(Computer, TypedXmlPullParser)}, or a new one will be generated. In either case, a
      * broadcast will be sent to the domain verification agent so it may re-run any verification
      * logic for the newly associated domains.
      * <p>
      * This will mutate internal {@link DomainVerificationPkgState} and so will hold the internal
      * lock. This should never be called from within the domain verification classes themselves.
      * <p>
-     * This will NOT call {@link #writeSettings(TypedXmlSerializer, boolean, int)}. That must be
+     * This will NOT call {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. That must be
      * handled by the caller.
      */
     void addPackage(@NonNull PackageStateInternal newPkgSetting);
@@ -249,7 +248,7 @@
      * This will mutate internal {@link DomainVerificationPkgState} and so will hold the internal
      * lock. This should never be called from within the domain verification classes themselves.
      * <p>
-     * This will NOT call {@link #writeSettings(TypedXmlSerializer, boolean, int)}. That must be
+     * This will NOT call {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. That must be
      * handled by the caller.
      */
     void migrateState(@NonNull PackageStateInternal oldPkgSetting,
@@ -259,24 +258,24 @@
      * Serializes the entire internal state. This is equivalent to a full backup of the existing
      * verification state. This write includes legacy state, as a sibling tag the modern state.
      *
+     * @param snapshot
      * @param includeSignatures Whether to include the package signatures in the output, mainly
      *                          used for backing up the user settings and ensuring they're
      *                          re-attached to the same package.
      * @param userId The user to write out. Supports {@link UserHandle#USER_ALL} if all users
-     *               should be written.
      */
-    void writeSettings(@NonNull TypedXmlSerializer serializer, boolean includeSignatures,
-            @UserIdInt int userId) throws IOException;
+    void writeSettings(@NonNull Computer snapshot, @NonNull TypedXmlSerializer serializer,
+            boolean includeSignatures, @UserIdInt int userId) throws IOException;
 
     /**
      * Read back a list of {@link DomainVerificationPkgState}s previously written by {@link
-     * #writeSettings(TypedXmlSerializer, boolean, int)}. Assumes that the
+     * #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. Assumes that the
      * {@link DomainVerificationPersistence#TAG_DOMAIN_VERIFICATIONS} tag has already been entered.
      * <p>
      * This is expected to only be used to re-attach states for packages already known to be on the
-     * device. If restoring from a backup, use {@link #restoreSettings(TypedXmlPullParser)}.
+     * device. If restoring from a backup, use {@link #restoreSettings(Computer, TypedXmlPullParser)}.
      */
-    void readSettings(@NonNull TypedXmlPullParser parser)
+    void readSettings(@NonNull Computer snapshot, @NonNull TypedXmlPullParser parser)
             throws IOException, XmlPullParserException;
 
     /**
@@ -306,7 +305,7 @@
 
     /**
      * Restore a list of {@link DomainVerificationPkgState}s previously written by {@link
-     * #writeSettings(TypedXmlSerializer, boolean, int)}. Assumes that the
+     * #writeSettings(Computer, TypedXmlSerializer, boolean, int)}. Assumes that the
      * {@link DomainVerificationPersistence#TAG_DOMAIN_VERIFICATIONS}
      * tag has already been entered.
      * <p>
@@ -321,7 +320,7 @@
      * TODO(b/170746586): Figure out how to verify that package signatures match at snapshot time
      *  and restore time.
      */
-    void restoreSettings(@NonNull TypedXmlPullParser parser)
+    void restoreSettings(@NonNull Computer snapshot, @NonNull TypedXmlPullParser parser)
             throws IOException, XmlPullParserException;
 
     /**
@@ -349,17 +348,14 @@
     /**
      * Print the verification state and user selection state of a package.
      *
+     * @param snapshot
      * @param packageName        the package whose state to change, or all packages if none is
      *                           specified
      * @param userId             the specific user to print, or null to skip printing user selection
-     *                           states, supports {@link android.os.UserHandle#USER_ALL}
-     * @param pkgSettingFunction the method by which to retrieve package data; if this is called
-     *                           from {@link PackageManagerService}, it is expected to pass in the
-     *                           snapshot of {@link PackageStateInternal} objects
+ *                           states, supports {@link UserHandle#USER_ALL}
      */
-    void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
-            @Nullable @UserIdInt Integer userId,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction)
+    void printState(@NonNull Computer snapshot, @NonNull IndentingPrintWriter writer,
+            @Nullable String packageName, @Nullable @UserIdInt Integer userId)
             throws NameNotFoundException;
 
     @NonNull
@@ -406,12 +402,11 @@
             @NonNull Set<String> domains, int state) throws NameNotFoundException;
 
 
-    interface Connection extends DomainVerificationEnforcer.Callback,
-            PackageSettingsSnapshotProvider {
+    interface Connection extends DomainVerificationEnforcer.Callback {
 
         /**
          * Notify that a settings change has been made and that eventually
-         * {@link #writeSettings(TypedXmlSerializer, boolean, int)} should be invoked by the parent.
+         * {@link #writeSettings(Computer, TypedXmlSerializer, boolean, int)} should be invoked by the parent.
          */
         void scheduleWriteSettings();
 
@@ -433,5 +428,8 @@
 
         @UserIdInt
         int[] getAllUserIds();
+
+        @NonNull
+        Computer snapshot();
     }
 }
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index d6c89f7..13218ea 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -37,7 +37,6 @@
 import android.content.pm.verify.domain.DomainVerificationState;
 import android.content.pm.verify.domain.DomainVerificationUserState;
 import android.content.pm.verify.domain.IDomainVerificationManager;
-import android.os.Build;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -52,11 +51,10 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.CollectionUtils;
-import com.android.internal.util.FunctionalUtils;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.Settings;
+import com.android.server.pm.Computer;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
@@ -80,7 +78,6 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
-import java.util.function.Consumer;
 import java.util.function.Function;
 
 @SuppressLint("MissingPermission")
@@ -109,9 +106,9 @@
      * immediately attached once its available.
      * <p>
      * Generally this should be not accessed directly. Prefer calling {@link
-     * #getAndValidateAttachedLocked(UUID, Set, boolean, int, Integer, Function)}.
+     * #getAndValidateAttachedLocked(UUID, Set, boolean, int, Integer, Computer)}.
      *
-     * @see #getAndValidateAttachedLocked(UUID, Set, boolean, int, Integer, Function)
+     * @see #getAndValidateAttachedLocked(UUID, Set, boolean, int, Integer, Computer)
      **/
     @GuardedBy("mLock")
     @NonNull
@@ -178,12 +175,7 @@
 
     @Override
     public void setConnection(@NonNull Connection connection) {
-        if (Build.IS_USERDEBUG || Build.IS_ENG) {
-            mConnection = new LockSafeConnection(connection);
-        } else {
-            mConnection = connection;
-        }
-
+        mConnection = connection;
         mEnforcer.setCallback(mConnection);
     }
 
@@ -264,44 +256,43 @@
     public DomainVerificationInfo getDomainVerificationInfo(@NonNull String packageName)
             throws NameNotFoundException {
         mEnforcer.assertApprovedQuerent(mConnection.getCallingUid(), mProxy);
-        return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> {
-            synchronized (mLock) {
-                PackageStateInternal pkgSetting = pkgSettings.apply(packageName);
-                AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
-                if (pkg == null) {
-                    throw DomainVerificationUtils.throwPackageUnavailable(packageName);
-                }
-
-                DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
-                if (pkgState == null) {
-                    return null;
-                }
-
-                ArrayMap<String, Integer> hostToStateMap = new ArrayMap<>(pkgState.getStateMap());
-
-                // TODO(b/159952358): Should the domain list be cached?
-                ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
-                if (domains.isEmpty()) {
-                    return null;
-                }
-
-                int size = domains.size();
-                for (int index = 0; index < size; index++) {
-                    hostToStateMap.putIfAbsent(domains.valueAt(index),
-                            DomainVerificationState.STATE_NO_RESPONSE);
-                }
-
-                final int mapSize = hostToStateMap.size();
-                for (int index = 0; index < mapSize; index++) {
-                    int internalValue = hostToStateMap.valueAt(index);
-                    int publicValue = DomainVerificationState.convertToInfoState(internalValue);
-                    hostToStateMap.setValueAt(index, publicValue);
-                }
-
-                // TODO(b/159952358): Do not return if no values are editable (all ignored states)?
-                return new DomainVerificationInfo(pkgState.getId(), packageName, hostToStateMap);
+        synchronized (mLock) {
+            final Computer snapshot = mConnection.snapshot();
+            PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
+            AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
+            if (pkg == null) {
+                throw DomainVerificationUtils.throwPackageUnavailable(packageName);
             }
-        });
+
+            DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
+            if (pkgState == null) {
+                return null;
+            }
+
+            ArrayMap<String, Integer> hostToStateMap = new ArrayMap<>(pkgState.getStateMap());
+
+            // TODO(b/159952358): Should the domain list be cached?
+            ArraySet<String> domains = mCollector.collectValidAutoVerifyDomains(pkg);
+            if (domains.isEmpty()) {
+                return null;
+            }
+
+            int size = domains.size();
+            for (int index = 0; index < size; index++) {
+                hostToStateMap.putIfAbsent(domains.valueAt(index),
+                        DomainVerificationState.STATE_NO_RESPONSE);
+            }
+
+            final int mapSize = hostToStateMap.size();
+            for (int index = 0; index < mapSize; index++) {
+                int internalValue = hostToStateMap.valueAt(index);
+                int publicValue = DomainVerificationState.convertToInfoState(internalValue);
+                hostToStateMap.setValueAt(index, publicValue);
+            }
+
+            // TODO(b/159952358): Do not return if no values are editable (all ignored states)?
+            return new DomainVerificationInfo(pkgState.getId(), packageName, hostToStateMap);
+        }
     }
 
     @DomainVerificationManager.Error
@@ -324,42 +315,40 @@
             @NonNull Set<String> domains, int state)
             throws NameNotFoundException {
         mEnforcer.assertApprovedVerifier(callingUid, mProxy);
-        return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> {
-            synchronized (mLock) {
-                List<String> verifiedDomains = new ArrayList<>();
+        synchronized (mLock) {
+            final Computer snapshot = mConnection.snapshot();
+            List<String> verifiedDomains = new ArrayList<>();
 
-                GetAttachedResult result = getAndValidateAttachedLocked(domainSetId, domains,
-                        true /* forAutoVerify */, callingUid, null /* userId */,
-                        pkgSettings);
-                if (result.isError()) {
-                    return result.getErrorCode();
-                }
-
-                DomainVerificationPkgState pkgState = result.getPkgState();
-                ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
-                for (String domain : domains) {
-                    Integer previousState = stateMap.get(domain);
-                    if (previousState != null
-                            && !DomainVerificationState.isModifiable(previousState)) {
-                        continue;
-                    }
-
-                    if (DomainVerificationState.isVerified(state)) {
-                        verifiedDomains.add(domain);
-                    }
-
-                    stateMap.put(domain, state);
-                }
-
-                int size = verifiedDomains.size();
-                for (int index = 0; index < size; index++) {
-                    removeUserStatesForDomain(verifiedDomains.get(index));
-                }
+            GetAttachedResult result = getAndValidateAttachedLocked(domainSetId, domains,
+                    true /* forAutoVerify */, callingUid, null /* userId */, snapshot);
+            if (result.isError()) {
+                return result.getErrorCode();
             }
 
-            mConnection.scheduleWriteSettings();
-            return DomainVerificationManager.STATUS_OK;
-        });
+            DomainVerificationPkgState pkgState = result.getPkgState();
+            ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
+            for (String domain : domains) {
+                Integer previousState = stateMap.get(domain);
+                if (previousState != null
+                        && !DomainVerificationState.isModifiable(previousState)) {
+                    continue;
+                }
+
+                if (DomainVerificationState.isVerified(state)) {
+                    verifiedDomains.add(domain);
+                }
+
+                stateMap.put(domain, state);
+            }
+
+            int size = verifiedDomains.size();
+            for (int index = 0; index < size; index++) {
+                removeUserStatesForDomain(verifiedDomains.get(index));
+            }
+        }
+
+        mConnection.scheduleWriteSettings();
+        return DomainVerificationManager.STATUS_OK;
     }
 
     @Override
@@ -380,60 +369,30 @@
 
         ArraySet<String> verifiedDomains = new ArraySet<>();
         if (packageName == null) {
-            mConnection.withPackageSettingsSnapshot(pkgSettings -> {
-                synchronized (mLock) {
-                    ArraySet<String> validDomains = new ArraySet<>();
+            synchronized (mLock) {
+                final Computer snapshot = mConnection.snapshot();
+                ArraySet<String> validDomains = new ArraySet<>();
 
-                    int size = mAttachedPkgStates.size();
-                    for (int index = 0; index < size; index++) {
-                        DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
-                        String pkgName = pkgState.getPackageName();
-                        PackageStateInternal pkgSetting = pkgSettings.apply(pkgName);
-                        if (pkgSetting == null || pkgSetting.getPkg() == null) {
-                            continue;
-                        }
-
-                        AndroidPackage pkg = pkgSetting.getPkg();
-
-                        validDomains.clear();
-
-                        ArraySet<String> autoVerifyDomains =
-                                mCollector.collectValidAutoVerifyDomains(pkg);
-                        if (domains == null) {
-                            validDomains.addAll(autoVerifyDomains);
-                        } else {
-                            validDomains.addAll(domains);
-                            validDomains.retainAll(autoVerifyDomains);
-                        }
-
-                        if (DomainVerificationState.isVerified(state)) {
-                            verifiedDomains.addAll(validDomains);
-                        }
-
-                        setDomainVerificationStatusInternal(pkgState, state, validDomains);
-                    }
-                }
-            });
-        } else {
-            mConnection.withPackageSettingsSnapshotThrowing(pkgSettings -> {
-                synchronized (mLock) {
-                    DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
-                    if (pkgState == null) {
-                        throw DomainVerificationUtils.throwPackageUnavailable(packageName);
-                    }
-
-                    PackageStateInternal pkgSetting = pkgSettings.apply(packageName);
+                int size = mAttachedPkgStates.size();
+                for (int index = 0; index < size; index++) {
+                    DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
+                    String pkgName = pkgState.getPackageName();
+                    PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName);
                     if (pkgSetting == null || pkgSetting.getPkg() == null) {
-                        throw DomainVerificationUtils.throwPackageUnavailable(packageName);
+                        continue;
                     }
 
                     AndroidPackage pkg = pkgSetting.getPkg();
-                    final ArraySet<String> validDomains;
+
+                    validDomains.clear();
+
+                    ArraySet<String> autoVerifyDomains =
+                            mCollector.collectValidAutoVerifyDomains(pkg);
                     if (domains == null) {
-                        validDomains = mCollector.collectValidAutoVerifyDomains(pkg);
+                        validDomains.addAll(autoVerifyDomains);
                     } else {
-                        validDomains = domains;
-                        validDomains.retainAll(mCollector.collectValidAutoVerifyDomains(pkg));
+                        validDomains.addAll(domains);
+                        validDomains.retainAll(autoVerifyDomains);
                     }
 
                     if (DomainVerificationState.isVerified(state)) {
@@ -442,7 +401,35 @@
 
                     setDomainVerificationStatusInternal(pkgState, state, validDomains);
                 }
-            });
+            }
+        } else {
+            synchronized (mLock) {
+                final Computer snapshot = mConnection.snapshot();
+                DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
+                if (pkgState == null) {
+                    throw DomainVerificationUtils.throwPackageUnavailable(packageName);
+                }
+
+                PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
+                if (pkgSetting == null || pkgSetting.getPkg() == null) {
+                    throw DomainVerificationUtils.throwPackageUnavailable(packageName);
+                }
+
+                AndroidPackage pkg = pkgSetting.getPkg();
+                final ArraySet<String> validDomains;
+                if (domains == null) {
+                    validDomains = mCollector.collectValidAutoVerifyDomains(pkg);
+                } else {
+                    validDomains = domains;
+                    validDomains.retainAll(mCollector.collectValidAutoVerifyDomains(pkg));
+                }
+
+                if (DomainVerificationState.isVerified(state)) {
+                    verifiedDomains.addAll(validDomains);
+                }
+
+                setDomainVerificationStatusInternal(pkgState, state, validDomains);
+            }
         }
 
         // Mirror SystemApi behavior of revoking user selection for approved domains.
@@ -552,39 +539,38 @@
             return DomainVerificationManager.ERROR_DOMAIN_SET_ID_INVALID;
         }
 
-        return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> {
-            synchronized (mLock) {
-                GetAttachedResult result = getAndValidateAttachedLocked(domainSetId, domains,
-                        false /* forAutoVerify */, callingUid, userId, pkgSettings);
-                if (result.isError()) {
-                    return result.getErrorCode();
-                }
+        synchronized (mLock) {
+            final Computer snapshot = mConnection.snapshot();
+            GetAttachedResult result = getAndValidateAttachedLocked(domainSetId, domains,
+                    false /* forAutoVerify */, callingUid, userId, snapshot);
+            if (result.isError()) {
+                return result.getErrorCode();
+            }
 
-                DomainVerificationPkgState pkgState = result.getPkgState();
-                DomainVerificationInternalUserState userState = pkgState.getOrCreateUserState(
-                        userId);
+            DomainVerificationPkgState pkgState = result.getPkgState();
+            DomainVerificationInternalUserState userState = pkgState.getOrCreateUserState(
+                    userId);
 
-                // Disable other packages if approving this one. Note that this check is only done
-                // for enabling. This allows an escape hatch in case multiple packages somehow get
-                // selected. They can be disabled without blocking in a circular dependency.
-                if (enabled) {
-                    int statusCode = revokeOtherUserSelectionsLocked(userState, userId, domains,
-                            pkgSettings);
-                    if (statusCode != DomainVerificationManager.STATUS_OK) {
-                        return statusCode;
-                    }
-                }
-
-                if (enabled) {
-                    userState.addHosts(domains);
-                } else {
-                    userState.removeHosts(domains);
+            // Disable other packages if approving this one. Note that this check is only done
+            // for enabling. This allows an escape hatch in case multiple packages somehow get
+            // selected. They can be disabled without blocking in a circular dependency.
+            if (enabled) {
+                int statusCode = revokeOtherUserSelectionsLocked(userState, userId, domains,
+                        snapshot);
+                if (statusCode != DomainVerificationManager.STATUS_OK) {
+                    return statusCode;
                 }
             }
 
-            mConnection.scheduleWriteSettings();
-            return DomainVerificationManager.STATUS_OK;
-        });
+            if (enabled) {
+                userState.addHosts(domains);
+            } else {
+                userState.removeHosts(domains);
+            }
+        }
+
+        mConnection.scheduleWriteSettings();
+        return DomainVerificationManager.STATUS_OK;
     }
 
     @Override
@@ -592,48 +578,47 @@
             @NonNull String packageName, boolean enabled, @Nullable ArraySet<String> domains)
             throws NameNotFoundException {
         mEnforcer.assertInternal(mConnection.getCallingUid());
-        mConnection.withPackageSettingsSnapshotThrowing(pkgSettings -> {
-            synchronized (mLock) {
-                DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
-                if (pkgState == null) {
-                    throw DomainVerificationUtils.throwPackageUnavailable(packageName);
-                }
+        synchronized (mLock) {
+            final Computer snapshot = mConnection.snapshot();
+            DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
+            if (pkgState == null) {
+                throw DomainVerificationUtils.throwPackageUnavailable(packageName);
+            }
 
-                PackageStateInternal pkgSetting = pkgSettings.apply(packageName);
-                AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
-                if (pkg == null) {
-                    throw DomainVerificationUtils.throwPackageUnavailable(packageName);
-                }
+            PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
+            AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
+            if (pkg == null) {
+                throw DomainVerificationUtils.throwPackageUnavailable(packageName);
+            }
 
-                Set<String> validDomains =
-                        domains == null ? mCollector.collectAllWebDomains(pkg) : domains;
+            Set<String> validDomains =
+                    domains == null ? mCollector.collectAllWebDomains(pkg) : domains;
 
-                validDomains.retainAll(mCollector.collectAllWebDomains(pkg));
+            validDomains.retainAll(mCollector.collectAllWebDomains(pkg));
 
-                if (userId == UserHandle.USER_ALL) {
-                    for (int aUserId : mConnection.getAllUserIds()) {
-                        DomainVerificationInternalUserState userState =
-                                pkgState.getOrCreateUserState(aUserId);
-                        revokeOtherUserSelectionsLocked(userState, aUserId, validDomains,
-                                pkgSettings);
-                        if (enabled) {
-                            userState.addHosts(validDomains);
-                        } else {
-                            userState.removeHosts(validDomains);
-                        }
-                    }
-                } else {
+            if (userId == UserHandle.USER_ALL) {
+                for (int aUserId : mConnection.getAllUserIds()) {
                     DomainVerificationInternalUserState userState =
-                            pkgState.getOrCreateUserState(userId);
-                    revokeOtherUserSelectionsLocked(userState, userId, validDomains, pkgSettings);
+                            pkgState.getOrCreateUserState(aUserId);
+                    revokeOtherUserSelectionsLocked(userState, aUserId, validDomains,
+                            snapshot);
                     if (enabled) {
                         userState.addHosts(validDomains);
                     } else {
                         userState.removeHosts(validDomains);
                     }
                 }
+            } else {
+                DomainVerificationInternalUserState userState =
+                        pkgState.getOrCreateUserState(userId);
+                revokeOtherUserSelectionsLocked(userState, userId, validDomains, snapshot);
+                if (enabled) {
+                    userState.addHosts(validDomains);
+                } else {
+                    userState.removeHosts(validDomains);
+                }
             }
-        });
+        }
 
         mConnection.scheduleWriteSettings();
     }
@@ -641,8 +626,7 @@
     @GuardedBy("mLock")
     private int revokeOtherUserSelectionsLocked(
             @NonNull DomainVerificationInternalUserState userState, @UserIdInt int userId,
-            @NonNull Set<String> domains,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction) {
+            @NonNull Set<String> domains, @NonNull Computer snapshot) {
         // Cache the approved packages from the 1st pass because the search is expensive
         ArrayMap<String, List<String>> domainToApprovedPackages = new ArrayMap<>();
 
@@ -652,7 +636,7 @@
             }
 
             Pair<List<String>, Integer> packagesToLevel = getApprovedPackagesLocked(domain,
-                    userId, APPROVAL_LEVEL_NONE + 1, pkgSettingFunction);
+                    userId, APPROVAL_LEVEL_NONE + 1, snapshot);
             int highestApproval = packagesToLevel.second;
             if (highestApproval > APPROVAL_LEVEL_SELECTION) {
                 return DomainVerificationManager.ERROR_UNABLE_TO_APPROVE;
@@ -698,51 +682,50 @@
             throw DomainVerificationUtils.throwPackageUnavailable(packageName);
         }
 
-        return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> {
-            synchronized (mLock) {
-                PackageStateInternal pkgSetting = pkgSettings.apply(packageName);
-                AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
-                if (pkg == null) {
-                    throw DomainVerificationUtils.throwPackageUnavailable(packageName);
-                }
-
-                DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
-                if (pkgState == null) {
-                    return null;
-                }
-
-                ArraySet<String> webDomains = mCollector.collectAllWebDomains(pkg);
-                int webDomainsSize = webDomains.size();
-
-                Map<String, Integer> domains = new ArrayMap<>(webDomainsSize);
-                ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
-                DomainVerificationInternalUserState userState = pkgState.getUserState(userId);
-                Set<String> enabledHosts =
-                        userState == null ? emptySet() : userState.getEnabledHosts();
-
-                for (int index = 0; index < webDomainsSize; index++) {
-                    String host = webDomains.valueAt(index);
-                    Integer state = stateMap.get(host);
-
-                    int domainState;
-                    if (state != null && DomainVerificationState.isVerified(state)) {
-                        domainState = DomainVerificationUserState.DOMAIN_STATE_VERIFIED;
-                    } else if (enabledHosts.contains(host)) {
-                        domainState = DomainVerificationUserState.DOMAIN_STATE_SELECTED;
-                    } else {
-                        domainState = DomainVerificationUserState.DOMAIN_STATE_NONE;
-                    }
-
-                    domains.put(host, domainState);
-                }
-
-                boolean linkHandlingAllowed =
-                        userState == null || userState.isLinkHandlingAllowed();
-
-                return new DomainVerificationUserState(pkgState.getId(), packageName,
-                        UserHandle.of(userId), linkHandlingAllowed, domains);
+        synchronized (mLock) {
+            final Computer snapshot = mConnection.snapshot();
+            PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
+            AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
+            if (pkg == null) {
+                throw DomainVerificationUtils.throwPackageUnavailable(packageName);
             }
-        });
+
+            DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
+            if (pkgState == null) {
+                return null;
+            }
+
+            ArraySet<String> webDomains = mCollector.collectAllWebDomains(pkg);
+            int webDomainsSize = webDomains.size();
+
+            Map<String, Integer> domains = new ArrayMap<>(webDomainsSize);
+            ArrayMap<String, Integer> stateMap = pkgState.getStateMap();
+            DomainVerificationInternalUserState userState = pkgState.getUserState(userId);
+            Set<String> enabledHosts =
+                    userState == null ? emptySet() : userState.getEnabledHosts();
+
+            for (int index = 0; index < webDomainsSize; index++) {
+                String host = webDomains.valueAt(index);
+                Integer state = stateMap.get(host);
+
+                int domainState;
+                if (state != null && DomainVerificationState.isVerified(state)) {
+                    domainState = DomainVerificationUserState.DOMAIN_STATE_VERIFIED;
+                } else if (enabledHosts.contains(host)) {
+                    domainState = DomainVerificationUserState.DOMAIN_STATE_SELECTED;
+                } else {
+                    domainState = DomainVerificationUserState.DOMAIN_STATE_NONE;
+                }
+
+                domains.put(host, domainState);
+            }
+
+            boolean linkHandlingAllowed =
+                    userState == null || userState.isLinkHandlingAllowed();
+
+            return new DomainVerificationUserState(pkgState.getId(), packageName,
+                    UserHandle.of(userId), linkHandlingAllowed, domains);
+        }
     }
 
     @NonNull
@@ -751,27 +734,26 @@
         mEnforcer.assertOwnerQuerent(mConnection.getCallingUid(), mConnection.getCallingUserId(),
                 userId);
 
-        return mConnection.withPackageSettingsSnapshotReturningThrowing(pkgSettings -> {
-            SparseArray<List<String>> levelToPackages = getOwnersForDomainInternal(domain, false,
-                    userId, pkgSettings);
-            if (levelToPackages.size() == 0) {
-                return emptyList();
-            }
+        final Computer snapshot = mConnection.snapshot();
+        SparseArray<List<String>> levelToPackages = getOwnersForDomainInternal(domain, false,
+                userId, snapshot);
+        if (levelToPackages.size() == 0) {
+            return emptyList();
+        }
 
-            List<DomainOwner> owners = new ArrayList<>();
-            int size = levelToPackages.size();
-            for (int index = 0; index < size; index++) {
-                int level = levelToPackages.keyAt(index);
-                boolean overrideable = level <= APPROVAL_LEVEL_SELECTION;
-                List<String> packages = levelToPackages.valueAt(index);
-                int packagesSize = packages.size();
-                for (int packageIndex = 0; packageIndex < packagesSize; packageIndex++) {
-                    owners.add(new DomainOwner(packages.get(packageIndex), overrideable));
-                }
+        List<DomainOwner> owners = new ArrayList<>();
+        int size = levelToPackages.size();
+        for (int index = 0; index < size; index++) {
+            int level = levelToPackages.keyAt(index);
+            boolean overrideable = level <= APPROVAL_LEVEL_SELECTION;
+            List<String> packages = levelToPackages.valueAt(index);
+            int packagesSize = packages.size();
+            for (int packageIndex = 0; packageIndex < packagesSize; packageIndex++) {
+                owners.add(new DomainOwner(packages.get(packageIndex), overrideable));
             }
+        }
 
-            return owners;
-        });
+        return owners;
     }
 
     /**
@@ -782,8 +764,7 @@
      */
     @NonNull
     private SparseArray<List<String>> getOwnersForDomainInternal(@NonNull String domain,
-            boolean includeNegative, @UserIdInt int userId,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction) {
+            boolean includeNegative, @UserIdInt int userId, @NonNull Computer snapshot) {
         SparseArray<List<String>> levelToPackages = new SparseArray<>();
         // First, collect the raw approval level values
         synchronized (mLock) {
@@ -791,7 +772,7 @@
             for (int index = 0; index < size; index++) {
                 DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
                 String packageName = pkgState.getPackageName();
-                PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName);
+                PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
                 if (pkgSetting == null) {
                     continue;
                 }
@@ -818,8 +799,8 @@
         // Then sort them ascending by first installed time, with package name as tie breaker
         for (int index = 0; index < size; index++) {
             levelToPackages.valueAt(index).sort((first, second) -> {
-                PackageStateInternal firstPkgSetting = pkgSettingFunction.apply(first);
-                PackageStateInternal secondPkgSetting = pkgSettingFunction.apply(second);
+                PackageStateInternal firstPkgSetting = snapshot.getPackageStateInternal(first);
+                PackageStateInternal secondPkgSetting = snapshot.getPackageStateInternal(second);
 
                 long firstInstallTime = firstPkgSetting == null
                         ? -1L : firstPkgSetting.getUserStateOrDefault(userId).getFirstInstallTime();
@@ -1060,44 +1041,38 @@
     }
 
     @Override
-    public void writeSettings(@NonNull TypedXmlSerializer serializer, boolean includeSignatures,
-            @UserIdInt int userId)
-            throws IOException {
-        mConnection.withPackageSettingsSnapshotThrowing(pkgSettings -> {
-            synchronized (mLock) {
-                Function<String, String> pkgNameToSignature = null;
-                if (includeSignatures) {
-                    pkgNameToSignature = pkgName -> {
-                        PackageStateInternal pkgSetting = pkgSettings.apply(pkgName);
-                        if (pkgSetting == null) {
-                            // If querying for a user restored package that isn't installed on the
-                            // device yet, there will be no signature to write out. In that case,
-                            // it's expected that this returns null and it falls back to the
-                            // restored state's stored signature if it exists.
-                            return null;
-                        }
+    public void writeSettings(Computer snapshot, @NonNull TypedXmlSerializer serializer,
+            boolean includeSignatures, @UserIdInt int userId) throws IOException {
+        synchronized (mLock) {
+            Function<String, String> pkgNameToSignature = null;
+            if (includeSignatures) {
+                pkgNameToSignature = pkgName -> {
+                    PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName);
+                    if (pkgSetting == null) {
+                        // If querying for a user restored package that isn't installed on the
+                        // device yet, there will be no signature to write out. In that case,
+                        // it's expected that this returns null and it falls back to the
+                        // restored state's stored signature if it exists.
+                        return null;
+                    }
 
-                        return PackageUtils.computeSignaturesSha256Digest(
-                                pkgSetting.getSigningDetails().getSignatures());
-                    };
-                }
-
-                mSettings.writeSettings(serializer, mAttachedPkgStates, userId, pkgNameToSignature);
+                    return PackageUtils.computeSignaturesSha256Digest(
+                            pkgSetting.getSigningDetails().getSignatures());
+                };
             }
-        });
+
+            mSettings.writeSettings(serializer, mAttachedPkgStates, userId, pkgNameToSignature);
+        }
 
         mLegacySettings.writeSettings(serializer);
     }
 
     @Override
-    public void readSettings(@NonNull TypedXmlPullParser parser) throws IOException,
-            XmlPullParserException {
-        mConnection.<IOException, XmlPullParserException>withPackageSettingsSnapshotThrowing2(
-                pkgSettings -> {
-                    synchronized (mLock) {
-                        mSettings.readSettings(parser, mAttachedPkgStates, pkgSettings);
-                    }
-                });
+    public void readSettings(@NonNull Computer snapshot, @NonNull TypedXmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        synchronized (mLock) {
+            mSettings.readSettings(parser, mAttachedPkgStates, snapshot);
+        }
     }
 
     @Override
@@ -1107,14 +1082,11 @@
     }
 
     @Override
-    public void restoreSettings(@NonNull TypedXmlPullParser parser)
+    public void restoreSettings(Computer snapshot, @NonNull TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
-        mConnection.<IOException, XmlPullParserException>withPackageSettingsSnapshotThrowing2(
-                pkgSettings -> {
-                    synchronized (mLock) {
-                        mSettings.restoreSettings(parser, mAttachedPkgStates, pkgSettings);
-                    }
-                });
+        synchronized (mLock) {
+            mSettings.restoreSettings(parser, mAttachedPkgStates, snapshot);
+        }
     }
 
     @Override
@@ -1190,18 +1162,16 @@
     @Override
     public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
             @Nullable Integer userId) throws NameNotFoundException {
-        mConnection.withPackageSettingsSnapshotThrowing(
-                pkgSettings -> printState(writer, packageName, userId, pkgSettings));
+        printState(mConnection.snapshot(), writer, packageName, userId);
     }
 
     @Override
-    public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
-            @Nullable @UserIdInt Integer userId,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction)
+    public void printState(@NonNull Computer snapshot, @NonNull IndentingPrintWriter writer,
+            @Nullable String packageName, @Nullable @UserIdInt Integer userId)
             throws NameNotFoundException {
         mEnforcer.assertApprovedQuerent(mConnection.getCallingUid(), mProxy);
         synchronized (mLock) {
-            mDebug.printState(writer, packageName, userId, pkgSettingFunction, mAttachedPkgStates);
+            mDebug.printState(writer, packageName, userId, snapshot, mAttachedPkgStates);
         }
     }
 
@@ -1209,31 +1179,30 @@
     public void printOwnersForPackage(@NonNull IndentingPrintWriter writer,
             @Nullable String packageName, @Nullable @UserIdInt Integer userId)
             throws NameNotFoundException {
-        mConnection.withPackageSettingsSnapshotThrowing(pkgSettings -> {
-            synchronized (mLock) {
-                if (packageName == null) {
-                    int size = mAttachedPkgStates.size();
-                    for (int index = 0; index < size; index++) {
-                        try {
-                            printOwnersForPackage(writer,
-                                    mAttachedPkgStates.valueAt(index).getPackageName(), userId,
-                                    pkgSettings);
-                        } catch (NameNotFoundException ignored) {
-                            // When iterating packages, if one doesn't exist somehow, ignore
-                        }
+        synchronized (mLock) {
+            final Computer snapshot = mConnection.snapshot();
+            if (packageName == null) {
+                int size = mAttachedPkgStates.size();
+                for (int index = 0; index < size; index++) {
+                    try {
+                        printOwnersForPackage(writer,
+                                mAttachedPkgStates.valueAt(index).getPackageName(), userId,
+                                snapshot);
+                    } catch (NameNotFoundException ignored) {
+                        // When iterating packages, if one doesn't exist somehow, ignore
                     }
-                } else {
-                    printOwnersForPackage(writer, packageName, userId, pkgSettings);
                 }
+            } else {
+                printOwnersForPackage(writer, packageName, userId, snapshot);
             }
-        });
+        }
     }
 
     private void printOwnersForPackage(@NonNull IndentingPrintWriter writer,
             @NonNull String packageName, @Nullable @UserIdInt Integer userId,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction)
+            @NonNull Computer snapshot)
             throws NameNotFoundException {
-        PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName);
+        PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
         AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
         if (pkg == null) {
             throw DomainVerificationUtils.throwPackageUnavailable(packageName);
@@ -1249,7 +1218,7 @@
         writer.increaseIndent();
 
         for (int index = 0; index < size; index++) {
-            printOwnersForDomain(writer, domains.valueAt(index), userId, pkgSettingFunction);
+            printOwnersForDomain(writer, domains.valueAt(index), userId, snapshot);
         }
 
         writer.decreaseIndent();
@@ -1258,30 +1227,28 @@
     @Override
     public void printOwnersForDomains(@NonNull IndentingPrintWriter writer,
             @NonNull List<String> domains, @Nullable @UserIdInt Integer userId) {
-        mConnection.withPackageSettingsSnapshot(pkgSettings -> {
-            synchronized (mLock) {
-                int size = domains.size();
-                for (int index = 0; index < size; index++) {
-                    printOwnersForDomain(writer, domains.get(index), userId, pkgSettings);
-                }
+        synchronized (mLock) {
+            final Computer snapshot = mConnection.snapshot();
+            int size = domains.size();
+            for (int index = 0; index < size; index++) {
+                printOwnersForDomain(writer, domains.get(index), userId, snapshot);
             }
-        });
+        }
     }
 
     private void printOwnersForDomain(@NonNull IndentingPrintWriter writer, @NonNull String domain,
-            @Nullable @UserIdInt Integer userId,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction) {
+            @Nullable @UserIdInt Integer userId, @NonNull Computer snapshot) {
         SparseArray<SparseArray<List<String>>> userIdToApprovalLevelToOwners =
                 new SparseArray<>();
 
         if (userId == null || userId == UserHandle.USER_ALL) {
             for (int aUserId : mConnection.getAllUserIds()) {
                 userIdToApprovalLevelToOwners.put(aUserId,
-                        getOwnersForDomainInternal(domain, true, aUserId, pkgSettingFunction));
+                        getOwnersForDomainInternal(domain, true, aUserId, snapshot));
             }
         } else {
             userIdToApprovalLevelToOwners.put(userId,
-                    getOwnersForDomainInternal(domain, true, userId, pkgSettingFunction));
+                    getOwnersForDomainInternal(domain, true, userId, snapshot));
         }
 
         mDebug.printOwners(writer, domain, userIdToApprovalLevelToOwners);
@@ -1330,8 +1297,7 @@
     @GuardedBy("mLock")
     private GetAttachedResult getAndValidateAttachedLocked(@NonNull UUID domainSetId,
             @NonNull Set<String> domains, boolean forAutoVerify, int callingUid,
-            @Nullable Integer userIdForFilter,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction)
+            @Nullable Integer userIdForFilter, @NonNull Computer snapshot)
             throws NameNotFoundException {
         if (domainSetId == null) {
             throw new IllegalArgumentException("domainSetId cannot be null");
@@ -1349,7 +1315,7 @@
             return GetAttachedResult.error(DomainVerificationManager.ERROR_DOMAIN_SET_ID_INVALID);
         }
 
-        PackageStateInternal pkgSetting = pkgSettingFunction.apply(pkgName);
+        PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName);
         if (pkgSetting == null || pkgSetting.getPkg() == null) {
             throw DomainVerificationUtils.throwPackageUnavailable(pkgName);
         }
@@ -1437,33 +1403,32 @@
     @Override
     public void clearDomainVerificationState(@Nullable List<String> packageNames) {
         mEnforcer.assertInternal(mConnection.getCallingUid());
-        mConnection.withPackageSettingsSnapshot(pkgSettings -> {
-            synchronized (mLock) {
-                if (packageNames == null) {
-                    int size = mAttachedPkgStates.size();
-                    for (int index = 0; index < size; index++) {
-                        DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
-                        String pkgName = pkgState.getPackageName();
-                        PackageStateInternal pkgSetting = pkgSettings.apply(pkgName);
-                        if (pkgSetting == null || pkgSetting.getPkg() == null) {
-                            continue;
-                        }
-                        resetDomainState(pkgState.getStateMap(), pkgSetting);
+        synchronized (mLock) {
+            final Computer snapshot = mConnection.snapshot();
+            if (packageNames == null) {
+                int size = mAttachedPkgStates.size();
+                for (int index = 0; index < size; index++) {
+                    DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
+                    String pkgName = pkgState.getPackageName();
+                    PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName);
+                    if (pkgSetting == null || pkgSetting.getPkg() == null) {
+                        continue;
                     }
-                } else {
-                    int size = packageNames.size();
-                    for (int index = 0; index < size; index++) {
-                        String pkgName = packageNames.get(index);
-                        DomainVerificationPkgState pkgState = mAttachedPkgStates.get(pkgName);
-                        PackageStateInternal pkgSetting = pkgSettings.apply(pkgName);
-                        if (pkgSetting == null || pkgSetting.getPkg() == null) {
-                            continue;
-                        }
-                        resetDomainState(pkgState.getStateMap(), pkgSetting);
+                    resetDomainState(pkgState.getStateMap(), pkgSetting);
+                }
+            } else {
+                int size = packageNames.size();
+                for (int index = 0; index < size; index++) {
+                    String pkgName = packageNames.get(index);
+                    DomainVerificationPkgState pkgState = mAttachedPkgStates.get(pkgName);
+                    PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(pkgName);
+                    if (pkgSetting == null || pkgSetting.getPkg() == null) {
+                        continue;
                     }
+                    resetDomainState(pkgState.getStateMap(), pkgSetting);
                 }
             }
-        });
+        }
 
         mConnection.scheduleWriteSettings();
     }
@@ -1935,35 +1900,32 @@
     @GuardedBy("mLock")
     @NonNull
     private Pair<List<String>, Integer> getApprovedPackagesLocked(@NonNull String domain,
-            @UserIdInt int userId, int minimumApproval,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction) {
+            @UserIdInt int userId, int minimumApproval, @NonNull Computer snapshot) {
         boolean includeNegative = minimumApproval < APPROVAL_LEVEL_NONE;
         int highestApproval = minimumApproval;
         List<String> approvedPackages = emptyList();
 
-        synchronized (mLock) {
-            final int size = mAttachedPkgStates.size();
-            for (int index = 0; index < size; index++) {
-                DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
-                String packageName = pkgState.getPackageName();
-                PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName);
-                if (pkgSetting == null) {
-                    continue;
-                }
+        final int size = mAttachedPkgStates.size();
+        for (int index = 0; index < size; index++) {
+            DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
+            String packageName = pkgState.getPackageName();
+            PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
+            if (pkgSetting == null) {
+                continue;
+            }
 
-                int level = approvalLevelForDomain(pkgSetting, domain, includeNegative, userId,
-                        domain);
-                if (level < minimumApproval) {
-                    continue;
-                }
+            int level = approvalLevelForDomain(pkgSetting, domain, includeNegative, userId,
+                    domain);
+            if (level < minimumApproval) {
+                continue;
+            }
 
-                if (level > highestApproval) {
-                    approvedPackages.clear();
-                    approvedPackages = CollectionUtils.add(approvedPackages, packageName);
-                    highestApproval = level;
-                } else if (level == highestApproval) {
-                    approvedPackages = CollectionUtils.add(approvedPackages, packageName);
-                }
+            if (level > highestApproval) {
+                approvedPackages.clear();
+                approvedPackages = CollectionUtils.add(approvedPackages, packageName);
+                highestApproval = level;
+            } else if (level == highestApproval) {
+                approvedPackages = CollectionUtils.add(approvedPackages, packageName);
             }
         }
 
@@ -1976,7 +1938,7 @@
         final int approvedSize = approvedPackages.size();
         for (int index = 0; index < approvedSize; index++) {
             String packageName = approvedPackages.get(index);
-            PackageStateInternal pkgSetting = pkgSettingFunction.apply(packageName);
+            PackageStateInternal pkgSetting = snapshot.getPackageStateInternal(packageName);
             if (pkgSetting == null) {
                 continue;
             }
@@ -2035,108 +1997,4 @@
             return mErrorCode;
         }
     }
-
-    /**
-     * Wraps a {@link Connection} to verify that the {@link PackageStateInternal} calls do not hold
-     * {@link #mLock}, as that can cause deadlock when {@link Settings} tries to serialize state to
-     * disk. Only enabled if {@link Build#IS_USERDEBUG} or {@link Build#IS_ENG} is true.
-     */
-    private class LockSafeConnection implements Connection {
-
-        @NonNull
-        private final Connection mConnection;
-
-        private LockSafeConnection(@NonNull Connection connection) {
-            mConnection = connection;
-        }
-
-        private void enforceLocking() {
-            if (Thread.holdsLock(mLock)) {
-                Slog.wtf(TAG, "Method should not hold DVS lock when accessing package data");
-            }
-        }
-
-        @Override
-        public void withPackageSettingsSnapshot(
-                @NonNull Consumer<Function<String, PackageStateInternal>> block) {
-            enforceLocking();
-            mConnection.withPackageSettingsSnapshot(block);
-        }
-
-        @Override
-        public <Output> Output withPackageSettingsSnapshotReturning(
-                @NonNull FunctionalUtils.ThrowingFunction<Function<String, PackageStateInternal>,
-                        Output> block) {
-            enforceLocking();
-            return mConnection.withPackageSettingsSnapshotReturning(block);
-        }
-
-        @Override
-        public <ExceptionType extends Exception> void withPackageSettingsSnapshotThrowing(
-                @NonNull FunctionalUtils.ThrowingCheckedConsumer<
-                        Function<String, PackageStateInternal>, ExceptionType> block)
-                throws ExceptionType {
-            enforceLocking();
-            mConnection.withPackageSettingsSnapshotThrowing(block);
-        }
-
-        @Override
-        public <ExceptionOne extends Exception, ExceptionTwo extends Exception> void
-                withPackageSettingsSnapshotThrowing2(
-                        @NonNull FunctionalUtils.ThrowingChecked2Consumer<
-                                Function<String, PackageStateInternal>, ExceptionOne,
-                                ExceptionTwo> block)
-                throws ExceptionOne, ExceptionTwo {
-            enforceLocking();
-            mConnection.withPackageSettingsSnapshotThrowing2(block);
-        }
-
-        @Override
-        public <Output, ExceptionType extends Exception> Output
-                withPackageSettingsSnapshotReturningThrowing(
-                        @NonNull FunctionalUtils.ThrowingCheckedFunction<
-                                Function<String, PackageStateInternal>, Output,
-                                ExceptionType> block)
-                throws ExceptionType {
-            enforceLocking();
-            return mConnection.withPackageSettingsSnapshotReturningThrowing(block);
-        }
-
-        @Override
-        public void scheduleWriteSettings() {
-            mConnection.scheduleWriteSettings();
-        }
-
-        @Override
-        public int getCallingUid() {
-            return mConnection.getCallingUid();
-        }
-
-        @Override
-        @UserIdInt
-        public int getCallingUserId() {
-            return mConnection.getCallingUserId();
-        }
-
-        @Override
-        public void schedule(int code, @Nullable Object object) {
-            mConnection.schedule(code, object);
-        }
-
-        @Override
-        @UserIdInt
-        public int[] getAllUserIds() {
-            return mConnection.getAllUserIds();
-        }
-
-        @Override
-        public boolean filterAppAccess(@NonNull String packageName, int callingUid, int userId) {
-            return mConnection.filterAppAccess(packageName, callingUid, userId);
-        }
-
-        @Override
-        public boolean doesUserExist(int userId) {
-            return mConnection.doesUserExist(userId);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
index 015d4e9..8d1ae0b 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationSettings.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.Computer;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
@@ -101,8 +102,7 @@
      */
     public void readSettings(@NonNull TypedXmlPullParser parser,
             @NonNull DomainVerificationStateMap<DomainVerificationPkgState> liveState,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction)
-            throws IOException, XmlPullParserException {
+            @NonNull Computer snapshot) throws IOException, XmlPullParserException {
         DomainVerificationPersistence.ReadResult result =
                 DomainVerificationPersistence.readFromXml(parser);
         ArrayMap<String, DomainVerificationPkgState> active = result.active;
@@ -118,7 +118,7 @@
                     // This branch should never be possible. Settings should be read from disk
                     // before any states are attached. But just in case, handle it.
                     if (!existingState.getId().equals(pkgState.getId())) {
-                        mergePkgState(existingState, pkgState, pkgSettingFunction);
+                        mergePkgState(existingState, pkgState, snapshot);
                     }
                 } else {
                     mPendingPkgStates.put(pkgName, pkgState);
@@ -139,8 +139,7 @@
      */
     public void restoreSettings(@NonNull TypedXmlPullParser parser,
             @NonNull DomainVerificationStateMap<DomainVerificationPkgState> liveState,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction)
-            throws IOException, XmlPullParserException {
+            @NonNull Computer snapshot) throws IOException, XmlPullParserException {
         // TODO(b/170746586): Restoration assumes user IDs match, which is probably not the case on
         //  a new device.
 
@@ -166,7 +165,7 @@
                 }
 
                 if (existingState != null) {
-                    mergePkgState(existingState, newState, pkgSettingFunction);
+                    mergePkgState(existingState, newState, snapshot);
                 } else {
                     // If there's no existing state, that means the new state has to be transformed
                     // in preparation for attaching to brand new package that may eventually be
@@ -216,9 +215,9 @@
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public void mergePkgState(@NonNull DomainVerificationPkgState oldState,
-            @NonNull DomainVerificationPkgState newState,
-            @NonNull Function<String, PackageStateInternal> pkgSettingFunction) {
-        PackageStateInternal pkgSetting = pkgSettingFunction.apply(oldState.getPackageName());
+            @NonNull DomainVerificationPkgState newState, @NonNull Computer snapshot) {
+        PackageStateInternal pkgSetting =
+                snapshot.getPackageStateInternal(oldState.getPackageName());
         AndroidPackage pkg = pkgSetting == null ? null : pkgSetting.getPkg();
         Set<String> validDomains = pkg == null
                 ? Collections.emptySet() : mCollector.collectValidAutoVerifyDomains(pkg);
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
index da2d162..4b0a8e2 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationShell.java
@@ -32,6 +32,7 @@
 import android.util.IndentingPrintWriter;
 
 import com.android.modules.utils.BasicShellCommandHandler;
+import com.android.server.pm.Computer;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -39,7 +40,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
-import java.util.function.Function;
 
 public class DomainVerificationShell {
 
@@ -599,8 +599,8 @@
         void verifyPackages(@Nullable List<String> packageNames, boolean reVerify);
 
         /**
-         * @see DomainVerificationManagerInternal#printState(IndentingPrintWriter, String, Integer,
-         * Function)
+         * @see DomainVerificationManagerInternal#printState(Computer, IndentingPrintWriter, String,
+         * Integer)
          */
         void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
                 @Nullable @UserIdInt Integer userId) throws NameNotFoundException;
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 43b2e1e..dcc461b 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -265,12 +265,14 @@
         assertServiceInitialized() ?: return
         when (params.result) {
             is Result.Changed, Result.ChangedWithoutNotify -> {
-                assertThat(mockPendingBroadcasts.get(userId, params.pkgName) ?: emptyList<String>())
+                assertThat(mockPendingBroadcasts.copiedMap()?.get(userId)?.get(params.pkgName)
+                    ?: emptyList<String>())
                         .containsExactly(params.componentName!!.className)
                         .inOrder()
             }
             is Result.NotChanged, is Result.Exception -> {
-                assertThat(mockPendingBroadcasts.get(userId, params.pkgName)).isNull()
+                assertThat(mockPendingBroadcasts.copiedMap()?.get(userId)?.get(params.pkgName))
+                    .isNull()
             }
         }.run { /*exhaust*/ }
     }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 92cdb34..c9601de 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -20,8 +20,6 @@
 import android.content.Intent
 import android.content.pm.PackageManager
 import android.content.pm.SigningDetails
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import android.content.pm.verify.domain.DomainVerificationManager
 import android.content.pm.verify.domain.DomainVerificationState
 import android.os.Build
@@ -30,10 +28,12 @@
 import android.util.IndentingPrintWriter
 import android.util.SparseArray
 import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.pm.Computer
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationEnforcer
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
 import com.android.server.pm.verify.domain.DomainVerificationService
@@ -100,11 +100,15 @@
                     mockThrowOnUnmocked {
                         whenever(callingUid) { callingUidInt.get() }
                         whenever(callingUserId) { callingUserIdInt.get() }
-                        mockPackageStates {
-                            when (it) {
-                                VISIBLE_PKG -> visiblePkgState
-                                INVISIBLE_PKG -> invisiblePkgState
-                                else -> null
+                        whenever(snapshot()) {
+                            mockThrowOnUnmocked {
+                                whenever(getPackageStateInternal(anyString())) {
+                                    when (getArgument<String>(0)) {
+                                        VISIBLE_PKG -> visiblePkgState
+                                        INVISIBLE_PKG -> invisiblePkgState
+                                        else -> null
+                                    }
+                                }
                             }
                         }
                         whenever(schedule(anyInt(), any()))
@@ -211,9 +215,8 @@
                     printState(mock(IndentingPrintWriter::class.java), null, null)
                 },
                 service(Type.QUERENT, "printStateInternal") {
-                    printState(mock(IndentingPrintWriter::class.java), null, null) {
-                        mockPkgState(it, UUID.randomUUID())
-                    }
+                    printState(mock(Computer::class.java), mock(IndentingPrintWriter::class.java),
+                        null, null)
                 },
                 service(Type.VERIFIER, "setStatus") {
                     setDomainVerificationStatus(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index 878bee0..7273b0b 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -19,9 +19,6 @@
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.PackageUserStateInternal
 import android.content.pm.verify.domain.DomainOwner
 import android.content.pm.verify.domain.DomainVerificationInfo
 import android.content.pm.verify.domain.DomainVerificationManager
@@ -34,7 +31,9 @@
 import android.util.SparseArray
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
-import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates
+import com.android.server.pm.pkg.PackageUserStateInternal
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationManagerStub
 import com.android.server.pm.verify.domain.DomainVerificationService
 import com.android.server.testutils.mockThrowOnUnmocked
@@ -502,8 +501,12 @@
                 whenever(callingUid) { Process.ROOT_UID }
                 whenever(callingUserId) { 0 }
 
-                mockPackageStates {
-                    pkgStateFunction(it)
+                whenever(snapshot()) {
+                    mockThrowOnUnmocked {
+                        whenever(getPackageStateInternal(anyString())) {
+                            pkgStateFunction(getArgument(0))
+                        }
+                    }
                 }
             })
         }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index 0369bab..40f37a7 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -20,9 +20,6 @@
 import android.content.pm.PackageManager
 import android.content.pm.Signature
 import android.content.pm.SigningDetails
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.PackageUserStateInternal
 import android.content.pm.verify.domain.DomainOwner
 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_MODIFIABLE_VERIFIED
 import android.content.pm.verify.domain.DomainVerificationInfo.STATE_NO_RESPONSE
@@ -39,9 +36,12 @@
 import android.util.ArraySet
 import android.util.SparseArray
 import android.util.Xml
+import com.android.server.pm.Computer
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
-import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates
+import com.android.server.pm.pkg.PackageUserStateInternal
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
 import com.android.server.pm.verify.domain.DomainVerificationService
 import com.android.server.testutils.mock
 import com.android.server.testutils.mockThrowOnUnmocked
@@ -194,7 +194,8 @@
         """
 
         val service = makeService(pkg1, pkg2)
-        service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream()))
+        val computer = mockComputer(pkg1, pkg2)
+        service.restoreSettings(computer, Xml.resolvePullParser(xml.byteInputStream()))
         service.addPackage(pkg1)
         val info = service.getInfo(pkg1.packageName)
         assertThat(info.packageName).isEqualTo(pkg1.packageName)
@@ -243,7 +244,8 @@
         """
 
         val service = makeService(pkg1, pkg2)
-        service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream()))
+        val computer = mockComputer(pkg1, pkg2)
+        service.restoreSettings(computer, Xml.resolvePullParser(xml.byteInputStream()))
         service.addPackage(pkg1)
         val info = service.getInfo(pkg1.packageName)
         assertThat(info.packageName).isEqualTo(pkg1.packageName)
@@ -298,8 +300,9 @@
         """.trimIndent()
 
         val service = makeService(pkg1, pkg2)
+        val computer = mockComputer(pkg1, pkg2)
         xml.byteInputStream().use {
-            service.readSettings(Xml.resolvePullParser(it))
+            service.readSettings(computer, Xml.resolvePullParser(it))
         }
 
         service.addPackage(pkg1)
@@ -311,8 +314,9 @@
     fun addPackagePendingStripInvalidDomains() {
         val xml = addPackagePendingOrRestoredWithInvalidDomains()
         val service = makeService(pkg1, pkg2)
+        val computer = mockComputer(pkg1, pkg2)
         xml.byteInputStream().use {
-            service.readSettings(Xml.resolvePullParser(it))
+            service.readSettings(computer, Xml.resolvePullParser(it))
         }
 
         service.addPackage(pkg1)
@@ -334,8 +338,9 @@
     fun addPackageRestoredStripInvalidDomains() {
         val xml = addPackagePendingOrRestoredWithInvalidDomains()
         val service = makeService(pkg1, pkg2)
+        val computer = mockComputer(pkg1, pkg2)
         xml.byteInputStream().use {
-            service.restoreSettings(Xml.resolvePullParser(it))
+            service.restoreSettings(computer, Xml.resolvePullParser(it))
         }
 
         service.addPackage(pkg1)
@@ -686,6 +691,7 @@
         val pkg2 = mockPkgState(PKG_TWO, UUID_TWO, SIGNATURE_TWO,
             listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3))
         val serviceBefore = makeService(pkg1, pkg2)
+        val computerBefore = mockComputer(pkg1, pkg2)
         serviceBefore.addPackage(pkg1)
         serviceBefore.addPackage(pkg2)
 
@@ -729,16 +735,17 @@
         assertExpectedState(serviceBefore)
 
         val backupUser0 = ByteArrayOutputStream().use {
-            serviceBefore.writeSettings(Xml.resolveSerializer(it), true, 0)
+            serviceBefore.writeSettings(computerBefore, Xml.resolveSerializer(it), true, 0)
             it.toByteArray()
         }
 
         val backupUser1 = ByteArrayOutputStream().use {
-            serviceBefore.writeSettings(Xml.resolveSerializer(it), true, 10)
+            serviceBefore.writeSettings(computerBefore, Xml.resolveSerializer(it), true, 10)
             it.toByteArray()
         }
 
         val serviceAfter = makeService(pkg1, pkg2)
+        val computerAfter = mockComputer(pkg1, pkg2)
         serviceAfter.addPackage(pkg1)
         serviceAfter.addPackage(pkg2)
 
@@ -763,7 +770,7 @@
         }
 
         ByteArrayInputStream(backupUser1).use {
-            serviceAfter.restoreSettings(Xml.resolvePullParser(it))
+            serviceAfter.restoreSettings(computerAfter, Xml.resolvePullParser(it))
         }
 
         // Assert user 1 was restored
@@ -800,7 +807,7 @@
         )
 
         ByteArrayInputStream(backupUser0).use {
-            serviceAfter.restoreSettings(Xml.resolvePullParser(it))
+            serviceAfter.restoreSettings(computerAfter, Xml.resolvePullParser(it))
         }
 
         assertExpectedState(serviceAfter)
@@ -848,12 +855,20 @@
                 whenever(callingUid) { Process.ROOT_UID }
                 whenever(callingUserId) { 0 }
 
-                mockPackageStates {
-                    pkgStateFunction(it)
-                }
+                whenever(snapshot()) { mockComputer(pkgStateFunction) }
             })
         }
 
+    private fun mockComputer(vararg pkgStates: PackageStateInternal) =
+        mockComputer { pkgName -> pkgStates.find { pkgName == it.packageName } }
+
+    private fun mockComputer(pkgStateFunction: (String) -> PackageStateInternal? = { null }) =
+        mockThrowOnUnmocked<Computer> {
+            whenever(getPackageStateInternal(anyString())) {
+                pkgStateFunction(getArgument(0))
+            }
+        }
+
     private fun mockPkgState(
         pkgName: String,
         domainSetId: UUID,
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 3a602a8..fc20c26 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -29,7 +29,6 @@
 import android.util.SparseArray
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
-import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates
 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
 import com.android.server.pm.verify.domain.DomainVerificationService
 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
@@ -245,10 +244,14 @@
         mockThrowOnUnmocked {
             whenever(callingUid) { TEST_UID }
             whenever(callingUserId) { TEST_USER_ID }
-            mockPackageStates {
-                when (it) {
-                    TEST_PKG -> mockPkgState()
-                    else -> null
+            whenever(snapshot()) {
+                mockThrowOnUnmocked {
+                    whenever(getPackageStateInternal(anyString())) {
+                        when (getArgument<String>(0)) {
+                            TEST_PKG -> mockPkgState()
+                            else -> null
+                        }
+                    }
                 }
             }
             whenever(schedule(anyInt(), any()))
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationTestUtils.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationTestUtils.kt
deleted file mode 100644
index c5f0eb1..0000000
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationTestUtils.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server.pm.test.verify.domain
-
-import com.android.internal.util.FunctionalUtils
-import com.android.server.pm.pkg.PackageStateInternal
-import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
-import com.android.server.testutils.whenever
-import org.mockito.ArgumentMatchers.any
-import java.util.function.Consumer
-import java.util.function.Function
-
-internal object DomainVerificationTestUtils {
-
-    @Suppress("UNCHECKED_CAST")
-    fun DomainVerificationManagerInternal.Connection.mockPackageStates(
-        block: (String) -> PackageStateInternal?
-    ) {
-        whenever(withPackageSettingsSnapshot(any())) {
-            (arguments[0] as Consumer<Function<String, PackageStateInternal?>>).accept { block(it) }
-        }
-        whenever(withPackageSettingsSnapshotReturning(any())) {
-            (arguments[0] as FunctionalUtils.ThrowingFunction<
-                    Function<String, PackageStateInternal?>, *>)
-                .apply { block(it) }
-        }
-        whenever(withPackageSettingsSnapshotThrowing<Exception>(any())) {
-            (arguments[0] as FunctionalUtils.ThrowingCheckedConsumer<
-                    Function<String, PackageStateInternal?>, *>)
-                .accept { block(it) }
-        }
-        whenever(withPackageSettingsSnapshotThrowing2<Exception, Exception>(any())) {
-            (arguments[0] as FunctionalUtils.ThrowingChecked2Consumer<
-                    Function<String, PackageStateInternal?>, *, *>)
-                .accept { block(it) }
-        }
-        whenever(withPackageSettingsSnapshotReturningThrowing<Any, Exception>(any())) {
-            (arguments[0] as FunctionalUtils.ThrowingCheckedFunction<
-                    Function<String, PackageStateInternal?>, *, *>)
-                .apply { block(it) }
-        }
-    }
-}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index ffc2877..589633c 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -31,7 +31,6 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage
 import com.android.server.pm.pkg.PackageStateInternal
 import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.test.verify.domain.DomainVerificationTestUtils.mockPackageStates
 import com.android.server.pm.verify.domain.DomainVerificationService
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
@@ -85,11 +84,15 @@
                 // Need to provide an internal UID so some permission checks are ignored
                 whenever(callingUid) { Process.ROOT_UID }
                 whenever(callingUserId) { 0 }
-                mockPackageStates {
-                    when (it) {
-                        PKG_ONE -> pkg1
-                        PKG_TWO -> pkg2
-                        else -> null
+                whenever(snapshot()) {
+                    mockThrowOnUnmocked {
+                        whenever(getPackageStateInternal(anyString())) {
+                            when (getArgument<String>(0)) {
+                                PKG_ONE -> pkg1
+                                PKG_TWO -> pkg2
+                                else -> null
+                            }
+                        }
                     }
                 }
             })
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
index 1c480ee..03eff2a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
@@ -20,13 +20,18 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
 import android.content.pm.UserInfo;
+import android.net.Uri;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
@@ -35,11 +40,13 @@
 
 import com.android.internal.util.ConcurrentUtils;
 import com.android.server.SystemService;
+import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
@@ -61,10 +68,14 @@
             new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceA");
     private static final ComponentName PROVIDER_A_SERVICE_B =
             new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceB");
+    private static final ComponentName PROVIDER_A_SERVICE_C =
+            new ComponentName(PROVIDER_A_PACKAGE_NAME, "com.provider.a.ServiceC");
 
     private MockitoSession mMockingSession;
     private GameServiceController mGameServiceManager;
     @Mock
+    private Context mMockContext;
+    @Mock
     private GameServiceProviderSelector mMockGameServiceProviderSelector;
     @Mock
     private GameServiceProviderInstanceFactory mMockGameServiceProviderInstanceFactory;
@@ -77,7 +88,7 @@
                 .startMocking();
 
         mGameServiceManager = new GameServiceController(
-                ConcurrentUtils.DIRECT_EXECUTOR,
+                mMockContext, ConcurrentUtils.DIRECT_EXECUTOR,
                 mMockGameServiceProviderSelector,
                 mMockGameServiceProviderInstanceFactory);
     }
@@ -96,25 +107,30 @@
 
     @Test
     public void notifyUserStarted_createsAndStartsNewInstance() {
-        GameServiceProviderConfiguration configurationA =
-                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
-                        PROVIDER_A_SERVICE_B);
+        GameServiceConfiguration configurationA =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_B));
         FakeGameServiceProviderInstance instanceA =
                 seedConfigurationForUser(USER_10, configurationA);
 
         mGameServiceManager.onBootComplete();
         mGameServiceManager.notifyUserStarted(USER_10);
 
-        verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+        verify(mMockGameServiceProviderInstanceFactory).create(
+                configurationA.getGameServiceComponentConfiguration());
         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
         assertThat(instanceA.getIsRunning()).isTrue();
     }
 
     @Test
     public void notifyUserStarted_sameUser_doesNotCreateNewInstance() {
-        GameServiceProviderConfiguration configurationA =
-                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
-                        PROVIDER_A_SERVICE_B);
+        GameServiceConfiguration configurationA =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_B));
         FakeGameServiceProviderInstance instanceA =
                 seedConfigurationForUser(USER_10, configurationA);
 
@@ -122,16 +138,19 @@
         mGameServiceManager.notifyUserStarted(USER_10);
         mGameServiceManager.notifyUserStarted(USER_10);
 
-        verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+        verify(mMockGameServiceProviderInstanceFactory).create(
+                configurationA.getGameServiceComponentConfiguration());
         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
         assertThat(instanceA.getIsRunning()).isTrue();
     }
 
     @Test
     public void notifyUserUnlocking_noForegroundUser_ignores() {
-        GameServiceProviderConfiguration configurationA =
-                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
-                        PROVIDER_A_SERVICE_B);
+        GameServiceConfiguration configurationA =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_B));
         FakeGameServiceProviderInstance instanceA =
                 seedConfigurationForUser(USER_10, configurationA);
 
@@ -144,9 +163,11 @@
 
     @Test
     public void notifyUserUnlocking_sameAsForegroundUser_evaluatesProvider() {
-        GameServiceProviderConfiguration configurationA =
-                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
-                        PROVIDER_A_SERVICE_B);
+        GameServiceConfiguration configurationA =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_B));
         seedNoConfigurationForUser(USER_10);
 
         mGameServiceManager.onBootComplete();
@@ -155,16 +176,19 @@
                 seedConfigurationForUser(USER_10, configurationA);
         mGameServiceManager.notifyUserUnlocking(USER_10);
 
-        verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
+        verify(mMockGameServiceProviderInstanceFactory).create(
+                configurationA.getGameServiceComponentConfiguration());
         verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
         assertThat(instanceA.getIsRunning()).isTrue();
     }
 
     @Test
     public void notifyUserUnlocking_differentFromForegroundUser_ignores() {
-        GameServiceProviderConfiguration configurationA =
-                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
-                        PROVIDER_A_SERVICE_B);
+        GameServiceConfiguration configurationA =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_B));
         seedNoConfigurationForUser(USER_10);
 
         mGameServiceManager.onBootComplete();
@@ -180,14 +204,18 @@
     @Test
     public void
             notifyNewForegroundUser_differentUser_stopsPreviousInstanceAndThenStartsNewInstance() {
-        GameServiceProviderConfiguration configurationA =
-                new GameServiceProviderConfiguration(USER_HANDLE_10, PROVIDER_A_SERVICE_A,
-                        PROVIDER_A_SERVICE_B);
+        GameServiceConfiguration configurationA =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_B));
         FakeGameServiceProviderInstance instanceA =
                 seedConfigurationForUser(USER_10, configurationA);
-        GameServiceProviderConfiguration configurationB =
-                new GameServiceProviderConfiguration(USER_HANDLE_11, PROVIDER_A_SERVICE_A,
-                        PROVIDER_A_SERVICE_B);
+        GameServiceConfiguration configurationB =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_11,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_B));
         FakeGameServiceProviderInstance instanceB = seedConfigurationForUser(USER_11,
                 configurationB);
         InOrder instancesInOrder = Mockito.inOrder(instanceA, instanceB);
@@ -196,8 +224,50 @@
         mGameServiceManager.notifyUserStarted(USER_10);
         mGameServiceManager.notifyNewForegroundUser(USER_11);
 
-        verify(mMockGameServiceProviderInstanceFactory).create(configurationA);
-        verify(mMockGameServiceProviderInstanceFactory).create(configurationB);
+        verify(mMockGameServiceProviderInstanceFactory).create(
+                configurationA.getGameServiceComponentConfiguration());
+        verify(mMockGameServiceProviderInstanceFactory).create(
+                configurationB.getGameServiceComponentConfiguration());
+        instancesInOrder.verify(instanceA).start();
+        instancesInOrder.verify(instanceA).stop();
+        instancesInOrder.verify(instanceB).start();
+        verifyNoMoreInteractions(mMockGameServiceProviderInstanceFactory);
+        assertThat(instanceA.getIsRunning()).isFalse();
+        assertThat(instanceB.getIsRunning()).isTrue();
+    }
+
+    @Test
+    public void packageChanges_reevaluatesGameServiceProvider() {
+        GameServiceConfiguration configurationA =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_B));
+        FakeGameServiceProviderInstance instanceA =
+                seedConfigurationForUser(USER_10, configurationA);
+
+        mGameServiceManager.onBootComplete();
+        mGameServiceManager.notifyUserStarted(USER_10);
+        ArgumentCaptor<BroadcastReceiver> broadcastReceiverArgumentCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mMockContext).registerReceiver(broadcastReceiverArgumentCaptor.capture(), any());
+
+        GameServiceConfiguration configurationB =
+                new GameServiceConfiguration(PROVIDER_A_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                PROVIDER_A_SERVICE_A,
+                                PROVIDER_A_SERVICE_C));
+        FakeGameServiceProviderInstance instanceB =
+                seedConfigurationForUser(USER_10, configurationA);
+        Intent intent = new Intent();
+        intent.setData(Uri.parse("package:" + PROVIDER_A_PACKAGE_NAME));
+        broadcastReceiverArgumentCaptor.getValue().onReceive(mMockContext, intent);
+
+        InOrder instancesInOrder = Mockito.inOrder(instanceA, instanceB);
+        verify(mMockGameServiceProviderInstanceFactory).create(
+                configurationA.getGameServiceComponentConfiguration());
+        verify(mMockGameServiceProviderInstanceFactory).create(
+                configurationB.getGameServiceComponentConfiguration());
         instancesInOrder.verify(instanceA).start();
         instancesInOrder.verify(instanceA).stop();
         instancesInOrder.verify(instanceB).start();
@@ -207,15 +277,16 @@
     }
 
     private void seedNoConfigurationForUser(SystemService.TargetUser user) {
-        when(mMockGameServiceProviderSelector.get(user, "")).thenReturn(null);
+        when(mMockGameServiceProviderSelector.get(user, null)).thenReturn(null);
     }
 
     private FakeGameServiceProviderInstance seedConfigurationForUser(SystemService.TargetUser user,
-            GameServiceProviderConfiguration configuration) {
-        when(mMockGameServiceProviderSelector.get(user, "")).thenReturn(configuration);
+            GameServiceConfiguration configuration) {
+        when(mMockGameServiceProviderSelector.get(user, null)).thenReturn(configuration);
         FakeGameServiceProviderInstance instanceForConfiguration =
                 spy(new FakeGameServiceProviderInstance());
-        when(mMockGameServiceProviderInstanceFactory.create(configuration))
+        when(mMockGameServiceProviderInstanceFactory.create(
+                configuration.getGameServiceComponentConfiguration()))
                 .thenReturn(instanceForConfiguration);
 
         return instanceForConfiguration;
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java
index 23a6a49..cf9ba1e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderSelectorImplTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -26,7 +27,6 @@
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
@@ -49,6 +49,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.SystemService;
+import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
 
 import com.google.common.collect.ImmutableList;
 
@@ -137,10 +138,10 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(null, null);
 
-        assertThat(gameServiceProviderConfiguration).isNull();
+        assertThat(gameServiceConfiguration).isNull();
     }
 
     @Test
@@ -154,15 +155,16 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(managedTargetUser(USER_HANDLE_10), null);
 
-        assertThat(gameServiceProviderConfiguration).isNull();
+        assertThat(gameServiceConfiguration).isNull();
     }
 
     @Test
     public void get_noSystemGameService_returnsNull()
             throws Exception {
+        seedSystemGameServicePackageName("");
         seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
                 resolveInfo(GAME_SERVICE_SERVICE_INFO));
         seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
@@ -170,14 +172,14 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
 
-        assertThat(gameServiceProviderConfiguration).isNull();
+        assertThat(gameServiceConfiguration).isNull();
     }
 
     @Test
-    public void get_noGameServiceProvidersAvailable_returnsNull()
+    public void get_noGameServiceProvidersAvailable_returnsGameServicePackageName()
             throws Exception {
         seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
         seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10);
@@ -186,28 +188,30 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
 
-        assertThat(gameServiceProviderConfiguration).isNull();
+        assertThat(gameServiceConfiguration).isEqualTo(
+                new GameServiceConfiguration(GAME_SERVICE_PACKAGE_NAME, null));
     }
 
     @Test
-    public void get_gameServiceProviderHasNoMetaData_returnsNull()
+    public void get_gameServiceProviderHasNoMetaData_returnsGameServicePackageName()
             throws Exception {
         seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
         seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
                 resolveInfo(GAME_SERVICE_SERVICE_INFO_WITHOUT_META_DATA));
         seedServiceServiceInfo(GAME_SESSION_SERVICE_COMPONENT);
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
 
-        assertThat(gameServiceProviderConfiguration).isNull();
+        assertThat(gameServiceConfiguration).isEqualTo(
+                new GameServiceConfiguration(GAME_SERVICE_PACKAGE_NAME, null));
     }
 
     @Test
-    public void get_gameSessionServiceDoesNotExist_returnsNull()
+    public void get_gameSessionServiceDoesNotExist_returnsGameServicePackageName()
             throws Exception {
         seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
         seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
@@ -217,14 +221,15 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
 
-        assertThat(gameServiceProviderConfiguration).isNull();
+        assertThat(gameServiceConfiguration).isEqualTo(
+                new GameServiceConfiguration(GAME_SERVICE_PACKAGE_NAME, null));
     }
 
     @Test
-    public void get_metaDataWrongFirstTag_returnsNull() throws Exception {
+    public void get_metaDataWrongFirstTag_returnsGameServicePackageName() throws Exception {
         seedSystemGameServicePackageName(GAME_SERVICE_PACKAGE_NAME);
         seedGameServiceResolveInfos(GAME_SERVICE_PACKAGE_NAME, USER_HANDLE_10,
                 resolveInfo(GAME_SERVICE_SERVICE_INFO));
@@ -233,10 +238,11 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_wrong_first_tag.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
 
-        assertThat(gameServiceProviderConfiguration).isNull();
+        assertThat(gameServiceConfiguration).isEqualTo(
+                new GameServiceConfiguration(GAME_SERVICE_PACKAGE_NAME, null));
     }
 
     @Test
@@ -250,15 +256,17 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
 
-        GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
-                new GameServiceProviderConfiguration(USER_HANDLE_10,
-                        GAME_SERVICE_COMPONENT,
-                        GAME_SESSION_SERVICE_COMPONENT);
-        assertThat(gameServiceProviderConfiguration).isEqualTo(
-                expectedGameServiceProviderConfiguration);
+        GameServiceConfiguration expectedGameServiceConfiguration =
+                new GameServiceConfiguration(
+                        GAME_SERVICE_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                GAME_SERVICE_COMPONENT,
+                                GAME_SESSION_SERVICE_COMPONENT));
+        assertThat(gameServiceConfiguration).isEqualTo(
+                expectedGameServiceConfiguration);
     }
 
     @Test
@@ -276,15 +284,17 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
 
-        GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
-                new GameServiceProviderConfiguration(USER_HANDLE_10,
-                        GAME_SERVICE_B_COMPONENT,
-                        GAME_SESSION_SERVICE_COMPONENT);
-        assertThat(gameServiceProviderConfiguration).isEqualTo(
-                expectedGameServiceProviderConfiguration);
+        GameServiceConfiguration expectedGameServiceConfiguration =
+                new GameServiceConfiguration(
+                        GAME_SERVICE_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                GAME_SERVICE_B_COMPONENT,
+                                GAME_SESSION_SERVICE_COMPONENT));
+        assertThat(gameServiceConfiguration).isEqualTo(
+                expectedGameServiceConfiguration);
     }
 
     @Test
@@ -299,15 +309,17 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10), null);
 
-        GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
-                new GameServiceProviderConfiguration(USER_HANDLE_10,
-                        GAME_SERVICE_COMPONENT,
-                        GAME_SESSION_SERVICE_COMPONENT);
-        assertThat(gameServiceProviderConfiguration).isEqualTo(
-                expectedGameServiceProviderConfiguration);
+        GameServiceConfiguration expectedGameServiceConfiguration =
+                new GameServiceConfiguration(
+                        GAME_SERVICE_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(USER_HANDLE_10,
+                                GAME_SERVICE_COMPONENT,
+                                GAME_SESSION_SERVICE_COMPONENT));
+        assertThat(gameServiceConfiguration).isEqualTo(
+                expectedGameServiceConfiguration);
     }
 
     @Test
@@ -322,16 +334,19 @@
                 GAME_SERVICE_META_DATA_RES_ID,
                 "res/xml/game_service_metadata_valid.xml");
 
-        GameServiceProviderConfiguration gameServiceProviderConfiguration =
+        GameServiceConfiguration gameServiceConfiguration =
                 mGameServiceProviderSelector.get(eligibleTargetUser(USER_HANDLE_10),
                         GAME_SERVICE_PACKAGE_NAME);
 
-        GameServiceProviderConfiguration expectedGameServiceProviderConfiguration =
-                new GameServiceProviderConfiguration(USER_HANDLE_10,
-                        GAME_SERVICE_COMPONENT,
-                        GAME_SESSION_SERVICE_COMPONENT);
-        assertThat(gameServiceProviderConfiguration).isEqualTo(
-                expectedGameServiceProviderConfiguration);
+        GameServiceConfiguration expectedGameServiceConfiguration =
+                new GameServiceConfiguration(
+                        GAME_SERVICE_PACKAGE_NAME,
+                        new GameServiceComponentConfiguration(
+                                USER_HANDLE_10,
+                                GAME_SERVICE_COMPONENT,
+                                GAME_SESSION_SERVICE_COMPONENT));
+        assertThat(gameServiceConfiguration).isEqualTo(
+                expectedGameServiceConfiguration);
     }
 
     private void seedSystemGameServicePackageName(String gameServicePackageName) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index ca5bf20..6510cd1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -167,7 +167,7 @@
         }
         whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap)
         whenever(mocks.settings.getPackageLPr(anyString())) { mSettingsMap[getArgument<Any>(0)] }
-        whenever(mocks.settings.readLPw(nullable())) {
+        whenever(mocks.settings.readLPw(any(), nullable())) {
             mSettingsMap.putAll(mPreExistingSettings)
             !mPreExistingSettings.isEmpty()
         }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index f35986b..b063d22 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -120,17 +120,16 @@
         whenever(mStorageManager.findPathForUuid(nullable())).thenReturn(mFile)
         doAnswer { it.arguments[0] }.`when`(mPms).resolveInternalPackageName(any(), any())
         doAnswer {
-            it.getArgument<FunctionalUtils.ThrowingConsumer<Computer>>(0).acceptOrThrow(
-                mockThrowOnUnmocked {
-                    whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
-                    whenever(resolveInternalPackageName(anyString(), anyLong())) {
-                        mPms.resolveInternalPackageName(getArgument(0), getArgument(1))
-                    }
-                    whenever(getPackageStateInternal(anyString())) {
-                        mPms.getPackageStateInternal(getArgument(0))
-                    }
-                })
-        }.`when`(mPms).executeWithConsistentComputer(any())
+            mockThrowOnUnmocked<Computer> {
+                whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
+                whenever(resolveInternalPackageName(anyString(), anyLong())) {
+                    mPms.resolveInternalPackageName(getArgument(0), getArgument(1))
+                }
+                whenever(getPackageStateInternal(anyString())) {
+                    mPms.getPackageStateInternal(getArgument(0))
+                }
+            }
+        }.`when`(mPms).snapshotComputer()
         whenever(mDeletePackageHelper.deletePackageX(any(), any(), any(), any(), any()))
             .thenReturn(PackageManager.DELETE_SUCCEEDED)
         whenever(mRule.mocks().injector.compatibility).thenReturn(mPlatformCompat)
@@ -206,7 +205,8 @@
 
     @Test
     fun pruneUnusedStaticSharedLibraries() {
-        mSharedLibrariesImpl.pruneUnusedStaticSharedLibraries(Long.MAX_VALUE, 0)
+        mSharedLibrariesImpl.pruneUnusedStaticSharedLibraries(mPms.snapshotComputer(),
+            Long.MAX_VALUE, 0)
 
         verify(mDeletePackageHelper)
             .deletePackageX(eq(STATIC_LIB_PACKAGE_NAME), any(), any(), any(), any())
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index ac406b5..5230ea7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -123,8 +123,8 @@
     @Test
     fun setPackagesSuspended() {
         val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
-        val failedNames = suspendPackageHelper.setPackagesSuspended(targetPackages,
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
+        val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            targetPackages, true /* suspended */, null /* appExtras */, null /* launcherExtras */,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
         testHandler.flush()
 
@@ -144,14 +144,15 @@
 
     @Test
     fun setPackagesSuspended_emptyPackageName() {
-        var failedNames = suspendPackageHelper.setPackagesSuspended(null /* packageNames */,
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
-            null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
+        var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            null /* packageNames */, true /* suspended */, null /* appExtras */,
+            null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
+            deviceOwnerUid)
 
         assertThat(failedNames).isNull()
 
-        failedNames = suspendPackageHelper.setPackagesSuspended(arrayOfNulls(0),
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
+        failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOfNulls(0), true /* suspended */, null /* appExtras */, null /* launcherExtras */,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
 
         assertThat(failedNames).isEmpty()
@@ -159,9 +160,10 @@
 
     @Test
     fun setPackagesSuspended_callerIsNotAllowed() {
-        val failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_2),
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
-            null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID, Binder.getCallingUid())
+        val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */,
+            null /* launcherExtras */, null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID,
+            Binder.getCallingUid())
 
         assertThat(failedNames).asList().hasSize(1)
         assertThat(failedNames).asList().contains(TEST_PACKAGE_2)
@@ -169,9 +171,10 @@
 
     @Test
     fun setPackagesSuspended_callerSuspendItself() {
-        val failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(DEVICE_OWNER_PACKAGE),
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
-            null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
+        val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOf(DEVICE_OWNER_PACKAGE), true /* suspended */, null /* appExtras */,
+            null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
+            deviceOwnerUid)
 
         assertThat(failedNames).asList().hasSize(1)
         assertThat(failedNames).asList().contains(DEVICE_OWNER_PACKAGE)
@@ -179,9 +182,10 @@
 
     @Test
     fun setPackagesSuspended_nonexistentPackage() {
-        val failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(NONEXISTENT_PACKAGE),
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
-            null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
+        val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOf(NONEXISTENT_PACKAGE), true /* suspended */, null /* appExtras */,
+            null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
+            deviceOwnerUid)
 
         assertThat(failedNames).asList().hasSize(1)
         assertThat(failedNames).asList().contains(NONEXISTENT_PACKAGE)
@@ -191,8 +195,8 @@
     fun setPackagesSuspended_knownPackages() {
         val knownPackages = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE,
             INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE)
-        val failedNames = suspendPackageHelper.setPackagesSuspended(knownPackages,
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
+        val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            knownPackages, true /* suspended */, null /* appExtras */, null /* launcherExtras */,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
 
         assertThat(failedNames.size).isEqualTo(knownPackages.size)
@@ -204,13 +208,13 @@
     @Test
     fun setPackagesUnsuspended() {
         val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
-        var failedNames = suspendPackageHelper.setPackagesSuspended(targetPackages,
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
+        var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            targetPackages, true /* suspended */, null /* appExtras */, null /* launcherExtras */,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
-        failedNames = suspendPackageHelper.setPackagesSuspended(targetPackages,
-            false /* suspended */, null /* appExtras */, null /* launcherExtras */,
+        failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            targetPackages, false /* suspended */, null /* appExtras */, null /* launcherExtras */,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
         testHandler.flush()
 
@@ -235,7 +239,7 @@
         val suspendables = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
         val unsuspendables = arrayOf(DEVICE_ADMIN_PACKAGE, DEFAULT_HOME_PACKAGE, DIALER_PACKAGE,
             INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE)
-        val results = suspendPackageHelper.getUnsuspendablePackagesForUser(
+        val results = suspendPackageHelper.getUnsuspendablePackagesForUser(pms.snapshotComputer(),
             suspendables + unsuspendables, TEST_USER_ID, deviceOwnerUid)
 
         assertThat(results.size).isEqualTo(unsuspendables.size)
@@ -247,7 +251,7 @@
     @Test
     fun getUnsuspendablePackagesForUser_callerIsNotAllowed() {
         val suspendables = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
-        val results = suspendPackageHelper.getUnsuspendablePackagesForUser(
+        val results = suspendPackageHelper.getUnsuspendablePackagesForUser(pms.snapshotComputer(),
             suspendables, TEST_USER_ID, Binder.getCallingUid())
 
         assertThat(results.size).isEqualTo(suspendables.size)
@@ -260,8 +264,8 @@
     fun getSuspendedPackageAppExtras() {
         val appExtras = PersistableBundle()
         appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_1)
-        var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_1),
-            true /* suspended */, appExtras, null /* launcherExtras */,
+        var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOf(TEST_PACKAGE_1), true /* suspended */, appExtras, null /* launcherExtras */,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
@@ -277,8 +281,8 @@
         val appExtras = PersistableBundle()
         appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_2)
         val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
-        var failedNames = suspendPackageHelper.setPackagesSuspended(targetPackages,
-            true /* suspended */, appExtras, null /* launcherExtras */,
+        var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            targetPackages, true /* suspended */, appExtras, null /* launcherExtras */,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
@@ -291,8 +295,9 @@
         assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
             TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
 
-        suspendPackageHelper.removeSuspensionsBySuspendingPackage(targetPackages,
-            { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE }, TEST_USER_ID)
+        suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
+            targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
+            TEST_USER_ID)
 
         testHandler.flush()
         verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID))
@@ -320,8 +325,8 @@
     fun getSuspendedPackageLauncherExtras() {
         val launcherExtras = PersistableBundle()
         launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
-        var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_2),
-            true /* suspended */, null /* appExtras */, launcherExtras,
+        var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
@@ -334,9 +339,10 @@
 
     @Test
     fun isPackageSuspended() {
-        var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_1),
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
-            null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
+        var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
+            null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
+            deviceOwnerUid)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
@@ -348,8 +354,8 @@
     fun getSuspendingPackage() {
         val launcherExtras = PersistableBundle()
         launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
-        var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_2),
-            true /* suspended */, null /* appExtras */, launcherExtras,
+        var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
             null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
@@ -362,9 +368,10 @@
     fun getSuspendedDialogInfo() {
         val dialogInfo = SuspendDialogInfo.Builder()
             .setTitle(TEST_PACKAGE_1).build()
-        var failedNames = suspendPackageHelper.setPackagesSuspended(arrayOf(TEST_PACKAGE_1),
-            true /* suspended */, null /* appExtras */, null /* launcherExtras */,
-            dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
+        var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
+            arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
+            null /* launcherExtras */, dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
+            deviceOwnerUid)
         testHandler.flush()
         assertThat(failedNames).isEmpty()
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 6789af4..2b34bc2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -35,6 +35,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
@@ -109,6 +110,8 @@
     LegacyPermissionDataProvider mPermissionDataProvider;
     @Mock
     DomainVerificationManagerInternal mDomainVerificationManager;
+    @Mock
+    Computer computer;
 
     final ArrayMap<String, Long> mOrigFirstInstallTimes = new ArrayMap<>();
 
@@ -132,7 +135,7 @@
         /* write out files and read */
         writeOldFiles();
         Settings settings = makeSettings();
-        assertThat(settings.readLPw(createFakeUsers()), is(true));
+        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
         verifyKeySetMetaData(settings);
     }
 
@@ -143,11 +146,11 @@
         // write out files and read
         writeOldFiles();
         Settings settings = makeSettings();
-        assertThat(settings.readLPw(createFakeUsers()), is(true));
+        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
 
         // write out, read back in and verify the same
-        settings.writeLPr();
-        assertThat(settings.readLPw(createFakeUsers()), is(true));
+        settings.writeLPr(computer);
+        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
         verifyKeySetMetaData(settings);
     }
 
@@ -156,7 +159,7 @@
         // Write delegateshellthe package files and make sure they're parsed properly the first time
         writeOldFiles();
         Settings settings = makeSettings();
-        assertThat(settings.readLPw(createFakeUsers()), is(true));
+        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
         assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue()));
         assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue()));
 
@@ -175,12 +178,12 @@
         // Write the package files and make sure they're parsed properly the first time
         writeOldFiles();
         Settings settings = makeSettings();
-        assertThat(settings.readLPw(createFakeUsers()), is(true));
-        settings.writeLPr();
+        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
+        settings.writeLPr(computer);
 
         // Create Settings again to make it read from the new files
         settings = makeSettings();
-        assertThat(settings.readLPw(createFakeUsers()), is(true));
+        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
 
         PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
         assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER));
@@ -469,12 +472,12 @@
         ps2.setUsesStaticLibrariesVersions(new long[] { 34 });
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
 
-        settingsUnderTest.writeLPr();
+        settingsUnderTest.writeLPr(computer);
 
         settingsUnderTest.mPackages.clear();
         settingsUnderTest.mDisabledSysPackages.clear();
 
-        assertThat(settingsUnderTest.readLPw(createFakeUsers()), is(true));
+        assertThat(settingsUnderTest.readLPw(computer, createFakeUsers()), is(true));
 
         PackageSetting readPs1 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_1);
         PackageSetting readPs2 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_2);
@@ -534,12 +537,12 @@
         ps2.setUsesSdkLibrariesVersionsMajor(new long[] { 34 });
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
 
-        settingsUnderTest.writeLPr();
+        settingsUnderTest.writeLPr(computer);
 
         settingsUnderTest.mPackages.clear();
         settingsUnderTest.mDisabledSysPackages.clear();
 
-        assertThat(settingsUnderTest.readLPw(createFakeUsers()), is(true));
+        assertThat(settingsUnderTest.readLPw(computer, createFakeUsers()), is(true));
 
         PackageSetting readPs1 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_1);
         PackageSetting readPs2 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_2);
@@ -587,7 +590,7 @@
         Settings settings = makeSettings();
         final WatchableTester watcher = new WatchableTester(settings, "testEnableDisable");
         watcher.register();
-        assertThat(settings.readLPw(createFakeUsers()), is(true));
+        assertThat(settings.readLPw(computer, createFakeUsers()), is(true));
         watcher.verifyChangeReported("readLPw");
 
         // Enable/Disable a package