Merge changes Ic92e29c6,I6e044606 into rvc-dev

* changes:
  Null check on permission request check
  Pre-cache filter results
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 5b9db64..ccda587 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -19,6 +19,8 @@
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -27,6 +29,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
+import android.content.pm.UserInfo;
 import android.content.pm.parsing.component.ParsedComponent;
 import android.content.pm.parsing.component.ParsedInstrumentation;
 import android.content.pm.parsing.component.ParsedIntentInfo;
@@ -108,12 +111,25 @@
     private final boolean mSystemAppsQueryable;
 
     private final FeatureConfig mFeatureConfig;
-
     private final OverlayReferenceMapper mOverlayReferenceMapper;
+    private final StateProvider mStateProvider;
+
     private PackageParser.SigningDetails mSystemSigningDetails;
     private Set<String> mProtectedBroadcasts = new ArraySet<>();
 
-    AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist,
+    /**
+     * This structure maps uid -> uid and indicates whether access from the first should be
+     * filtered to the second. It's essentially a cache of the
+     * {@link #shouldFilterApplicationInternal(int, SettingBase, PackageSetting, int)} call.
+     * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on
+     * initial scam and is null until {@link #onSystemReady()} is called.
+     */
+    private volatile SparseArray<SparseBooleanArray> mShouldFilterCache;
+
+    @VisibleForTesting(visibility = PRIVATE)
+    AppsFilter(StateProvider stateProvider,
+            FeatureConfig featureConfig,
+            String[] forceQueryableWhitelist,
             boolean systemAppsQueryable,
             @Nullable OverlayReferenceMapper.Provider overlayProvider) {
         mFeatureConfig = featureConfig;
@@ -121,8 +137,23 @@
         mSystemAppsQueryable = systemAppsQueryable;
         mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
                 overlayProvider);
+        mStateProvider = stateProvider;
     }
 
