Improve the cache rebuild latency of AppsFilter on boot #2

Instead of iterating the list of all shared users, using
the getSharedUser api to get a better lookup time.

Bug: 262515424
Test: atest CtsAppEnumerationTestCases
Change-Id: I301a7f78231e1430e965bccd7870e387f77810e9
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index 4f7059d..1021e07 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -41,6 +41,7 @@
 import com.android.server.om.OverlayReferenceMapper;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.snapshot.PackageDataSnapshot;
 import com.android.server.utils.SnapshotCache;
 import com.android.server.utils.Watched;
@@ -51,7 +52,6 @@
 
 import java.io.PrintWriter;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -409,9 +409,11 @@
                 final PackageStateInternal packageState = (PackageStateInternal) callingSetting;
                 if (packageState.hasSharedUser()) {
                     callingPkgSetting = null;
-                    callingSharedPkgSettings.addAll(getSharedUserPackages(
-                            packageState.getSharedUserAppId(), snapshot.getAllSharedUsers()));
-
+                    final SharedUserApi sharedUserApi =
+                            snapshot.getSharedUser(packageState.getSharedUserAppId());
+                    if (sharedUserApi != null) {
+                        callingSharedPkgSettings.addAll(sharedUserApi.getPackageStates());
+                    }
                 } else {
                     callingPkgSetting = packageState;
                 }
@@ -698,17 +700,6 @@
                         + targetPkgSetting + " " + description);
     }
 
-    protected ArraySet<? extends PackageStateInternal> getSharedUserPackages(int sharedUserAppId,
-            Collection<SharedUserSetting> sharedUserSettings) {
-        for (SharedUserSetting setting : sharedUserSettings) {
-            if (setting.mAppId != sharedUserAppId) {
-                continue;
-            }
-            return setting.getPackageStates();
-        }
-        return new ArraySet<>();
-    }
-
     /**
      * See {@link AppsFilterSnapshot#dumpQueries(PrintWriter, Integer, DumpState, int[],
      * QuadFunction)}
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index f73deb3..5ff1909b 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -66,6 +66,7 @@
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.SharedUserApi;
 import com.android.server.pm.pkg.component.ParsedInstrumentation;
 import com.android.server.pm.pkg.component.ParsedPermission;
 import com.android.server.pm.pkg.component.ParsedUsesPermission;
@@ -80,7 +81,6 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 
@@ -1047,7 +1047,6 @@
         final ArrayMap<String, ? extends PackageStateInternal> settings =
                 snapshot.getPackageStates();
         final UserInfo[] users = snapshot.getUserInfos();
-        final Collection<SharedUserSetting> sharedUserSettings = snapshot.getAllSharedUsers();
         final int userCount = users.length;
         if (!isReplace || !retainImplicitGrantOnReplace) {
             synchronized (mImplicitlyQueryableLock) {
@@ -1156,9 +1155,11 @@
         // shared user members to re-establish visibility between them and other packages.
         // NOTE: this must come after all removals from data structures but before we update the
         // cache
-        if (setting.hasSharedUser()) {
+        final SharedUserApi sharedUserApi = setting.hasSharedUser()
+                ? snapshot.getSharedUser(setting.getSharedUserAppId()) : null;
+        if (sharedUserApi != null) {
             final ArraySet<? extends PackageStateInternal> sharedUserPackages =
-                    getSharedUserPackages(setting.getSharedUserAppId(), sharedUserSettings);
+                    sharedUserApi.getPackageStates();
             for (int i = sharedUserPackages.size() - 1; i >= 0; i--) {
                 if (sharedUserPackages.valueAt(i) == setting) {
                     continue;
@@ -1171,9 +1172,9 @@
         if (mCacheReady) {
             removeAppIdFromVisibilityCache(setting.getAppId());
 
-            if (setting.hasSharedUser()) {
+            if (sharedUserApi != null) {
                 final ArraySet<? extends PackageStateInternal> sharedUserPackages =
-                        getSharedUserPackages(setting.getSharedUserAppId(), sharedUserSettings);
+                        sharedUserApi.getPackageStates();
                 for (int i = sharedUserPackages.size() - 1; i >= 0; i--) {
                     PackageStateInternal siblingSetting =
                             sharedUserPackages.valueAt(i);
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
index 3575b57..7c4b9f8 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -225,6 +226,13 @@
         when(mSnapshot.getPackageStates()).thenAnswer(x -> mExisting);
         when(mSnapshot.getAllSharedUsers()).thenReturn(mSharedUserSettings);
         when(mSnapshot.getUserInfos()).thenReturn(USER_INFO_LIST);
+        when(mSnapshot.getSharedUser(anyInt())).thenAnswer(invocation -> {
+            final int sharedUserAppId = invocation.getArgument(0);
+            return mSharedUserSettings.stream()
+                    .filter(sharedUserSetting -> sharedUserSetting.getAppId() == sharedUserAppId)
+                    .findAny()
+                    .orElse(null);
+        });
         when(mPmInternal.snapshot()).thenReturn(mSnapshot);
 
         // Can't mock postDelayed because of some weird bug in Mockito.