Merge changes I301a7f78,Id9dbd4e5
* changes:
Improve the cache rebuild latency of AppsFilter on boot #2
Improve the cache rebuild latency of AppsFilter on boot
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index b4792c6..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;
@@ -137,10 +137,9 @@
protected SnapshotCache<WatchedSparseSetArray<Integer>> mQueryableViaUsesPermissionSnapshot;
/**
- * Handler for running reasonably short background tasks such as building the initial
- * visibility cache.
+ * Handler for running tasks such as building the initial visibility cache.
*/
- protected Handler mBackgroundHandler;
+ protected Handler mHandler;
/**
* Pending full recompute of mQueriesViaComponent. Occurs when a package adds a new set of
@@ -410,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;
}
@@ -699,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 5b837f1..5ff1909b 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -35,7 +35,6 @@
import static com.android.server.pm.AppsFilterUtils.canQueryViaComponents;
import static com.android.server.pm.AppsFilterUtils.canQueryViaPackage;
import static com.android.server.pm.AppsFilterUtils.canQueryViaUsesLibrary;
-import static com.android.server.pm.AppsFilterUtils.requestsQueryAllPackages;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -63,9 +62,11 @@
import com.android.server.FgThread;
import com.android.server.compat.CompatChange;
import com.android.server.om.OverlayReferenceMapper;
+import com.android.server.pm.AppsFilterUtils.ParallelComputeComponentVisibility;
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;
@@ -185,13 +185,13 @@
String[] forceQueryableList,
boolean systemAppsQueryable,
@Nullable OverlayReferenceMapper.Provider overlayProvider,
- Handler backgroundHandler) {
+ Handler handler) {
mFeatureConfig = featureConfig;
mForceQueryableByDevicePackageNames = forceQueryableList;
mSystemAppsQueryable = systemAppsQueryable;
mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
overlayProvider);
- mBackgroundHandler = backgroundHandler;
+ mHandler = handler;
mShouldFilterCache = new WatchedSparseBooleanMatrix();
mShouldFilterCacheSnapshot = new SnapshotCache.Auto<>(
mShouldFilterCache, mShouldFilterCache, "AppsFilter.mShouldFilterCache");
@@ -428,7 +428,7 @@
}
AppsFilterImpl appsFilter = new AppsFilterImpl(featureConfig,
forcedQueryablePackageNames, forceSystemAppsQueryable, null,
- injector.getBackgroundHandler());
+ injector.getHandler());
featureConfig.setAppsFilter(appsFilter);
return appsFilter;
}
@@ -797,7 +797,7 @@
private void updateEntireShouldFilterCacheAsync(PackageManagerInternal pmInternal,
long delayMs, int reason) {
- mBackgroundHandler.postDelayed(() -> {
+ mHandler.postDelayed(() -> {
if (!mCacheValid.compareAndSet(CACHE_INVALID, CACHE_VALID)) {
// Cache is already valid.
return;
@@ -990,34 +990,15 @@
*/
private void recomputeComponentVisibility(
ArrayMap<String, ? extends PackageStateInternal> existingSettings) {
+ final WatchedArraySet<String> protectedBroadcasts;
+ synchronized (mProtectedBroadcastsLock) {
+ protectedBroadcasts = mProtectedBroadcasts.snapshot();
+ }
+ final ParallelComputeComponentVisibility computer = new ParallelComputeComponentVisibility(
+ existingSettings, mForceQueryable, protectedBroadcasts);
synchronized (mQueriesViaComponentLock) {
mQueriesViaComponent.clear();
- }
- for (int i = existingSettings.size() - 1; i >= 0; i--) {
- PackageStateInternal setting = existingSettings.valueAt(i);
- if (setting.getPkg() == null || requestsQueryAllPackages(setting.getPkg())) {
- continue;
- }
- for (int j = existingSettings.size() - 1; j >= 0; j--) {
- if (i == j) {
- continue;
- }
- final PackageStateInternal otherSetting = existingSettings.valueAt(j);
- if (otherSetting.getPkg() == null || mForceQueryable.contains(
- otherSetting.getAppId())) {
- continue;
- }
- final boolean canQueryViaComponents;
- synchronized (mProtectedBroadcastsLock) {
- canQueryViaComponents = canQueryViaComponents(setting.getPkg(),
- otherSetting.getPkg(), mProtectedBroadcasts);
- }
- if (canQueryViaComponents) {
- synchronized (mQueriesViaComponentLock) {
- mQueriesViaComponent.add(setting.getAppId(), otherSetting.getAppId());
- }
- }
- }
+ computer.execute(mQueriesViaComponent);
}
mQueriesViaComponentRequireRecompute.set(false);
@@ -1066,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) {
@@ -1175,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;
@@ -1190,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/core/java/com/android/server/pm/AppsFilterSnapshotImpl.java b/services/core/java/com/android/server/pm/AppsFilterSnapshotImpl.java
index 4e268a2..9bfcabb 100644
--- a/services/core/java/com/android/server/pm/AppsFilterSnapshotImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterSnapshotImpl.java
@@ -77,6 +77,6 @@
mCacheEnabled = orig.mCacheEnabled;
mShouldFilterCacheSnapshot = new SnapshotCache.Sealed<>();
- mBackgroundHandler = null;
+ mHandler = null;
}
}
diff --git a/services/core/java/com/android/server/pm/AppsFilterUtils.java b/services/core/java/com/android/server/pm/AppsFilterUtils.java
index bf28479..8da1d21 100644
--- a/services/core/java/com/android/server/pm/AppsFilterUtils.java
+++ b/services/core/java/com/android/server/pm/AppsFilterUtils.java
@@ -16,24 +16,36 @@
package com.android.server.pm;
+import static android.os.Process.THREAD_PRIORITY_DEFAULT;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.IntentFilter;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.component.ParsedComponent;
import com.android.server.pm.pkg.component.ParsedIntentInfo;
import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.component.ParsedProvider;
import com.android.server.utils.WatchedArraySet;
+import com.android.server.utils.WatchedSparseSetArray;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
final class AppsFilterUtils {
public static boolean requestsQueryAllPackages(@NonNull AndroidPackage pkg) {
@@ -169,4 +181,93 @@
intent.getData(), intent.getCategories(), "AppsFilter", true,
protectedBroadcasts != null ? protectedBroadcasts.untrackedStorage() : null) > 0;
}
+
+ /**
+ * A helper class for parallel computing of component visibility of all packages on the device.
+ */
+ public static final class ParallelComputeComponentVisibility {
+ private static final int MAX_THREADS = 4;
+
+ private final ArrayMap<String, ? extends PackageStateInternal> mExistingSettings;
+ private final WatchedArraySet<Integer> mForceQueryable;
+ private final WatchedArraySet<String> mProtectedBroadcasts;
+
+ ParallelComputeComponentVisibility(
+ @NonNull ArrayMap<String, ? extends PackageStateInternal> existingSettings,
+ @NonNull WatchedArraySet<Integer> forceQueryable,
+ @NonNull WatchedArraySet<String> protectedBroadcasts) {
+ mExistingSettings = existingSettings;
+ mForceQueryable = forceQueryable;
+ mProtectedBroadcasts = protectedBroadcasts;
+ }
+
+ /**
+ * Computes component visibility of all packages in parallel from a thread pool.
+ */
+ void execute(@NonNull WatchedSparseSetArray<Integer> outQueriesViaComponent) {
+ final ExecutorService pool = ConcurrentUtils.newFixedThreadPool(
+ MAX_THREADS, ParallelComputeComponentVisibility.class.getSimpleName(),
+ THREAD_PRIORITY_DEFAULT);
+ try {
+ final List<Pair<PackageState, Future<ArraySet<Integer>>>> futures =
+ new ArrayList<>();
+ for (int i = mExistingSettings.size() - 1; i >= 0; i--) {
+ final PackageStateInternal setting = mExistingSettings.valueAt(i);
+ final AndroidPackage pkg = setting.getPkg();
+ if (pkg == null || requestsQueryAllPackages(pkg)) {
+ continue;
+ }
+ if (pkg.getQueriesIntents().isEmpty()
+ && pkg.getQueriesProviders().isEmpty()) {
+ continue;
+ }
+ futures.add(new Pair(setting,
+ pool.submit(() -> getVisibleListOfQueryViaComponents(setting))));
+ }
+ for (int i = 0; i < futures.size(); i++) {
+ final int appId = futures.get(i).first.getAppId();
+ final Future<ArraySet<Integer>> future = futures.get(i).second;
+ try {
+ final ArraySet<Integer> visibleList = future.get();
+ if (visibleList.size() != 0) {
+ outQueriesViaComponent.addAll(appId, visibleList);
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ } finally {
+ pool.shutdownNow();
+ }
+ }
+
+ /**
+ * Returns a set of app IDs that contains components resolved by the queries intent
+ * or provider that declared in the manifest of the querying package.
+ *
+ * @param setting The package to query.
+ * @return A set of app IDs.
+ */
+ @NonNull
+ private ArraySet<Integer> getVisibleListOfQueryViaComponents(
+ @NonNull PackageStateInternal setting) {
+ final ArraySet<Integer> result = new ArraySet();
+ for (int i = mExistingSettings.size() - 1; i >= 0; i--) {
+ final PackageStateInternal otherSetting = mExistingSettings.valueAt(i);
+ if (setting.getAppId() == otherSetting.getAppId()) {
+ continue;
+ }
+ if (otherSetting.getPkg() == null || mForceQueryable.contains(
+ otherSetting.getAppId())) {
+ continue;
+ }
+ final boolean canQuery = canQueryViaComponents(
+ setting.getPkg(), otherSetting.getPkg(), mProtectedBroadcasts);
+ if (canQuery) {
+ result.add(otherSetting.getAppId());
+ }
+ }
+ return result;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseSetArray.java b/services/core/java/com/android/server/utils/WatchedSparseSetArray.java
index 77750ed..0386e66 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseSetArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseSetArray.java
@@ -65,6 +65,14 @@
}
/**
+ * Add a set of values for key n.
+ */
+ public void addAll(int n, ArraySet<T> values) {
+ mStorage.addAll(n, values);
+ onChanged();
+ }
+
+ /**
* Removes all mappings from this SparseSetArray.
*/
public void clear() {
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.