+    /**
+     * Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding
+     * the data with the package lock.
+     */
+    @VisibleForTesting(visibility = PRIVATE)
+    public interface StateProvider {
+        void runWithState(CurrentStateCallback callback);
+
+        interface CurrentStateCallback {
+            void currentState(ArrayMap<String, PackageSetting> settings, UserInfo[] users);
+        }
+    }
+
+    @VisibleForTesting(visibility = PRIVATE)
     public interface FeatureConfig {
 
         /** Called when the system is ready and components can be queried. */
@@ -139,6 +170,7 @@
 
         /**
          * Turns on logging for the given appId
+         *
          * @param enable true if logging should be enabled, false if disabled.
          */
         void enableLogging(int appId, boolean enable);
@@ -146,6 +178,7 @@
         /**
          * Initializes the package enablement state for the given package. This gives opportunity
          * to do any expensive operations ahead of the actual checks.
+         *
          * @param removed true if adding, false if removing
          */
         void updatePackageState(PackageSetting setting, boolean removed);
@@ -161,6 +194,7 @@
 
         @Nullable
         private SparseBooleanArray mLoggingEnabled = null;
+        private AppsFilter mAppsFilter;
 
         private FeatureConfigImpl(
                 PackageManagerInternal pmInternal, PackageManagerService.Injector injector) {
@@ -168,6 +202,10 @@
             mInjector = injector;
         }
 
+        public void setAppsFilter(AppsFilter filter) {
+            mAppsFilter = filter;
+        }
+
         @Override
         public void onSystemReady() {
             mFeatureEnabled = DeviceConfig.getBoolean(
@@ -235,11 +273,12 @@
         @Override
         public void onCompatChange(String packageName) {
             updateEnabledState(mPmInternal.getPackage(packageName));
+            mAppsFilter.updateShouldFilterCacheForPackage(packageName);
         }
 
         private void updateEnabledState(AndroidPackage pkg) {
             // TODO(b/135203078): Do not use toAppInfo
-            final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternal(
+            final boolean enabled = mInjector.getCompatibility().isChangeEnabled(
                     PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
             if (enabled) {
                 mDisabledPackages.remove(pkg.getPackageName());
@@ -267,7 +306,7 @@
         final boolean forceSystemAppsQueryable =
                 injector.getContext().getResources()
                         .getBoolean(R.bool.config_forceSystemPackagesQueryable);
-        final FeatureConfig featureConfig = new FeatureConfigImpl(pms, injector);
+        final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector);
         final String[] forcedQueryablePackageNames;
         if (forceSystemAppsQueryable) {
             // all system apps already queryable, no need to read and parse individual exceptions
@@ -280,8 +319,16 @@
                 forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern();
             }
         }
-        return new AppsFilter(featureConfig, forcedQueryablePackageNames,
-                forceSystemAppsQueryable, null);
+        final StateProvider stateProvider = command -> {
+            synchronized (injector.getLock()) {
+                command.currentState(injector.getSettings().mPackages,
+                        injector.getUserManagerInternal().getUserInfos());
+            }
+        };
+        AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
+                forcedQueryablePackageNames, forceSystemAppsQueryable, null);
+        featureConfig.setAppsFilter(appsFilter);
+        return appsFilter;
     }
 
     public FeatureConfig getFeatureConfig() {
@@ -404,27 +451,59 @@
      * visibility of the caller from the target.
      *
      * @param recipientUid the uid gaining visibility of the {@code visibleUid}.
-     * @param visibleUid the uid becoming visible to the {@recipientUid}
+     * @param visibleUid   the uid becoming visible to the {@recipientUid}
      */
     public void grantImplicitAccess(int recipientUid, int visibleUid) {
-        if (recipientUid != visibleUid
-                && mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) {
-            Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
+        if (recipientUid != visibleUid) {
+            if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) {
+                Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
+            }
+            if (mShouldFilterCache != null) {
+                // update the cache in a one-off manner since we've got all the information we need.
+                SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid);
+                if (visibleUids == null) {
+                    visibleUids = new SparseBooleanArray();
+                    mShouldFilterCache.put(recipientUid, visibleUids);
+                }
+                visibleUids.put(visibleUid, false);
+            }
         }
     }
 
     public void onSystemReady() {
+        mStateProvider.runWithState(new StateProvider.CurrentStateCallback() {
+            @Override
+            public void currentState(ArrayMap<String, PackageSetting> settings,
+                    UserInfo[] users) {
+                mShouldFilterCache = new SparseArray<>(users.length * settings.size());
+            }
+        });
         mFeatureConfig.onSystemReady();
         mOverlayReferenceMapper.rebuildIfDeferred();
+        updateEntireShouldFilterCache();
     }
 
     /**
      * Adds a package that should be considered when filtering visibility between apps.
      *
-     * @param newPkgSetting    the new setting being added
-     * @param existingSettings all other settings currently on the device.
+     * @param newPkgSetting the new setting being added
      */
-    public void addPackage(PackageSetting newPkgSetting,
+    public void addPackage(PackageSetting newPkgSetting) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
+        try {
+            mStateProvider.runWithState((settings, users) -> {
+                addPackageInternal(newPkgSetting, settings);
+                if (mShouldFilterCache != null) {
+                    updateShouldFilterCacheForPackage(
+                            null, newPkgSetting, settings, users, settings.size());
+                } // else, rebuild entire cache when system is ready
+            });
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    private void addPackageInternal(PackageSetting newPkgSetting,
             ArrayMap<String, PackageSetting> existingSettings) {
         if (Objects.equals("android", newPkgSetting.name)) {
             // let's set aside the framework signatures
@@ -438,79 +517,153 @@
             }
         }
 
-        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
-        try {
-            final AndroidPackage newPkg = newPkgSetting.pkg;
-            if (newPkg == null) {
-                // nothing to add
-                return;
-            }
+        final AndroidPackage newPkg = newPkgSetting.pkg;
+        if (newPkg == null) {
+            // nothing to add
+            return;
+        }
 
-            if (!newPkg.getProtectedBroadcasts().isEmpty()) {
-                mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts());
-                recomputeComponentVisibility(existingSettings, newPkg.getPackageName());
-            }
+        if (!newPkg.getProtectedBroadcasts().isEmpty()) {
+            mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts());
+            recomputeComponentVisibility(existingSettings, newPkg.getPackageName());
+        }
 
-            final boolean newIsForceQueryable =
-                    mForceQueryable.contains(newPkgSetting.appId)
-                            /* shared user that is already force queryable */
-                            || newPkg.isForceQueryable()
-                            || newPkgSetting.forceQueryableOverride
-                            || (newPkgSetting.isSystem() && (mSystemAppsQueryable
-                            || ArrayUtils.contains(mForceQueryableByDevicePackageNames,
-                            newPkg.getPackageName())));
-            if (newIsForceQueryable
-                    || (mSystemSigningDetails != null
-                            && isSystemSigned(mSystemSigningDetails, newPkgSetting))) {
-                mForceQueryable.add(newPkgSetting.appId);
-            }
+        final boolean newIsForceQueryable =
+                mForceQueryable.contains(newPkgSetting.appId)
+                        /* shared user that is already force queryable */
+                        || newPkg.isForceQueryable()
+                        || newPkgSetting.forceQueryableOverride
+                        || (newPkgSetting.isSystem() && (mSystemAppsQueryable
+                        || ArrayUtils.contains(mForceQueryableByDevicePackageNames,
+                        newPkg.getPackageName())));
+        if (newIsForceQueryable
+                || (mSystemSigningDetails != null
+                && isSystemSigned(mSystemSigningDetails, newPkgSetting))) {
+            mForceQueryable.add(newPkgSetting.appId);
+        }
 
-            for (int i = existingSettings.size() - 1; i >= 0; i--) {
-                final PackageSetting existingSetting = existingSettings.valueAt(i);
-                if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) {
-                    continue;
+        for (int i = existingSettings.size() - 1; i >= 0; i--) {
+            final PackageSetting existingSetting = existingSettings.valueAt(i);
+            if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) {
+                continue;
+            }
+            final AndroidPackage existingPkg = existingSetting.pkg;
+            // let's evaluate the ability of already added packages to see this new package
+            if (!newIsForceQueryable) {
+                if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) {
+                    mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId);
                 }
-                final AndroidPackage existingPkg = existingSetting.pkg;
-                // let's evaluate the ability of already added packages to see this new package
-                if (!newIsForceQueryable) {
-                    if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) {
-                        mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId);
-                    }
-                    if (canQueryViaPackage(existingPkg, newPkg)
-                            || canQueryAsInstaller(existingSetting, newPkg)) {
-                        mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
-                    }
-                }
-                // now we'll evaluate our new package's ability to see existing packages
-                if (!mForceQueryable.contains(existingSetting.appId)) {
-                    if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) {
-                        mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId);
-                    }
-                    if (canQueryViaPackage(newPkg, existingPkg)
-                            || canQueryAsInstaller(newPkgSetting, existingPkg)) {
-                        mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
-                    }
-                }
-                // if either package instruments the other, mark both as visible to one another
-                if (pkgInstruments(newPkgSetting, existingSetting)
-                        || pkgInstruments(existingSetting, newPkgSetting)) {
-                    mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
+                if (canQueryViaPackage(existingPkg, newPkg)
+                        || canQueryAsInstaller(existingSetting, newPkg)) {
                     mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
                 }
             }
