Revert "Revert "[AppsFilter] read-only interface for snapshots""
This reverts commit 2e06c6008e.
Reason for revert: fixing the boot time regression
Provides a read-only interface that is used by computer and snapshots.
It fixes the data conflicts when AppsFilter is changed while a snapshot is
taken.
Test: atest AppsFilterTest
Test: atest com.android.server.utils.WatcherTest
Test: m RUN_ERROR_PRONE=true framework services.core |& grep AppsFilter
BUG: 218411030
Change-Id: I06624ea79ff85160488a6c7863213b0c44fe2154
This commit is contained in:
@@ -15,15 +15,34 @@
|
||||
*/
|
||||
package android.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* A sparse array of ArraySets, which is suitable to hold userid->packages association.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SparseSetArray<T> {
|
||||
private final SparseArray<ArraySet<T>> mData = new SparseArray<>();
|
||||
private final SparseArray<ArraySet<T>> mData;
|
||||
|
||||
public SparseSetArray() {
|
||||
mData = new SparseArray<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*/
|
||||
public SparseSetArray(@NonNull SparseSetArray<T> src) {
|
||||
final int arraySize = src.size();
|
||||
mData = new SparseArray<>(arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
final int key = src.keyAt(i);
|
||||
final ArraySet<T> set = src.get(key);
|
||||
final int setSize = set.size();
|
||||
for (int j = 0; j < setSize; j++) {
|
||||
add(key, set.valueAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,7 +44,6 @@ import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseSetArray;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -64,14 +63,18 @@ import com.android.server.pm.pkg.component.ParsedMainComponent;
|
||||
import com.android.server.pm.pkg.component.ParsedProvider;
|
||||
import com.android.server.utils.Snappable;
|
||||
import com.android.server.utils.SnapshotCache;
|
||||
import com.android.server.utils.Snapshots;
|
||||
import com.android.server.utils.Watchable;
|
||||
import com.android.server.utils.WatchableImpl;
|
||||
import com.android.server.utils.Watched;
|
||||
import com.android.server.utils.WatchedArrayList;
|
||||
import com.android.server.utils.WatchedArrayMap;
|
||||
import com.android.server.utils.WatchedArraySet;
|
||||
import com.android.server.utils.WatchedSparseBooleanMatrix;
|
||||
import com.android.server.utils.WatchedSparseSetArray;
|
||||
import com.android.server.utils.Watcher;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -84,7 +87,7 @@ import java.util.concurrent.Executor;
|
||||
* manifests.
|
||||
*/
|
||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
||||
public class AppsFilter implements Watchable, Snappable {
|
||||
public class AppsFilterImpl implements AppsFilterSnapshot, Watchable, Snappable {
|
||||
|
||||
private static final String TAG = "AppsFilter";
|
||||
|
||||
@@ -99,32 +102,43 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
* application B is implicitly allowed to query for application A; regardless of any manifest
|
||||
* entries.
|
||||
*/
|
||||
private final SparseSetArray<Integer> mImplicitlyQueryable = new SparseSetArray<>();
|
||||
@Watched
|
||||
private final WatchedSparseSetArray<Integer> mImplicitlyQueryable;
|
||||
private final SnapshotCache<WatchedSparseSetArray<Integer>> mImplicitQueryableSnapshot;
|
||||
|
||||
/**
|
||||
* This contains a list of app UIDs that are implicitly queryable because another app explicitly
|
||||
* interacted with it, but could keep across package updates. For example, if application A
|
||||
* grants persistable uri permission to application B; regardless of any manifest entries.
|
||||
*/
|
||||
private final SparseSetArray<Integer> mRetainedImplicitlyQueryable = new SparseSetArray<>();
|
||||
@Watched
|
||||
private final WatchedSparseSetArray<Integer> mRetainedImplicitlyQueryable;
|
||||
private final SnapshotCache<WatchedSparseSetArray<Integer>>
|
||||
mRetainedImplicitlyQueryableSnapshot;
|
||||
|
||||
/**
|
||||
* A mapping from the set of App IDs that query other App IDs via package name to the
|
||||
* list of packages that they can see.
|
||||
*/
|
||||
private final SparseSetArray<Integer> mQueriesViaPackage = new SparseSetArray<>();
|
||||
@Watched
|
||||
private final WatchedSparseSetArray<Integer> mQueriesViaPackage;
|
||||
private final SnapshotCache<WatchedSparseSetArray<Integer>> mQueriesViaPackageSnapshot;
|
||||
|
||||
/**
|
||||
* A mapping from the set of App IDs that query others via component match to the list
|
||||
* of packages that the they resolve to.
|
||||
*/
|
||||
private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>();
|
||||
@Watched
|
||||
private final WatchedSparseSetArray<Integer> mQueriesViaComponent;
|
||||
private final SnapshotCache<WatchedSparseSetArray<Integer>> mQueriesViaComponentSnapshot;
|
||||
|
||||
/**
|
||||
* A mapping from the set of App IDs that query other App IDs via library name to the
|
||||
* list of packages that they can see.
|
||||
*/
|
||||
private final SparseSetArray<Integer> mQueryableViaUsesLibrary = new SparseSetArray<>();
|
||||
@Watched
|
||||
private final WatchedSparseSetArray<Integer> mQueryableViaUsesLibrary;
|
||||
private final SnapshotCache<WatchedSparseSetArray<Integer>> mQueryableViaUsesLibrarySnapshot;
|
||||
|
||||
/**
|
||||
* Executor for running reasonably short background tasks such as building the initial
|
||||
@@ -144,7 +158,9 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
* A set of App IDs that are always queryable by any package, regardless of their manifest
|
||||
* content.
|
||||
*/
|
||||
private final ArraySet<Integer> mForceQueryable = new ArraySet<>();
|
||||
@Watched
|
||||
private final WatchedArraySet<Integer> mForceQueryable;
|
||||
private final SnapshotCache<WatchedArraySet<Integer>> mForceQueryableSnapshot;
|
||||
|
||||
/**
|
||||
* The set of package names provided by the device that should be force queryable regardless of
|
||||
@@ -154,14 +170,15 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
|
||||
/** True if all system apps should be made queryable by default. */
|
||||
private final boolean mSystemAppsQueryable;
|
||||
|
||||
private final FeatureConfig mFeatureConfig;
|
||||
private final OverlayReferenceMapper mOverlayReferenceMapper;
|
||||
private final StateProvider mStateProvider;
|
||||
private final PackageManagerInternal mPmInternal;
|
||||
|
||||
private SigningDetails mSystemSigningDetails;
|
||||
private Set<String> mProtectedBroadcasts = new ArraySet<>();
|
||||
|
||||
@Watched
|
||||
private final WatchedArrayList<String> mProtectedBroadcasts;
|
||||
private final SnapshotCache<WatchedArrayList<String>> mProtectedBroadcastsSnapshot;
|
||||
|
||||
private final Object mCacheLock = new Object();
|
||||
|
||||
@@ -175,19 +192,21 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
@GuardedBy("mCacheLock")
|
||||
@NonNull
|
||||
private final WatchedSparseBooleanMatrix mShouldFilterCache;
|
||||
private final SnapshotCache<WatchedSparseBooleanMatrix> mShouldFilterCacheSnapshot;
|
||||
|
||||
private volatile boolean mSystemReady = false;
|
||||
|
||||
/**
|
||||
* A cached snapshot.
|
||||
*/
|
||||
private final SnapshotCache<AppsFilter> mSnapshot;
|
||||
private final SnapshotCache<AppsFilterImpl> mSnapshot;
|
||||
|
||||
private SnapshotCache<AppsFilter> makeCache() {
|
||||
return new SnapshotCache<AppsFilter>(this, this) {
|
||||
private SnapshotCache<AppsFilterImpl> makeCache() {
|
||||
return new SnapshotCache<AppsFilterImpl>(this, this) {
|
||||
@Override
|
||||
public AppsFilter createSnapshot() {
|
||||
AppsFilter s = new AppsFilter(mSource);
|
||||
public AppsFilterImpl createSnapshot() {
|
||||
AppsFilterImpl s = new AppsFilterImpl(mSource);
|
||||
s.mWatchable.seal();
|
||||
return s;
|
||||
}
|
||||
};
|
||||
@@ -197,6 +216,15 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
* Watchable machinery
|
||||
*/
|
||||
private final WatchableImpl mWatchable = new WatchableImpl();
|
||||
/**
|
||||
* The observer that watches for changes from array members
|
||||
*/
|
||||
private final Watcher mObserver = new Watcher() {
|
||||
@Override
|
||||
public void onChange(@Nullable Watchable what) {
|
||||
AppsFilterImpl.this.dispatchChange(what);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensures an observer is in the list, exactly once. The observer cannot be null. The
|
||||
@@ -251,7 +279,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = PRIVATE)
|
||||
AppsFilter(StateProvider stateProvider,
|
||||
AppsFilterImpl(StateProvider stateProvider,
|
||||
FeatureConfig featureConfig,
|
||||
String[] forceQueryableList,
|
||||
boolean systemAppsQueryable,
|
||||
@@ -267,31 +295,67 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
mPmInternal = pmInternal;
|
||||
mBackgroundExecutor = backgroundExecutor;
|
||||
mShouldFilterCache = new WatchedSparseBooleanMatrix();
|
||||
mShouldFilterCacheSnapshot = new SnapshotCache.Auto<>(
|
||||
mShouldFilterCache, mShouldFilterCache, "AppsFilter.mShouldFilterCache");
|
||||
mImplicitlyQueryable = new WatchedSparseSetArray<>();
|
||||
mImplicitQueryableSnapshot = new SnapshotCache.Auto<>(
|
||||
mImplicitlyQueryable, mImplicitlyQueryable, "AppsFilter.mImplicitlyQueryable");
|
||||
mRetainedImplicitlyQueryable = new WatchedSparseSetArray<>();
|
||||
mRetainedImplicitlyQueryableSnapshot = new SnapshotCache.Auto<>(
|
||||
mRetainedImplicitlyQueryable, mRetainedImplicitlyQueryable,
|
||||
"AppsFilter.mRetainedImplicitlyQueryable");
|
||||
mQueriesViaPackage = new WatchedSparseSetArray<>();
|
||||
mQueriesViaPackageSnapshot = new SnapshotCache.Auto<>(
|
||||
mQueriesViaPackage, mQueriesViaPackage, "AppsFilter.mQueriesViaPackage");
|
||||
mQueriesViaComponent = new WatchedSparseSetArray<>();
|
||||
mQueriesViaComponentSnapshot = new SnapshotCache.Auto<>(
|
||||
mQueriesViaComponent, mQueriesViaComponent, "AppsFilter.mQueriesViaComponent");
|
||||
mQueryableViaUsesLibrary = new WatchedSparseSetArray<>();
|
||||
mQueryableViaUsesLibrarySnapshot = new SnapshotCache.Auto<>(
|
||||
mQueryableViaUsesLibrary, mQueryableViaUsesLibrary,
|
||||
"AppsFilter.mQueryableViaUsesLibrary");
|
||||
mForceQueryable = new WatchedArraySet<>();
|
||||
mForceQueryableSnapshot = new SnapshotCache.Auto<>(
|
||||
mForceQueryable, mForceQueryable, "AppsFilter.mForceQueryable");
|
||||
mProtectedBroadcasts = new WatchedArrayList<>();
|
||||
mProtectedBroadcastsSnapshot = new SnapshotCache.Auto<>(
|
||||
mProtectedBroadcasts, mProtectedBroadcasts, "AppsFilter.mProtectedBroadcasts");
|
||||
|
||||
registerObservers();
|
||||
Watchable.verifyWatchedAttributes(this, mObserver);
|
||||
mSnapshot = makeCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* The copy constructor is used by PackageManagerService to construct a snapshot.
|
||||
* Attributes are not deep-copied since these are supposed to be immutable.
|
||||
* TODO: deep-copy the attributes, if necessary.
|
||||
*/
|
||||
private AppsFilter(AppsFilter orig) {
|
||||
Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
|
||||
Snapshots.copy(mRetainedImplicitlyQueryable, orig.mRetainedImplicitlyQueryable);
|
||||
Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
|
||||
Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
|
||||
Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary);
|
||||
private AppsFilterImpl(AppsFilterImpl orig) {
|
||||
mImplicitlyQueryable = orig.mImplicitQueryableSnapshot.snapshot();
|
||||
mImplicitQueryableSnapshot = new SnapshotCache.Sealed<>();
|
||||
mRetainedImplicitlyQueryable = orig.mRetainedImplicitlyQueryableSnapshot.snapshot();
|
||||
mRetainedImplicitlyQueryableSnapshot = new SnapshotCache.Sealed<>();
|
||||
mQueriesViaPackage = orig.mQueriesViaPackageSnapshot.snapshot();
|
||||
mQueriesViaPackageSnapshot = new SnapshotCache.Sealed<>();
|
||||
mQueriesViaComponent = orig.mQueriesViaComponentSnapshot.snapshot();
|
||||
mQueriesViaComponentSnapshot = new SnapshotCache.Sealed<>();
|
||||
mQueryableViaUsesLibrary = orig.mQueryableViaUsesLibrarySnapshot.snapshot();
|
||||
mQueryableViaUsesLibrarySnapshot = new SnapshotCache.Sealed<>();
|
||||
mForceQueryable = orig.mForceQueryableSnapshot.snapshot();
|
||||
mForceQueryableSnapshot = new SnapshotCache.Sealed<>();
|
||||
mProtectedBroadcasts = orig.mProtectedBroadcastsSnapshot.snapshot();
|
||||
mProtectedBroadcastsSnapshot = new SnapshotCache.Sealed<>();
|
||||
mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute;
|
||||
mForceQueryable.addAll(orig.mForceQueryable);
|
||||
mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames;
|
||||
mForceQueryableByDevicePackageNames =
|
||||
Arrays.copyOf(orig.mForceQueryableByDevicePackageNames,
|
||||
orig.mForceQueryableByDevicePackageNames.length);
|
||||
mSystemAppsQueryable = orig.mSystemAppsQueryable;
|
||||
mFeatureConfig = orig.mFeatureConfig;
|
||||
mOverlayReferenceMapper = orig.mOverlayReferenceMapper;
|
||||
mStateProvider = orig.mStateProvider;
|
||||
mSystemSigningDetails = orig.mSystemSigningDetails;
|
||||
mProtectedBroadcasts = orig.mProtectedBroadcasts;
|
||||
synchronized (orig.mCacheLock) {
|
||||
mShouldFilterCache = orig.mShouldFilterCache.snapshot();
|
||||
mShouldFilterCache = orig.mShouldFilterCacheSnapshot.snapshot();
|
||||
mShouldFilterCacheSnapshot = new SnapshotCache.Sealed<>();
|
||||
}
|
||||
|
||||
mBackgroundExecutor = null;
|
||||
@@ -300,12 +364,24 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
mSystemReady = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("GuardedBy")
|
||||
private void registerObservers() {
|
||||
mImplicitlyQueryable.registerObserver(mObserver);
|
||||
mRetainedImplicitlyQueryable.registerObserver(mObserver);
|
||||
mQueriesViaPackage.registerObserver(mObserver);
|
||||
mQueriesViaComponent.registerObserver(mObserver);
|
||||
mQueryableViaUsesLibrary.registerObserver(mObserver);
|
||||
mForceQueryable.registerObserver(mObserver);
|
||||
mProtectedBroadcasts.registerObserver(mObserver);
|
||||
mShouldFilterCache.registerObserver(mObserver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a snapshot. If the cached snapshot is null, build a new one. The logic in
|
||||
* the function ensures that this function returns a valid snapshot even if a race
|
||||
* condition causes the cached snapshot to be cleared asynchronously to this method.
|
||||
*/
|
||||
public AppsFilter snapshot() {
|
||||
public AppsFilterSnapshot snapshot() {
|
||||
return mSnapshot.snapshot();
|
||||
}
|
||||
|
||||
@@ -366,7 +442,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
|
||||
@Nullable
|
||||
private SparseBooleanArray mLoggingEnabled = null;
|
||||
private AppsFilter mAppsFilter;
|
||||
private AppsFilterImpl mAppsFilter;
|
||||
|
||||
private FeatureConfigImpl(
|
||||
PackageManagerInternal pmInternal, PackageManagerServiceInjector injector) {
|
||||
@@ -374,7 +450,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
mInjector = injector;
|
||||
}
|
||||
|
||||
public void setAppsFilter(AppsFilter filter) {
|
||||
public void setAppsFilter(AppsFilterImpl filter) {
|
||||
mAppsFilter = filter;
|
||||
}
|
||||
|
||||
@@ -478,8 +554,9 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
|
||||
@Override
|
||||
public void updatePackageState(PackageStateInternal setting, boolean removed) {
|
||||
final boolean enableLogging = setting.getPkg() != null &&
|
||||
!removed && (setting.getPkg().isTestOnly() || setting.getPkg().isDebuggable());
|
||||
final boolean enableLogging = setting.getPkg() != null
|
||||
&& !removed && (setting.getPkg().isTestOnly()
|
||||
|| setting.getPkg().isDebuggable());
|
||||
enableLogging(setting.getAppId(), enableLogging);
|
||||
if (removed) {
|
||||
mDisabledPackages.remove(setting.getPackageName());
|
||||
@@ -490,7 +567,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
|
||||
/** Builder method for an AppsFilter */
|
||||
public static AppsFilter create(@NonNull PackageManagerServiceInjector injector,
|
||||
public static AppsFilterImpl create(@NonNull PackageManagerServiceInjector injector,
|
||||
@NonNull PackageManagerInternal pmInt) {
|
||||
final boolean forceSystemAppsQueryable =
|
||||
injector.getContext().getResources()
|
||||
@@ -514,7 +591,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
injector.getUserManagerInternal().getUserInfos());
|
||||
}
|
||||
};
|
||||
AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
|
||||
AppsFilterImpl appsFilter = new AppsFilterImpl(stateProvider, featureConfig,
|
||||
forcedQueryablePackageNames, forceSystemAppsQueryable, null,
|
||||
injector.getBackgroundExecutor(), pmInt);
|
||||
featureConfig.setAppsFilter(appsFilter);
|
||||
@@ -527,7 +604,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
|
||||
/** Returns true if the querying package may query for the potential target package */
|
||||
private static boolean canQueryViaComponents(AndroidPackage querying,
|
||||
AndroidPackage potentialTarget, Set<String> protectedBroadcasts) {
|
||||
AndroidPackage potentialTarget, WatchedArrayList<String> protectedBroadcasts) {
|
||||
if (!querying.getQueriesIntents().isEmpty()) {
|
||||
for (Intent intent : querying.getQueriesIntents()) {
|
||||
if (matchesPackage(intent, potentialTarget, protectedBroadcasts)) {
|
||||
@@ -599,7 +676,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
|
||||
private static boolean matchesPackage(Intent intent, AndroidPackage potentialTarget,
|
||||
Set<String> protectedBroadcasts) {
|
||||
WatchedArrayList<String> protectedBroadcasts) {
|
||||
if (matchesAnyComponents(
|
||||
intent, potentialTarget.getServices(), null /*protectedBroadcasts*/)) {
|
||||
return true;
|
||||
@@ -620,7 +697,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
|
||||
private static boolean matchesAnyComponents(Intent intent,
|
||||
List<? extends ParsedMainComponent> components,
|
||||
Set<String> protectedBroadcasts) {
|
||||
WatchedArrayList<String> protectedBroadcasts) {
|
||||
for (int i = ArrayUtils.size(components) - 1; i >= 0; i--) {
|
||||
ParsedMainComponent component = components.get(i);
|
||||
if (!component.isExported()) {
|
||||
@@ -634,7 +711,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
|
||||
private static boolean matchesAnyFilter(Intent intent, ParsedComponent component,
|
||||
Set<String> protectedBroadcasts) {
|
||||
WatchedArrayList<String> protectedBroadcasts) {
|
||||
List<ParsedIntentInfo> intents = component.getIntents();
|
||||
for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) {
|
||||
IntentFilter intentFilter = intents.get(i).getIntentFilter();
|
||||
@@ -646,10 +723,10 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
|
||||
private static boolean matchesIntentFilter(Intent intent, IntentFilter intentFilter,
|
||||
@Nullable Set<String> protectedBroadcasts) {
|
||||
@Nullable WatchedArrayList<String> protectedBroadcasts) {
|
||||
return intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
|
||||
intent.getData(), intent.getCategories(), "AppsFilter", true, protectedBroadcasts)
|
||||
> 0;
|
||||
intent.getData(), intent.getCategories(), "AppsFilter", true,
|
||||
protectedBroadcasts != null ? protectedBroadcasts.untrackedStorage() : null) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -665,7 +742,8 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
if (recipientUid == visibleUid) {
|
||||
return false;
|
||||
}
|
||||
final boolean changed = retainOnUpdate
|
||||
final boolean changed;
|
||||
changed = retainOnUpdate
|
||||
? mRetainedImplicitlyQueryable.add(recipientUid, visibleUid)
|
||||
: mImplicitlyQueryable.add(recipientUid, visibleUid);
|
||||
if (changed && DEBUG_LOGGING) {
|
||||
@@ -787,7 +865,8 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
|
||||
for (int i = existingSettings.size() - 1; i >= 0; i--) {
|
||||
final PackageStateInternal existingSetting = existingSettings.valueAt(i);
|
||||
if (existingSetting.getAppId() == newPkgSetting.getAppId() || existingSetting.getPkg()
|
||||
if (existingSetting.getAppId() == newPkgSetting.getAppId()
|
||||
|| existingSetting.getPkg()
|
||||
== null) {
|
||||
continue;
|
||||
}
|
||||
@@ -796,11 +875,13 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
if (!newIsForceQueryable) {
|
||||
if (!mQueriesViaComponentRequireRecompute && canQueryViaComponents(existingPkg,
|
||||
newPkg, mProtectedBroadcasts)) {
|
||||
mQueriesViaComponent.add(existingSetting.getAppId(), newPkgSetting.getAppId());
|
||||
mQueriesViaComponent.add(existingSetting.getAppId(),
|
||||
newPkgSetting.getAppId());
|
||||
}
|
||||
if (canQueryViaPackage(existingPkg, newPkg)
|
||||
|| canQueryAsInstaller(existingSetting, newPkg)) {
|
||||
mQueriesViaPackage.add(existingSetting.getAppId(), newPkgSetting.getAppId());
|
||||
mQueriesViaPackage.add(existingSetting.getAppId(),
|
||||
newPkgSetting.getAppId());
|
||||
}
|
||||
if (canQueryViaUsesLibrary(existingPkg, newPkg)) {
|
||||
mQueryableViaUsesLibrary.add(existingSetting.getAppId(),
|
||||
@@ -811,11 +892,13 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
if (!mForceQueryable.contains(existingSetting.getAppId())) {
|
||||
if (!mQueriesViaComponentRequireRecompute && canQueryViaComponents(newPkg,
|
||||
existingPkg, mProtectedBroadcasts)) {
|
||||
mQueriesViaComponent.add(newPkgSetting.getAppId(), existingSetting.getAppId());
|
||||
mQueriesViaComponent.add(newPkgSetting.getAppId(),
|
||||
existingSetting.getAppId());
|
||||
}
|
||||
if (canQueryViaPackage(newPkg, existingPkg)
|
||||
|| canQueryAsInstaller(newPkgSetting, existingPkg)) {
|
||||
mQueriesViaPackage.add(newPkgSetting.getAppId(), existingSetting.getAppId());
|
||||
mQueriesViaPackage.add(newPkgSetting.getAppId(),
|
||||
existingSetting.getAppId());
|
||||
}
|
||||
if (canQueryViaUsesLibrary(newPkg, existingPkg)) {
|
||||
mQueryableViaUsesLibrary.add(newPkgSetting.getAppId(),
|
||||
@@ -1048,10 +1131,10 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
&& pkgSetting.getSigningDetails().signaturesMatchExactly(sysSigningDetails);
|
||||
}
|
||||
|
||||
private ArraySet<String> collectProtectedBroadcasts(
|
||||
private void collectProtectedBroadcasts(
|
||||
ArrayMap<String, ? extends PackageStateInternal> existingSettings,
|
||||
@Nullable String excludePackage) {
|
||||
ArraySet<String> ret = new ArraySet<>();
|
||||
mProtectedBroadcasts.clear();
|
||||
for (int i = existingSettings.size() - 1; i >= 0; i--) {
|
||||
PackageStateInternal setting = existingSettings.valueAt(i);
|
||||
if (setting.getPkg() == null || setting.getPkg().getPackageName().equals(
|
||||
@@ -1060,10 +1143,9 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
final List<String> protectedBroadcasts = setting.getPkg().getProtectedBroadcasts();
|
||||
if (!protectedBroadcasts.isEmpty()) {
|
||||
ret.addAll(protectedBroadcasts);
|
||||
mProtectedBroadcasts.addAll(protectedBroadcasts);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1097,19 +1179,9 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* all applications.
|
||||
*
|
||||
* 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 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 allow list should be
|
||||
* applied.
|
||||
* See {@link AppsFilterSnapshot#getVisibilityAllowList(PackageStateInternal, int[], ArrayMap)}
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public SparseArray<int[]> getVisibilityAllowList(PackageStateInternal setting, int[] users,
|
||||
ArrayMap<String, ? extends PackageStateInternal> existingSettings) {
|
||||
@@ -1164,7 +1236,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
* Equivalent to calling {@link #addPackage(PackageStateInternal, boolean)} with
|
||||
* {@code isReplace} equal to {@code false}.
|
||||
*
|
||||
* @see AppsFilter#addPackage(PackageStateInternal, boolean)
|
||||
* @see AppsFilterImpl#addPackage(PackageStateInternal, boolean)
|
||||
*/
|
||||
public void addPackage(PackageStateInternal newPkgSetting) {
|
||||
addPackage(newPkgSetting, false /* isReplace */);
|
||||
@@ -1178,13 +1250,15 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
*/
|
||||
public void removePackage(PackageStateInternal setting, boolean isReplace) {
|
||||
mStateProvider.runWithState((settings, users) -> {
|
||||
final ArraySet<String> additionalChangedPackages;
|
||||
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.getAppId());
|
||||
mImplicitlyQueryable.remove(removingUid);
|
||||
for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
|
||||
mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
|
||||
mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i),
|
||||
removingUid);
|
||||
}
|
||||
|
||||
if (isReplace) {
|
||||
@@ -1201,12 +1275,14 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
if (!mQueriesViaComponentRequireRecompute) {
|
||||
mQueriesViaComponent.remove(setting.getAppId());
|
||||
for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) {
|
||||
mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.getAppId());
|
||||
mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i),
|
||||
setting.getAppId());
|
||||
}
|
||||
}
|
||||
mQueriesViaPackage.remove(setting.getAppId());
|
||||
for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) {
|
||||
mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.getAppId());
|
||||
mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i),
|
||||
setting.getAppId());
|
||||
}
|
||||
mQueryableViaUsesLibrary.remove(setting.getAppId());
|
||||
for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) {
|
||||
@@ -1216,23 +1292,26 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
|
||||
mForceQueryable.remove(setting.getAppId());
|
||||
|
||||
if (setting.getPkg() != null && !setting.getPkg().getProtectedBroadcasts().isEmpty()) {
|
||||
if (setting.getPkg() != null
|
||||
&& !setting.getPkg().getProtectedBroadcasts().isEmpty()) {
|
||||
final String removingPackageName = setting.getPkg().getPackageName();
|
||||
final Set<String> protectedBroadcasts = mProtectedBroadcasts;
|
||||
mProtectedBroadcasts = collectProtectedBroadcasts(settings, removingPackageName);
|
||||
final ArrayList<String> protectedBroadcasts = new ArrayList<>();
|
||||
protectedBroadcasts.addAll(mProtectedBroadcasts.untrackedStorage());
|
||||
collectProtectedBroadcasts(settings, removingPackageName);
|
||||
if (!mProtectedBroadcasts.containsAll(protectedBroadcasts)) {
|
||||
mQueriesViaComponentRequireRecompute = true;
|
||||
}
|
||||
}
|
||||
|
||||
ArraySet<String> additionalChangedPackages =
|
||||
mOverlayReferenceMapper.removePkg(setting.getPackageName());
|
||||
|
||||
additionalChangedPackages = mOverlayReferenceMapper.removePkg(setting.getPackageName());
|
||||
mFeatureConfig.updatePackageState(setting, true /*removed*/);
|
||||
|
||||
// After removing all traces of the package, if it's part of a shared user, re-add other
|
||||
// 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
|
||||
// After removing all traces of the package, if it's part of a shared user,
|
||||
// re-add other
|
||||
// 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 ArraySet<PackageStateInternal> sharedUserPackages =
|
||||
@@ -1285,15 +1364,11 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the calling package should not be able to see the target package, false if no
|
||||
* filtering should be done.
|
||||
*
|
||||
* @param callingUid the uid of the caller attempting to access a package
|
||||
* @param callingSetting the setting attempting to access a package or null if it could not be
|
||||
* found
|
||||
* @param targetPkgSetting the package being accessed
|
||||
* @param userId the user in which this access is being attempted
|
||||
* See
|
||||
* {@link AppsFilterSnapshot#shouldFilterApplication(int, Object, PackageStateInternal,
|
||||
* int)}
|
||||
*/
|
||||
@Override
|
||||
public boolean shouldFilterApplication(int callingUid, @Nullable Object callingSetting,
|
||||
PackageStateInternal targetPkgSetting, int userId) {
|
||||
if (DEBUG_TRACING) {
|
||||
@@ -1610,7 +1685,11 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
}
|
||||
|
||||
boolean canQueryPackage(@NonNull AndroidPackage querying, String potentialTarget) {
|
||||
/**
|
||||
* See {@link AppsFilterSnapshot#canQueryPackage(AndroidPackage, String)}
|
||||
*/
|
||||
@Override
|
||||
public boolean canQueryPackage(@NonNull AndroidPackage querying, String potentialTarget) {
|
||||
int appId = UserHandle.getAppId(querying.getUid());
|
||||
if (appId < Process.FIRST_APPLICATION_UID) {
|
||||
return true;
|
||||
@@ -1665,6 +1744,11 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
+ targetPkgSetting + " " + description);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link AppsFilterSnapshot#dumpQueries(PrintWriter, Integer, DumpState, int[],
|
||||
* QuadFunction)}
|
||||
*/
|
||||
@Override
|
||||
public void dumpQueries(
|
||||
PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState, int[] users,
|
||||
QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid) {
|
||||
@@ -1699,7 +1783,8 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
}
|
||||
pw.println(" system apps queryable: " + mSystemAppsQueryable);
|
||||
dumpPackageSet(pw, filteringAppId, mForceQueryable, "forceQueryable", " ", expandPackages);
|
||||
dumpPackageSet(pw, filteringAppId, mForceQueryable.untrackedStorage(),
|
||||
"forceQueryable", " ", expandPackages);
|
||||
pw.println(" queries via package name:");
|
||||
dumpQueriesMap(pw, filteringAppId, mQueriesViaPackage, " ", expandPackages);
|
||||
pw.println(" queries via component:");
|
||||
@@ -1715,11 +1800,12 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
mRetainedImplicitlyQueryable, " ", expandPackages);
|
||||
}
|
||||
pw.println(" queryable via uses-library:");
|
||||
dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages);
|
||||
dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ",
|
||||
expandPackages);
|
||||
}
|
||||
|
||||
private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId,
|
||||
SparseSetArray<Integer> queriesMap, String spacing,
|
||||
WatchedSparseSetArray<Integer> queriesMap, String spacing,
|
||||
@Nullable ToString<Integer> toString) {
|
||||
for (int i = 0; i < queriesMap.size(); i++) {
|
||||
Integer callingId = queriesMap.keyAt(i);
|
||||
@@ -1748,7 +1834,7 @@ public class AppsFilter implements Watchable, Snappable {
|
||||
}
|
||||
|
||||
private static <T> void dumpPackageSet(PrintWriter pw, @Nullable T filteringId,
|
||||
Set<T> targetPkgSet, String subTitle, String spacing,
|
||||
ArraySet<T> targetPkgSet, String subTitle, String spacing,
|
||||
@Nullable ToString<T> toString) {
|
||||
if (targetPkgSet != null && targetPkgSet.size() > 0
|
||||
&& (filteringId == null || targetPkgSet.contains(filteringId))) {
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Process;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.util.function.QuadFunction;
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||
import com.android.server.pm.pkg.PackageStateInternal;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Read-only interface used by computer and snapshots to query the visibility of packages
|
||||
*/
|
||||
public interface AppsFilterSnapshot {
|
||||
/**
|
||||
* 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
|
||||
* all applications.
|
||||
*
|
||||
* 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 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 allow list should be
|
||||
* applied.
|
||||
*/
|
||||
SparseArray<int[]> getVisibilityAllowList(PackageStateInternal setting, int[] users,
|
||||
ArrayMap<String, ? extends PackageStateInternal> existingSettings);
|
||||
|
||||
/**
|
||||
* Returns true if the calling package should not be able to see the target package, false if no
|
||||
* filtering should be done.
|
||||
*
|
||||
* @param callingUid the uid of the caller attempting to access a package
|
||||
* @param callingSetting the setting attempting to access a package or null if it could not be
|
||||
* found
|
||||
* @param targetPkgSetting the package being accessed
|
||||
* @param userId the user in which this access is being attempted
|
||||
*/
|
||||
boolean shouldFilterApplication(int callingUid, @Nullable Object callingSetting,
|
||||
PackageStateInternal targetPkgSetting, int userId);
|
||||
|
||||
/**
|
||||
* Returns whether the querying package is allowed to see the target package.
|
||||
*
|
||||
* @param querying the querying package
|
||||
* @param potentialTarget the package name of the target package
|
||||
*/
|
||||
boolean canQueryPackage(@NonNull AndroidPackage querying, String potentialTarget);
|
||||
|
||||
/**
|
||||
* Dump the packages that are queryable by the querying package.
|
||||
*
|
||||
* @param pw the output print writer
|
||||
* @param filteringAppId the querying package's app ID
|
||||
* @param dumpState the state of the dumping
|
||||
* @param users the users for which the packages are installed
|
||||
* @param getPackagesForUid the function that produces the package names for given uids
|
||||
*/
|
||||
void dumpQueries(PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState,
|
||||
int[] users,
|
||||
QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid);
|
||||
|
||||
}
|
||||
@@ -385,7 +385,7 @@ public class ComputerEngine implements Computer {
|
||||
private final ResolveInfo mInstantAppInstallerInfo;
|
||||
private final InstantAppRegistry mInstantAppRegistry;
|
||||
private final ApplicationInfo mLocalAndroidApplication;
|
||||
private final AppsFilter mAppsFilter;
|
||||
private final AppsFilterSnapshot mAppsFilter;
|
||||
private final WatchedArrayMap<String, Integer> mFrozenPackages;
|
||||
|
||||
// Immutable service attribute
|
||||
|
||||
@@ -720,7 +720,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
}
|
||||
|
||||
@Watched
|
||||
final AppsFilter mAppsFilter;
|
||||
final AppsFilterImpl mAppsFilter;
|
||||
|
||||
final PackageParser2.Callback mPackageParserCallback;
|
||||
|
||||
@@ -979,7 +979,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
public final InstantAppRegistry instantAppRegistry;
|
||||
public final ApplicationInfo androidApplication;
|
||||
public final String appPredictionServicePackage;
|
||||
public final AppsFilter appsFilter;
|
||||
public final AppsFilterSnapshot appsFilter;
|
||||
public final ComponentResolverApi componentResolver;
|
||||
public final PackageManagerService service;
|
||||
public final WatchedArrayMap<String, Integer> frozenPackages;
|
||||
@@ -1431,7 +1431,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
|
||||
RuntimePermissionsPersistence.createInstance(),
|
||||
i.getPermissionManagerServiceInternal(),
|
||||
domainVerificationService, lock),
|
||||
(i, pm) -> AppsFilter.create(i, i.getLocalService(PackageManagerInternal.class)),
|
||||
(i, pm) -> AppsFilterImpl.create(i,
|
||||
i.getLocalService(PackageManagerInternal.class)),
|
||||
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
|
||||
(i, pm) -> SystemConfig.getInstance(),
|
||||
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
|
||||
|
||||
@@ -99,7 +99,7 @@ public class PackageManagerServiceInjector {
|
||||
private final Singleton<UserManagerService>
|
||||
mUserManagerProducer;
|
||||
private final Singleton<Settings> mSettingsProducer;
|
||||
private final Singleton<AppsFilter> mAppsFilterProducer;
|
||||
private final Singleton<AppsFilterImpl> mAppsFilterProducer;
|
||||
private final Singleton<PlatformCompat>
|
||||
mPlatformCompatProducer;
|
||||
private final Singleton<SystemConfig> mSystemConfigProducer;
|
||||
@@ -148,7 +148,7 @@ public class PackageManagerServiceInjector {
|
||||
Producer<PermissionManagerServiceInternal> permissionManagerServiceProducer,
|
||||
Producer<UserManagerService> userManagerProducer,
|
||||
Producer<Settings> settingsProducer,
|
||||
Producer<AppsFilter> appsFilterProducer,
|
||||
Producer<AppsFilterImpl> appsFilterProducer,
|
||||
Producer<PlatformCompat> platformCompatProducer,
|
||||
Producer<SystemConfig> systemConfigProducer,
|
||||
Producer<PackageDexOptimizer> packageDexOptimizerProducer,
|
||||
@@ -282,7 +282,7 @@ public class PackageManagerServiceInjector {
|
||||
return mSettingsProducer.get(this, mPackageManager);
|
||||
}
|
||||
|
||||
public AppsFilter getAppsFilter() {
|
||||
public AppsFilterImpl getAppsFilter() {
|
||||
return mAppsFilterProducer.get(this, mPackageManager);
|
||||
}
|
||||
|
||||
|
||||
@@ -272,6 +272,13 @@ public class WatchedArrayList<E> extends WatchableImpl
|
||||
return mStorage.contains(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if all the objects in the given collection are in this array list.
|
||||
*/
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return mStorage.containsAll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure capacity.
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.utils;
|
||||
|
||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.Size;
|
||||
|
||||
@@ -168,12 +169,19 @@ public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappab
|
||||
* A copy constructor that can be used for snapshotting.
|
||||
*/
|
||||
private WatchedSparseBooleanMatrix(WatchedSparseBooleanMatrix r) {
|
||||
mOrder = r.mOrder;
|
||||
mSize = r.mSize;
|
||||
mKeys = r.mKeys.clone();
|
||||
mMap = r.mMap.clone();
|
||||
mInUse = r.mInUse.clone();
|
||||
mValues = r.mValues.clone();
|
||||
copyFrom(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from src to this.
|
||||
*/
|
||||
public void copyFrom(@NonNull WatchedSparseBooleanMatrix src) {
|
||||
mOrder = src.mOrder;
|
||||
mSize = src.mSize;
|
||||
mKeys = src.mKeys.clone();
|
||||
mMap = src.mMap.clone();
|
||||
mInUse = src.mInUse.clone();
|
||||
mValues = src.mValues.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.utils;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.util.ArraySet;
|
||||
import android.util.SparseSetArray;
|
||||
|
||||
|
||||
/**
|
||||
* A watched variant of SparseSetArray. Changes to the array are notified to
|
||||
* registered {@link Watcher}s.
|
||||
* @param <T> The element type, stored in the SparseSetArray.
|
||||
*/
|
||||
public class WatchedSparseSetArray<T> extends WatchableImpl implements Snappable {
|
||||
// The storage
|
||||
private final SparseSetArray mStorage;
|
||||
|
||||
// A private convenience function
|
||||
private void onChanged() {
|
||||
dispatchChange(this);
|
||||
}
|
||||
|
||||
public WatchedSparseSetArray() {
|
||||
mStorage = new SparseSetArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new WatchedSparseSetArray from an existing WatchedSparseSetArray and copy its data
|
||||
*/
|
||||
public WatchedSparseSetArray(@NonNull WatchedSparseSetArray<T> watchedSparseSetArray) {
|
||||
mStorage = new SparseSetArray(watchedSparseSetArray.untrackedStorage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying storage. This breaks the wrapper but is necessary when
|
||||
* passing the array to distant methods.
|
||||
*/
|
||||
public SparseSetArray<T> untrackedStorage() {
|
||||
return mStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a value for key n.
|
||||
* @return FALSE when the value already existed for the given key, TRUE otherwise.
|
||||
*/
|
||||
public boolean add(int n, T value) {
|
||||
final boolean res = mStorage.add(n, value);
|
||||
onChanged();
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all mappings from this SparseSetArray.
|
||||
*/
|
||||
public void clear() {
|
||||
mStorage.clear();
|
||||
onChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the value exists for the key n.
|
||||
*/
|
||||
public boolean contains(int n, T value) {
|
||||
return mStorage.contains(n, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the set of items of key n
|
||||
*/
|
||||
public ArraySet<T> get(int n) {
|
||||
return mStorage.get(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a value for key n.
|
||||
* @return TRUE when the value existed for the given key and removed, FALSE otherwise.
|
||||
*/
|
||||
public boolean remove(int n, T value) {
|
||||
if (mStorage.remove(n, value)) {
|
||||
onChanged();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all values for key n.
|
||||
*/
|
||||
public void remove(int n) {
|
||||
mStorage.remove(n);
|
||||
onChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the SparseSetArray.
|
||||
*/
|
||||
public int size() {
|
||||
return mStorage.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key stored at the given index.
|
||||
*/
|
||||
public int keyAt(int index) {
|
||||
return mStorage.keyAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the array at the given index.
|
||||
*/
|
||||
public int sizeAt(int index) {
|
||||
return mStorage.sizeAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value in the SetArray at the given key index and value index.
|
||||
*/
|
||||
public T valueAt(int intIndex, int valueIndex) {
|
||||
return (T) mStorage.valueAt(intIndex, valueIndex);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object snapshot() {
|
||||
WatchedSparseSetArray l = new WatchedSparseSetArray(this);
|
||||
l.seal();
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make <this> a snapshot of the argument. Note that <this> is immutable when the
|
||||
* method returns. <this> must be empty when the function is called.
|
||||
* @param r The source array, which is copied into <this>
|
||||
*/
|
||||
public void snapshot(@NonNull WatchedSparseSetArray<T> r) {
|
||||
snapshot(this, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the destination a copy of the source. If the element is a subclass of Snapper then the
|
||||
* copy contains snapshots of the elements. Otherwise the copy contains references to the
|
||||
* elements. The destination must be initially empty. Upon return, the destination is
|
||||
* immutable.
|
||||
* @param dst The destination array. It must be empty.
|
||||
* @param src The source array. It is not modified.
|
||||
*/
|
||||
public static void snapshot(@NonNull WatchedSparseSetArray dst,
|
||||
@NonNull WatchedSparseSetArray src) {
|
||||
if (dst.size() != 0) {
|
||||
throw new IllegalArgumentException("snapshot destination is not empty");
|
||||
}
|
||||
final int arraySize = src.size();
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
final ArraySet set = src.get(i);
|
||||
final int setSize = set.size();
|
||||
for (int j = 0; j < setSize; j++) {
|
||||
dst.add(src.keyAt(i), set.valueAt(j));
|
||||
}
|
||||
}
|
||||
dst.seal();
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverr
|
||||
import com.android.server.testutils.TestHandler
|
||||
import com.android.server.testutils.mock
|
||||
import com.android.server.testutils.mockThrowOnUnmocked
|
||||
import com.android.server.testutils.spy
|
||||
import com.android.server.testutils.whenever
|
||||
import com.android.server.wm.ActivityTaskManagerInternal
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
@@ -46,13 +45,9 @@ import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.doAnswer
|
||||
import org.mockito.Mockito.doReturn
|
||||
import org.mockito.Mockito.intThat
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.same
|
||||
import org.mockito.Mockito.verify
|
||||
import org.testng.Assert.assertThrows
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
@@ -365,7 +360,7 @@ class PackageManagerComponentLabelIconOverrideTest {
|
||||
val mockActivityTaskManager: ActivityTaskManagerInternal = mockThrowOnUnmocked {
|
||||
whenever(this.isCallerRecents(anyInt())) { false }
|
||||
}
|
||||
val mockAppsFilter: AppsFilter = mockThrowOnUnmocked {
|
||||
val mockAppsFilter: AppsFilterImpl = mockThrowOnUnmocked {
|
||||
whenever(this.shouldFilterApplication(anyInt(), any<PackageSetting>(),
|
||||
any<PackageSetting>(), anyInt())) { false }
|
||||
whenever(this.snapshot()) { this@mockThrowOnUnmocked }
|
||||
|
||||
@@ -194,7 +194,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
|
||||
val packageParser: PackageParser2 = mock()
|
||||
val keySetManagerService: KeySetManagerService = mock()
|
||||
val packageAbiHelper: PackageAbiHelper = mock()
|
||||
val appsFilter: AppsFilter = mock {
|
||||
val appsFilter: AppsFilterImpl = mock {
|
||||
whenever(snapshot()) { this@mock }
|
||||
}
|
||||
val dexManager: DexManager = mock()
|
||||
|
||||
@@ -77,7 +77,7 @@ import java.util.concurrent.Executor;
|
||||
|
||||
@Presubmit
|
||||
@RunWith(JUnit4.class)
|
||||
public class AppsFilterTest {
|
||||
public class AppsFilterImplTest {
|
||||
|
||||
private static final int DUMMY_CALLING_APPID = 10345;
|
||||
private static final int DUMMY_TARGET_APPID = 10556;
|
||||
@@ -98,9 +98,9 @@ public class AppsFilterTest {
|
||||
}
|
||||
|
||||
@Mock
|
||||
AppsFilter.FeatureConfig mFeatureConfigMock;
|
||||
AppsFilterImpl.FeatureConfig mFeatureConfigMock;
|
||||
@Mock
|
||||
AppsFilter.StateProvider mStateProvider;
|
||||
AppsFilterImpl.StateProvider mStateProvider;
|
||||
@Mock
|
||||
Executor mMockExecutor;
|
||||
@Mock
|
||||
@@ -204,11 +204,11 @@ public class AppsFilterTest {
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
doAnswer(invocation -> {
|
||||
((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
|
||||
((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
|
||||
.currentState(mExisting, USER_INFO_LIST);
|
||||
return new Object();
|
||||
}).when(mStateProvider)
|
||||
.runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
|
||||
.runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
|
||||
|
||||
doAnswer(invocation -> {
|
||||
((Runnable) invocation.getArgument(0)).run();
|
||||
@@ -218,14 +218,14 @@ public class AppsFilterTest {
|
||||
when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true);
|
||||
when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))).thenAnswer(
|
||||
(Answer<Boolean>) invocation ->
|
||||
((AndroidPackage)invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
|
||||
((AndroidPackage) invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
|
||||
>= Build.VERSION_CODES.R);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemReadyPropogates() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -236,8 +236,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testQueriesAction_FilterMatches() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -259,8 +259,8 @@ public class AppsFilterTest {
|
||||
}
|
||||
@Test
|
||||
public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -308,8 +308,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testQueriesProvider_FilterMatches() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -333,8 +333,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testOnUserUpdated_FilterMatches() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
|
||||
@@ -356,11 +356,11 @@ public class AppsFilterTest {
|
||||
|
||||
// adds new user
|
||||
doAnswer(invocation -> {
|
||||
((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
|
||||
((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
|
||||
.currentState(mExisting, USER_INFO_LIST_WITH_ADDED);
|
||||
return new Object();
|
||||
}).when(mStateProvider)
|
||||
.runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
|
||||
.runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
|
||||
appsFilter.onUserCreated(ADDED_USER);
|
||||
|
||||
for (int subjectUserId : USER_ARRAY_WITH_ADDED) {
|
||||
@@ -373,11 +373,11 @@ public class AppsFilterTest {
|
||||
|
||||
// delete user
|
||||
doAnswer(invocation -> {
|
||||
((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0))
|
||||
((AppsFilterImpl.StateProvider.CurrentStateCallback) invocation.getArgument(0))
|
||||
.currentState(mExisting, USER_INFO_LIST);
|
||||
return new Object();
|
||||
}).when(mStateProvider)
|
||||
.runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class));
|
||||
.runWithState(any(AppsFilterImpl.StateProvider.CurrentStateCallback.class));
|
||||
appsFilter.onUserDeleted(ADDED_USER);
|
||||
|
||||
for (int subjectUserId : USER_ARRAY) {
|
||||
@@ -391,8 +391,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testQueriesDifferentProvider_Filters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -416,8 +416,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -435,8 +435,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testQueriesAction_NoMatchingAction_Filters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -452,8 +452,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -473,8 +473,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testNoQueries_Filters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -490,7 +490,7 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testNoUsesLibrary_Filters() throws Exception {
|
||||
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
|
||||
final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
|
||||
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
|
||||
@@ -516,7 +516,7 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testUsesLibrary_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
|
||||
final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
|
||||
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
|
||||
@@ -543,7 +543,7 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testUsesOptionalLibrary_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
|
||||
final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
|
||||
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
|
||||
@@ -570,7 +570,7 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock,
|
||||
final AppsFilterImpl appsFilter = new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
|
||||
new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
|
||||
@@ -602,8 +602,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testForceQueryable_SystemDoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -621,8 +621,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testForceQueryable_NonSystemFilters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -638,9 +638,10 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
|
||||
false, null, mMockExecutor, mMockPmInternal);
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
|
||||
new String[]{"com.some.package"}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
|
||||
@@ -657,8 +658,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testSystemSignedTarget_DoesntFilter() throws CertificateException {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
appsFilter.onSystemReady();
|
||||
|
||||
@@ -686,9 +687,10 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"},
|
||||
false, null, mMockExecutor, mMockPmInternal);
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock,
|
||||
new String[]{"com.some.package"}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
|
||||
@@ -704,8 +706,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testSystemQueryable_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{},
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{},
|
||||
true /* system force queryable */, null, mMockExecutor,
|
||||
mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
@@ -723,8 +725,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testQueriesPackage_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -742,8 +744,8 @@ public class AppsFilterTest {
|
||||
public void testNoQueries_FeatureOff_DoesntFilter() throws Exception {
|
||||
when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class)))
|
||||
.thenReturn(false);
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -759,8 +761,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testSystemUid_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -775,8 +777,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testSystemUidSecondaryUser_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -792,8 +794,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testNonSystemUid_NoCallingSetting_Filters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -807,8 +809,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testNoTargetPackage_filters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -838,7 +840,7 @@ public class AppsFilterTest {
|
||||
.setOverlayTargetOverlayableName("overlayableName");
|
||||
ParsingPackage actor = pkg("com.some.package.actor");
|
||||
|
||||
final AppsFilter appsFilter = new AppsFilter(
|
||||
final AppsFilterImpl appsFilter = new AppsFilterImpl(
|
||||
mStateProvider,
|
||||
mFeatureConfigMock,
|
||||
new String[]{},
|
||||
@@ -933,7 +935,7 @@ public class AppsFilterTest {
|
||||
when(mMockPmInternal.getSharedUserPackages(any(Integer.class))).thenReturn(
|
||||
actorSharedSettingPackages
|
||||
);
|
||||
final AppsFilter appsFilter = new AppsFilter(
|
||||
final AppsFilterImpl appsFilter = new AppsFilterImpl(
|
||||
mStateProvider,
|
||||
mFeatureConfigMock,
|
||||
new String[]{},
|
||||
@@ -985,8 +987,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testInitiatingApp_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -1003,8 +1005,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testUninstalledInitiatingApp_Filters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -1021,8 +1023,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testOriginatingApp_Filters() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -1046,8 +1048,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testInstallingApp_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -1071,8 +1073,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testInstrumentation_DoesntFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -1100,8 +1102,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testWhoCanSee() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -1173,8 +1175,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testOnChangeReport() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
|
||||
watcher.register();
|
||||
@@ -1246,8 +1248,8 @@ public class AppsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testOnChangeReportedFilter() throws Exception {
|
||||
final AppsFilter appsFilter =
|
||||
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
@@ -1270,6 +1272,53 @@ public class AppsFilterTest {
|
||||
watcher.verifyNoChangeReported("shouldFilterApplication");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppsFilterRead() throws Exception {
|
||||
final AppsFilterImpl appsFilter =
|
||||
new AppsFilterImpl(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
|
||||
mMockExecutor, mMockPmInternal);
|
||||
simulateAddBasicAndroid(appsFilter);
|
||||
appsFilter.onSystemReady();
|
||||
|
||||
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
|
||||
DUMMY_TARGET_APPID);
|
||||
PackageSetting instrumentation = simulateAddPackage(appsFilter,
|
||||
pkgWithInstrumentation("com.some.other.package", "com.some.package"),
|
||||
DUMMY_CALLING_APPID);
|
||||
|
||||
final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1;
|
||||
final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
|
||||
PackageSetting queriesProvider = simulateAddPackage(appsFilter,
|
||||
pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
|
||||
queriesProviderAppId);
|
||||
appsFilter.grantImplicitAccess(
|
||||
hasProviderAppId, queriesProviderAppId, false /* retainOnUpdate */);
|
||||
|
||||
AppsFilterSnapshot snapshot = appsFilter.snapshot();
|
||||
assertFalse(
|
||||
snapshot.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
|
||||
SYSTEM_USER));
|
||||
assertFalse(
|
||||
snapshot.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
|
||||
SYSTEM_USER));
|
||||
|
||||
SparseArray<int[]> queriesProviderFilter =
|
||||
snapshot.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
|
||||
assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)), contains(queriesProviderAppId));
|
||||
assertTrue(snapshot.canQueryPackage(instrumentation.getPkg(),
|
||||
target.getPackageName()));
|
||||
|
||||
// New changes don't affect the snapshot
|
||||
appsFilter.removePackage(target, false);
|
||||
assertTrue(
|
||||
appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
|
||||
SYSTEM_USER));
|
||||
assertFalse(
|
||||
snapshot.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
|
||||
SYSTEM_USER));
|
||||
|
||||
}
|
||||
|
||||
private List<Integer> toList(int[] array) {
|
||||
ArrayList<Integer> ret = new ArrayList<>(array.length);
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
@@ -1282,7 +1331,7 @@ public class AppsFilterTest {
|
||||
PackageSettingBuilder withBuilder(PackageSettingBuilder builder);
|
||||
}
|
||||
|
||||
private void simulateAddBasicAndroid(AppsFilter appsFilter) throws Exception {
|
||||
private void simulateAddBasicAndroid(AppsFilterImpl appsFilter) throws Exception {
|
||||
final Signature frameworkSignature = Mockito.mock(Signature.class);
|
||||
final SigningDetails frameworkSigningDetails =
|
||||
new SigningDetails(new Signature[]{frameworkSignature}, 1);
|
||||
@@ -1291,17 +1340,17 @@ public class AppsFilterTest {
|
||||
b -> b.setSigningDetails(frameworkSigningDetails));
|
||||
}
|
||||
|
||||
private PackageSetting simulateAddPackage(AppsFilter filter,
|
||||
private PackageSetting simulateAddPackage(AppsFilterImpl filter,
|
||||
ParsingPackage newPkgBuilder, int appId) {
|
||||
return simulateAddPackage(filter, newPkgBuilder, appId, null /*settingBuilder*/);
|
||||
}
|
||||
|
||||
private PackageSetting simulateAddPackage(AppsFilter filter,
|
||||
private PackageSetting simulateAddPackage(AppsFilterImpl filter,
|
||||
ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) {
|
||||
return simulateAddPackage(filter, newPkgBuilder, appId, action, null /*sharedUserSetting*/);
|
||||
}
|
||||
|
||||
private PackageSetting simulateAddPackage(AppsFilter filter,
|
||||
private PackageSetting simulateAddPackage(AppsFilterImpl filter,
|
||||
ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action,
|
||||
@Nullable SharedUserSetting sharedUserSetting) {
|
||||
final PackageSetting setting =
|
||||
@@ -1324,7 +1373,7 @@ public class AppsFilterTest {
|
||||
return setting;
|
||||
}
|
||||
|
||||
private void simulateAddPackage(PackageSetting setting, AppsFilter filter,
|
||||
private void simulateAddPackage(PackageSetting setting, AppsFilterImpl filter,
|
||||
@Nullable SharedUserSetting sharedUserSetting) {
|
||||
mExisting.put(setting.getPackageName(), setting);
|
||||
if (sharedUserSetting != null) {
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.server.utils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -860,6 +861,54 @@ public class WatcherTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWatchedSparseSetArray() {
|
||||
final String name = "WatchedSparseSetArray";
|
||||
WatchableTester tester;
|
||||
|
||||
// Test WatchedSparseSetArray
|
||||
WatchedSparseSetArray array = new WatchedSparseSetArray();
|
||||
tester = new WatchableTester(array, name);
|
||||
tester.verify(0, "Initial array - no registration");
|
||||
array.add(INDEX_A, 1);
|
||||
tester.verify(0, "Updates with no registration");
|
||||
tester.register();
|
||||
tester.verify(0, "Updates with no registration");
|
||||
array.add(INDEX_B, 2);
|
||||
tester.verify(1, "Updates with registration");
|
||||
array.add(INDEX_B, 4);
|
||||
array.add(INDEX_C, 5);
|
||||
tester.verify(3, "Updates with registration");
|
||||
// Special methods
|
||||
assertTrue(array.remove(INDEX_C, 5));
|
||||
tester.verify(4, "Removed 5 from key 3");
|
||||
array.remove(INDEX_B);
|
||||
tester.verify(5, "Removed everything for key 2");
|
||||
|
||||
// Snapshot
|
||||
{
|
||||
WatchedSparseSetArray arraySnap = (WatchedSparseSetArray) array.snapshot();
|
||||
tester.verify(5, "Generate snapshot");
|
||||
// Verify that the snapshot is a proper copy of the source.
|
||||
assertEquals("WatchedSparseSetArray snap same size",
|
||||
array.size(), arraySnap.size());
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
ArraySet set = array.get(array.keyAt(i));
|
||||
ArraySet setSnap = arraySnap.get(arraySnap.keyAt(i));
|
||||
assertNotNull(set);
|
||||
assertTrue(set.equals(setSnap));
|
||||
}
|
||||
array.add(INDEX_D, 9);
|
||||
tester.verify(6, "Tick after snapshot");
|
||||
// Verify that the array is sealed
|
||||
verifySealed(name, ()->arraySnap.add(INDEX_D, 10));
|
||||
assertTrue(!array.isSealed());
|
||||
assertTrue(arraySnap.isSealed());
|
||||
}
|
||||
array.clear();
|
||||
tester.verify(7, "Cleared all entries");
|
||||
}
|
||||
|
||||
private static class IndexGenerator {
|
||||
private final int mSeed;
|
||||
private final Random mRandom;
|
||||
@@ -1084,6 +1133,18 @@ public class WatcherTest {
|
||||
assertEquals(a.equals(s), true);
|
||||
a.put(rowIndex, colIndex, !a.get(rowIndex, colIndex));
|
||||
assertEquals(a.equals(s), false);
|
||||
|
||||
// Verify copy-in/out
|
||||
{
|
||||
final String msg = name + " copy";
|
||||
WatchedSparseBooleanMatrix copy = new WatchedSparseBooleanMatrix();
|
||||
copy.copyFrom(matrix);
|
||||
final int end = copy.size();
|
||||
assertTrue(msg + " size mismatch " + end + " " + matrix.size(), end == matrix.size());
|
||||
for (int i = 0; i < end; i++) {
|
||||
assertEquals(copy.keyAt(i), keys[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user