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

Commit 4336e7ca authored by Patrick Baumann's avatar Patrick Baumann Committed by Android (Google) Code Review
Browse files

Merge "Build AppsFilter cache in background" into rvc-qpr-dev

parents 354b3ec3 1c1ea159
Loading
Loading
Loading
Loading
+162 −71
Original line number Diff line number Diff line
@@ -35,6 +35,9 @@ import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedProvider;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.Process;
import android.os.Trace;
import android.os.UserHandle;
@@ -48,6 +51,7 @@ import android.util.SparseBooleanArray;
import android.util.SparseSetArray;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.server.FgThread;
@@ -61,6 +65,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.Executor;

/**
 * The entity responsible for filtering visibility between apps based on declarations in their
@@ -95,6 +100,12 @@ public class AppsFilter {
     */
    private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>();

    /**
     * Executor for running reasonably short background tasks such as building the initial
     * visibility cache.
     */
    private final Executor mBackgroundExecutor;

    /**
     * Pending full recompute of mQueriesViaComponent. Occurs when a package adds a new set of
     * protected broadcast. This in turn invalidates all prior additions and require a very
@@ -125,6 +136,8 @@ public class AppsFilter {
    private PackageParser.SigningDetails mSystemSigningDetails;
    private Set<String> mProtectedBroadcasts = new ArraySet<>();

    private final Object mCacheLock = new Object();

    /**
     * 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
@@ -132,6 +145,7 @@ public class AppsFilter {
     * 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.
     */
    @GuardedBy("mCacheLock")
    private volatile SparseArray<SparseBooleanArray> mShouldFilterCache;

    @VisibleForTesting(visibility = PRIVATE)