-
-            int existingSize = existingSettings.size();
-            ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize);
-            for (int index = 0; index < existingSize; index++) {
-                PackageSetting pkgSetting = existingSettings.valueAt(index);
-                if (pkgSetting.pkg != null) {
-                    existingPkgs.put(pkgSetting.name, pkgSetting.pkg);
+            // now we'll evaluate our new package's ability to see existing packages
+            if (!mForceQueryable.contains(existingSetting.appId)) {
+                if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) {
+                    mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId);
+                }
+                if (canQueryViaPackage(newPkg, existingPkg)
+                        || canQueryAsInstaller(newPkgSetting, existingPkg)) {
+                    mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
                 }
             }
-            mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
-            mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/);
-        } finally {
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            // if either package instruments the other, mark both as visible to one another
+            if (pkgInstruments(newPkgSetting, existingSetting)
+                    || pkgInstruments(existingSetting, newPkgSetting)) {
+                mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId);
+                mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId);
+            }
+        }
+
+        int existingSize = existingSettings.size();
+        ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize);
+        for (int index = 0; index < existingSize; index++) {
+            PackageSetting pkgSetting = existingSettings.valueAt(index);
+            if (pkgSetting.pkg != null) {
+                existingPkgs.put(pkgSetting.name, pkgSetting.pkg);
+            }
+        }
+        mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
+        mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/);
+    }
+
+    private void removeAppIdFromVisibilityCache(int appId) {
+        if (mShouldFilterCache == null) {
+            return;
+        }
+        for (int i = mShouldFilterCache.size() - 1; i >= 0; i--) {
+            if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) {
+                mShouldFilterCache.removeAt(i);
+                continue;
+            }
+            SparseBooleanArray targetSparseArray = mShouldFilterCache.valueAt(i);
+            for (int j = targetSparseArray.size() - 1; j >= 0; j--) {
+                if (UserHandle.getAppId(targetSparseArray.keyAt(j)) == appId) {
+                    targetSparseArray.removeAt(j);
+                }
+            }
+        }
+    }
+
+    private void updateEntireShouldFilterCache() {
+        mStateProvider.runWithState((settings, users) -> {
+            mShouldFilterCache.clear();
+            for (int i = settings.size() - 1; i >= 0; i--) {
+                updateShouldFilterCacheForPackage(
+                        null /*skipPackage*/, settings.valueAt(i), settings, users, i);
+            }
+        });
+    }
+
+    public void onUsersChanged() {
+        if (mShouldFilterCache != null) {
+            updateEntireShouldFilterCache();
+        }
+    }
+
+    private void updateShouldFilterCacheForPackage(String packageName) {
+        mStateProvider.runWithState((settings, users) -> {
+            updateShouldFilterCacheForPackage(null /* skipPackage */, settings.get(packageName),
+                    settings, users, settings.size() /*maxIndex*/);
+        });
+
+    }
+
+    private void updateShouldFilterCacheForPackage(@Nullable String skipPackageName,
+            PackageSetting subjectSetting, ArrayMap<String, PackageSetting> allSettings,
+            UserInfo[] allUsers, int maxIndex) {
+        for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) {
+            PackageSetting otherSetting = allSettings.valueAt(i);
+            if (subjectSetting.appId == otherSetting.appId) {
+                continue;
+            }
+            //noinspection StringEquality
+            if (subjectSetting.name == skipPackageName || otherSetting.name == skipPackageName) {
+                continue;
+            }
+            final int userCount = allUsers.length;
+            final int appxUidCount = userCount * allSettings.size();
+            for (int su = 0; su < userCount; su++) {
+                int subjectUser = allUsers[su].id;
+                for (int ou = su; ou < userCount; ou++) {
+                    int otherUser = allUsers[ou].id;
+                    int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId);
+                    if (!mShouldFilterCache.contains(subjectUid)) {
+                        mShouldFilterCache.put(subjectUid, new SparseBooleanArray(appxUidCount));
+                    }
+                    int otherUid = UserHandle.getUid(otherUser, otherSetting.appId);
+                    if (!mShouldFilterCache.contains(otherUid)) {
+                        mShouldFilterCache.put(otherUid, new SparseBooleanArray(appxUidCount));
+                    }
+                    mShouldFilterCache.get(subjectUid).put(otherUid,
+                            shouldFilterApplicationInternal(
+                                    subjectUid, subjectSetting, otherSetting, otherUser));
+                    mShouldFilterCache.get(otherUid).put(subjectUid,
+                            shouldFilterApplicationInternal(
+                                    otherUid, otherSetting, subjectSetting, subjectUser));
+                }
+            }
         }
     }
 
@@ -561,6 +714,7 @@
             }
         }
     }
