Loading services/core/java/com/android/server/pm/AppsFilter.java +329 −134 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -27,6 +29,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.UserInfo; import android.content.pm.parsing.component.ParsedComponent; import android.content.pm.parsing.component.ParsedInstrumentation; import android.content.pm.parsing.component.ParsedIntentInfo; Loading Loading @@ -108,12 +111,25 @@ public class AppsFilter { private final boolean mSystemAppsQueryable; private final FeatureConfig mFeatureConfig; private final OverlayReferenceMapper mOverlayReferenceMapper; private final StateProvider mStateProvider; private PackageParser.SigningDetails mSystemSigningDetails; private Set<String> mProtectedBroadcasts = new ArraySet<>(); AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist, /** * This structure maps uid -> uid and indicates whether access from the first should be * filtered to the second. It's essentially a cache of the * {@link #shouldFilterApplicationInternal(int, SettingBase, PackageSetting, int)} call. * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on * initial scam and is null until {@link #onSystemReady()} is called. */ private volatile SparseArray<SparseBooleanArray> mShouldFilterCache; @VisibleForTesting(visibility = PRIVATE) AppsFilter(StateProvider stateProvider, FeatureConfig featureConfig, String[] forceQueryableWhitelist, boolean systemAppsQueryable, @Nullable OverlayReferenceMapper.Provider overlayProvider) { mFeatureConfig = featureConfig; Loading @@ -121,8 +137,23 @@ public class AppsFilter { mSystemAppsQueryable = systemAppsQueryable; mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/, overlayProvider); mStateProvider = stateProvider; } /** * Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding * the data with the package lock. */ @VisibleForTesting(visibility = PRIVATE) public interface StateProvider { void runWithState(CurrentStateCallback callback); interface CurrentStateCallback { void currentState(ArrayMap<String, PackageSetting> settings, List<UserInfo> users); } } @VisibleForTesting(visibility = PRIVATE) public interface FeatureConfig { /** Called when the system is ready and components can be queried. */ Loading @@ -139,6 +170,7 @@ public class AppsFilter { /** * Turns on logging for the given appId * * @param enable true if logging should be enabled, false if disabled. */ void enableLogging(int appId, boolean enable); Loading @@ -146,6 +178,7 @@ public class AppsFilter { /** * Initializes the package enablement state for the given package. This gives opportunity * to do any expensive operations ahead of the actual checks. * * @param removed true if adding, false if removing */ void updatePackageState(PackageSetting setting, boolean removed); Loading @@ -161,6 +194,7 @@ public class AppsFilter { @Nullable private SparseBooleanArray mLoggingEnabled = null; private AppsFilter mAppsFilter; private FeatureConfigImpl( PackageManagerInternal pmInternal, PackageManagerService.Injector injector) { Loading @@ -168,6 +202,10 @@ public class AppsFilter { mInjector = injector; } public void setAppsFilter(AppsFilter filter) { mAppsFilter = filter; } @Override public void onSystemReady() { mFeatureEnabled = DeviceConfig.getBoolean( Loading Loading @@ -235,6 +273,7 @@ public class AppsFilter { @Override public void onCompatChange(String packageName) { updateEnabledState(mPmInternal.getPackage(packageName)); mAppsFilter.updateShouldFilterCacheForPackage(packageName); } private void updateEnabledState(AndroidPackage pkg) { Loading Loading @@ -267,7 +306,7 @@ public class AppsFilter { final boolean forceSystemAppsQueryable = injector.getContext().getResources() .getBoolean(R.bool.config_forceSystemPackagesQueryable); final FeatureConfig featureConfig = new FeatureConfigImpl(pms, injector); final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector); final String[] forcedQueryablePackageNames; if (forceSystemAppsQueryable) { // all system apps already queryable, no need to read and parse individual exceptions Loading @@ -280,8 +319,16 @@ public class AppsFilter { forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern(); } } return new AppsFilter(featureConfig, forcedQueryablePackageNames, forceSystemAppsQueryable, null); final StateProvider stateProvider = command -> { synchronized (injector.getLock()) { command.currentState(injector.getSettings().mPackages, injector.getUserManagerService().getUsers(false, false, false)); } }; AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig, forcedQueryablePackageNames, forceSystemAppsQueryable, null); featureConfig.setAppsFilter(appsFilter); return appsFilter; } public FeatureConfig getFeatureConfig() { Loading Loading @@ -407,24 +454,56 @@ public class AppsFilter { * @param visibleUid the uid becoming visible to the {@recipientUid} */ public void grantImplicitAccess(int recipientUid, int visibleUid) { if (recipientUid != visibleUid && mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { if (recipientUid != visibleUid) { if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid); } if (mShouldFilterCache != null) { // update the cache in a one-off manner since we've got all the information we need. SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid); if (visibleUids == null) { visibleUids = new SparseBooleanArray(); mShouldFilterCache.put(recipientUid, visibleUids); } visibleUids.put(visibleUid, false); } } } public void onSystemReady() { mStateProvider.runWithState(new StateProvider.CurrentStateCallback() { @Override public void currentState(ArrayMap<String, PackageSetting> settings, List<UserInfo> users) { mShouldFilterCache = new SparseArray<>(users.size() * settings.size()); } }); mFeatureConfig.onSystemReady(); mOverlayReferenceMapper.rebuildIfDeferred(); updateEntireShouldFilterCache(); } /** * Adds a package that should be considered when filtering visibility between apps. * * @param newPkgSetting the new setting being added * @param existingSettings all other settings currently on the device. */ public void addPackage(PackageSetting newPkgSetting, public void addPackage(PackageSetting newPkgSetting) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); try { mStateProvider.runWithState((settings, users) -> { addPackageInternal(newPkgSetting, settings); if (mShouldFilterCache != null) { updateShouldFilterCacheForPackage( null, newPkgSetting, settings, users, settings.size()); } // else, rebuild entire cache when system is ready }); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private void addPackageInternal(PackageSetting newPkgSetting, ArrayMap<String, PackageSetting> existingSettings) { if (Objects.equals("android", newPkgSetting.name)) { // let's set aside the framework signatures Loading @@ -438,8 +517,6 @@ public class AppsFilter { } } Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); try { final AndroidPackage newPkg = newPkgSetting.pkg; if (newPkg == null) { // nothing to add Loading Loading @@ -509,8 +586,84 @@ public class AppsFilter { } mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } private void removeAppIdFromVisibilityCache(int appId) { if (mShouldFilterCache == null) { return; } for (int i = mShouldFilterCache.size() - 1; i >= 0; i--) { if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) { mShouldFilterCache.removeAt(i); continue; } SparseBooleanArray targetSparseArray = mShouldFilterCache.valueAt(i); for (int j = targetSparseArray.size() - 1; j >= 0; j--) { if (UserHandle.getAppId(targetSparseArray.keyAt(j)) == appId) { targetSparseArray.removeAt(j); } } } } private void updateEntireShouldFilterCache() { mStateProvider.runWithState((settings, users) -> { mShouldFilterCache.clear(); for (int i = settings.size() - 1; i >= 0; i--) { updateShouldFilterCacheForPackage( null /*skipPackage*/, settings.valueAt(i), settings, users, i); } }); } public void onUsersChanged() { if (mShouldFilterCache != null) { updateEntireShouldFilterCache(); } } private void updateShouldFilterCacheForPackage(String packageName) { mStateProvider.runWithState((settings, users) -> { updateShouldFilterCacheForPackage(null /* skipPackage */, settings.get(packageName), settings, users, settings.size() /*maxIndex*/); }); } private void updateShouldFilterCacheForPackage(@Nullable String skipPackageName, PackageSetting subjectSetting, ArrayMap<String, PackageSetting> allSettings, List<UserInfo> allUsers, int maxIndex) { for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) { PackageSetting otherSetting = allSettings.valueAt(i); if (subjectSetting.appId == otherSetting.appId) { continue; } //noinspection StringEquality if (subjectSetting.name == skipPackageName || otherSetting.name == skipPackageName) { continue; } final int userCount = allUsers.size(); final int appxUidCount = userCount * allSettings.size(); for (int su = 0; su < userCount; su++) { int subjectUser = allUsers.get(su).id; for (int ou = su; ou < userCount; ou++) { int otherUser = allUsers.get(ou).id; int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId); if (!mShouldFilterCache.contains(subjectUid)) { mShouldFilterCache.put(subjectUid, new SparseBooleanArray(appxUidCount)); } int otherUid = UserHandle.getUid(otherUser, otherSetting.appId); if (!mShouldFilterCache.contains(otherUid)) { mShouldFilterCache.put(otherUid, new SparseBooleanArray(appxUidCount)); } mShouldFilterCache.get(subjectUid).put(otherUid, shouldFilterApplicationInternal( subjectUid, subjectSetting, otherSetting, otherUser)); mShouldFilterCache.get(otherUid).put(subjectUid, shouldFilterApplicationInternal( otherUid, otherSetting, subjectSetting, subjectUser)); } } } } Loading Loading @@ -561,6 +714,7 @@ public class AppsFilter { } } } /** * 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 Loading Loading @@ -619,14 +773,13 @@ public class AppsFilter { * Removes a package for consideration when filtering visibility between apps. * * @param setting the setting of the package being removed. * @param allUsers array of all current users on device. */ public void removePackage(PackageSetting setting, int[] allUsers, ArrayMap<String, PackageSetting> existingSettings) { mForceQueryable.remove(setting.appId); for (int u = 0; u < allUsers.length; u++) { final int userId = allUsers[u]; public void removePackage(PackageSetting setting) { removeAppIdFromVisibilityCache(setting.appId); mStateProvider.runWithState((settings, users) -> { final int userCount = users.size(); for (int u = 0; u < userCount; u++) { final int userId = users.get(u).id; final int removingUid = UserHandle.getUid(userId, setting.appId); mImplicitlyQueryable.remove(removingUid); for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) { Loading @@ -650,7 +803,8 @@ public class AppsFilter { if (setting.sharedUser.packages.valueAt(i) == setting) { continue; } addPackage(setting.sharedUser.packages.valueAt(i), existingSettings); addPackageInternal( setting.sharedUser.packages.valueAt(i), settings); } } Loading @@ -658,12 +812,21 @@ public class AppsFilter { final String removingPackageName = setting.pkg.getPackageName(); mProtectedBroadcasts.clear(); mProtectedBroadcasts.addAll( collectProtectedBroadcasts(existingSettings, removingPackageName)); recomputeComponentVisibility(existingSettings, removingPackageName); collectProtectedBroadcasts(settings, removingPackageName)); recomputeComponentVisibility(settings, removingPackageName); } mOverlayReferenceMapper.removePkg(setting.name); mFeatureConfig.updatePackageState(setting, true /*removed*/); if (mShouldFilterCache != null) { updateShouldFilterCacheForPackage( setting.name, setting, settings, users, settings.size()); } }); mForceQueryable.remove(setting.appId); } /** Loading @@ -680,11 +843,32 @@ public class AppsFilter { PackageSetting targetPkgSetting, int userId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication"); try { if (callingUid < Process.FIRST_APPLICATION_UID || UserHandle.getAppId(callingUid) == targetPkgSetting.appId) { return false; } if (mShouldFilterCache != null) { // use cache SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid); final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId); if (shouldFilterTargets == null) { Slog.wtf(TAG, "Encountered calling uid with no cached rules: " + callingUid); return true; } int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid); if (indexOfTargetUid < 0) { Slog.w(TAG, "Encountered calling -> target with no cached rules: " + callingUid + " -> " + targetUid); return true; } if (!shouldFilterTargets.valueAt(indexOfTargetUid)) { return false; } } else { if (!shouldFilterApplicationInternal( callingUid, callingSetting, targetPkgSetting, userId)) { return false; } } if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) { log(callingSetting, targetPkgSetting, "BLOCKED"); } Loading @@ -695,7 +879,7 @@ public class AppsFilter { } private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting, PackageSetting targetPkgSetting, int userId) { PackageSetting targetPkgSetting, int targetUserId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal"); try { final boolean featureEnabled = mFeatureConfig.isGloballyEnabled(); Loading @@ -705,12 +889,6 @@ public class AppsFilter { } return false; } if (callingUid < Process.FIRST_APPLICATION_UID) { if (DEBUG_LOGGING) { Slog.d(TAG, "filtering skipped; " + callingUid + " is system"); } return false; } if (callingSetting == null) { Slog.wtf(TAG, "No setting found for non system uid " + callingUid); return true; Loading @@ -719,8 +897,14 @@ public class AppsFilter { final ArraySet<PackageSetting> callingSharedPkgSettings; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof"); if (callingSetting instanceof PackageSetting) { if (((PackageSetting) callingSetting).sharedUser == null) { callingPkgSetting = (PackageSetting) callingSetting; callingSharedPkgSettings = null; } else { callingPkgSetting = null; callingSharedPkgSettings = ((PackageSetting) callingSetting).sharedUser.packages; } } else { callingPkgSetting = null; callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages; Loading Loading @@ -778,14 +962,18 @@ public class AppsFilter { } try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "hasPermission"); if (callingSetting.getPermissionsState().hasPermission( Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) { if (DEBUG_LOGGING) { log(callingSetting, targetPkgSetting, "has query-all permission"); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages"); if (callingPkgSetting != null) { if (requestsQueryAllPackages(callingPkgSetting)) { return false; } } else { for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) { if (requestsQueryAllPackages(callingSharedPkgSettings.valueAt(i))) { return false; } } } } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Loading Loading @@ -825,7 +1013,7 @@ public class AppsFilter { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable"); final int targetUid = UserHandle.getUid(userId, targetAppId); final int targetUid = UserHandle.getUid(targetUserId, targetAppId); if (mImplicitlyQueryable.contains(callingUid, targetUid)) { if (DEBUG_LOGGING) { log(callingSetting, targetPkgSetting, "implicitly queryable for user"); Loading Loading @@ -863,13 +1051,20 @@ public class AppsFilter { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } return true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private static boolean requestsQueryAllPackages(PackageSetting pkgSetting) { // we're not guaranteed to have permissions yet analyzed at package add, so we inspect the // package directly return pkgSetting.pkg.getRequestedPermissions().contains( Manifest.permission.QUERY_ALL_PACKAGES); } /** Returns {@code true} if the source package instruments the target package. */ private static boolean pkgInstruments(PackageSetting source, PackageSetting target) { try { Loading services/core/java/com/android/server/pm/PackageManagerService.java +4 −4 Original line number Diff line number Diff line Loading @@ -12359,7 +12359,7 @@ public class PackageManagerService extends IPackageManager.Stub ksms.addScannedPackageLPw(pkg); mComponentResolver.addAllComponents(pkg, chatty); mAppsFilter.addPackage(pkgSetting, mSettings.mPackages); mAppsFilter.addPackage(pkgSetting); // Don't allow ephemeral applications to define new permissions groups. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { Loading Loading @@ -12533,8 +12533,6 @@ public class PackageManagerService extends IPackageManager.Stub void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) { mComponentResolver.removeAllComponents(pkg, chatty); mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()), mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages); mPermissionManager.removeAllPermissions(pkg, chatty); final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations()); Loading Loading @@ -14261,7 +14259,7 @@ public class PackageManagerService extends IPackageManager.Stub // Okay! targetPackageSetting.setInstallerPackageName(installerPackageName); mSettings.addInstallerPackageNames(targetPackageSetting.installSource); mAppsFilter.addPackage(targetPackageSetting, mSettings.mPackages); mAppsFilter.addPackage(targetPackageSetting); scheduleWriteSettingsLocked(); } } Loading Loading @@ -18686,6 +18684,7 @@ public class PackageManagerService extends IPackageManager.Stub clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true); clearDefaultBrowserIfNeeded(packageName); mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); mAppsFilter.removePackage(getPackageSetting(packageName)); removedAppId = mSettings.removePackageLPw(packageName); if (outInfo != null) { outInfo.removedAppId = removedAppId; Loading Loading @@ -23443,6 +23442,7 @@ public class PackageManagerService extends IPackageManager.Stub scheduleWritePackageRestrictionsLocked(userId); scheduleWritePackageListLocked(userId); primeDomainVerificationsLPw(userId); mAppsFilter.onUsersChanged(); } } services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +229 −157 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/pm/AppsFilter.java +329 −134 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -27,6 +29,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.UserInfo; import android.content.pm.parsing.component.ParsedComponent; import android.content.pm.parsing.component.ParsedInstrumentation; import android.content.pm.parsing.component.ParsedIntentInfo; Loading Loading @@ -108,12 +111,25 @@ public class AppsFilter { private final boolean mSystemAppsQueryable; private final FeatureConfig mFeatureConfig; private final OverlayReferenceMapper mOverlayReferenceMapper; private final StateProvider mStateProvider; private PackageParser.SigningDetails mSystemSigningDetails; private Set<String> mProtectedBroadcasts = new ArraySet<>(); AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist, /** * This structure maps uid -> uid and indicates whether access from the first should be * filtered to the second. It's essentially a cache of the * {@link #shouldFilterApplicationInternal(int, SettingBase, PackageSetting, int)} call. * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on * initial scam and is null until {@link #onSystemReady()} is called. */ private volatile SparseArray<SparseBooleanArray> mShouldFilterCache; @VisibleForTesting(visibility = PRIVATE) AppsFilter(StateProvider stateProvider, FeatureConfig featureConfig, String[] forceQueryableWhitelist, boolean systemAppsQueryable, @Nullable OverlayReferenceMapper.Provider overlayProvider) { mFeatureConfig = featureConfig; Loading @@ -121,8 +137,23 @@ public class AppsFilter { mSystemAppsQueryable = systemAppsQueryable; mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/, overlayProvider); mStateProvider = stateProvider; } /** * Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding * the data with the package lock. */ @VisibleForTesting(visibility = PRIVATE) public interface StateProvider { void runWithState(CurrentStateCallback callback); interface CurrentStateCallback { void currentState(ArrayMap<String, PackageSetting> settings, List<UserInfo> users); } } @VisibleForTesting(visibility = PRIVATE) public interface FeatureConfig { /** Called when the system is ready and components can be queried. */ Loading @@ -139,6 +170,7 @@ public class AppsFilter { /** * Turns on logging for the given appId * * @param enable true if logging should be enabled, false if disabled. */ void enableLogging(int appId, boolean enable); Loading @@ -146,6 +178,7 @@ public class AppsFilter { /** * Initializes the package enablement state for the given package. This gives opportunity * to do any expensive operations ahead of the actual checks. * * @param removed true if adding, false if removing */ void updatePackageState(PackageSetting setting, boolean removed); Loading @@ -161,6 +194,7 @@ public class AppsFilter { @Nullable private SparseBooleanArray mLoggingEnabled = null; private AppsFilter mAppsFilter; private FeatureConfigImpl( PackageManagerInternal pmInternal, PackageManagerService.Injector injector) { Loading @@ -168,6 +202,10 @@ public class AppsFilter { mInjector = injector; } public void setAppsFilter(AppsFilter filter) { mAppsFilter = filter; } @Override public void onSystemReady() { mFeatureEnabled = DeviceConfig.getBoolean( Loading Loading @@ -235,6 +273,7 @@ public class AppsFilter { @Override public void onCompatChange(String packageName) { updateEnabledState(mPmInternal.getPackage(packageName)); mAppsFilter.updateShouldFilterCacheForPackage(packageName); } private void updateEnabledState(AndroidPackage pkg) { Loading Loading @@ -267,7 +306,7 @@ public class AppsFilter { final boolean forceSystemAppsQueryable = injector.getContext().getResources() .getBoolean(R.bool.config_forceSystemPackagesQueryable); final FeatureConfig featureConfig = new FeatureConfigImpl(pms, injector); final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector); final String[] forcedQueryablePackageNames; if (forceSystemAppsQueryable) { // all system apps already queryable, no need to read and parse individual exceptions Loading @@ -280,8 +319,16 @@ public class AppsFilter { forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern(); } } return new AppsFilter(featureConfig, forcedQueryablePackageNames, forceSystemAppsQueryable, null); final StateProvider stateProvider = command -> { synchronized (injector.getLock()) { command.currentState(injector.getSettings().mPackages, injector.getUserManagerService().getUsers(false, false, false)); } }; AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig, forcedQueryablePackageNames, forceSystemAppsQueryable, null); featureConfig.setAppsFilter(appsFilter); return appsFilter; } public FeatureConfig getFeatureConfig() { Loading Loading @@ -407,24 +454,56 @@ public class AppsFilter { * @param visibleUid the uid becoming visible to the {@recipientUid} */ public void grantImplicitAccess(int recipientUid, int visibleUid) { if (recipientUid != visibleUid && mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { if (recipientUid != visibleUid) { if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid); } if (mShouldFilterCache != null) { // update the cache in a one-off manner since we've got all the information we need. SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid); if (visibleUids == null) { visibleUids = new SparseBooleanArray(); mShouldFilterCache.put(recipientUid, visibleUids); } visibleUids.put(visibleUid, false); } } } public void onSystemReady() { mStateProvider.runWithState(new StateProvider.CurrentStateCallback() { @Override public void currentState(ArrayMap<String, PackageSetting> settings, List<UserInfo> users) { mShouldFilterCache = new SparseArray<>(users.size() * settings.size()); } }); mFeatureConfig.onSystemReady(); mOverlayReferenceMapper.rebuildIfDeferred(); updateEntireShouldFilterCache(); } /** * Adds a package that should be considered when filtering visibility between apps. * * @param newPkgSetting the new setting being added * @param existingSettings all other settings currently on the device. */ public void addPackage(PackageSetting newPkgSetting, public void addPackage(PackageSetting newPkgSetting) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); try { mStateProvider.runWithState((settings, users) -> { addPackageInternal(newPkgSetting, settings); if (mShouldFilterCache != null) { updateShouldFilterCacheForPackage( null, newPkgSetting, settings, users, settings.size()); } // else, rebuild entire cache when system is ready }); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private void addPackageInternal(PackageSetting newPkgSetting, ArrayMap<String, PackageSetting> existingSettings) { if (Objects.equals("android", newPkgSetting.name)) { // let's set aside the framework signatures Loading @@ -438,8 +517,6 @@ public class AppsFilter { } } Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); try { final AndroidPackage newPkg = newPkgSetting.pkg; if (newPkg == null) { // nothing to add Loading Loading @@ -509,8 +586,84 @@ public class AppsFilter { } mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } private void removeAppIdFromVisibilityCache(int appId) { if (mShouldFilterCache == null) { return; } for (int i = mShouldFilterCache.size() - 1; i >= 0; i--) { if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) { mShouldFilterCache.removeAt(i); continue; } SparseBooleanArray targetSparseArray = mShouldFilterCache.valueAt(i); for (int j = targetSparseArray.size() - 1; j >= 0; j--) { if (UserHandle.getAppId(targetSparseArray.keyAt(j)) == appId) { targetSparseArray.removeAt(j); } } } } private void updateEntireShouldFilterCache() { mStateProvider.runWithState((settings, users) -> { mShouldFilterCache.clear(); for (int i = settings.size() - 1; i >= 0; i--) { updateShouldFilterCacheForPackage( null /*skipPackage*/, settings.valueAt(i), settings, users, i); } }); } public void onUsersChanged() { if (mShouldFilterCache != null) { updateEntireShouldFilterCache(); } } private void updateShouldFilterCacheForPackage(String packageName) { mStateProvider.runWithState((settings, users) -> { updateShouldFilterCacheForPackage(null /* skipPackage */, settings.get(packageName), settings, users, settings.size() /*maxIndex*/); }); } private void updateShouldFilterCacheForPackage(@Nullable String skipPackageName, PackageSetting subjectSetting, ArrayMap<String, PackageSetting> allSettings, List<UserInfo> allUsers, int maxIndex) { for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) { PackageSetting otherSetting = allSettings.valueAt(i); if (subjectSetting.appId == otherSetting.appId) { continue; } //noinspection StringEquality if (subjectSetting.name == skipPackageName || otherSetting.name == skipPackageName) { continue; } final int userCount = allUsers.size(); final int appxUidCount = userCount * allSettings.size(); for (int su = 0; su < userCount; su++) { int subjectUser = allUsers.get(su).id; for (int ou = su; ou < userCount; ou++) { int otherUser = allUsers.get(ou).id; int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId); if (!mShouldFilterCache.contains(subjectUid)) { mShouldFilterCache.put(subjectUid, new SparseBooleanArray(appxUidCount)); } int otherUid = UserHandle.getUid(otherUser, otherSetting.appId); if (!mShouldFilterCache.contains(otherUid)) { mShouldFilterCache.put(otherUid, new SparseBooleanArray(appxUidCount)); } mShouldFilterCache.get(subjectUid).put(otherUid, shouldFilterApplicationInternal( subjectUid, subjectSetting, otherSetting, otherUser)); mShouldFilterCache.get(otherUid).put(subjectUid, shouldFilterApplicationInternal( otherUid, otherSetting, subjectSetting, subjectUser)); } } } } Loading Loading @@ -561,6 +714,7 @@ public class AppsFilter { } } } /** * 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 Loading Loading @@ -619,14 +773,13 @@ public class AppsFilter { * Removes a package for consideration when filtering visibility between apps. * * @param setting the setting of the package being removed. * @param allUsers array of all current users on device. */ public void removePackage(PackageSetting setting, int[] allUsers, ArrayMap<String, PackageSetting> existingSettings) { mForceQueryable.remove(setting.appId); for (int u = 0; u < allUsers.length; u++) { final int userId = allUsers[u]; public void removePackage(PackageSetting setting) { removeAppIdFromVisibilityCache(setting.appId); mStateProvider.runWithState((settings, users) -> { final int userCount = users.size(); for (int u = 0; u < userCount; u++) { final int userId = users.get(u).id; final int removingUid = UserHandle.getUid(userId, setting.appId); mImplicitlyQueryable.remove(removingUid); for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) { Loading @@ -650,7 +803,8 @@ public class AppsFilter { if (setting.sharedUser.packages.valueAt(i) == setting) { continue; } addPackage(setting.sharedUser.packages.valueAt(i), existingSettings); addPackageInternal( setting.sharedUser.packages.valueAt(i), settings); } } Loading @@ -658,12 +812,21 @@ public class AppsFilter { final String removingPackageName = setting.pkg.getPackageName(); mProtectedBroadcasts.clear(); mProtectedBroadcasts.addAll( collectProtectedBroadcasts(existingSettings, removingPackageName)); recomputeComponentVisibility(existingSettings, removingPackageName); collectProtectedBroadcasts(settings, removingPackageName)); recomputeComponentVisibility(settings, removingPackageName); } mOverlayReferenceMapper.removePkg(setting.name); mFeatureConfig.updatePackageState(setting, true /*removed*/); if (mShouldFilterCache != null) { updateShouldFilterCacheForPackage( setting.name, setting, settings, users, settings.size()); } }); mForceQueryable.remove(setting.appId); } /** Loading @@ -680,11 +843,32 @@ public class AppsFilter { PackageSetting targetPkgSetting, int userId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication"); try { if (callingUid < Process.FIRST_APPLICATION_UID || UserHandle.getAppId(callingUid) == targetPkgSetting.appId) { return false; } if (mShouldFilterCache != null) { // use cache SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid); final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId); if (shouldFilterTargets == null) { Slog.wtf(TAG, "Encountered calling uid with no cached rules: " + callingUid); return true; } int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid); if (indexOfTargetUid < 0) { Slog.w(TAG, "Encountered calling -> target with no cached rules: " + callingUid + " -> " + targetUid); return true; } if (!shouldFilterTargets.valueAt(indexOfTargetUid)) { return false; } } else { if (!shouldFilterApplicationInternal( callingUid, callingSetting, targetPkgSetting, userId)) { return false; } } if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) { log(callingSetting, targetPkgSetting, "BLOCKED"); } Loading @@ -695,7 +879,7 @@ public class AppsFilter { } private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting, PackageSetting targetPkgSetting, int userId) { PackageSetting targetPkgSetting, int targetUserId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal"); try { final boolean featureEnabled = mFeatureConfig.isGloballyEnabled(); Loading @@ -705,12 +889,6 @@ public class AppsFilter { } return false; } if (callingUid < Process.FIRST_APPLICATION_UID) { if (DEBUG_LOGGING) { Slog.d(TAG, "filtering skipped; " + callingUid + " is system"); } return false; } if (callingSetting == null) { Slog.wtf(TAG, "No setting found for non system uid " + callingUid); return true; Loading @@ -719,8 +897,14 @@ public class AppsFilter { final ArraySet<PackageSetting> callingSharedPkgSettings; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof"); if (callingSetting instanceof PackageSetting) { if (((PackageSetting) callingSetting).sharedUser == null) { callingPkgSetting = (PackageSetting) callingSetting; callingSharedPkgSettings = null; } else { callingPkgSetting = null; callingSharedPkgSettings = ((PackageSetting) callingSetting).sharedUser.packages; } } else { callingPkgSetting = null; callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages; Loading Loading @@ -778,14 +962,18 @@ public class AppsFilter { } try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "hasPermission"); if (callingSetting.getPermissionsState().hasPermission( Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) { if (DEBUG_LOGGING) { log(callingSetting, targetPkgSetting, "has query-all permission"); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages"); if (callingPkgSetting != null) { if (requestsQueryAllPackages(callingPkgSetting)) { return false; } } else { for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) { if (requestsQueryAllPackages(callingSharedPkgSettings.valueAt(i))) { return false; } } } } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Loading Loading @@ -825,7 +1013,7 @@ public class AppsFilter { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable"); final int targetUid = UserHandle.getUid(userId, targetAppId); final int targetUid = UserHandle.getUid(targetUserId, targetAppId); if (mImplicitlyQueryable.contains(callingUid, targetUid)) { if (DEBUG_LOGGING) { log(callingSetting, targetPkgSetting, "implicitly queryable for user"); Loading Loading @@ -863,13 +1051,20 @@ public class AppsFilter { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } return true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private static boolean requestsQueryAllPackages(PackageSetting pkgSetting) { // we're not guaranteed to have permissions yet analyzed at package add, so we inspect the // package directly return pkgSetting.pkg.getRequestedPermissions().contains( Manifest.permission.QUERY_ALL_PACKAGES); } /** Returns {@code true} if the source package instruments the target package. */ private static boolean pkgInstruments(PackageSetting source, PackageSetting target) { try { Loading
services/core/java/com/android/server/pm/PackageManagerService.java +4 −4 Original line number Diff line number Diff line Loading @@ -12359,7 +12359,7 @@ public class PackageManagerService extends IPackageManager.Stub ksms.addScannedPackageLPw(pkg); mComponentResolver.addAllComponents(pkg, chatty); mAppsFilter.addPackage(pkgSetting, mSettings.mPackages); mAppsFilter.addPackage(pkgSetting); // Don't allow ephemeral applications to define new permissions groups. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { Loading Loading @@ -12533,8 +12533,6 @@ public class PackageManagerService extends IPackageManager.Stub void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) { mComponentResolver.removeAllComponents(pkg, chatty); mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()), mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages); mPermissionManager.removeAllPermissions(pkg, chatty); final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations()); Loading Loading @@ -14261,7 +14259,7 @@ public class PackageManagerService extends IPackageManager.Stub // Okay! targetPackageSetting.setInstallerPackageName(installerPackageName); mSettings.addInstallerPackageNames(targetPackageSetting.installSource); mAppsFilter.addPackage(targetPackageSetting, mSettings.mPackages); mAppsFilter.addPackage(targetPackageSetting); scheduleWriteSettingsLocked(); } } Loading Loading @@ -18686,6 +18684,7 @@ public class PackageManagerService extends IPackageManager.Stub clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true); clearDefaultBrowserIfNeeded(packageName); mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); mAppsFilter.removePackage(getPackageSetting(packageName)); removedAppId = mSettings.removePackageLPw(packageName); if (outInfo != null) { outInfo.removedAppId = removedAppId; Loading Loading @@ -23443,6 +23442,7 @@ public class PackageManagerService extends IPackageManager.Stub scheduleWritePackageRestrictionsLocked(userId); scheduleWritePackageListLocked(userId); primeDomainVerificationsLPw(userId); mAppsFilter.onUsersChanged(); } }
services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +229 −157 File changed.Preview size limit exceeded, changes collapsed. Show changes