Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f250c3f authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Pre-cache filter results" into rvc-dev am: 7da3f04b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11622391

Change-Id: If7d438d7e64ef326a2818db05a7bc72e5edc10d9
parents 720e6900 7da3f04b
Loading
Loading
Loading
Loading
+334 −149
Original line number Diff line number Diff line
@@ -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;
@@ -109,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 scan 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;
@@ -122,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, int[] users);
        }
    }

    @VisibleForTesting(visibility = PRIVATE)
    public interface FeatureConfig {

        /** Called when the system is ready and components can be queried. */
@@ -140,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);
@@ -147,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);
@@ -162,6 +194,7 @@ public class AppsFilter {

        @Nullable
        private SparseBooleanArray mLoggingEnabled = null;
        private AppsFilter mAppsFilter;

        private FeatureConfigImpl(
                PackageManagerInternal pmInternal, PackageManagerService.Injector injector) {
@@ -169,6 +202,10 @@ public class AppsFilter {
            mInjector = injector;
        }

        public void setAppsFilter(AppsFilter filter) {
            mAppsFilter = filter;
        }

        @Override
        public void onSystemReady() {
            mFeatureEnabled = DeviceConfig.getBoolean(
@@ -235,12 +272,16 @@ public class AppsFilter {

        @Override
        public void onCompatChange(String packageName) {
            final long token = Binder.clearCallingIdentity();
            try {
                updateEnabledState(mPmInternal.getPackage(packageName));
                mAppsFilter.updateShouldFilterCacheForPackage(packageName);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        private void updateEnabledState(AndroidPackage pkg) {
            final long token = Binder.clearCallingIdentity();
            try {
            // TODO(b/135203078): Do not use toAppInfo
            final boolean enabled =
                    mInjector.getCompatibility().isChangeEnabled(
@@ -251,9 +292,6 @@ public class AppsFilter {
            } else {
                mDisabledPackages.add(pkg.getPackageName());
            }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        @Override
@@ -275,7 +313,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
@@ -288,8 +326,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.getUserManagerInternal().getUserIds());
            }
        };
        AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
                forcedQueryablePackageNames, forceSystemAppsQueryable, null);
        featureConfig.setAppsFilter(appsFilter);
        return appsFilter;
    }

    public FeatureConfig getFeatureConfig() {
@@ -415,25 +461,51 @@ 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() {
        mShouldFilterCache = new SparseArray<>();
        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,
            ArrayMap<String, PackageSetting> existingSettings) {
    public void addPackage(PackageSetting newPkgSetting) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
        try {
            mStateProvider.runWithState((settings, users) -> {
                addPackageInternal(newPkgSetting, settings, users);
                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, int[] allUsers) {
        if (Objects.equals("android", newPkgSetting.name)) {
            // let's set aside the framework signatures
            mSystemSigningDetails = newPkgSetting.signatures.mSigningDetails;
@@ -446,8 +518,6 @@ public class AppsFilter {
            }
        }

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
        try {
        final AndroidPackage newPkg = newPkgSetting.pkg;
        if (newPkg == null) {
            // nothing to add
@@ -517,8 +587,82 @@ 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,
            int[] 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;
            }
            for (int su = 0; su < allUsers.length; su++) {
                int subjectUser = allUsers[su];
                for (int ou = su; ou < allUsers.length; ou++) {
                    int otherUser = allUsers[ou];
                    int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId);
                    if (!mShouldFilterCache.contains(subjectUid)) {
                        mShouldFilterCache.put(subjectUid, new SparseBooleanArray());
                    }
                    int otherUid = UserHandle.getUid(otherUser, otherSetting.appId);
                    if (!mShouldFilterCache.contains(otherUid)) {
                        mShouldFilterCache.put(otherUid, new SparseBooleanArray());
                    }
                    mShouldFilterCache.get(subjectUid).put(otherUid,
                            shouldFilterApplicationInternal(
                                    subjectUid, subjectSetting, otherSetting, otherUser));
                    mShouldFilterCache.get(otherUid).put(subjectUid,
                            shouldFilterApplicationInternal(
                                    otherUid, otherSetting, subjectSetting, subjectUser));
                }
            }
        }
    }

@@ -569,6 +713,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
@@ -627,14 +772,12 @@ 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) -> {
            for (int u = 0; u < users.length; u++) {
                final int userId = users[u];
                final int removingUid = UserHandle.getUid(userId, setting.appId);
                mImplicitlyQueryable.remove(removingUid);
                for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
@@ -658,7 +801,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, users);
                }
            }

@@ -666,12 +810,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);


    }

    /**
@@ -688,11 +841,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");
            }
@@ -703,7 +877,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();
@@ -713,12 +887,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;
@@ -727,8 +895,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;
@@ -786,14 +960,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);
            }
@@ -833,7 +1011,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");
@@ -871,13 +1049,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 {
+4 −4
Original line number Diff line number Diff line
@@ -12362,7 +12362,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) {
@@ -12536,8 +12536,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());
@@ -14253,7 +14251,7 @@ public class PackageManagerService extends IPackageManager.Stub
            // Okay!
            targetPackageSetting.setInstallerPackageName(installerPackageName);
            mSettings.addInstallerPackageNames(targetPackageSetting.installSource);
            mAppsFilter.addPackage(targetPackageSetting, mSettings.mPackages);
            mAppsFilter.addPackage(targetPackageSetting);
            scheduleWriteSettingsLocked();
        }
    }
@@ -18706,6 +18704,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;
@@ -23463,6 +23462,7 @@ public class PackageManagerService extends IPackageManager.Stub
            scheduleWritePackageRestrictionsLocked(userId);
            scheduleWritePackageListLocked(userId);
            primeDomainVerificationsLPw(userId);
            mAppsFilter.onUsersChanged();
        }
    }
+214 −148

File changed.

Preview size limit exceeded, changes collapsed.