+
     /**
      * Fetches all app Ids that a given setting is currently visible to, per provided user. This
      * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see
@@ -569,11 +723,11 @@
      * If the setting is visible to all UIDs, null is returned. If an app is not visible to any
      * applications, the int array will be empty.
      *
-     * @param users the set of users that should be evaluated for this calculation
+     * @param users            the set of users that should be evaluated for this calculation
      * @param existingSettings the set of all package settings that currently exist on device
      * @return a SparseArray mapping userIds to a sorted int array of appIds that may view the
-     *         provided setting or null if the app is visible to all and no whitelist should be
-     *         applied.
+     * provided setting or null if the app is visible to all and no whitelist should be
+     * applied.
      */
     @Nullable
     public SparseArray<int[]> getVisibilityWhitelist(PackageSetting setting, int[] users,
@@ -618,52 +772,61 @@
     /**
      * Removes a package for consideration when filtering visibility between apps.
      *
-     * @param setting  the setting of the package being removed.
-     * @param allUsers array of all current users on device.
+     * @param setting the setting of the package being removed.
      */
-    public void removePackage(PackageSetting setting, int[] allUsers,
-            ArrayMap<String, PackageSetting> existingSettings) {
+    public void removePackage(PackageSetting setting) {
+        removeAppIdFromVisibilityCache(setting.appId);
+        mStateProvider.runWithState((settings, users) -> {
+            final int userCount = users.length;
+            for (int u = 0; u < userCount; u++) {
+                final int userId = users[u].id;
+                final int removingUid = UserHandle.getUid(userId, setting.appId);
+                mImplicitlyQueryable.remove(removingUid);
+                for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
+                    mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
+                }
+            }
+
+            mQueriesViaComponent.remove(setting.appId);
+            for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) {
+                mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId);
+            }
+            mQueriesViaPackage.remove(setting.appId);
+            for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
+                mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId);
+            }
+
+            // re-add other shared user members to re-establish visibility between them and other
+            // packages
+            if (setting.sharedUser != null) {
+                for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) {
+                    if (setting.sharedUser.packages.valueAt(i) == setting) {
+                        continue;
+                    }
+                    addPackageInternal(
+                            setting.sharedUser.packages.valueAt(i), settings);
+                }
+            }
+
+            if (!setting.pkg.getProtectedBroadcasts().isEmpty()) {
+                final String removingPackageName = setting.pkg.getPackageName();
+                mProtectedBroadcasts.clear();
+                mProtectedBroadcasts.addAll(
+                        collectProtectedBroadcasts(settings, removingPackageName));
+                recomputeComponentVisibility(settings, removingPackageName);
+            }
+
+            mOverlayReferenceMapper.removePkg(setting.name);
+            mFeatureConfig.updatePackageState(setting, true /*removed*/);
+
+            if (mShouldFilterCache != null) {
+                updateShouldFilterCacheForPackage(
+                        setting.name, setting, settings, users, settings.size());
+            }
+        });
         mForceQueryable.remove(setting.appId);
 
-        for (int u = 0; u < allUsers.length; u++) {
-            final int userId = allUsers[u];
-            final int removingUid = UserHandle.getUid(userId, setting.appId);
-            mImplicitlyQueryable.remove(removingUid);
-            for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
-                mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
-            }
-        }
 
