From 3fd950c54cc387402253a9623249aab467a9fce0 Mon Sep 17 00:00:00 2001 From: Sumedh Sen Date: Wed, 1 Jun 2022 15:05:49 -0700 Subject: [PATCH] Add a permissions filter in AppsFilter An app using custom permissions can now get visibility of the packages declaring these custom permissions. Bug: 216823786 Test: atest FrameworksServicesTests:AppsFilterImplTest Change-Id: I5359e3d921fcd99b9ab6565c86901d19068de172 --- .../com/android/server/pm/AppsFilterBase.java | 37 ++ .../com/android/server/pm/AppsFilterImpl.java | 105 ++++++ .../android/server/pm/AppsFilterLocked.java | 10 +- .../server/pm/AppsFilterSnapshotImpl.java | 4 + .../android/server/pm/AppsFilterImplTest.java | 340 +++++++++++++----- 5 files changed, 410 insertions(+), 86 deletions(-) diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java index cf3a3d6160783..8501c5e5d236a 100644 --- a/services/core/java/com/android/server/pm/AppsFilterBase.java +++ b/services/core/java/com/android/server/pm/AppsFilterBase.java @@ -127,6 +127,16 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot { @NonNull protected SnapshotCache> mQueryableViaUsesLibrarySnapshot; + /** + * A mapping from the set of App IDs that query other App IDs via custom permissions to the + * list of packages that they can see. + */ + @NonNull + @Watched + protected WatchedSparseSetArray mQueryableViaUsesPermission; + @NonNull + protected SnapshotCache> mQueryableViaUsesPermissionSnapshot; + /** * Handler for running reasonably short background tasks such as building the initial * visibility cache. @@ -217,6 +227,10 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot { return mQueryableViaUsesLibrary.contains(callingAppId, targetAppId); } + protected boolean isQueryableViaUsesPermission(int callingAppId, int targetAppId) { + return mQueryableViaUsesPermission.contains(callingAppId, targetAppId); + } + protected boolean isQueryableViaComponentWhenRequireRecompute( ArrayMap existingSettings, PackageStateInternal callingPkgSetting, @@ -628,6 +642,22 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot { } } + try { + if (DEBUG_TRACING) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesPermission"); + } + if (isQueryableViaUsesPermission(callingAppId, targetAppId)) { + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "queryable for permission users"); + } + return false; + } + } finally { + if (DEBUG_TRACING) { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + return true; } finally { if (DEBUG_TRACING) { @@ -763,6 +793,13 @@ public abstract class AppsFilterBase implements AppsFilterSnapshot { expandPackages); } + protected void dumpQueriesViaUsesPermission(PrintWriter pw, @Nullable Integer filteringAppId, + ToString expandPackages) { + pw.println(" queryable via uses-permission:"); + dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesPermission, " ", + expandPackages); + } + private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId, WatchedSparseSetArray queriesMap, String spacing, @Nullable ToString toString) { diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java index dae7a6ffae0ee..5e0b47a987568 100644 --- a/services/core/java/com/android/server/pm/AppsFilterImpl.java +++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java @@ -55,6 +55,8 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.component.ParsedInstrumentation; +import com.android.server.pm.pkg.component.ParsedPermission; +import com.android.server.pm.pkg.component.ParsedUsesPermission; import com.android.server.utils.Snappable; import com.android.server.utils.SnapshotCache; import com.android.server.utils.Watchable; @@ -68,8 +70,11 @@ import com.android.server.utils.Watcher; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; /** * Implementation of the methods that update the internal structures of AppsFilter. Because of the @@ -89,6 +94,26 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable, */ private final WatchableImpl mWatchable = new WatchableImpl(); + /** + * A cache that maps parsed {@link android.R.styleable#AndroidManifestPermission + * <permission>} to the packages that define them. While computing visibility based on + * permissions, this cache is used to save the cost of reading through every existing package + * to determine the App Ids that define a particular permission. + */ + @GuardedBy("mQueryableViaUsesPermissionLock") + @NonNull + private HashMap> mPermissionToUids; + + /** + * A cache that maps parsed {@link android.R.styleable#AndroidManifestUsesPermission + * <uses-permission>} to the packages that request them. While computing visibility based + * on permissions, this cache is used to save the cost of reading through every existing + * package to determine the App Ids that request a particular permission. + */ + @GuardedBy("mQueryableViaUsesPermissionLock") + @NonNull + private HashMap> mUsesPermissionToUids; + /** * Ensures an observer is in the list, exactly once. The observer cannot be null. The * function quietly returns if the observer is already in the list. @@ -179,12 +204,18 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable, mQueryableViaUsesLibrarySnapshot = new SnapshotCache.Auto<>( mQueryableViaUsesLibrary, mQueryableViaUsesLibrary, "AppsFilter.mQueryableViaUsesLibrary"); + mQueryableViaUsesPermission = new WatchedSparseSetArray<>(); + mQueryableViaUsesPermissionSnapshot = new SnapshotCache.Auto<>( + mQueryableViaUsesPermission, mQueryableViaUsesPermission, + "AppsFilter.mQueryableViaUsesPermission"); mForceQueryable = new WatchedArraySet<>(); mForceQueryableSnapshot = new SnapshotCache.Auto<>( mForceQueryable, mForceQueryable, "AppsFilter.mForceQueryable"); mProtectedBroadcasts = new WatchedArrayList<>(); mProtectedBroadcastsSnapshot = new SnapshotCache.Auto<>( mProtectedBroadcasts, mProtectedBroadcasts, "AppsFilter.mProtectedBroadcasts"); + mPermissionToUids = new HashMap<>(); + mUsesPermissionToUids = new HashMap<>(); mSnapshot = new SnapshotCache(this, this) { @Override @@ -532,6 +563,54 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable, } } + if (!newPkg.getUsesPermissions().isEmpty()) { + // newPkg requests some permissions + synchronized (mQueryableViaUsesPermissionLock) { + for (ParsedUsesPermission usesPermission : newPkg.getUsesPermissions()) { + String usesPermissionName = usesPermission.getName(); + // Lookup in the mPermissionToUids cache if installed packages have + // defined this permission. + if (mPermissionToUids.containsKey(usesPermissionName)) { + for (int targetAppId : mPermissionToUids.get(usesPermissionName)) { + if (targetAppId != newPkgSetting.getAppId()) { + mQueryableViaUsesPermission.add(newPkgSetting.getAppId(), + targetAppId); + } + } + } + // Record in mUsesPermissionToUids that a permission was requested + // by a new package + if (!mUsesPermissionToUids.containsKey(usesPermissionName)) { + mUsesPermissionToUids.put(usesPermissionName, new HashSet<>()); + } + mUsesPermissionToUids.get(usesPermissionName).add(newPkgSetting.getAppId()); + } + } + } + if (!newPkg.getPermissions().isEmpty()) { + synchronized (mQueryableViaUsesPermissionLock) { + // newPkg defines some permissions + for (ParsedPermission permission : newPkg.getPermissions()) { + String permissionName = permission.getName(); + // Lookup in the mUsesPermissionToUids cache if installed packages have + // requested this permission. + if (mUsesPermissionToUids.containsKey(permissionName)) { + for (int queryingAppId : mUsesPermissionToUids.get(permissionName)) { + if (queryingAppId != newPkgSetting.getAppId()) { + mQueryableViaUsesPermission.add(queryingAppId, + newPkgSetting.getAppId()); + } + } + } + // Record in mPermissionToUids that a permission was defined by a new package + if (!mPermissionToUids.containsKey(permissionName)) { + mPermissionToUids.put(permissionName, new HashSet<>()); + } + mPermissionToUids.get(permissionName).add(newPkgSetting.getAppId()); + } + } + } + for (int i = existingSettings.size() - 1; i >= 0; i--) { final PackageStateInternal existingSetting = existingSettings.valueAt(i); if (existingSetting.getAppId() == newPkgSetting.getAppId() @@ -960,6 +1039,32 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable, } } + synchronized (mQueryableViaUsesPermissionLock) { + if (setting.getPkg() != null && !setting.getPkg().getPermissions().isEmpty()) { + for (ParsedPermission permission : setting.getPkg().getPermissions()) { + String permissionName = permission.getName(); + if (mPermissionToUids.containsKey(permissionName)) { + mPermissionToUids.get(permissionName).remove(setting.getAppId()); + if (mPermissionToUids.get(permissionName).isEmpty()) { + mPermissionToUids.remove(permissionName); + } + } + } + } + if (setting.getPkg() != null && !setting.getPkg().getUsesPermissions().isEmpty()) { + for (ParsedUsesPermission usesPermission : setting.getPkg().getUsesPermissions()) { + String usesPermissionName = usesPermission.getName(); + if (mUsesPermissionToUids.containsKey(usesPermissionName)) { + mUsesPermissionToUids.get(usesPermissionName).remove(setting.getAppId()); + if (mUsesPermissionToUids.get(usesPermissionName).isEmpty()) { + mUsesPermissionToUids.remove(usesPermissionName); + } + } + } + } + mQueryableViaUsesPermission.remove(setting.getAppId()); + } + synchronized (mForceQueryableLock) { mForceQueryable.remove(setting.getAppId()); } diff --git a/services/core/java/com/android/server/pm/AppsFilterLocked.java b/services/core/java/com/android/server/pm/AppsFilterLocked.java index 30eb09e61d3f7..870f9da262108 100644 --- a/services/core/java/com/android/server/pm/AppsFilterLocked.java +++ b/services/core/java/com/android/server/pm/AppsFilterLocked.java @@ -33,10 +33,11 @@ abstract class AppsFilterLocked extends AppsFilterBase { protected final Object mQueriesViaComponentLock = new Object(); /** * This lock covers both {@link #mImplicitlyQueryable} and {@link #mRetainedImplicitlyQueryable} - */ + */ protected final Object mImplicitlyQueryableLock = new Object(); protected final Object mQueryableViaUsesLibraryLock = new Object(); protected final Object mProtectedBroadcastsLock = new Object(); + protected final Object mQueryableViaUsesPermissionLock = new Object(); /** * Guards the access for {@link AppsFilterBase#mShouldFilterCache}; @@ -85,6 +86,13 @@ abstract class AppsFilterLocked extends AppsFilterBase { } } + @Override + protected boolean isQueryableViaUsesPermission(int callingAppId, int targetAppId) { + synchronized (mQueryableViaUsesPermissionLock) { + return super.isQueryableViaUsesPermission(callingAppId, targetAppId); + } + } + @Override protected boolean shouldFilterApplicationUsingCache(int callingUid, int appId, int userId) { synchronized (mCacheLock) { diff --git a/services/core/java/com/android/server/pm/AppsFilterSnapshotImpl.java b/services/core/java/com/android/server/pm/AppsFilterSnapshotImpl.java index 6ae6efae12302..019c853471fe5 100644 --- a/services/core/java/com/android/server/pm/AppsFilterSnapshotImpl.java +++ b/services/core/java/com/android/server/pm/AppsFilterSnapshotImpl.java @@ -44,6 +44,10 @@ public final class AppsFilterSnapshotImpl extends AppsFilterBase { mQueryableViaUsesLibrary = orig.mQueryableViaUsesLibrarySnapshot.snapshot(); } mQueryableViaUsesLibrarySnapshot = new SnapshotCache.Sealed<>(); + synchronized (orig.mQueryableViaUsesPermissionLock) { + mQueryableViaUsesPermission = orig.mQueryableViaUsesPermissionSnapshot.snapshot(); + } + mQueryableViaUsesPermissionSnapshot = new SnapshotCache.Sealed<>(); synchronized (orig.mForceQueryableLock) { mForceQueryable = orig.mForceQueryableSnapshot.snapshot(); } diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java index 46727a6c0eb4a..48c58bbeb4052 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterImplTest.java @@ -52,9 +52,13 @@ import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.pm.pkg.component.ParsedActivity; import com.android.server.pm.pkg.component.ParsedActivityImpl; +import com.android.server.pm.pkg.component.ParsedComponentImpl; import com.android.server.pm.pkg.component.ParsedInstrumentationImpl; import com.android.server.pm.pkg.component.ParsedIntentInfoImpl; +import com.android.server.pm.pkg.component.ParsedPermission; +import com.android.server.pm.pkg.component.ParsedPermissionImpl; import com.android.server.pm.pkg.component.ParsedProviderImpl; +import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl; import com.android.server.pm.pkg.parsing.ParsingPackage; import com.android.server.utils.WatchableTester; @@ -160,6 +164,17 @@ public class AppsFilterImplTest { return pkg(packageName).addLibraryName(libName); } + private static ParsingPackage pkgWithCustomPermissions(String packageName, + String... permNames) { + ParsingPackage newPkg = pkg(packageName); + for (String permName : permNames) { + ParsedPermission permission = new ParsedPermissionImpl(); + ((ParsedComponentImpl) permission).setName(permName); + newPkg.addPermission(permission); + } + return newPkg; + } + private static ParsedActivity createActivity(String packageName, IntentFilter[] filters) { ParsedActivityImpl activity = new ParsedActivityImpl(); activity.setPackageName(packageName); @@ -227,8 +242,8 @@ public class AppsFilterImplTest { @Test public void testSystemReadyPropogates() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); appsFilter.onSystemReady(mPmInternal); @@ -239,8 +254,8 @@ public class AppsFilterImplTest { @Test public void testQueriesAction_FilterMatches() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); simulateAddBasicAndroid(appsFilter); @@ -264,8 +279,8 @@ public class AppsFilterImplTest { @Test public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); final Signature frameworkSignature = Mockito.mock(Signature.class); @@ -313,8 +328,8 @@ public class AppsFilterImplTest { @Test public void testQueriesProvider_FilterMatches() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); simulateAddBasicAndroid(appsFilter); @@ -338,8 +353,8 @@ public class AppsFilterImplTest { @Test public void testOnUserUpdated_FilterMatches() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -386,8 +401,8 @@ public class AppsFilterImplTest { @Test public void testQueriesDifferentProvider_Filters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); simulateAddBasicAndroid(appsFilter); @@ -411,8 +426,8 @@ public class AppsFilterImplTest { @Test public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -430,8 +445,8 @@ public class AppsFilterImplTest { @Test public void testQueriesAction_NoMatchingAction_Filters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -447,8 +462,8 @@ public class AppsFilterImplTest { @Test public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -469,8 +484,8 @@ public class AppsFilterImplTest { @Test public void testNoQueries_Filters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -486,10 +501,9 @@ public class AppsFilterImplTest { @Test public void testNoUsesLibrary_Filters() throws Exception { - final AppsFilterImpl appsFilter = new AppsFilterImpl(mFeatureConfigMock, - new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, - mMockHandler); - + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -513,10 +527,9 @@ public class AppsFilterImplTest { @Test public void testUsesLibrary_DoesntFilter() throws Exception { - final AppsFilterImpl appsFilter = new AppsFilterImpl(mFeatureConfigMock, - new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, - mMockHandler); - + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -541,10 +554,9 @@ public class AppsFilterImplTest { @Test public void testUsesOptionalLibrary_DoesntFilter() throws Exception { - final AppsFilterImpl appsFilter = new AppsFilterImpl(mFeatureConfigMock, - new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, - mMockHandler); - + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -569,10 +581,9 @@ public class AppsFilterImplTest { @Test public void testUsesLibrary_ShareUid_DoesntFilter() throws Exception { - final AppsFilterImpl appsFilter = new AppsFilterImpl(mFeatureConfigMock, - new String[]{}, /* systemAppsQueryable */ false, /* overlayProvider */ null, - mMockHandler); - + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -603,8 +614,8 @@ public class AppsFilterImplTest { @Test public void testForceQueryable_SystemDoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -623,8 +634,8 @@ public class AppsFilterImplTest { @Test public void testForceQueryable_NonSystemFilters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -641,9 +652,8 @@ public class AppsFilterImplTest { @Test public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, - new String[]{"com.some.package"}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{"com.some.package"}, + /* systemAppsQueryable */ false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -662,8 +672,8 @@ public class AppsFilterImplTest { @Test public void testSystemSignedTarget_DoesntFilter() throws CertificateException { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); appsFilter.onSystemReady(mPmInternal); final Signature frameworkSignature = Mockito.mock(Signature.class); @@ -692,9 +702,8 @@ public class AppsFilterImplTest { @Test public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, - new String[]{"com.some.package"}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{"com.some.package"}, + /* systemAppsQueryable */ false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -712,8 +721,8 @@ public class AppsFilterImplTest { @Test public void testSystemQueryable_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, - true /* system force queryable */, null, mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + true, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -731,8 +740,8 @@ public class AppsFilterImplTest { @Test public void testQueriesPackage_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -751,8 +760,8 @@ public class AppsFilterImplTest { when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(false); final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -769,8 +778,8 @@ public class AppsFilterImplTest { @Test public void testSystemUid_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -786,8 +795,8 @@ public class AppsFilterImplTest { @Test public void testSystemUidSecondaryUser_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -804,8 +813,8 @@ public class AppsFilterImplTest { @Test public void testNonSystemUid_NoCallingSetting_Filters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -817,10 +826,10 @@ public class AppsFilterImplTest { } @Test - public void testNoTargetPackage_filters() throws Exception { + public void testNoTargetPackage_Filters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -991,8 +1000,8 @@ public class AppsFilterImplTest { @Test public void testInitiatingApp_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -1010,8 +1019,8 @@ public class AppsFilterImplTest { @Test public void testUninstalledInitiatingApp_Filters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -1029,8 +1038,8 @@ public class AppsFilterImplTest { @Test public void testOriginatingApp_Filters() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); simulateAddBasicAndroid(appsFilter); @@ -1055,8 +1064,8 @@ public class AppsFilterImplTest { @Test public void testInstallingApp_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); simulateAddBasicAndroid(appsFilter); @@ -1081,8 +1090,8 @@ public class AppsFilterImplTest { @Test public void testInstrumentation_DoesntFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); simulateAddBasicAndroid(appsFilter); @@ -1110,8 +1119,8 @@ public class AppsFilterImplTest { @Test public void testWhoCanSee() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); simulateAddBasicAndroid(appsFilter); @@ -1185,8 +1194,8 @@ public class AppsFilterImplTest { @Test public void testOnChangeReport() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange"); watcher.register(); simulateAddBasicAndroid(appsFilter); @@ -1260,8 +1269,8 @@ public class AppsFilterImplTest { @Test public void testOnChangeReportedFilter() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); final WatchableTester watcher = new WatchableTester(appsFilter, "onChange filter"); @@ -1287,8 +1296,8 @@ public class AppsFilterImplTest { public void testAppsFilterRead() throws Exception { when(mFeatureConfigMock.snapshot()).thenReturn(mFeatureConfigMock); final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -1338,8 +1347,8 @@ public class AppsFilterImplTest { @Test public void testSdkSandbox_canSeeForceQueryable() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -1358,8 +1367,8 @@ public class AppsFilterImplTest { @Test public void testSdkSandbox_cannotSeeNonForceQueryable() throws Exception { final AppsFilterImpl appsFilter = - new AppsFilterImpl(mFeatureConfigMock, new String[]{}, false, null, - mMockHandler); + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(mPmInternal); @@ -1408,6 +1417,167 @@ public class AppsFilterImplTest { null /* callingSetting */, target, SYSTEM_USER)); } + @Test + public void testUsesPermission_installPermissionDefinerBeforeRequester_DoesntFilter() + throws Exception { + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(mPmInternal); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithCustomPermissions("com.some.package", + "com.some.custom_permission"), + DUMMY_TARGET_APPID); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package").addUsesPermission( + new ParsedUsesPermissionImpl("com.some.custom_permission", 0)), + DUMMY_CALLING_APPID); + + assertFalse( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesPermission_installPermissionRequesterBeforeDefiner_DoesntFilter() + throws Exception { + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(mPmInternal); + + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package").addUsesPermission( + new ParsedUsesPermissionImpl("com.some.custom_permission", 0)), + DUMMY_CALLING_APPID); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithCustomPermissions("com.some.package", + "com.some.custom_permission"), + DUMMY_TARGET_APPID); + + assertFalse( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesPermission_visibilityFromPermissionDefinerToRequester_Filters() + throws Exception { + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(mPmInternal); + + final PackageSetting calling = simulateAddPackage(appsFilter, + pkgWithCustomPermissions("com.some.package", + "com.some.custom_permission"), + DUMMY_CALLING_APPID); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkg("com.some.other.package").addUsesPermission( + new ParsedUsesPermissionImpl("com.some.custom_permission", 0)), + DUMMY_TARGET_APPID); + + assertTrue( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } + + @Test + public void testUsesPermission_multipleCustomPermissions() throws Exception { + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(mPmInternal); + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithCustomPermissions("com.some.package", + "com.some.custom_permission1", "com.some.custom_permission2"), + DUMMY_TARGET_APPID); + + final PackageSetting calling1 = simulateAddPackage(appsFilter, + pkg("com.some.other.package") + .addUsesPermission(new ParsedUsesPermissionImpl( + "com.some.custom_permission1", 0)), + DUMMY_CALLING_APPID); + + final PackageSetting calling2 = simulateAddPackage(appsFilter, + pkg("com.some.another.package") + .addUsesPermission(new ParsedUsesPermissionImpl( + "com.some.custom_permission2", 0)) + .addUsesPermission(new ParsedUsesPermissionImpl( + "com.some.custom_permission3", 0)), + DUMMY_CALLING_APPID + 1); + + assertFalse( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling1, target, + SYSTEM_USER)); + assertFalse( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID + 1, + calling2, target, SYSTEM_USER)); + assertTrue( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling1, + calling2, SYSTEM_USER)); + } + + @Test + public void testUsesPermission_multiplePermissionDefiners_DoesntFilter() throws Exception { + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(mPmInternal); + + + final PackageSetting target1 = simulateAddPackage(appsFilter, + pkgWithCustomPermissions("com.some.package1", "com.some.custom_permission"), + DUMMY_TARGET_APPID); + final PackageSetting target2 = simulateAddPackage(appsFilter, + pkgWithCustomPermissions("com.some.package2", "com.some.custom_permission"), + DUMMY_TARGET_APPID + 1); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package") + .addUsesPermission(new ParsedUsesPermissionImpl( + "com.some.custom_permission", 0)), + DUMMY_CALLING_APPID); + + assertFalse( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target1, + SYSTEM_USER)); + assertFalse( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target2, + SYSTEM_USER)); + + } + + @Test + public void testNoUsesPermission_Filters() throws Exception { + final AppsFilterImpl appsFilter = + new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */ + false, /* overlayProvider */ null, mMockHandler); + + simulateAddBasicAndroid(appsFilter); + appsFilter.onSystemReady(mPmInternal); + + + final PackageSetting target = simulateAddPackage(appsFilter, + pkgWithCustomPermissions("com.some.package", "com.some.custom_permission"), + DUMMY_TARGET_APPID); + final PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package"), + DUMMY_CALLING_APPID); + + assertTrue( + appsFilter.shouldFilterApplication(mSnapshot, DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); + } private List toList(int[] array) { ArrayList ret = new ArrayList<>(array.length); for (int i = 0; i < array.length; i++) {