Move to non-hidden APIs for handleUser and broadcast registration.

The implementation of handleIncomingUser is copied from
ag/13200660 (1d1547b).

Bug: 181787682
Test: Presubmit
Change-Id: I946199a8844e7fd6ea5574b873da56d8b8630f62
diff --git a/service/java/com/android/server/appsearch/AppSearchManagerService.java b/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 0c07fa0..0709ff5 100644
--- a/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -17,11 +17,10 @@
 
 import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
 import static android.os.Process.INVALID_UID;
-import static android.os.UserHandle.USER_NULL;
 
+import android.Manifest;
 import android.annotation.ElapsedRealtimeLong;
 import android.annotation.NonNull;
-import android.app.ActivityManager;
 import android.app.appsearch.AppSearchBatchResult;
 import android.app.appsearch.AppSearchMigrationHelper;
 import android.app.appsearch.AppSearchResult;
@@ -63,6 +62,7 @@
 import com.android.server.appsearch.external.localstorage.stats.CallStats;
 import com.android.server.appsearch.stats.LoggerInstanceManager;
 import com.android.server.appsearch.stats.PlatformLogger;
+import com.android.server.appsearch.util.PackageUtil;
 import com.android.server.usage.StorageStatsManagerLocal;
 import com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter;
 
@@ -124,8 +124,10 @@
     }
 
     private void registerReceivers() {
-        mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL,
-                new IntentFilter(Intent.ACTION_USER_REMOVED), /*broadcastPermission=*/ null,
+        mContext.registerReceiverForAllUsers(
+                new UserActionReceiver(),
+                new IntentFilter(Intent.ACTION_USER_REMOVED),
+                /*broadcastPermission=*/ null,
                 /*scheduler=*/ null);
 
         //TODO(b/145759910) Add a direct callback when user clears the data instead of relying on
@@ -135,8 +137,10 @@
         packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
         packageChangedFilter.addDataScheme("package");
         packageChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL,
-                packageChangedFilter, /*broadcastPermission=*/ null,
+        mContext.registerReceiverForAllUsers(
+                new PackageChangedReceiver(),
+                packageChangedFilter,
+                /*broadcastPermission=*/ null,
                 /*scheduler=*/ null);
     }
 