-        mQueriesViaComponent.remove(setting.appId);
-        for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) {
-            mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId);
-        }
-        mQueriesViaPackage.remove(setting.appId);
-        for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
-            mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId);
-        }
-
-        // re-add other shared user members to re-establish visibility between them and other
-        // packages
-        if (setting.sharedUser != null) {
-            for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) {
-                if (setting.sharedUser.packages.valueAt(i) == setting) {
-                    continue;
-                }
-                addPackage(setting.sharedUser.packages.valueAt(i), existingSettings);
-            }
-        }
-
-        if (!setting.pkg.getProtectedBroadcasts().isEmpty()) {
-            final String removingPackageName = setting.pkg.getPackageName();
-            mProtectedBroadcasts.clear();
-            mProtectedBroadcasts.addAll(
-                    collectProtectedBroadcasts(existingSettings, removingPackageName));
-            recomputeComponentVisibility(existingSettings, removingPackageName);
-        }
-
-        mOverlayReferenceMapper.removePkg(setting.name);
-        mFeatureConfig.updatePackageState(setting, true /*removed*/);
     }
 
     /**
@@ -680,11 +843,32 @@
             PackageSetting targetPkgSetting, int userId) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication");
         try {
-
-            if (!shouldFilterApplicationInternal(
-                    callingUid, callingSetting, targetPkgSetting, userId)) {
+            if (callingUid < Process.FIRST_APPLICATION_UID
+                    || UserHandle.getAppId(callingUid) == targetPkgSetting.appId) {
                 return false;
             }
+            if (mShouldFilterCache != null) { // use cache
+                SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid);
+                final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId);
+                if (shouldFilterTargets == null) {
+                    Slog.wtf(TAG, "Encountered calling uid with no cached rules: " + callingUid);
+                    return true;
+                }
+                int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid);
+                if (indexOfTargetUid < 0) {
+                    Slog.w(TAG, "Encountered calling -> target with no cached rules: "
+                            + callingUid + " -> " + targetUid);
+                    return true;
+                }
+                if (!shouldFilterTargets.valueAt(indexOfTargetUid)) {
+                    return false;
+                }
+            } else {
+                if (!shouldFilterApplicationInternal(
+                        callingUid, callingSetting, targetPkgSetting, userId)) {
+                    return false;
+                }
+            }
             if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) {
                 log(callingSetting, targetPkgSetting, "BLOCKED");
             }
@@ -695,7 +879,7 @@
     }
 
     private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting,
-            PackageSetting targetPkgSetting, int userId) {
+            PackageSetting targetPkgSetting, int targetUserId) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal");
         try {
             final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
@@ -705,12 +889,6 @@
                 }
                 return false;
             }
-            if (callingUid < Process.FIRST_APPLICATION_UID) {
-                if (DEBUG_LOGGING) {
-                    Slog.d(TAG, "filtering skipped; " + callingUid + " is system");
-                }
-                return false;
-            }
             if (callingSetting == null) {
                 Slog.wtf(TAG, "No setting found for non system uid " + callingUid);
                 return true;
@@ -719,8 +897,14 @@
             final ArraySet<PackageSetting> callingSharedPkgSettings;
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof");
             if (callingSetting instanceof PackageSetting) {
-                callingPkgSetting = (PackageSetting) callingSetting;
-                callingSharedPkgSettings = null;
+                if (((PackageSetting) callingSetting).sharedUser == null) {
+                    callingPkgSetting = (PackageSetting) callingSetting;
+                    callingSharedPkgSettings = null;
+                } else {
+                    callingPkgSetting = null;
+                    callingSharedPkgSettings =
+                            ((PackageSetting) callingSetting).sharedUser.packages;
+                }
             } else {
                 callingPkgSetting = null;
                 callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages;
@@ -778,13 +962,19 @@
             }
 
             try {
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "hasPermission");
-                if (callingSetting.getPermissionsState().hasPermission(
-                        Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) {
-                    if (DEBUG_LOGGING) {
-                        log(callingSetting, targetPkgSetting, "has query-all permission");
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages");
+                if (callingPkgSetting != null) {
+                        if (callingPkgSetting.pkg != null
+                                && requestsQueryAllPackages(callingPkgSetting.pkg)) {
+                            return false;
+                        }
+                } else {
+                    for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
+                        AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).pkg;
+                        if (pkg != null && requestsQueryAllPackages(pkg)) {
+                            return false;
+                        }
                     }
-                    return false;
                 }
             } finally {
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -825,7 +1015,7 @@
 
             try {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable");
-                final int targetUid = UserHandle.getUid(userId, targetAppId);
+                final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
                 if (mImplicitlyQueryable.contains(callingUid, targetUid)) {
                     if (DEBUG_LOGGING) {
                         log(callingSetting, targetPkgSetting, "implicitly queryable for user");
@@ -863,13 +1053,20 @@
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
 
-
             return true;
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
 
+
+    private static boolean requestsQueryAllPackages(@NonNull AndroidPackage pkg) {
+        // we're not guaranteed to have permissions yet analyzed at package add, so we inspect the
+        // package directly
+        return pkg.getRequestedPermissions().contains(
+                Manifest.permission.QUERY_ALL_PACKAGES);
+    }
+
     /** Returns {@code true} if the source package instruments the target package. */
     private static boolean pkgInstruments(PackageSetting source, PackageSetting target) {
         try {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ae8b3a0..f3bc056 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12362,7 +12362,7 @@
             ksms.addScannedPackageLPw(pkg);
 
             mComponentResolver.addAllComponents(pkg, chatty);
-            mAppsFilter.addPackage(pkgSetting, mSettings.mPackages);
+            mAppsFilter.addPackage(pkgSetting);
 
             // Don't allow ephemeral applications to define new permissions groups.
             if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
@@ -12536,8 +12536,6 @@
 
     void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) {
         mComponentResolver.removeAllComponents(pkg, chatty);
-        mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()),
-                mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages);
         mPermissionManager.removeAllPermissions(pkg, chatty);
 
         final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations());
@@ -14264,7 +14262,7 @@
             // Okay!
             targetPackageSetting.setInstallerPackageName(installerPackageName);
             mSettings.addInstallerPackageNames(targetPackageSetting.installSource);
-            mAppsFilter.addPackage(targetPackageSetting, mSettings.mPackages);
+            mAppsFilter.addPackage(targetPackageSetting);
             scheduleWriteSettingsLocked();
         }
     }
@@ -18717,6 +18715,7 @@
                     clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true);
                     clearDefaultBrowserIfNeeded(packageName);
                     mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
