Loading core/java/android/app/ActivityManagerInternal.java +16 −0 Original line number Diff line number Diff line Loading @@ -403,4 +403,20 @@ public abstract class ActivityManagerInternal { * Called by DevicePolicyManagerService to set the uid of the device owner. */ public abstract void setDeviceOwnerUid(int uid); /** * Sends a broadcast, assuming the caller to be the system and allowing the inclusion of an * approved whitelist of app Ids >= {@link android.os.Process#FIRST_APPLICATION_UID} that the * broadcast my be sent to; any app Ids < {@link android.os.Process#FIRST_APPLICATION_UID} are * automatically whitelisted. * * @see com.android.server.am.ActivityManagerService#broadcastIntentWithFeature( * IApplicationThread, String, Intent, String, IIntentReceiver, int, String, Bundle, * String[], int, Bundle, boolean, boolean, int) */ public abstract int broadcastIntent(Intent intent, IIntentReceiver resultTo, String[] requiredPermissions, boolean serialized, int userId, int[] appIdWhitelist); } services/core/java/com/android/server/am/ActivityManagerService.java +61 −5 Original line number Diff line number Diff line Loading @@ -15568,7 +15568,7 @@ public class ActivityManagerService extends IActivityManager.Stub } private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, int callingUid, int[] users) { int callingUid, int[] users, int[] broadcastWhitelist) { // TODO: come back and remove this assumption to triage all broadcasts int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING; Loading Loading @@ -15644,6 +15644,15 @@ public class ActivityManagerService extends IActivityManager.Stub } catch (RemoteException ex) { // pm is in same process, this will never happen. } if (receivers != null && broadcastWhitelist != null) { for (int i = receivers.size() - 1; i >= 0; i--) { final int uid = receivers.get(i).activityInfo.applicationInfo.uid; if (uid >= Process.FIRST_APPLICATION_UID && Arrays.binarySearch(broadcastWhitelist, UserHandle.getAppId(uid)) < 0) { receivers.remove(i); } } } return receivers; } Loading Loading @@ -15738,7 +15747,8 @@ public class ActivityManagerService extends IActivityManager.Stub return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */); realCallingPid, userId, false /* allowBackgroundActivityStarts */, null /*broadcastWhitelist*/); } @GuardedBy("this") Loading @@ -15747,7 +15757,8 @@ public class ActivityManagerService extends IActivityManager.Stub IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid, int realCallingPid, int userId, boolean allowBackgroundActivityStarts) { int realCallingPid, int userId, boolean allowBackgroundActivityStarts, @Nullable int[] broadcastWhitelist) { intent = new Intent(intent); final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid); Loading @@ -15756,6 +15767,12 @@ public class ActivityManagerService extends IActivityManager.Stub intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); } if (userId == UserHandle.USER_ALL && broadcastWhitelist != null) { Slog.e(TAG, "broadcastWhitelist only applies when sending to individual users. " + "Assuming restrictive whitelist."); broadcastWhitelist = new int[]{}; } // By default broadcasts do not go to stopped apps. intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); Loading Loading @@ -16242,7 +16259,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Need to resolve the intent to interested receivers... if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); receivers = collectReceiverComponents( intent, resolvedType, callingUid, users, broadcastWhitelist); } if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) { Loading Loading @@ -16272,6 +16290,17 @@ public class ActivityManagerService extends IActivityManager.Stub if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction() + " replacePending=" + replacePending); if (registeredReceivers != null && broadcastWhitelist != null) { // if a uid whitelist was provided, remove anything in the application space that wasn't // in it. for (int i = registeredReceivers.size() - 1; i >= 0; i--) { final int uid = registeredReceivers.get(i).owningUid; if (uid >= Process.FIRST_APPLICATION_UID && Arrays.binarySearch(broadcastWhitelist, UserHandle.getAppId(uid)) < 0) { registeredReceivers.remove(i); } } } int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { Loading Loading @@ -16555,7 +16584,8 @@ public class ActivityManagerService extends IActivityManager.Stub return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid, realCallingPid, userId, allowBackgroundActivityStarts); realCallingPid, userId, allowBackgroundActivityStarts, null /*broadcastWhitelist*/); } finally { Binder.restoreCallingIdentity(origId); } Loading Loading @@ -19185,6 +19215,32 @@ public class ActivityManagerService extends IActivityManager.Stub } } @Override public int broadcastIntent(Intent intent, IIntentReceiver resultTo, String[] requiredPermissions, boolean serialized, int userId, int[] appIdWhitelist) { synchronized (ActivityManagerService.this) { intent = verifyBroadcastLocked(intent); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { return ActivityManagerService.this.broadcastIntentLocked(null /*callerApp*/, null /*callerPackage*/, null /*callingFeatureId*/, intent, null /*resolvedType*/, resultTo, 0 /*resultCode*/, null /*resultData*/, null /*resultExtras*/, requiredPermissions, AppOpsManager.OP_NONE, null /*options*/, serialized, false /*sticky*/, callingPid, callingUid, callingUid, callingPid, userId, false /*allowBackgroundStarts*/, appIdWhitelist); } finally { Binder.restoreCallingIdentity(origId); } } } @Override public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, boolean fgRequired, String callingPackage, @Nullable String callingFeatureId, services/core/java/com/android/server/pm/AppsFilter.java +60 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import com.android.server.om.OverlayReferenceMapper; import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.PrintWriter; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Set; Loading Loading @@ -510,6 +511,64 @@ public class AppsFilter { && pkgSetting.signatures.mSigningDetails.signaturesMatchExactly(sysSigningDetails); } private static void sort(int[] uids, int nextUidIndex) { Arrays.sort(uids, 0, nextUidIndex); } /** * 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 whitelist should be * applied. */ @Nullable public SparseArray<int[]> getVisibilityWhitelist(PackageSetting setting, int[] users, ArrayMap<String, PackageSetting> existingSettings) { if (mForceQueryable.contains(setting.appId)) { return null; } // let's reserve max memory to limit the number of allocations SparseArray<int[]> result = new SparseArray<>(users.length); for (int u = 0; u < users.length; u++) { final int userId = users[u]; int[] appIds = new int[existingSettings.size()]; int[] buffer = null; int whitelistSize = 0; for (int i = existingSettings.size() - 1; i >= 0; i--) { final PackageSetting existingSetting = existingSettings.valueAt(i); final int existingAppId = existingSetting.appId; if (existingAppId < Process.FIRST_APPLICATION_UID) { continue; } final int loc = Arrays.binarySearch(appIds, 0, whitelistSize, existingAppId); if (loc >= 0) { continue; } final int existingUid = UserHandle.getUid(userId, existingAppId); if (!shouldFilterApplication(existingUid, existingSetting, setting, userId)) { if (buffer == null) { buffer = new int[appIds.length]; } final int insert = ~loc; System.arraycopy(appIds, insert, buffer, 0, whitelistSize - insert); appIds[insert] = existingUid; System.arraycopy(buffer, 0, appIds, insert + 1, whitelistSize - insert); whitelistSize++; } } result.put(userId, Arrays.copyOf(appIds, whitelistSize)); } return result; } /** * Removes a package for consideration when filtering visibility between apps. * Loading services/core/java/com/android/server/pm/PackageManagerService.java +93 −64 File changed.Preview size limit exceeded, changes collapsed. Show changes services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +55 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.pm; import static org.hamcrest.Matchers.arrayContaining; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -47,6 +48,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.parsing.pkg.ParsedPackage; import org.hamcrest.Matcher; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -56,7 +58,9 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.security.cert.CertificateException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; Loading Loading @@ -635,6 +639,57 @@ public class AppsFilterTest { appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, target, instrumentation, 0)); } @Test public void testWhoCanSee() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); appsFilter.onSystemReady(); final int systemAppId = Process.FIRST_APPLICATION_UID - 1; final int seesNothingAppId = Process.FIRST_APPLICATION_UID; final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1; final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2; PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId); PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("some.system.pkg"), seesNothingAppId); PackageSetting hasProvider = simulateAddPackage(appsFilter, pkgWithProvider("com.some.package", "com.some.authority"), hasProviderAppId); PackageSetting queriesProvider = simulateAddPackage(appsFilter, pkgQueriesProvider("com.some.other.package", "com.some.authority"), queriesProviderAppId); final int[] systemFilter = appsFilter.getVisibilityWhitelist(system, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(systemFilter), arrayContaining(systemAppId)); final int[] seesNothingFilter = appsFilter.getVisibilityWhitelist(seesNothing, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(seesNothingFilter), arrayContaining(systemAppId, seesNothingAppId)); final int[] hasProviderFilter = appsFilter.getVisibilityWhitelist(hasProvider, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(hasProviderFilter), arrayContaining(systemAppId, hasProviderAppId, queriesProviderAppId)); int[] queriesProviderFilter = appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(queriesProviderFilter), arrayContaining(systemAppId, queriesProviderAppId)); // provider read appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId); // ensure implicit access is included in the filter queriesProviderFilter = appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(queriesProviderFilter), arrayContaining(systemAppId, hasProviderAppId, queriesProviderAppId)); } private void assertThat(List<int[]> asList, Matcher<Integer[]> arrayContainingInAnyOrder) { } private interface WithSettingBuilder { PackageSettingBuilder withBuilder(PackageSettingBuilder builder); } Loading Loading
core/java/android/app/ActivityManagerInternal.java +16 −0 Original line number Diff line number Diff line Loading @@ -403,4 +403,20 @@ public abstract class ActivityManagerInternal { * Called by DevicePolicyManagerService to set the uid of the device owner. */ public abstract void setDeviceOwnerUid(int uid); /** * Sends a broadcast, assuming the caller to be the system and allowing the inclusion of an * approved whitelist of app Ids >= {@link android.os.Process#FIRST_APPLICATION_UID} that the * broadcast my be sent to; any app Ids < {@link android.os.Process#FIRST_APPLICATION_UID} are * automatically whitelisted. * * @see com.android.server.am.ActivityManagerService#broadcastIntentWithFeature( * IApplicationThread, String, Intent, String, IIntentReceiver, int, String, Bundle, * String[], int, Bundle, boolean, boolean, int) */ public abstract int broadcastIntent(Intent intent, IIntentReceiver resultTo, String[] requiredPermissions, boolean serialized, int userId, int[] appIdWhitelist); }
services/core/java/com/android/server/am/ActivityManagerService.java +61 −5 Original line number Diff line number Diff line Loading @@ -15568,7 +15568,7 @@ public class ActivityManagerService extends IActivityManager.Stub } private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, int callingUid, int[] users) { int callingUid, int[] users, int[] broadcastWhitelist) { // TODO: come back and remove this assumption to triage all broadcasts int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING; Loading Loading @@ -15644,6 +15644,15 @@ public class ActivityManagerService extends IActivityManager.Stub } catch (RemoteException ex) { // pm is in same process, this will never happen. } if (receivers != null && broadcastWhitelist != null) { for (int i = receivers.size() - 1; i >= 0; i--) { final int uid = receivers.get(i).activityInfo.applicationInfo.uid; if (uid >= Process.FIRST_APPLICATION_UID && Arrays.binarySearch(broadcastWhitelist, UserHandle.getAppId(uid)) < 0) { receivers.remove(i); } } } return receivers; } Loading Loading @@ -15738,7 +15747,8 @@ public class ActivityManagerService extends IActivityManager.Stub return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */); realCallingPid, userId, false /* allowBackgroundActivityStarts */, null /*broadcastWhitelist*/); } @GuardedBy("this") Loading @@ -15747,7 +15757,8 @@ public class ActivityManagerService extends IActivityManager.Stub IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid, int realCallingPid, int userId, boolean allowBackgroundActivityStarts) { int realCallingPid, int userId, boolean allowBackgroundActivityStarts, @Nullable int[] broadcastWhitelist) { intent = new Intent(intent); final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid); Loading @@ -15756,6 +15767,12 @@ public class ActivityManagerService extends IActivityManager.Stub intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); } if (userId == UserHandle.USER_ALL && broadcastWhitelist != null) { Slog.e(TAG, "broadcastWhitelist only applies when sending to individual users. " + "Assuming restrictive whitelist."); broadcastWhitelist = new int[]{}; } // By default broadcasts do not go to stopped apps. intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); Loading Loading @@ -16242,7 +16259,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Need to resolve the intent to interested receivers... if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); receivers = collectReceiverComponents( intent, resolvedType, callingUid, users, broadcastWhitelist); } if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) { Loading Loading @@ -16272,6 +16290,17 @@ public class ActivityManagerService extends IActivityManager.Stub if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction() + " replacePending=" + replacePending); if (registeredReceivers != null && broadcastWhitelist != null) { // if a uid whitelist was provided, remove anything in the application space that wasn't // in it. for (int i = registeredReceivers.size() - 1; i >= 0; i--) { final int uid = registeredReceivers.get(i).owningUid; if (uid >= Process.FIRST_APPLICATION_UID && Arrays.binarySearch(broadcastWhitelist, UserHandle.getAppId(uid)) < 0) { registeredReceivers.remove(i); } } } int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { Loading Loading @@ -16555,7 +16584,8 @@ public class ActivityManagerService extends IActivityManager.Stub return broadcastIntentLocked(null, packageName, featureId, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid, realCallingPid, userId, allowBackgroundActivityStarts); realCallingPid, userId, allowBackgroundActivityStarts, null /*broadcastWhitelist*/); } finally { Binder.restoreCallingIdentity(origId); } Loading Loading @@ -19185,6 +19215,32 @@ public class ActivityManagerService extends IActivityManager.Stub } } @Override public int broadcastIntent(Intent intent, IIntentReceiver resultTo, String[] requiredPermissions, boolean serialized, int userId, int[] appIdWhitelist) { synchronized (ActivityManagerService.this) { intent = verifyBroadcastLocked(intent); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { return ActivityManagerService.this.broadcastIntentLocked(null /*callerApp*/, null /*callerPackage*/, null /*callingFeatureId*/, intent, null /*resolvedType*/, resultTo, 0 /*resultCode*/, null /*resultData*/, null /*resultExtras*/, requiredPermissions, AppOpsManager.OP_NONE, null /*options*/, serialized, false /*sticky*/, callingPid, callingUid, callingUid, callingPid, userId, false /*allowBackgroundStarts*/, appIdWhitelist); } finally { Binder.restoreCallingIdentity(origId); } } } @Override public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, boolean fgRequired, String callingPackage, @Nullable String callingFeatureId,
services/core/java/com/android/server/pm/AppsFilter.java +60 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import com.android.server.om.OverlayReferenceMapper; import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.PrintWriter; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Set; Loading Loading @@ -510,6 +511,64 @@ public class AppsFilter { && pkgSetting.signatures.mSigningDetails.signaturesMatchExactly(sysSigningDetails); } private static void sort(int[] uids, int nextUidIndex) { Arrays.sort(uids, 0, nextUidIndex); } /** * 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 whitelist should be * applied. */ @Nullable public SparseArray<int[]> getVisibilityWhitelist(PackageSetting setting, int[] users, ArrayMap<String, PackageSetting> existingSettings) { if (mForceQueryable.contains(setting.appId)) { return null; } // let's reserve max memory to limit the number of allocations SparseArray<int[]> result = new SparseArray<>(users.length); for (int u = 0; u < users.length; u++) { final int userId = users[u]; int[] appIds = new int[existingSettings.size()]; int[] buffer = null; int whitelistSize = 0; for (int i = existingSettings.size() - 1; i >= 0; i--) { final PackageSetting existingSetting = existingSettings.valueAt(i); final int existingAppId = existingSetting.appId; if (existingAppId < Process.FIRST_APPLICATION_UID) { continue; } final int loc = Arrays.binarySearch(appIds, 0, whitelistSize, existingAppId); if (loc >= 0) { continue; } final int existingUid = UserHandle.getUid(userId, existingAppId); if (!shouldFilterApplication(existingUid, existingSetting, setting, userId)) { if (buffer == null) { buffer = new int[appIds.length]; } final int insert = ~loc; System.arraycopy(appIds, insert, buffer, 0, whitelistSize - insert); appIds[insert] = existingUid; System.arraycopy(buffer, 0, appIds, insert + 1, whitelistSize - insert); whitelistSize++; } } result.put(userId, Arrays.copyOf(appIds, whitelistSize)); } return result; } /** * Removes a package for consideration when filtering visibility between apps. * Loading
services/core/java/com/android/server/pm/PackageManagerService.java +93 −64 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +55 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.pm; import static org.hamcrest.Matchers.arrayContaining; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -47,6 +48,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.parsing.pkg.ParsedPackage; import org.hamcrest.Matcher; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -56,7 +58,9 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.security.cert.CertificateException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; Loading Loading @@ -635,6 +639,57 @@ public class AppsFilterTest { appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, target, instrumentation, 0)); } @Test public void testWhoCanSee() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); appsFilter.onSystemReady(); final int systemAppId = Process.FIRST_APPLICATION_UID - 1; final int seesNothingAppId = Process.FIRST_APPLICATION_UID; final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1; final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2; PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId); PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("some.system.pkg"), seesNothingAppId); PackageSetting hasProvider = simulateAddPackage(appsFilter, pkgWithProvider("com.some.package", "com.some.authority"), hasProviderAppId); PackageSetting queriesProvider = simulateAddPackage(appsFilter, pkgQueriesProvider("com.some.other.package", "com.some.authority"), queriesProviderAppId); final int[] systemFilter = appsFilter.getVisibilityWhitelist(system, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(systemFilter), arrayContaining(systemAppId)); final int[] seesNothingFilter = appsFilter.getVisibilityWhitelist(seesNothing, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(seesNothingFilter), arrayContaining(systemAppId, seesNothingAppId)); final int[] hasProviderFilter = appsFilter.getVisibilityWhitelist(hasProvider, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(hasProviderFilter), arrayContaining(systemAppId, hasProviderAppId, queriesProviderAppId)); int[] queriesProviderFilter = appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(queriesProviderFilter), arrayContaining(systemAppId, queriesProviderAppId)); // provider read appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId); // ensure implicit access is included in the filter queriesProviderFilter = appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); assertThat(Arrays.asList(queriesProviderFilter), arrayContaining(systemAppId, hasProviderAppId, queriesProviderAppId)); } private void assertThat(List<int[]> asList, Matcher<Integer[]> arrayContainingInAnyOrder) { } private interface WithSettingBuilder { PackageSettingBuilder withBuilder(PackageSettingBuilder builder); } Loading