@@ -148,12 +152,13 @@
 
             switch (intent.getAction()) {
                 case Intent.ACTION_USER_REMOVED:
-                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
-                    if (userId == USER_NULL) {
-                        Log.e(TAG, "userId is missing in the intent: " + intent);
+                    UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
+                    if (userHandle == null) {
+                        Log.e(TAG, "Extra "
+                                + Intent.EXTRA_USER + " is missing in the intent: " + intent);
                         return;
                     }
-                    handleUserRemoved(UserHandle.of(userId));
+                    handleUserRemoved(userHandle);
                     break;
                 default:
                     Log.e(TAG, "Received unknown intent: " + intent);
@@ -1183,13 +1188,9 @@
             Objects.requireNonNull(actualCallingUser);
             Objects.requireNonNull(claimedCallingPackage);
 
-            int claimedCallingUid;
-            try {
-                Context claimedCallingContext =
-                        mContext.createContextAsUser(actualCallingUser, /*flags=*/ 0);
-                claimedCallingUid = claimedCallingContext.getPackageManager().getPackageUid(
-                        claimedCallingPackage, /*flags=*/ 0);
-            } catch (PackageManager.NameNotFoundException e) {
+            int claimedCallingUid = PackageUtil.getPackageUidAsUser(
+                    mContext, claimedCallingPackage, actualCallingUser);
+            if (claimedCallingUid == INVALID_UID) {
                 throw new SecurityException(
                         "Specified calling package [" + claimedCallingPackage + "] not found");
             }
@@ -1257,23 +1258,44 @@
      *
      * <p>Takes care of checking permissions and converting USER_CURRENT to the actual current user.
      *
+     * @param requestedUser The user which the caller is requesting to execute as.
+     * @param callingUid The actual uid of the caller as determined by Binder.
      * @return the user handle that the call should run as. Will always be a concrete user.
      */
     // TODO(b/173553485) verifying that the caller has permission to access target user's data
     // TODO(b/173553485) Handle ACTION_USER_REMOVED broadcast
     // TODO(b/173553485) Implement SystemService.onUserStopping()
     @NonNull
-    private static UserHandle handleIncomingUser(@NonNull UserHandle userHandle, int callingUid) {
+    private UserHandle handleIncomingUser(@NonNull UserHandle requestedUser, int callingUid) {
         int callingPid = Binder.getCallingPid();
-        int finalUserId = ActivityManager.handleIncomingUser(
+        UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
+        if (callingUser.equals(requestedUser)) {
+            return requestedUser;
+        }
+        // Duplicates UserController#ensureNotSpecialUser
+        if (requestedUser.getIdentifier() < 0) {
+            throw new IllegalArgumentException(
+                    "Call does not support special user " + requestedUser);
+        }
+        boolean canInteractAcrossUsers = mContext.checkPermission(
+                Manifest.permission.INTERACT_ACROSS_USERS,
                 callingPid,
-                callingUid,
-                userHandle.getIdentifier(),
-                /*allowAll=*/ false,
-                /*requireFull=*/ false,
-                /*name=*/ null,
-                /*callerPackage=*/ null);
-        return UserHandle.of(finalUserId);
+                callingUid) == PackageManager.PERMISSION_GRANTED;
+        if (!canInteractAcrossUsers) {
+            canInteractAcrossUsers = mContext.checkPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    callingPid,
+                    callingUid) == PackageManager.PERMISSION_GRANTED;
+        }
+        if (canInteractAcrossUsers) {
+            return requestedUser;
+        }
+        throw new SecurityException(
+                "Permission denied while calling from uid " + callingUid
+                        + " with " + requestedUser + "; Need to run as either the calling user ("
+                        + callingUser + "), or with one of the following permissions: "
+                        + Manifest.permission.INTERACT_ACROSS_USERS + " or "
+                        + Manifest.permission.INTERACT_ACROSS_USERS_FULL);
     }
 
     // TODO(b/179160886): Cache the previous storage stats.
diff --git a/service/java/com/android/server/appsearch/ImplInstanceManager.java b/service/java/com/android/server/appsearch/ImplInstanceManager.java
index beb4d24..0775272 100644
--- a/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -172,11 +172,6 @@
             @Nullable AppSearchLogger logger)
             throws AppSearchException {
         File appSearchDir = getAppSearchDir(userHandle);
-        // TODO(b/181787682): Swap AppSearchImpl and VisibilityStore to accept a UserHandle too
-        return AppSearchImpl.create(
-                appSearchDir,
-                userContext,
-                userHandle.getIdentifier(),
-                /*logger=*/ null);
+        return AppSearchImpl.create(appSearchDir, userContext, /*logger=*/ null);
     }
 }
diff --git a/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index a940dde..29cb57c 100644
--- a/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -201,7 +201,6 @@
     public static AppSearchImpl create(
             @NonNull File icingDir,
             @NonNull Context userContext,
-            int userId,
             @Nullable AppSearchLogger logger)
             throws AppSearchException {
         Objects.requireNonNull(icingDir);
@@ -213,8 +212,7 @@
             initStatsBuilder = new InitializeStats.Builder();
         }
 
-        AppSearchImpl appSearchImpl =
-                new AppSearchImpl(icingDir, userContext, userId, initStatsBuilder);
+        AppSearchImpl appSearchImpl = new AppSearchImpl(icingDir, userContext, initStatsBuilder);
 
         long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime();
         appSearchImpl.initializeVisibilityStore();
@@ -238,7 +236,6 @@
     private AppSearchImpl(
             @NonNull File icingDir,
             @NonNull Context userContext,
-            int userId,
             @Nullable InitializeStats.Builder initStatsBuilder)
             throws AppSearchException {
         mReadWriteLock.writeLock().lock();
@@ -256,7 +253,7 @@
                     "Constructing IcingSearchEngine, response",
                     Objects.hashCode(mIcingSearchEngineLocked));
 
-            mVisibilityStoreLocked = new VisibilityStore(this, userContext, userId);
+            mVisibilityStoreLocked = new VisibilityStore(this, userContext);
 
             // The core initialization procedure. If any part of this fails, we bail into
             // resetLocked(), deleting all data (but hopefully allowing AppSearchImpl to come up).
diff --git a/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/service/java/com/android/server/appsearch/stats/PlatformLogger.java
index 7d0ce41..c857fb6 100644
--- a/service/java/com/android/server/appsearch/stats/PlatformLogger.java
+++ b/service/java/com/android/server/appsearch/stats/PlatformLogger.java
@@ -20,7 +20,6 @@
 import android.annotation.Nullable;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -36,6 +35,7 @@
 import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
 import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
 import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.util.PackageUtil;
 
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
@@ -493,21 +493,13 @@
     @GuardedBy("mLock")
     private int getPackageUidAsUserLocked(@NonNull String packageName) {
         Integer packageUid = mPackageUidCacheLocked.get(packageName);
-        if (packageUid != null) {
-            return packageUid;
+        if (packageUid == null) {
+            packageUid = PackageUtil.getPackageUidAsUser(mContext, packageName, mUserHandle);
+            if (packageUid != Process.INVALID_UID) {
+                mPackageUidCacheLocked.put(packageName, packageUid);
+            }
         }
-
-        // TODO(b/173532925) since VisibilityStore has the same method, we can make this a
-        //  utility function
-        try {
-            packageUid = mContext.getPackageManager().getPackageUidAsUser(
-                    packageName, mUserHandle.getIdentifier());
-            mPackageUidCacheLocked.put(packageName, packageUid);
-            return packageUid;
-        } catch (PackageManager.NameNotFoundException e) {
-            // Package doesn't exist, continue
-        }
-        return Process.INVALID_UID;
+        return packageUid;
     }
 
     //
diff --git a/service/java/com/android/server/appsearch/util/PackageUtil.java b/service/java/com/android/server/appsearch/util/PackageUtil.java
new file mode 100644
index 0000000..53a1bed
--- /dev/null
+++ b/service/java/com/android/server/appsearch/util/PackageUtil.java
@@ -0,0 +1,55 @@
+/*
+ * 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.appsearch.util;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+
+/**
+ * Utilities for interacting with {@link android.content.pm.PackageManager},
+ * {@link android.os.UserHandle}, and other parts of dealing with apps and binder.
+ *
+ * @hide
+ */
+public class PackageUtil {
+    private PackageUtil() {}
+
+    /**
+     * Finds the UID of the {@code packageName}. Returns {@link Process#INVALID_UID} if unable to
+     * find the UID.
+     */
+    public static int getPackageUidAsUser(
+            @NonNull Context context, @NonNull String packageName, @NonNull UserHandle user) {
+        Context userContext = context.createContextAsUser(user, /*flags=*/ 0);
+        return getPackageUid(userContext, packageName);
+    }
+
+    /**
+     * Finds the UID of the {@code packageName} in the given {@code context}. Returns
+     * {@link Process#INVALID_UID} if unable to find the UID.
+     */
+    public static int getPackageUid(@NonNull Context context, @NonNull String packageName) {
+        try {
+            return context.getPackageManager().getPackageUid(packageName, /*flags=*/ 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return Process.INVALID_UID;
+        }
+    }
+}
diff --git a/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java b/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
index acff792..95ed368 100644
--- a/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
+++ b/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
@@ -18,7 +18,6 @@
 import static android.Manifest.permission.READ_GLOBAL_APP_SEARCH_DATA;
 
 import android.annotation.NonNull;
-import android.annotation.UserIdInt;
 import android.app.appsearch.AppSearchResult;
 import android.app.appsearch.AppSearchSchema;
 import android.app.appsearch.GenericDocument;
@@ -27,7 +26,6 @@
 import android.app.appsearch.exceptions.AppSearchException;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.Process;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -35,6 +33,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.appsearch.external.localstorage.AppSearchImpl;
 import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
+import com.android.server.appsearch.util.PackageUtil;
 
 import com.google.android.icing.proto.PersistType;
 
@@ -67,9 +66,6 @@
  * @hide
  */
 public class VisibilityStore {
-
-    private static final String TAG = "AppSearchVisibilityStore";
-
     /** No-op user id that won't have any visibility settings. */
     public static final int NO_OP_USER_ID = -1;
 
@@ -95,9 +91,6 @@
     // Context of the user that the call is being made as.
     private final Context mUserContext;
 
-    // User ID of the caller who we're checking visibility settings for.
-    private final int mUserId;
-
     /** Stores the schemas that are platform-hidden. All values are prefixed. */
     private final NotPlatformSurfaceableMap mNotPlatformSurfaceableMap =
             new NotPlatformSurfaceableMap();
@@ -112,13 +105,9 @@
      * @param appSearchImpl AppSearchImpl instance
      * @param userContext Context of the user that the call is being made as
      */
-    public VisibilityStore(
-            @NonNull AppSearchImpl appSearchImpl,
-            @NonNull Context userContext,
-            @UserIdInt int userId) {
+    public VisibilityStore(@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext) {
         mAppSearchImpl = appSearchImpl;
-        mUserContext = userContext;
-        mUserId = userId;
+        mUserContext = Objects.requireNonNull(userContext);
     }
 
     /**
@@ -348,6 +337,9 @@
         Set<PackageIdentifier> packageIdentifiers =
                 mPackageAccessibleMap.getAccessiblePackages(
                         packageName, databaseName, prefixedSchema);
+        if (packageIdentifiers.isEmpty()) {
+            return false;
+        }
         for (PackageIdentifier packageIdentifier : packageIdentifiers) {
             // TODO(b/169883602): Consider caching the UIDs of packages. Looking this up in the
             // package manager could be costly. We would also need to update the cache on
@@ -357,9 +349,10 @@
             // the callerUid since clients can createContextAsUser with some other user, and then
             // make calls to us. So just check if the appId portion of the uid is the same. This is
             // essentially UserHandle.isSameApp, but that's not a system API for us to use.
-            int callerAppId = UserHandle.getAppId((callerUid));
-            int userAppId =
-                    UserHandle.getAppId(getPackageUidAsUser(packageIdentifier.getPackageName()));
+            int callerAppId = UserHandle.getAppId(callerUid);
+            int packageUid =
+                    PackageUtil.getPackageUid(mUserContext, packageIdentifier.getPackageName());
+            int userAppId = UserHandle.getAppId(packageUid);
             if (callerAppId != userAppId) {
                 continue;
             }
@@ -401,17 +394,4 @@
             @NonNull String packageName, @NonNull String databaseName) {
         return ID_PREFIX + PrefixUtil.createPrefix(packageName, databaseName);
     }
-
-    /**
-     * Finds the UID of the {@code packageName}. Returns {@link Process#INVALID_UID} if unable to
-     * find the UID.
-     */
-    private int getPackageUidAsUser(@NonNull String packageName) {
-        try {
-            return mUserContext.getPackageManager().getPackageUidAsUser(packageName, mUserId);
-        } catch (PackageManager.NameNotFoundException e) {
-            // Package doesn't exist, continue
-        }
-        return Process.INVALID_UID;
-    }
 }
diff --git a/testing/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/testing/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
index 755795d..3bcbcbd 100644
--- a/testing/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
+++ b/testing/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -25,11 +25,18 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
 import android.app.appsearch.AppSearchSchema;
 import android.app.appsearch.PackageIdentifier;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.util.ArrayMap;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -43,13 +50,15 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
 
 import java.util.Collections;
+import java.util.Map;
 
 /** This tests AppSearchImpl when it's running with a platform-backed VisibilityStore. */
 public class AppSearchImplPlatformTest {
     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
-    private MockPackageManager mMockPackageManager = new MockPackageManager();
+    private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
     private Context mContext;
     private AppSearchImpl mAppSearchImpl;
     private int mGlobalQuerierUid;
@@ -57,20 +66,28 @@
     @Before
     public void setUp() throws Exception {
         Context context = ApplicationProvider.getApplicationContext();
-        mContext =
-                new ContextWrapper(context) {
+        mContext = new ContextWrapper(context) {
+            @Override
+            public Context createContextAsUser(UserHandle user, int flags) {
+                return new ContextWrapper(super.createContextAsUser(user, flags)) {
                     @Override
                     public PackageManager getPackageManager() {
-                        return mMockPackageManager.getMockPackageManager();
+                        return getMockPackageManager(user);
                     }
                 };
+            }
+
+            @Override
+            public PackageManager getPackageManager() {
+                return createContextAsUser(getUser(), /*flags=*/ 0).getPackageManager();
+            }
+        };
 
         // Give ourselves global query permissions
         mAppSearchImpl =
                 AppSearchImpl.create(
                         mTemporaryFolder.newFolder(),
                         mContext,
-                        mContext.getUserId(),
                         /*logger=*/ null);
 
         mGlobalQuerierUid =
@@ -85,14 +102,19 @@
         int uidFoo = 1;
 
         // Make sure foo package will pass package manager checks.
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
-        mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenReturn(uidFoo);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
 
         // Make sure we have global query privileges and "foo" doesn't
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
+        when(mockPackageManager.checkPermission(
+                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
+                .thenReturn(PERMISSION_GRANTED);
+        when(mockPackageManager.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo))
+                .thenReturn(PERMISSION_DENIED);
 
         // Set schema1
         String prefix = PrefixUtil.createPrefix("package", "database");
@@ -145,19 +167,16 @@
                 /*schemaVersion=*/ 0);
 
         // Check that "schema1" still has the same visibility settings
-        SystemUtil.runWithShellPermissionIdentity(
-                () -> {
-                    assertThat(
-                                    mAppSearchImpl
-                                            .getVisibilityStoreLocked()
-                                            .isSchemaSearchableByCaller(
-                                                    "package",
-                                                    "database",
-                                                    prefix + "schema1",
-                                                    mContext.getPackageName(),
-                                                    mGlobalQuerierUid))
-                            .isFalse();
-                },
+        SystemUtil.runWithShellPermissionIdentity(() -> assertThat(
+                mAppSearchImpl
+                        .getVisibilityStoreLocked()
+                        .isSchemaSearchableByCaller(
+                                "package",
+                                "database",
+                                prefix + "schema1",
+                                mContext.getPackageName(),
+                                mGlobalQuerierUid))
+                        .isFalse(),
                 READ_GLOBAL_APP_SEARCH_DATA);
 
         assertThat(
@@ -172,19 +191,16 @@
                 .isTrue();
 
         // "schema2" has default visibility settings
-        SystemUtil.runWithShellPermissionIdentity(
-                () -> {
-                    assertThat(
-                                    mAppSearchImpl
-                                            .getVisibilityStoreLocked()
-                                            .isSchemaSearchableByCaller(
-                                                    "package",
-                                                    "database",
-                                                    prefix + "schema2",
-                                                    mContext.getPackageName(),
-                                                    mGlobalQuerierUid))
-                            .isTrue();
-                },
+        SystemUtil.runWithShellPermissionIdentity(() -> assertThat(
+                mAppSearchImpl
+                        .getVisibilityStoreLocked()
+                        .isSchemaSearchableByCaller(
+                                "package",
+                                "database",
+                                prefix + "schema2",
+                                mContext.getPackageName(),
+                                mGlobalQuerierUid))
+                        .isTrue(),
                 READ_GLOBAL_APP_SEARCH_DATA);
 
         assertThat(
@@ -207,14 +223,19 @@
         int uidFoo = 1;
 
         // Make sure foo package will pass package manager checks.
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
-        mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenReturn(uidFoo);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
 
         // Make sure we have global query privileges and "foo" doesn't
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
+        when(mockPackageManager.checkPermission(
+                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
+                .thenReturn(PERMISSION_GRANTED);
+        when(mockPackageManager.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo))
+                .thenReturn(PERMISSION_DENIED);
 
         String prefix = PrefixUtil.createPrefix("package", "database");
         mAppSearchImpl.setSchema(
@@ -320,8 +341,10 @@
     @Test
     public void testSetSchema_defaultPlatformVisible() throws Exception {
         // Make sure we have global query privileges
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.checkPermission(
+                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
+                .thenReturn(PERMISSION_GRANTED);
 
         String prefix = PrefixUtil.createPrefix("package", "database");
         mAppSearchImpl.setSchema(
@@ -348,8 +371,10 @@
     @Test
     public void testSetSchema_platformHidden() throws Exception {
         // Make sure we have global query privileges
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.checkPermission(
+                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
+                .thenReturn(PERMISSION_GRANTED);
 
         String prefix = PrefixUtil.createPrefix("package", "database");
         mAppSearchImpl.setSchema(
@@ -378,8 +403,9 @@
         String packageName = "com.package";
 
         // Make sure package doesn't global query privileges
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, packageName, PERMISSION_DENIED);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.checkPermission(
+                READ_GLOBAL_APP_SEARCH_DATA, packageName)).thenReturn(PERMISSION_DENIED);
 
         String prefix = PrefixUtil.createPrefix("package", "database");
         mAppSearchImpl.setSchema(
@@ -410,12 +436,16 @@
         int uidFoo = 1;
 
         // Make sure foo package will pass package manager checks.
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
-        mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenReturn(uidFoo);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
 
         // Make sure foo doesn't have global query privileges
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
+        when(mockPackageManager.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo))
+                .thenReturn(PERMISSION_DENIED);
 
         String prefix = PrefixUtil.createPrefix("package", "database");
         mAppSearchImpl.setSchema(
@@ -439,4 +469,14 @@
                                         uidFoo))
                 .isTrue();
     }
+
+    @NonNull
+    private PackageManager getMockPackageManager(@NonNull UserHandle user) {
+        PackageManager pm = mMockPackageManagers.get(user);
+        if (pm == null) {
+            pm = Mockito.mock(PackageManager.class);
+            mMockPackageManagers.put(user, pm);
+        }
+        return pm;
+    }
 }
diff --git a/testing/servicestests/src/com/android/server/appsearch/MockPackageManager.java b/testing/servicestests/src/com/android/server/appsearch/MockPackageManager.java
deleted file mode 100644
index 60e1a8f..0000000
--- a/testing/servicestests/src/com/android/server/appsearch/MockPackageManager.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.
- */
-
-// TODO(b/169883602): This is purposely a different package from the path so that AppSearchImplTest
-// can use it without an extra import. This should be moved into a proper package once
-// AppSearchImpl-VisibilityStore's dependencies are refactored.
-package com.android.server.appsearch.external.localstorage;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.content.pm.PackageManager;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/** Mock to help test package name, UID, and certificate verification. */
-public class MockPackageManager {
-
-    @Mock private PackageManager mMockPackageManager;
-
-    public MockPackageManager() {
-        MockitoAnnotations.initMocks(this);
-    }
-
-    @NonNull
-    public PackageManager getMockPackageManager() {
-        return mMockPackageManager;
-    }
-
-    /** Mock a checkPermission call. */
-    public void mockCheckPermission(String permission, String packageName, int permissionResult) {
-        when(mMockPackageManager.checkPermission(permission, packageName))
-                .thenReturn(permissionResult);
-    }
-
-    /** Mock a NameNotFoundException if the package name isn't installed. */
-    public void mockThrowsNameNotFoundException(String packageName) {
-        try {
-            when(mMockPackageManager.getPackageUidAsUser(eq(packageName), /*userId=*/ anyInt()))
-                    .thenThrow(new PackageManager.NameNotFoundException());
-            when(mMockPackageManager.getPackageUidAsUser(
-                            eq(packageName), /*flags=*/ anyInt(), /*userId=*/ anyInt()))
-                    .thenThrow(new PackageManager.NameNotFoundException());
-        } catch (PackageManager.NameNotFoundException e) {
-            // Shouldn't ever happen since we're mocking the exception
-            e.printStackTrace();
-        }
-    }
-
-    /** Mocks that {@code uid} contains the {@code packageName} */
-    public void mockGetPackageUidAsUser(String packageName, @UserIdInt int callerUserId, int uid) {
-        try {
-            when(mMockPackageManager.getPackageUidAsUser(eq(packageName), eq(callerUserId)))
-                    .thenReturn(uid);
-            when(mMockPackageManager.getPackageUidAsUser(
-                            eq(packageName), /*flags=*/ anyInt(), eq(callerUserId)))
-                    .thenReturn(uid);
-        } catch (PackageManager.NameNotFoundException e) {
-            // Shouldn't ever happen since we're mocking the method.
-            e.printStackTrace();
-        }
-    }
-
-    /** Mocks that {@code packageName} has been signed with {@code sha256Cert}. */
-    public void mockAddSigningCertificate(String packageName, byte[] sha256Cert) {
-        when(mMockPackageManager.hasSigningCertificate(
-                        packageName, sha256Cert, PackageManager.CERT_INPUT_SHA256))
-                .thenReturn(true);
-    }
-
-    /** Mocks that {@code packageName} has NOT been signed with {@code sha256Cert}. */
-    public void mockRemoveSigningCertificate(String packageName, byte[] sha256Cert) {
-        when(mMockPackageManager.hasSigningCertificate(
-                        packageName, sha256Cert, PackageManager.CERT_INPUT_SHA256))
-                .thenReturn(false);
-    }
-}
diff --git a/testing/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java b/testing/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
index d9cfc54..6ac4d13 100644
--- a/testing/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
+++ b/testing/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
@@ -25,10 +25,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
 import android.app.appsearch.PackageIdentifier;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.util.ArrayMap;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -43,39 +50,47 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
 
 import java.util.Collections;
+import java.util.Map;
 
 public class VisibilityStoreTest {
-
     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
-    private MockPackageManager mMockPackageManager = new MockPackageManager();
+    private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
     private Context mContext;
-    private AppSearchImpl mAppSearchImpl;
     private VisibilityStore mVisibilityStore;
     private int mUid;
 
     @Before
     public void setUp() throws Exception {
         Context context = ApplicationProvider.getApplicationContext();
-        mContext =
-                new ContextWrapper(context) {
+        mContext = new ContextWrapper(context) {
+            @Override
+            public Context createContextAsUser(UserHandle user, int flags) {
+                return new ContextWrapper(super.createContextAsUser(user, flags)) {
                     @Override
                     public PackageManager getPackageManager() {
-                        return mMockPackageManager.getMockPackageManager();
+                        return getMockPackageManager(user);
                     }
                 };
+            }
+
+            @Override
+            public PackageManager getPackageManager() {
+                return createContextAsUser(getUser(), /*flags=*/ 0).getPackageManager();
+            }
+        };
 
         // Give ourselves global query permissions
-        mAppSearchImpl =
+        AppSearchImpl appSearchImpl =
                 AppSearchImpl.create(
                         mTemporaryFolder.newFolder(),
                         mContext,
-                        mContext.getUserId(),
                         /*logger=*/ null);
 
         mUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
-        mVisibilityStore = mAppSearchImpl.getVisibilityStoreLocked();
+        mVisibilityStore = appSearchImpl.getVisibilityStoreLocked();
     }
 
     /**
@@ -103,8 +118,10 @@
     @Test
     public void testSetVisibility_platformSurfaceable() throws Exception {
         // Make sure we have global query privileges
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager
+                .checkPermission(READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
+                .thenReturn(PERMISSION_GRANTED);
 
         mVisibilityStore.setVisibility(
                 "package",
@@ -210,10 +227,13 @@
         int uidNotFooOrBar = 3;
 
         // Make sure none of them have global query privileges
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, packageNameBar, PERMISSION_DENIED);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager
+                .checkPermission(READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo))
+                .thenReturn(PERMISSION_DENIED);
+        when(mockPackageManager
+                .checkPermission(READ_GLOBAL_APP_SEARCH_DATA, packageNameBar))
+                .thenReturn(PERMISSION_DENIED);
 
         // By default, a schema isn't package accessible.
         assertThat(
@@ -237,32 +257,43 @@
                         ImmutableList.of(new PackageIdentifier(packageNameBar, sha256CertBar))));
 
         // Should fail if PackageManager doesn't see that it has the proper certificate
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
-        mMockPackageManager.mockRemoveSigningCertificate(packageNameFoo, sha256CertFoo);
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenReturn(uidFoo);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(false);
         assertThat(
                         mVisibilityStore.isSchemaSearchableByCaller(
                                 "package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
                 .isFalse();
 
         // Should fail if PackageManager doesn't think the package belongs to the uid
-        mMockPackageManager.mockGetPackageUidAsUser(
-                packageNameFoo, mContext.getUserId(), uidNotFooOrBar);
-        mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenReturn(uidNotFooOrBar);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
         assertThat(
                         mVisibilityStore.isSchemaSearchableByCaller(
                                 "package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
                 .isFalse();
 
         // But if uid and certificate match, then we should have access
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
-        mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenReturn(uidFoo);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
         assertThat(
                         mVisibilityStore.isSchemaSearchableByCaller(
                                 "package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
                 .isTrue();
 
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameBar, mContext.getUserId(), uidBar);
-        mMockPackageManager.mockAddSigningCertificate(packageNameBar, sha256CertBar);
+        when(mockPackageManager.getPackageUid(eq(packageNameBar), /*flags=*/ anyInt()))
+                .thenReturn(uidBar);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameBar, sha256CertBar, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
         assertThat(
                         mVisibilityStore.isSchemaSearchableByCaller(
                                 "package", "database", "prefix/schemaBar", packageNameBar, uidBar))
@@ -278,15 +309,21 @@
                         "prefix/schemaFoo",
                         ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))));
 
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
-        mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenReturn(uidFoo);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
         assertThat(
                         mVisibilityStore.isSchemaSearchableByCaller(
                                 "package", "database", "prefix/schemaFoo", packageNameFoo, uidFoo))
                 .isTrue();
 
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameBar, mContext.getUserId(), uidBar);
-        mMockPackageManager.mockAddSigningCertificate(packageNameBar, sha256CertBar);
+        when(mockPackageManager.getPackageUid(eq(packageNameBar), /*flags=*/ anyInt()))
+                .thenReturn(uidBar);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameBar, sha256CertBar, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
         assertThat(
                         mVisibilityStore.isSchemaSearchableByCaller(
                                 "package", "database", "prefix/schemaBar", packageNameBar, uidBar))
@@ -302,11 +339,13 @@
         int uidFoo = 1;
 
         // Pretend we can't find the Foo package.
-        mMockPackageManager.mockThrowsNameNotFoundException(packageNameFoo);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenThrow(new PackageManager.NameNotFoundException());
 
         // Make sure "foo" doesn't have global query privileges
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
+        when(mockPackageManager.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo))
+                .thenReturn(PERMISSION_DENIED);
 
         // Grant package access
         mVisibilityStore.setVisibility(
@@ -332,10 +371,12 @@
         int uidFoo = 1;
 
         // Set it up such that the test package has global query privileges, but "foo" doesn't.
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName(), PERMISSION_GRANTED);
-        mMockPackageManager.mockCheckPermission(
-                READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo, PERMISSION_DENIED);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.checkPermission(
+                READ_GLOBAL_APP_SEARCH_DATA, mContext.getPackageName()))
+                .thenReturn(PERMISSION_GRANTED);
+        when(mockPackageManager.checkPermission(READ_GLOBAL_APP_SEARCH_DATA, packageNameFoo))
+                .thenReturn(PERMISSION_DENIED);
 
         mVisibilityStore.setVisibility(
                 /*packageName=*/ "",
@@ -354,8 +395,11 @@
                                 mUid))
                 .isTrue();
 
-        mMockPackageManager.mockGetPackageUidAsUser(packageNameFoo, mContext.getUserId(), uidFoo);
-        mMockPackageManager.mockAddSigningCertificate(packageNameFoo, sha256CertFoo);
+        when(mockPackageManager.getPackageUid(eq(packageNameFoo), /*flags=*/ anyInt()))
+                .thenReturn(uidFoo);
+        when(mockPackageManager.hasSigningCertificate(
+                packageNameFoo, sha256CertFoo, PackageManager.CERT_INPUT_SHA256))
+                .thenReturn(true);
         assertThat(
                         mVisibilityStore.isSchemaSearchableByCaller(
                                 /*packageName=*/ "",
@@ -365,4 +409,14 @@
                                 uidFoo))
                 .isTrue();
     }
+
+    @NonNull
+    private PackageManager getMockPackageManager(@NonNull UserHandle user) {
+        PackageManager pm = mMockPackageManagers.get(user);
+        if (pm == null) {
+            pm = Mockito.mock(PackageManager.class);
+            mMockPackageManagers.put(user, pm);
+        }
+        return pm;
+    }
 }
diff --git a/testing/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/testing/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index 031532b..5a8c44c 100644
--- a/testing/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/testing/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -86,7 +86,6 @@
                 AppSearchImpl.create(
                         mTemporaryFolder.newFolder(),
                         context,
-                        VisibilityStore.NO_OP_USER_ID,
                         /*logger=*/ null);
     }
 
@@ -494,9 +493,7 @@
         // Setup the index
         Context context = ApplicationProvider.getApplicationContext();
         File appsearchDir = mTemporaryFolder.newFolder();
-        AppSearchImpl appSearchImpl =
-                AppSearchImpl.create(
-                        appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
+        AppSearchImpl appSearchImpl = AppSearchImpl.create(appsearchDir, context, /*logger=*/ null);
 
         // Insert schema
         List<AppSearchSchema> schemas =
@@ -557,9 +554,7 @@
 
         // Initialize AppSearchImpl. This should cause a reset.
         appSearchImpl.close();
-        appSearchImpl =
-                AppSearchImpl.create(
-                        appsearchDir, context, VisibilityStore.NO_OP_USER_ID, testLogger);
+        appSearchImpl = AppSearchImpl.create(appsearchDir, context, testLogger);
 
         // Check recovery state
         InitializeStats initStats = testLogger.mInitializeStats;
@@ -1688,7 +1683,6 @@
                 AppSearchImpl.create(
                         mTemporaryFolder.newFolder(),
                         context,
-                        VisibilityStore.NO_OP_USER_ID,
                         /*logger=*/ null);
 
         // Initial check that we could do something at first.
@@ -1836,9 +1830,7 @@
         // Setup the index
         Context context = ApplicationProvider.getApplicationContext();
         File appsearchDir = mTemporaryFolder.newFolder();
-        AppSearchImpl appSearchImpl =
-                AppSearchImpl.create(
-                        appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
+        AppSearchImpl appSearchImpl = AppSearchImpl.create(appsearchDir, context, /*logger=*/ null);
 
         List<AppSearchSchema> schemas =
                 Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -1864,8 +1856,7 @@
 
         // That document should be visible even from another instance.
         AppSearchImpl appSearchImpl2 =
-                AppSearchImpl.create(
-                        appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
+                AppSearchImpl.create(appsearchDir, context, /*logger=*/ null);
         getResult =
                 appSearchImpl2.getDocument(
                         "package", "database", "namespace1", "id1", Collections.emptyMap());
@@ -1877,9 +1868,7 @@
         // Setup the index
         Context context = ApplicationProvider.getApplicationContext();
         File appsearchDir = mTemporaryFolder.newFolder();
-        AppSearchImpl appSearchImpl =
-                AppSearchImpl.create(
-                        appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
+        AppSearchImpl appSearchImpl = AppSearchImpl.create(appsearchDir, context, /*logger=*/ null);
 
         List<AppSearchSchema> schemas =
                 Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -1929,8 +1918,7 @@
 
         // Only the second document should be retrievable from another instance.
         AppSearchImpl appSearchImpl2 =
-                AppSearchImpl.create(
-                        appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
+                AppSearchImpl.create(appsearchDir, context, /*logger=*/ null);
         expectThrows(
                 AppSearchException.class,
                 () ->
@@ -1951,9 +1939,7 @@
         // Setup the index
         Context context = ApplicationProvider.getApplicationContext();
         File appsearchDir = mTemporaryFolder.newFolder();
-        AppSearchImpl appSearchImpl =
-                AppSearchImpl.create(
-                        appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
+        AppSearchImpl appSearchImpl = AppSearchImpl.create(appsearchDir, context, /*logger=*/ null);
 
         List<AppSearchSchema> schemas =
                 Collections.singletonList(new AppSearchSchema.Builder("type").build());
@@ -2011,8 +1997,7 @@
 
         // Only the second document should be retrievable from another instance.
         AppSearchImpl appSearchImpl2 =
-                AppSearchImpl.create(
-                        appsearchDir, context, VisibilityStore.NO_OP_USER_ID, /*logger=*/ null);
+                AppSearchImpl.create(appsearchDir, context, /*logger=*/ null);
         expectThrows(
                 AppSearchException.class,
                 () ->
diff --git a/testing/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/testing/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
index d1ca759..f0a6ef1 100644
--- a/testing/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
+++ b/testing/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
@@ -40,7 +40,6 @@
 import com.android.server.appsearch.proto.QueryStatsProto;
 import com.android.server.appsearch.proto.ScoringSpecProto;
 import com.android.server.appsearch.proto.TermMatchType;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -64,7 +63,6 @@
                 AppSearchImpl.create(
                         mTemporaryFolder.newFolder(),
                         context,
-                        VisibilityStore.NO_OP_USER_ID,
                         /*logger=*/ null);
         mLogger = new TestLogger();
     }
@@ -292,7 +290,6 @@
                 AppSearchImpl.create(
                         mTemporaryFolder.newFolder(),
                         context,
-                        VisibilityStore.NO_OP_USER_ID,
                         mLogger);
 
         InitializeStats iStats = mLogger.mInitializeStats;
diff --git a/testing/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/testing/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
index 734f05a..7e1639e 100644
--- a/testing/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
+++ b/testing/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -29,46 +30,46 @@
 import android.content.pm.PackageManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.SparseIntArray;
 
 import androidx.test.core.app.ApplicationProvider;
 
-import com.android.server.appsearch.external.localstorage.MockPackageManager;
 import com.android.server.appsearch.external.localstorage.stats.CallStats;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 import java.io.UnsupportedEncodingException;
 import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.Map;
 
 public class PlatformLoggerTest {
     private static final int TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS = 100;
     private static final int TEST_DEFAULT_SAMPLING_INTERVAL = 10;
     private static final String TEST_PACKAGE_NAME = "packageName";
-    private MockPackageManager mMockPackageManager = new MockPackageManager();
+
+    private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
     private Context mContext;
 
     @Before
     public void setUp() throws Exception {
         Context context = ApplicationProvider.getApplicationContext();
-        mContext =
-                new ContextWrapper(context) {
+        mContext = new ContextWrapper(context) {
+            @Override
+            public Context createContextAsUser(UserHandle user, int flags) {
+                return new ContextWrapper(super.createContextAsUser(user, flags)) {
                     @Override
                     public PackageManager getPackageManager() {
-                        return mMockPackageManager.getMockPackageManager();
+                        return getMockPackageManager(user);
                     }
                 };
-    }
-
-    static int calculateHashCodeMd5withBigInteger(@NonNull String str) throws
-            NoSuchAlgorithmException, UnsupportedEncodingException {
-        MessageDigest md = MessageDigest.getInstance("MD5");
-        md.update(str.getBytes(/*charsetName=*/ "UTF-8"));
-        byte[] digest = md.digest();
-        return new BigInteger(digest).intValue();
+            }
+        };
     }
 
     @Test
@@ -294,39 +295,51 @@
                         TEST_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
                         TEST_DEFAULT_SAMPLING_INTERVAL,
                         /*samplingIntervals=*/ new SparseIntArray()));
-        mMockPackageManager.mockGetPackageUidAsUser(testPackageName, mContext.getUserId(), testUid);
+        PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
+        when(mockPackageManager.getPackageUid(testPackageName, /*flags=*/0)).thenReturn(testUid);
 
-        //
         // First time, no cache
-        //
         PlatformLogger.ExtraStats extraStats = logger.createExtraStatsLocked(testPackageName,
                 CallStats.CALL_TYPE_PUT_DOCUMENT);
-
-        verify(mMockPackageManager.getMockPackageManager(), times(1)).getPackageUidAsUser(
-                eq(testPackageName), /*userId=*/ anyInt());
+        verify(mockPackageManager, times(1))
+                .getPackageUid(eq(testPackageName), /*flags=*/ anyInt());
         assertThat(extraStats.mPackageUid).isEqualTo(testUid);
 
-        //
         // Second time, we have cache
-        //
         extraStats = logger.createExtraStatsLocked(testPackageName,
                 CallStats.CALL_TYPE_PUT_DOCUMENT);
 
         // Count is still one since we will use the cache
-        verify(mMockPackageManager.getMockPackageManager(), times(1)).getPackageUidAsUser(
-                eq(testPackageName), /*userId=*/ anyInt());
+        verify(mockPackageManager, times(1))
+                .getPackageUid(eq(testPackageName), /*flags=*/ anyInt());
         assertThat(extraStats.mPackageUid).isEqualTo(testUid);
 
-        //
         // Remove the cache and try again
-        //
         assertThat(logger.removeCachedUidForPackage(testPackageName)).isEqualTo(testUid);
         extraStats = logger.createExtraStatsLocked(testPackageName,
                 CallStats.CALL_TYPE_PUT_DOCUMENT);
 
         // count increased by 1 since cache is cleared
-        verify(mMockPackageManager.getMockPackageManager(), times(2)).getPackageUidAsUser(
-                eq(testPackageName), /*userId=*/ anyInt());
+        verify(mockPackageManager, times(2))
+                .getPackageUid(eq(testPackageName), /*flags=*/ anyInt());
         assertThat(extraStats.mPackageUid).isEqualTo(testUid);
     }
+
+    private static int calculateHashCodeMd5withBigInteger(@NonNull String str)
+            throws NoSuchAlgorithmException {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update(str.getBytes(StandardCharsets.UTF_8));
+        byte[] digest = md.digest();
+        return new BigInteger(digest).intValue();
+    }
+
+    @NonNull
+    private PackageManager getMockPackageManager(@NonNull UserHandle user) {
+        PackageManager pm = mMockPackageManagers.get(user);
+        if (pm == null) {
+            pm = Mockito.mock(PackageManager.class);
+            mMockPackageManagers.put(user, pm);
+        }
+        return pm;
+    }
 }