+                    mAppsFilter.removePackage(getPackageSetting(packageName));
                     removedAppId = mSettings.removePackageLPw(packageName);
                     if (outInfo != null) {
                         outInfo.removedAppId = removedAppId;
@@ -23474,6 +23473,7 @@
             scheduleWritePackageRestrictionsLocked(userId);
             scheduleWritePackageListLocked(userId);
             primeDomainVerificationsLPw(userId);
+            mAppsFilter.onUsersChanged();
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index f205fde..4f21ee1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -23,6 +23,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -32,6 +33,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
+import android.content.pm.UserInfo;
 import android.content.pm.parsing.ParsingPackage;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedInstrumentation;
@@ -39,9 +41,11 @@
 import android.content.pm.parsing.component.ParsedProvider;
 import android.os.Build;
 import android.os.Process;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.SparseArray;
 
 import androidx.annotation.NonNull;
 
@@ -57,26 +61,36 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
 
 import java.security.cert.CertificateException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.IntFunction;
+import java.util.stream.Collectors;
 
 @Presubmit
 @RunWith(JUnit4.class)
 public class AppsFilterTest {
 
-    private static final int DUMMY_CALLING_UID = 10345;
-    private static final int DUMMY_TARGET_UID = 10556;
-    private static final int DUMMY_ACTOR_UID = 10656;
-    private static final int DUMMY_OVERLAY_UID = 10756;
-    private static final int DUMMY_ACTOR_TWO_UID = 10856;
+    private static final int DUMMY_CALLING_APPID = 10345;
+    private static final int DUMMY_TARGET_APPID = 10556;
+    private static final int DUMMY_ACTOR_APPID = 10656;
+    private static final int DUMMY_OVERLAY_APPID = 10756;
+    private static final int SYSTEM_USER = 0;
+    private static final int SECONDARY_USER = 10;
+    private static final int[] USER_ARRAY = {SYSTEM_USER, SECONDARY_USER};
+    private static final UserInfo[] USER_INFO_LIST = Arrays.stream(USER_ARRAY).mapToObj(
+            id -> new UserInfo(id, Integer.toString(id), 0)).toArray(UserInfo[]::new);
 
     @Mock
     AppsFilter.FeatureConfig mFeatureConfigMock;
+    @Mock
+    AppsFilter.StateProvider mStateProvider;
 
     private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>();
 
@@ -170,15 +184,24 @@
         mExisting = new ArrayMap<>();
 
         MockitoAnnotations.initMocks(this);
+        doAnswer(invocation -> {
+            ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
+                    .currentState(mExisting, USER_INFO_LIST);
+            return null;
+        }).when(mStateProvider)
+                .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
+
         when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
-        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
-                .thenReturn(true);
+        when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))).thenAnswer(
+                (Answer<Boolean>) invocation ->
+                        ((AndroidPackage)invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
+                                >= Build.VERSION_CODES.R);
     }
 
     @Test
     public void testSystemReadyPropogates() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         appsFilter.onSystemReady();
         verify(mFeatureConfigMock).onSystemReady();
     }
@@ -186,22 +209,23 @@
     @Test
     public void testQueriesAction_FilterMatches() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_UID);
+                pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID);
+                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         final Signature frameworkSignature = Mockito.mock(Signature.class);
         final PackageParser.SigningDetails frameworkSigningDetails =
                 new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1);
@@ -211,164 +235,174 @@
                 b -> b.setSigningDetails(frameworkSigningDetails));
         appsFilter.onSystemReady();
 
-        final int activityUid = DUMMY_TARGET_UID;
+        final int activityUid = DUMMY_TARGET_APPID;
         PackageSetting targetActivity = simulateAddPackage(appsFilter,
                 pkg("com.target.activity", new IntentFilter("TEST_ACTION")), activityUid);
-        final int receiverUid = DUMMY_TARGET_UID + 1;
+        final int receiverUid = DUMMY_TARGET_APPID + 1;
         PackageSetting targetReceiver = simulateAddPackage(appsFilter,
                 pkgWithReceiver("com.target.receiver", new IntentFilter("TEST_ACTION")),
                 receiverUid);
-        final int callingUid = DUMMY_CALLING_UID;
+        final int callingUid = DUMMY_CALLING_APPID;
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkg("com.calling.action", new Intent("TEST_ACTION")), callingUid);
-        final int wildcardUid = DUMMY_CALLING_UID + 1;
+        final int wildcardUid = DUMMY_CALLING_APPID + 1;
         PackageSetting callingWildCard = simulateAddPackage(appsFilter,
                 pkg("com.calling.wildcard", new Intent("*")), wildcardUid);
 
-        assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity, 0));
-        assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver, 0));
+        assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity,
+                SYSTEM_USER));
+        assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver,
+                SYSTEM_USER));
 
         assertFalse(appsFilter.shouldFilterApplication(
-                wildcardUid, callingWildCard, targetActivity, 0));
+                wildcardUid, callingWildCard, targetActivity, SYSTEM_USER));
         assertTrue(appsFilter.shouldFilterApplication(
-                wildcardUid, callingWildCard, targetReceiver, 0));
+                wildcardUid, callingWildCard, targetReceiver, SYSTEM_USER));
     }
 
     @Test
     public void testQueriesProvider_FilterMatches() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID);
+                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.some.other.package", "com.some.authority"),
-                DUMMY_CALLING_UID);
+                DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesDifferentProvider_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID);
+                pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.some.other.package", "com.some.other.authority"),
-                DUMMY_CALLING_UID);
+                DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkgWithProvider("com.some.package", "com.some.authority;com.some.other.authority"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.some.other.package", "com.some.authority"),
-                DUMMY_CALLING_UID);
+                DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesAction_NoMatchingAction_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID);
+                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
-        PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package",
-                        new Intent("TEST_ACTION"))
-                        .setTargetSdkVersion(Build.VERSION_CODES.P),
-                DUMMY_CALLING_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
+        ParsingPackage callingPkg = pkg("com.some.other.package",
+                new Intent("TEST_ACTION"))
+                .setTargetSdkVersion(Build.VERSION_CODES.P);
+        PackageSetting calling = simulateAddPackage(appsFilter, callingPkg,
+                DUMMY_CALLING_APPID);
 
-        when(mFeatureConfigMock.packageIsEnabled(calling.pkg)).thenReturn(false);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testNoQueries_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testForceQueryable_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID);
+                pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
+                        false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID,
+                pkg("com.some.package"), DUMMY_TARGET_APPID,
                 setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
 
     @Test
     public void testSystemSignedTarget_DoesntFilter() throws CertificateException {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         appsFilter.onSystemReady();
 
         final Signature frameworkSignature = Mockito.mock(Signature.class);
@@ -382,62 +416,67 @@
         simulateAddPackage(appsFilter, pkg("android"), 1000,
                 b -> b.setSigningDetails(frameworkSigningDetails));
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID,
+                DUMMY_TARGET_APPID,
                 b -> b.setSigningDetails(frameworkSigningDetails)
                         .setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID,
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID,
                 b -> b.setSigningDetails(otherSigningDetails));
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
+                        false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
 
     @Test
     public void testSystemQueryable_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{},
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{},
                         true /* system force queryable */, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID,