@@ -139,13 +153,15 @@ public class AppsFilter {
            FeatureConfig featureConfig,
            String[] forceQueryableWhitelist,
            boolean systemAppsQueryable,
            @Nullable OverlayReferenceMapper.Provider overlayProvider) {
            @Nullable OverlayReferenceMapper.Provider overlayProvider,
            Executor backgroundExecutor) {
        mFeatureConfig = featureConfig;
        mForceQueryableByDevicePackageNames = forceQueryableWhitelist;
        mSystemAppsQueryable = systemAppsQueryable;
        mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/,
                overlayProvider);
        mStateProvider = stateProvider;
        mBackgroundExecutor = backgroundExecutor;
    }

    /**
@@ -337,8 +353,13 @@ public class AppsFilter {
                        injector.getUserManagerInternal().getUserInfos());
            }
        };
        HandlerThread appsFilterThread = new HandlerThread("appsFilter");
        appsFilterThread.start();
        Handler appsFilterHandler = new Handler(appsFilterThread.getLooper());
        Executor executor = new HandlerExecutor(appsFilterHandler);

        AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
                forcedQueryablePackageNames, forceSystemAppsQueryable, null);
                forcedQueryablePackageNames, forceSystemAppsQueryable, null, executor);
        featureConfig.setAppsFilter(appsFilter);
        return appsFilter;
    }
@@ -470,8 +491,10 @@ public class AppsFilter {
            if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) {
                Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
            }
            synchronized (mCacheLock) {
                if (mShouldFilterCache != null) {
                // update the cache in a one-off manner since we've got all the information we need.
                    // 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();
@@ -481,18 +504,13 @@ public class AppsFilter {
                }
            }
        }
    }

    public void onSystemReady() {
        mStateProvider.runWithState(new StateProvider.CurrentStateCallback() {
            @Override
            public void currentState(ArrayMap<String, PackageSetting> settings,
                    UserInfo[] users) {
                mShouldFilterCache = new SparseArray<>(users.length * settings.size());
            }
        });
        mFeatureConfig.onSystemReady();
        mOverlayReferenceMapper.rebuildIfDeferred();
        updateEntireShouldFilterCache();
        mFeatureConfig.onSystemReady();

        updateEntireShouldFilterCacheAsync();
    }

    /**
@@ -510,10 +528,12 @@ public class AppsFilter {
            }
            mStateProvider.runWithState((settings, users) -> {
                addPackageInternal(newPkgSetting, settings);
                synchronized (mCacheLock) {
                    if (mShouldFilterCache != null) {
                    updateShouldFilterCacheForPackage(
                            null, newPkgSetting, settings, users, settings.size());
                        updateShouldFilterCacheForPackage(mShouldFilterCache, null, newPkgSetting,
                                settings, users, settings.size());
                    } // else, rebuild entire cache when system is ready
                }
            });
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -607,6 +627,7 @@ public class AppsFilter {
        mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/);
    }

    @GuardedBy("mCacheLock")
    private void removeAppIdFromVisibilityCache(int appId) {
        if (mShouldFilterCache == null) {
            return;
@@ -627,31 +648,95 @@ public class AppsFilter {

    private void updateEntireShouldFilterCache() {
        mStateProvider.runWithState((settings, users) -> {
            mShouldFilterCache.clear();
            SparseArray<SparseBooleanArray> cache =
                    updateEntireShouldFilterCacheInner(settings, users);
            synchronized (mCacheLock) {
                mShouldFilterCache = cache;
            }
        });
    }

    private SparseArray<SparseBooleanArray> updateEntireShouldFilterCacheInner(
            ArrayMap<String, PackageSetting> settings, UserInfo[] users) {
        SparseArray<SparseBooleanArray> cache =
                new SparseArray<>(users.length * settings.size());
        for (int i = settings.size() - 1; i >= 0; i--) {
                updateShouldFilterCacheForPackage(
            updateShouldFilterCacheForPackage(cache,
                    null /*skipPackage*/, settings.valueAt(i), settings, users, i);
        }
        return cache;
    }

    private void updateEntireShouldFilterCacheAsync() {
        mBackgroundExecutor.execute(() -> {
            final ArrayMap<String, PackageSetting> settingsCopy = new ArrayMap<>();
            final ArrayMap<String, AndroidPackage> packagesCache = new ArrayMap<>();
            final UserInfo[][] usersRef = new UserInfo[1][];
            mStateProvider.runWithState((settings, users) -> {
                packagesCache.ensureCapacity(settings.size());
                settingsCopy.putAll(settings);
                usersRef[0] = users;
                // store away the references to the immutable packages, since settings are retained
                // during updates.
                for (int i = 0, max = settings.size(); i < max; i++) {
                    final AndroidPackage pkg = settings.valueAt(i).pkg;
                    packagesCache.put(settings.keyAt(i), pkg);
                }
            });
            SparseArray<SparseBooleanArray> cache =
                    updateEntireShouldFilterCacheInner(settingsCopy, usersRef[0]);
            boolean[] changed = new boolean[1];
            // We have a cache, let's make sure the world hasn't changed out from under us.
            mStateProvider.runWithState((settings, users) -> {
                if (settings.size() != settingsCopy.size()) {
                    changed[0] = true;
                    return;
                }
                for (int i = 0, max = settings.size(); i < max; i++) {
                    final AndroidPackage pkg = settings.valueAt(i).pkg;
                    if (!Objects.equals(pkg, packagesCache.get(settings.keyAt(i)))) {
                        changed[0] = true;
                        return;
                    }
                }
            });
            if (changed[0]) {
                // Something has changed, just update the cache inline with the lock held
                updateEntireShouldFilterCache();
                if (DEBUG_LOGGING) {
                    Slog.i(TAG, "Rebuilding cache with lock due to package change.");
                }
            } else {
                synchronized (mCacheLock) {
                    mShouldFilterCache = cache;
                }
            }
        });
    }

    public void onUsersChanged() {
        synchronized (mCacheLock) {
            if (mShouldFilterCache != null) {
                updateEntireShouldFilterCache();
            }
        }
    }

    private void updateShouldFilterCacheForPackage(String packageName) {
        synchronized (mCacheLock) {
            if (mShouldFilterCache != null) {
                mStateProvider.runWithState((settings, users) -> {
            updateShouldFilterCacheForPackage(null /* skipPackage */, settings.get(packageName),
                    settings, users, settings.size() /*maxIndex*/);
                    updateShouldFilterCacheForPackage(mShouldFilterCache, null /* skipPackage */,
                            settings.get(packageName), settings, users,
                            settings.size() /*maxIndex*/);
                });

            }
        }
    }

    private void updateShouldFilterCacheForPackage(@Nullable String skipPackageName,
            PackageSetting subjectSetting, ArrayMap<String, PackageSetting> allSettings,
            UserInfo[] allUsers, int maxIndex) {
    private void updateShouldFilterCacheForPackage(SparseArray<SparseBooleanArray> cache,
            @Nullable String skipPackageName, PackageSetting subjectSetting, ArrayMap<String,
            PackageSetting> allSettings, 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) {
@@ -668,17 +753,17 @@ public class AppsFilter {
                for (int ou = 0; ou < userCount; ou++) {
                    int otherUser = allUsers[ou].id;
                    int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId);
                    if (!mShouldFilterCache.contains(subjectUid)) {
                        mShouldFilterCache.put(subjectUid, new SparseBooleanArray(appxUidCount));
                    if (!cache.contains(subjectUid)) {
                        cache.put(subjectUid, new SparseBooleanArray(appxUidCount));
                    }
                    int otherUid = UserHandle.getUid(otherUser, otherSetting.appId);
                    if (!mShouldFilterCache.contains(otherUid)) {
                        mShouldFilterCache.put(otherUid, new SparseBooleanArray(appxUidCount));
                    if (!cache.contains(otherUid)) {
                        cache.put(otherUid, new SparseBooleanArray(appxUidCount));
                    }
                    mShouldFilterCache.get(subjectUid).put(otherUid,
                    cache.get(subjectUid).put(otherUid,
                            shouldFilterApplicationInternal(
                                    subjectUid, subjectSetting, otherSetting, otherUser));
                    mShouldFilterCache.get(otherUid).put(subjectUid,
                    cache.get(otherUid).put(subjectUid,
                            shouldFilterApplicationInternal(
                                    otherUid, otherSetting, subjectSetting, subjectUser));
                }
@@ -712,7 +797,8 @@ public class AppsFilter {
     * This method recomputes all component / intent-based visibility and is intended to match the
     * relevant logic of {@link #addPackageInternal(PackageSetting, ArrayMap)}
     */
    private void recomputeComponentVisibility(ArrayMap<String, PackageSetting> existingSettings) {
    private void recomputeComponentVisibility(
            ArrayMap<String, PackageSetting> existingSettings) {
        mQueriesViaComponent.clear();
        for (int i = existingSettings.size() - 1; i >= 0; i--) {
            PackageSetting setting = existingSettings.valueAt(i);
@@ -854,6 +940,7 @@ public class AppsFilter {
                }
            }

            synchronized (mCacheLock) {
                removeAppIdFromVisibilityCache(setting.appId);
                if (mShouldFilterCache != null && setting.sharedUser != null) {
                    for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) {
@@ -861,8 +948,9 @@ public class AppsFilter {
                        if (siblingSetting == setting) {
                            continue;
                        }
                    updateShouldFilterCacheForPackage(
                            setting.name, siblingSetting, settings, users, settings.size());
                        updateShouldFilterCacheForPackage(mShouldFilterCache, setting.name,
                                siblingSetting, settings, users, settings.size());
                    }
                }
            }
        });
@@ -888,11 +976,13 @@ public class AppsFilter {
                    || callingAppId == targetPkgSetting.appId) {
                return false;
            }
            synchronized (mCacheLock) {
                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);
                        Slog.wtf(TAG, "Encountered calling uid with no cached rules: "
                                + callingUid);
                        return true;
                    }
                    int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid);
@@ -910,6 +1000,7 @@ public class AppsFilter {
                        return false;
                    }
                }
            }
            if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(callingAppId)) {
                log(callingSetting, targetPkgSetting, "BLOCKED");
            }
+64 −30

File changed.

Preview size limit exceeded, changes collapsed.