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

Commit dfb121d7 authored by Patrick Baumann's avatar Patrick Baumann
Browse files

Use PlatformConfig to gate behavior

This change moves away from AppOps and explicit targetSdk
checks in favor of PlatformConfig.

Test: atest AppsFilterTest
Test: adb shell device_config put package_manager_service package_query_filtering_enabled true && atest AppEnumerationTests
Fixes: 139348423
Bug: 136675067
Change-Id: If0af198c86210c05c2e10b71f7ae6dc0b7a3ea9a
parent 6272065e
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
import android.app.admin.DevicePolicyManager;
import android.app.usage.StorageStatsManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -3369,6 +3371,17 @@ public abstract class PackageManager {
     */
    public static final int VERSION_CODE_HIGHEST = -1;

    /**
     * Apps targeting Android R and above will need to declare the packages and intents they intend
     * to use to get details about other apps on a device. Such declarations must be made via the
     * {@code <queries>} tag in the manifest.
     *
     * @hide
     */
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
    public static final long FILTER_APPLICATION_QUERY = 135549675L;

    /** {@hide} */
    public int getUserId() {
        return UserHandle.myUserId();
+1 −0
Original line number Diff line number Diff line
@@ -1707,6 +1707,7 @@
         manifest. -->
    <string-array name="config_forceQueryablePackages" translatable="false">
        <item>com.android.settings</item>
        <item>com.android.providers.settings</item>
        <!-- Add packages here -->
    </string-array>

+98 −48
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@

package com.android.server.pm;

import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;

import android.Manifest;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
@@ -28,11 +28,14 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.permission.IPermissionManager;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.R;
import com.android.server.FgThread;
import com.android.server.compat.PlatformCompat;

import java.io.PrintWriter;
import java.util.Collections;
@@ -41,7 +44,6 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * The entity responsible for filtering visibility between apps based on declarations in their
@@ -98,14 +100,11 @@ class AppsFilter {

    private final IPermissionManager mPermissionManager;

    private final AppOpsManager mAppOpsManager;
    private final ConfigProvider mConfigProvider;
    private final FeatureConfig mFeatureConfig;

    AppsFilter(ConfigProvider configProvider, IPermissionManager permissionManager,
            AppOpsManager appOpsManager, String[] forceQueryableWhitelist,
            boolean systemAppsQueryable) {
        mConfigProvider = configProvider;
        mAppOpsManager = appOpsManager;
    AppsFilter(FeatureConfig featureConfig, IPermissionManager permissionManager,
            String[] forceQueryableWhitelist, boolean systemAppsQueryable) {
        mFeatureConfig = featureConfig;
        final HashSet<String> forceQueryableByDeviceSet = new HashSet<>();
        Collections.addAll(forceQueryableByDeviceSet, forceQueryableWhitelist);
        this.mForceQueryableByDevice = Collections.unmodifiableSet(forceQueryableByDeviceSet);
@@ -114,27 +113,83 @@ class AppsFilter {
        mSystemAppsQueryable = systemAppsQueryable;
    }

    public static AppsFilter create(Context context) {
        // tracks whether the feature is enabled where -1 is unknown, 0 is false and 1 is true;
        final AtomicInteger featureEnabled = new AtomicInteger(-1);
    public interface FeatureConfig {
        /** Called when the system is ready and components can be queried. */
        void onSystemReady();

        /** @return true if we should filter apps at all. */
        boolean isGloballyEnabled();

        /** @return true if the feature is enabled for the given package. */
        boolean packageIsEnabled(PackageParser.Package pkg);
    }

    private static class FeatureConfigImpl implements FeatureConfig {
        private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled";

        // STOPSHIP(patb): set this to true if we plan to launch this in R
        private static final boolean DEFAULT_ENABLED_STATE = false;
        private final PackageManagerService.Injector mInjector;
        private volatile boolean mFeatureEnabled = DEFAULT_ENABLED_STATE;

        private FeatureConfigImpl(PackageManagerService.Injector injector) {
            mInjector = injector;
        }

        @Override
        public void onSystemReady() {
            mFeatureEnabled = DeviceConfig.getBoolean(
                    NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME,
                    DEFAULT_ENABLED_STATE);
            DeviceConfig.addOnPropertiesChangedListener(
                    NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(),
                    properties -> {
                        synchronized (FeatureConfigImpl.this) {
                            mFeatureEnabled = properties.getBoolean(
                                    FILTERING_ENABLED_NAME, DEFAULT_ENABLED_STATE);
                        }
                    });
        }

        @Override
        public boolean isGloballyEnabled() {
            return mFeatureEnabled;
        }

        @Override
        public boolean packageIsEnabled(PackageParser.Package pkg) {
            final PlatformCompat compatibility = mInjector.getCompatibility();
            if (compatibility == null) {
                Slog.wtf(TAG, "PlatformCompat is null");
                return mFeatureEnabled;
            }
            return compatibility.isChangeEnabled(
                    PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo);
        }
    }


    public static AppsFilter create(PackageManagerService.Injector injector) {
        final boolean forceSystemAppsQueryable =
                context.getResources().getBoolean(R.bool.config_forceSystemPackagesQueryable);
                injector.getContext().getResources()
                        .getBoolean(R.bool.config_forceSystemPackagesQueryable);
        final FeatureConfig featureConfig = new FeatureConfigImpl(injector);
        final String[] forcedQueryablePackageNames;
        if (forceSystemAppsQueryable) {
            // all system apps already queryable, no need to read and parse individual exceptions
            forcedQueryablePackageNames = new String[]{};
        } else {
            forcedQueryablePackageNames =
                    context.getResources().getStringArray(R.array.config_forceQueryablePackages);
                    injector.getContext().getResources()
                            .getStringArray(R.array.config_forceQueryablePackages);
            for (int i = 0; i < forcedQueryablePackageNames.length; i++) {
                forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern();
            }
        }
        IPermissionManager permissionmgr =
                (IPermissionManager) ServiceManager.getService("permissionmgr");
        return new AppsFilter(() -> false, permissionmgr,
                context.getSystemService(AppOpsManager.class), forcedQueryablePackageNames,

        return new AppsFilter(featureConfig, permissionmgr, forcedQueryablePackageNames,
                forceSystemAppsQueryable);
    }

@@ -186,6 +241,10 @@ class AppsFilter {
        currentUser.get(targetPackage.pkg.packageName).add(initiatingPackage.pkg.packageName);
    }

    public void onSystemReady() {
        mFeatureConfig.onSystemReady();
    }

    /**
     * Adds a package that should be considered when filtering visibility between apps.
     *
@@ -267,11 +326,11 @@ class AppsFilter {
     */
    public boolean shouldFilterApplication(int callingUid, @Nullable SettingBase callingSetting,
            PackageSetting targetPkgSetting, int userId) {
        if (callingUid < Process.FIRST_APPLICATION_UID) {
        final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
        if (!featureEnabled && !DEBUG_RUN_WHEN_DISABLED) {
            return false;
        }
        final boolean featureEnabled = mConfigProvider.isEnabled();
        if (!featureEnabled && !DEBUG_RUN_WHEN_DISABLED) {
        if (callingUid < Process.FIRST_APPLICATION_UID) {
            return false;
        }
        if (callingSetting == null) {
@@ -312,31 +371,21 @@ class AppsFilter {
                return true;
            }
        }

        if (!featureEnabled) {
            return false;
        }
        final int mode = mAppOpsManager
                .checkOpNoThrow(AppOpsManager.OP_QUERY_ALL_PACKAGES, callingUid,
                        callingPkgSetting.pkg.packageName);
        switch (mode) {
            case AppOpsManager.MODE_DEFAULT:
        if (mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) {
            if (DEBUG_LOGGING) {
                    Slog.d(TAG, "filtered interaction: " + callingPkgSetting.name + " -> "
                            + targetPkgSetting.name + (DEBUG_ALLOW_ALL ? " ALLOWED" : ""));
                Slog.d(TAG, "interaction: " + callingPkgSetting.name + " -> "
                        + targetPkgSetting.name + (DEBUG_ALLOW_ALL ? " ALLOWED" : "BLOCKED"));
            }
            return !DEBUG_ALLOW_ALL;
            case AppOpsManager.MODE_ALLOWED:
                // explicitly allowed to see all packages, don't filter
        } else {
            if (DEBUG_LOGGING) {
                Slog.d(TAG, "interaction: " + callingPkgSetting.name + " -> "
                        + targetPkgSetting.name + " DISABLED");
            }
            return false;
            case AppOpsManager.MODE_ERRORED:
                // deny / error: let's log so developer can audit usages
                Slog.i(TAG, callingPkgSetting.pkg.packageName
                        + " blocked from accessing " + targetPkgSetting.pkg.packageName);
            case AppOpsManager.MODE_IGNORED:
                // fall through
            default:
                return true;
        }
    }

@@ -377,6 +426,13 @@ class AppsFilter {
                && mImplicitlyQueryable.get(userId).get(callingName).contains(targetName)) {
            return false;
        }
        if (callingPkgSetting.pkg.instrumentation.size() > 0) {
            for (int i = 0, max = callingPkgSetting.pkg.instrumentation.size(); i < max; i++) {
                if (callingPkgSetting.pkg.instrumentation.get(i).info.targetPackage == targetName) {
                    return false;
                }
            }
        }
        try {
            if (mPermissionManager.checkPermission(
                    Manifest.permission.QUERY_ALL_PACKAGES, callingName, userId)
@@ -400,7 +456,6 @@ class AppsFilter {
        pw.println();
        pw.println("Queries:");
        dumpState.onTitlePrinted();
        pw.println("  enabled: " + mConfigProvider.isEnabled());
        pw.println("  system apps queryable: " + mSystemAppsQueryable);
        dumpPackageSet(pw, filteringPackageName, mForceQueryableByDevice, "System whitelist", "  ");
        dumpPackageSet(pw, filteringPackageName, mForceQueryable, "forceQueryable", "  ");
@@ -442,9 +497,4 @@ class AppsFilter {
            }
        }
    }

    public interface ConfigProvider {
        boolean isEnabled();
    }

}
+26 −11
Original line number Diff line number Diff line
@@ -300,6 +300,7 @@ import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.Watchdog;
import com.android.server.compat.PlatformCompat;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.Settings.DatabaseVersion;
@@ -824,6 +825,8 @@ public class PackageManagerService extends IPackageManager.Stub
        private final Singleton<DisplayManager> mDisplayManagerProducer;
        private final Singleton<StorageManager> mStorageManagerProducer;
        private final Singleton<AppOpsManager> mAppOpsManagerProducer;
        private final Singleton<AppsFilter> mAppsFilterProducer;
        private final Singleton<PlatformCompat> mPlatformCompatProducer;
        Injector(Context context, Object lock, Installer installer,
                Object installLock, PackageAbiHelper abiHelper,
@@ -839,7 +842,9 @@ public class PackageManagerService extends IPackageManager.Stub
                Producer<DeviceStorageMonitorInternal> deviceStorageMonitorProducer,
                Producer<DisplayManager> displayManagerProducer,
                Producer<StorageManager> storageManagerProducer,
                Producer<AppOpsManager> appOpsManagerProducer) {
                Producer<AppOpsManager> appOpsManagerProducer,
                Producer<AppsFilter> appsFilterProducer,
                Producer<PlatformCompat> platformCompatProducer) {
            mContext = context;
            mLock = lock;
            mInstaller = installer;
@@ -858,6 +863,8 @@ public class PackageManagerService extends IPackageManager.Stub
            mDisplayManagerProducer = new Singleton<>(displayManagerProducer);
            mStorageManagerProducer = new Singleton<>(storageManagerProducer);
            mAppOpsManagerProducer = new Singleton<>(appOpsManagerProducer);
            mAppsFilterProducer = new Singleton<>(appsFilterProducer);
            mPlatformCompatProducer = new Singleton<>(platformCompatProducer);
        }
        /**
@@ -943,6 +950,14 @@ public class PackageManagerService extends IPackageManager.Stub
        public AppOpsManager getAppOpsManager() {
            return mAppOpsManagerProducer.get(this, mPackageManager);
        }
        public AppsFilter getAppsFilter() {
            return mAppsFilterProducer.get(this, mPackageManager);
        }
        public PlatformCompat getCompatibility() {
            return mPlatformCompatProducer.get(this, mPackageManager);
        }
    }
    private final AppsFilter mAppsFilter;
@@ -2273,9 +2288,9 @@ public class PackageManagerService extends IPackageManager.Stub
     * @param packageVolume The storage volume of the package.
     * @param packageIsExternal true if the package is currently installed on
     * external/removable/unprotected storage.
     * @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
     * corresponding {@link StorageEnum} storage type value if it is.
     * corresponding {@link StorageEnum} storage type value if it is.
     * @return {@link StorageEnums#UNKNOWN} if the package is not stored externally or the
     * corresponding {@link StorageEnums} storage type value if it is.
     * corresponding {@link StorageEnums} storage type value if it is.
     */
    private static int getPackageExternalStorageType(VolumeInfo packageVolume,
            boolean packageIsExternal) {
@@ -2432,7 +2447,9 @@ public class PackageManagerService extends IPackageManager.Stub
                new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class),
                new Injector.SystemServiceProducer<>(DisplayManager.class),
                new Injector.SystemServiceProducer<>(StorageManager.class),
                new Injector.SystemServiceProducer<>(AppOpsManager.class));
                new Injector.SystemServiceProducer<>(AppOpsManager.class),
                (i, pm) -> AppsFilter.create(i),
                (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"));
        PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore);
        t.traceEnd(); // "create package manager"
@@ -2617,7 +2634,7 @@ public class PackageManagerService extends IPackageManager.Stub
        mProtectedPackages = new ProtectedPackages(mContext);
        mApexManager = ApexManager.create(mContext);
        mAppsFilter = AppsFilter.create(mContext);
        mAppsFilter = mInjector.getAppsFilter();
        // CHECKSTYLE:OFF IndentationCheck
        synchronized (mInstallLock) {
@@ -2725,14 +2742,10 @@ public class PackageManagerService extends IPackageManager.Stub
            mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
            mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
            int preUpgradeSdkVersion = ver.sdkVersion;
            // save off the names of pre-existing system packages prior to scanning; we don't
            // want to automatically grant runtime permissions for new system apps
            if (mPromoteSystemApps) {
                Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
                while (pkgSettingIter.hasNext()) {
                    PackageSetting ps = pkgSettingIter.next();
                for (PackageSetting ps : mSettings.mPackages.values()) {
                    if (isSystemApp(ps)) {
                        mExistingSystemPackages.add(ps.name);
                    }
@@ -20459,6 +20472,8 @@ public class PackageManagerService extends IPackageManager.Stub
                        .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL);
        co.onChange(true);
        mAppsFilter.onSystemReady();
        // Disable any carrier apps. We do this very early in boot to prevent the apps from being
        // disabled after already being started.
        CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
+29 −70

File changed.

Preview size limit exceeded, changes collapsed.