Improve the cache rebuild latency of AppsFilter on boot
- Moving the rebuild task from background thread to the service thread in order to get more cpu resource for visibility computing. - Using a thread pool to compute component visibility of all packages on the device in parallel. It can improve the latency if lots of packages on device. Bug: 257339238 Bug: 262515424 Test: atest CtsAppEnumerationTestCases Change-Id: Id9dbd4e55fa8fdd0a3f07e3ff7b953e1d9c5f1a9
This commit is contained in:
@@ -137,10 +137,9 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot {
|
||||
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
|
||||
|
||||
@@ -35,7 +35,6 @@ import static com.android.server.pm.AppsFilterUtils.canQueryAsInstaller;
|
||||
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,6 +62,7 @@ import com.android.internal.util.FrameworkStatsLog;
|
||||
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;
|
||||
@@ -185,13 +185,13 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable,
|
||||
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 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable,
|
||||
}
|
||||
AppsFilterImpl appsFilter = new AppsFilterImpl(featureConfig,
|
||||
forcedQueryablePackageNames, forceSystemAppsQueryable, null,
|
||||
injector.getBackgroundHandler());
|
||||
injector.getHandler());
|
||||
featureConfig.setAppsFilter(appsFilter);
|
||||
return appsFilter;
|
||||
}
|
||||
@@ -797,7 +797,7 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable,
|
||||
|
||||
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 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable,
|
||||
*/
|
||||
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);
|
||||
|
||||
@@ -77,6 +77,6 @@ public final class AppsFilterSnapshotImpl extends AppsFilterBase {
|
||||
mCacheEnabled = orig.mCacheEnabled;
|
||||
mShouldFilterCacheSnapshot = new SnapshotCache.Sealed<>();
|
||||
|
||||
mBackgroundHandler = null;
|
||||
mHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 @@ final class AppsFilterUtils {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,14 @@ public class WatchedSparseSetArray<T> extends WatchableImpl implements Snappable
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user