+                pkg("com.some.package"), DUMMY_TARGET_APPID,
                 setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testQueriesPackage_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package", "com.some.package"), DUMMY_CALLING_UID);
+                pkg("com.some.other.package", "com.some.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
@@ -445,63 +484,67 @@
         when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
                 .thenReturn(false);
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(
-                appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID);
+                appsFilter, pkg("com.some.package"), DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(
-                appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_UID);
+                appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testSystemUid_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
 
-        assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(SYSTEM_USER, null, target, SYSTEM_USER));
         assertFalse(appsFilter.shouldFilterApplication(Process.FIRST_APPLICATION_UID - 1,
-                null, target, 0));
+                null, target, SYSTEM_USER));
     }
 
     @Test
     public void testNonSystemUid_NoCallingSetting_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter,
-                pkg("com.some.package"), DUMMY_TARGET_UID);
+                pkg("com.some.package"), DUMMY_TARGET_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, null, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, null, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testNoTargetPackage_filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = new PackageSettingBuilder()
+                .setAppId(DUMMY_TARGET_APPID)
                 .setName("com.some.package")
                 .setCodePath("/")
                 .setResourcePath("/")
                 .setPVersionCode(1L)
                 .build();
         PackageSetting calling = simulateAddPackage(appsFilter,
-                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID);
+                pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID);
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
@@ -516,7 +559,11 @@
                 .setOverlayTargetName("overlayableName");
         ParsingPackage actor = pkg("com.some.package.actor");
 
-        final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false,
+        final AppsFilter appsFilter = new AppsFilter(
+                mStateProvider,
+                mFeatureConfigMock,
+                new String[]{},
+                false,
                 new OverlayReferenceMapper.Provider() {
                     @Nullable
                     @Override
@@ -544,31 +591,34 @@
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
-        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID);
-        PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID);
-        PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_UID);
+        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID);
+        PackageSetting overlaySetting =
+                simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID);
+        PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_APPID);
 
         // Actor can see both target and overlay
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting,
-                targetSetting, 0));
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting,
-                overlaySetting, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
+                targetSetting, SYSTEM_USER));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
+                overlaySetting, SYSTEM_USER));
 
         // But target/overlay can't see each other
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting,
-                overlaySetting, 0));
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting,
-                targetSetting, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, targetSetting,
+                overlaySetting, SYSTEM_USER));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting,
+                targetSetting, SYSTEM_USER));
 
         // And can't see the actor
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting,
-                actorSetting, 0));
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting,
-                actorSetting, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, targetSetting,
+                actorSetting, SYSTEM_USER));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting,
+                actorSetting, SYSTEM_USER));
     }
 
     @Test
     public void testActsOnTargetOfOverlayThroughSharedUser() throws Exception {
+//        Debug.waitForDebugger();
+
         final String actorName = "overlay://test/actorName";
 
         ParsingPackage target = pkg("com.some.package.target")
@@ -580,7 +630,11 @@
         ParsingPackage actorOne = pkg("com.some.package.actor.one");
         ParsingPackage actorTwo = pkg("com.some.package.actor.two");
 
-        final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false,
+        final AppsFilter appsFilter = new AppsFilter(
+                mStateProvider,
+                mFeatureConfigMock,
+                new String[]{},
+                false,
                 new OverlayReferenceMapper.Provider() {
                     @Nullable
                     @Override
@@ -609,108 +663,114 @@
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
-        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID);
-        PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID);
-        PackageSetting actorOneSetting = simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_UID);
-        PackageSetting actorTwoSetting = simulateAddPackage(appsFilter, actorTwo,
-                DUMMY_ACTOR_TWO_UID);
-
+        PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID);
         SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser",
-                actorOneSetting.pkgFlags, actorOneSetting.pkgPrivateFlags);
-        actorSharedSetting.addPackage(actorOneSetting);
-        actorSharedSetting.addPackage(actorTwoSetting);
+                targetSetting.pkgFlags, targetSetting.pkgPrivateFlags);
+        PackageSetting overlaySetting =
+                simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID);
+        simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_APPID,
+                null /*settingBuilder*/, actorSharedSetting);
+        simulateAddPackage(appsFilter, actorTwo, DUMMY_ACTOR_APPID,
+                null /*settingBuilder*/, actorSharedSetting);
+
 
         // actorTwo can see both target and overlay
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting,
-                targetSetting, 0));
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting,
-                overlaySetting, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting,
+                targetSetting, SYSTEM_USER));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting,
+                overlaySetting, SYSTEM_USER));
     }
 
     @Test
     public void testInitiatingApp_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
-                DUMMY_CALLING_UID, withInstallSource(target.name, null, null, false));
+                DUMMY_CALLING_APPID, withInstallSource(target.name, null, null, false));
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testUninstalledInitiatingApp_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
-                DUMMY_CALLING_UID, withInstallSource(target.name, null, null, true));
+                DUMMY_CALLING_APPID, withInstallSource(target.name, null, null, true));
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testOriginatingApp_Filters() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
-                DUMMY_CALLING_UID, withInstallSource(null, target.name, null, false));
+                DUMMY_CALLING_APPID, withInstallSource(null, target.name, null, false));
 
