Merge changes I301a7f78,Id9dbd4e5
* changes: Improve the cache rebuild latency of AppsFilter on boot #2 Improve the cache rebuild latency of AppsFilter on boot
This commit is contained in:
@@ -41,6 +41,7 @@ import com.android.internal.util.function.QuadFunction;
|
||||
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 com.android.server.utils.WatchedSparseSetArray;
|
||||
|
||||
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 @@ 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
|
||||
@@ -410,9 +409,11 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot {
|
||||
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 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot {
|
||||
+ 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)}
|
||||
|
||||
@@ -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,9 +62,11 @@ 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;
|
||||
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 com.android.server.utils.Watcher;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -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);
|
||||
@@ -1066,7 +1047,6 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable,
|
||||
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 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable,
|
||||
// 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 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable,
|
||||
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);
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,7 @@ import static org.hamcrest.Matchers.contains;
|
||||
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 @@ public class AppsFilterImplTest {
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user