-        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testInstallingApp_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
-                DUMMY_CALLING_UID, withInstallSource(null, null, target.name, false));
+                DUMMY_CALLING_APPID, withInstallSource(null, null, target.name, false));
 
-        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0));
+        assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+                SYSTEM_USER));
     }
 
     @Test
     public void testInstrumentation_DoesntFilter() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
-                DUMMY_TARGET_UID);
+                DUMMY_TARGET_APPID);
         PackageSetting instrumentation = simulateAddPackage(appsFilter,
                 pkgWithInstrumentation("com.some.other.package", "com.some.package"),
-                DUMMY_CALLING_UID);
+                DUMMY_CALLING_APPID);
 
         assertFalse(
-                appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, instrumentation, target, 0));
+                appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
+                        SYSTEM_USER));
         assertFalse(
-                appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, target, instrumentation, 0));
+                appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
+                        SYSTEM_USER));
     }
 
     @Test
     public void testWhoCanSee() throws Exception {
         final AppsFilter appsFilter =
-                new AppsFilter(mFeatureConfigMock, new String[]{}, false, null);
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null);
         simulateAddBasicAndroid(appsFilter);
         appsFilter.onSystemReady();
 
@@ -718,6 +778,7 @@
         final int seesNothingAppId = Process.FIRST_APPLICATION_UID;
         final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1;
         final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
+
         PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId);
         PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("com.some.package"),
                 seesNothingAppId);
@@ -727,23 +788,25 @@
                 pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
                 queriesProviderAppId);
 
-        final int[] systemFilter =
-                appsFilter.getVisibilityWhitelist(system, new int[]{0}, mExisting).get(0);
-        assertThat(toList(systemFilter), empty());
+        final SparseArray<int[]> systemFilter =
+                appsFilter.getVisibilityWhitelist(system, USER_ARRAY, mExisting);
+        assertThat(toList(systemFilter.get(SYSTEM_USER)), empty());
 
-        final int[] seesNothingFilter =
-                appsFilter.getVisibilityWhitelist(seesNothing, new int[]{0}, mExisting).get(0);
-        assertThat(toList(seesNothingFilter),
+        final SparseArray<int[]> seesNothingFilter =
+                appsFilter.getVisibilityWhitelist(seesNothing, USER_ARRAY, mExisting);
+        assertThat(toList(seesNothingFilter.get(SYSTEM_USER)),
+                contains(seesNothingAppId));
+        assertThat(toList(seesNothingFilter.get(SECONDARY_USER)),
                 contains(seesNothingAppId));
 
-        final int[] hasProviderFilter =
-                appsFilter.getVisibilityWhitelist(hasProvider, new int[]{0}, mExisting).get(0);
-        assertThat(toList(hasProviderFilter),
+        final SparseArray<int[]> hasProviderFilter =
+                appsFilter.getVisibilityWhitelist(hasProvider, USER_ARRAY, mExisting);
+        assertThat(toList(hasProviderFilter.get(SYSTEM_USER)),
                 contains(hasProviderAppId, queriesProviderAppId));
 
-        int[] queriesProviderFilter =
-                appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0);
-        assertThat(toList(queriesProviderFilter),
+        SparseArray<int[]> queriesProviderFilter =
+                appsFilter.getVisibilityWhitelist(queriesProvider, USER_ARRAY, mExisting);
+        assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
                 contains(queriesProviderAppId));
 
         // provider read
@@ -751,8 +814,8 @@
 
         // ensure implicit access is included in the filter
         queriesProviderFilter =
-                appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0);
-        assertThat(toList(queriesProviderFilter),
+                appsFilter.getVisibilityWhitelist(queriesProvider, USER_ARRAY, mExisting);
+        assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
                 contains(hasProviderAppId, queriesProviderAppId));
     }
 
@@ -779,11 +842,17 @@
 
     private PackageSetting simulateAddPackage(AppsFilter filter,
             ParsingPackage newPkgBuilder, int appId) {
-        return simulateAddPackage(filter, newPkgBuilder, appId, null);
+        return simulateAddPackage(filter, newPkgBuilder, appId, null /*settingBuilder*/);
     }
 
     private PackageSetting simulateAddPackage(AppsFilter filter,
             ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
+        return simulateAddPackage(filter, newPkgBuilder, appId, action, null /*sharedUserSetting*/);
+    }
+
+    private PackageSetting simulateAddPackage(AppsFilter filter,
+                ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action,
+            @Nullable SharedUserSetting sharedUserSetting) {
         AndroidPackage newPkg = ((ParsedPackage) newPkgBuilder.hideAsParsed()).hideAsFinal();
 
         final PackageSettingBuilder settingBuilder = new PackageSettingBuilder()
@@ -795,8 +864,12 @@
                 .setPVersionCode(1L);
         final PackageSetting setting =
                 (action == null ? settingBuilder : action.withBuilder(settingBuilder)).build();
-        filter.addPackage(setting, mExisting);
         mExisting.put(newPkg.getPackageName(), setting);
+        if (sharedUserSetting != null) {
+            sharedUserSetting.addPackage(setting);
+            setting.sharedUser = sharedUserSetting;
+        }
+        filter.addPackage(setting);
         return setting;
     }
 
@@ -809,4 +882,3 @@
         return setting -> setting.setInstallSource(installSource);
     }
 }
-