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

Commit 9fdc67f9 authored by Fyodor Kupolov's avatar Fyodor Kupolov Committed by Android (Google) Code Review
Browse files

Merge "Moved system user apps whitelisting to PM"

parents a1ace221 1682dad7
Loading
Loading
Loading
Loading
+45 −50
Original line number Diff line number Diff line
@@ -18,13 +18,11 @@ package android.content.pm;

import android.Manifest;
import android.app.AppGlobals;
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArraySet;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethod;

import com.android.internal.annotations.VisibleForTesting;

@@ -44,36 +42,37 @@ public class AppsQueryHelper {
    public static int GET_NON_LAUNCHABLE_APPS = 1;

    /**
     * Return apps with {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission
     * Return apps with {@link Manifest.permission#INTERACT_ACROSS_USERS} permission
     */
    public static int GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM = 1 << 1;

    /**
     * Return all input methods that are marked as default.
     * <p>When this flag is set, {@code user} specified in
     * {@link #queryApps(int, boolean, UserHandle)} must be
     * {@link UserHandle#myUserId user of the current process}.
     * Return all input methods available for the current user.
     */
    public static int GET_DEFAULT_IMES = 1 << 2;
    public static int GET_IMES = 1 << 2;

    private final Context mContext;
    private final IPackageManager mPackageManager;
    private List<ApplicationInfo> mAllApps;

    public AppsQueryHelper(Context context) {
        mContext = context;
    public AppsQueryHelper(IPackageManager packageManager) {
        mPackageManager = packageManager;
    }

    public AppsQueryHelper() {
        this(AppGlobals.getPackageManager());
    }

    /**
     * Return a List of all packages that satisfy a specified criteria.
     * @param flags search flags. Use any combination of {@link #GET_NON_LAUNCHABLE_APPS},
     * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_DEFAULT_IMES}.
     * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_IMES}.
     * @param systemAppsOnly if true, only system apps will be returned
     * @param user user, whose apps are queried
     */
    public List<String> queryApps(int flags, boolean systemAppsOnly, UserHandle user) {
        boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0;
        boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0;
        boolean defaultImes = (flags & GET_DEFAULT_IMES) > 0;
        boolean imes = (flags & GET_IMES) > 0;
        if (mAllApps == null) {
            mAllApps = getAllApps(user.getIdentifier());
        }
@@ -113,7 +112,6 @@ public class AppsQueryHelper {
                }
            }
        }

        if (interactAcrossUsers) {
            final List<PackageInfo> packagesHoldingPermissions = getPackagesHoldingPermission(
                    Manifest.permission.INTERACT_ACROSS_USERS, user.getIdentifier());
@@ -129,29 +127,18 @@ public class AppsQueryHelper {
            }
        }

        if (defaultImes) {
            if (UserHandle.myUserId() != user.getIdentifier()) {
                throw new IllegalArgumentException("Specified user handle " + user
                        + " is not a user of the current process.");
            }
            List<InputMethodInfo> imis = getInputMethodList();
            int imisSize = imis.size();
            ArraySet<String> defaultImePackages = new ArraySet<>();
            for (int i = 0; i < imisSize; i++) {
                InputMethodInfo imi = imis.get(i);
                if (imi.isDefault(mContext)) {
                    defaultImePackages.add(imi.getPackageName());
                }
            }
            final int allAppsSize = mAllApps.size();
            for (int i = 0; i < allAppsSize; i++) {
                final ApplicationInfo appInfo = mAllApps.get(i);
                if (systemAppsOnly && !appInfo.isSystemApp()) {
        if (imes) {
            final List<ResolveInfo> resolveInfos = queryIntentServicesAsUser(
                    new Intent(InputMethod.SERVICE_INTERFACE), user.getIdentifier());
            final int resolveInfosSize = resolveInfos.size();

            for (int i = 0; i < resolveInfosSize; i++) {
                ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
                if (systemAppsOnly && !serviceInfo.applicationInfo.isSystemApp()) {
                    continue;
                }
                final String packageName = appInfo.packageName;
                if (defaultImePackages.contains(packageName)) {
                    result.add(packageName);
                if (!result.contains(serviceInfo.packageName)) {
                    result.add(serviceInfo.packageName);
                }
            }
        }
@@ -163,8 +150,7 @@ public class AppsQueryHelper {
    @SuppressWarnings("unchecked")
    protected List<ApplicationInfo> getAllApps(int userId) {
        try {
            return AppGlobals.getPackageManager().getInstalledApplications(
                    PackageManager.GET_UNINSTALLED_PACKAGES
            return mPackageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
                    | PackageManager.GET_DISABLED_COMPONENTS, userId).getList();
        } catch (RemoteException e) {
            throw new IllegalStateException("Package manager has died", e);
@@ -173,17 +159,22 @@ public class AppsQueryHelper {

    @VisibleForTesting
    protected List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int userId) {
        return mContext.getPackageManager()
                .queryIntentActivitiesAsUser(intent, PackageManager.GET_DISABLED_COMPONENTS
                        | PackageManager.GET_UNINSTALLED_PACKAGES, userId);
        try {
            return mPackageManager.queryIntentActivities(intent, null,
                    PackageManager.GET_DISABLED_COMPONENTS
                            | PackageManager.GET_UNINSTALLED_PACKAGES,
                    userId);
        } catch (RemoteException e) {
            throw new IllegalStateException("Package manager has died", e);
        }
    }

    @VisibleForTesting
    @SuppressWarnings("unchecked")
    protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
    protected List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int userId) {
        try {
            return AppGlobals.getPackageManager().getPackagesHoldingPermissions(new String[]{perm},
                    0, userId).getList();
            return mPackageManager.queryIntentServices(intent, null,
                    PackageManager.GET_META_DATA
                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
        } catch (RemoteException e) {
            throw new IllegalStateException("Package manager has died", e);
        }
@@ -191,9 +182,13 @@ public class AppsQueryHelper {

    @VisibleForTesting
    @SuppressWarnings("unchecked")
    protected List<InputMethodInfo> getInputMethodList() {
        InputMethodManager imm = (InputMethodManager)
                mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        return imm.getInputMethodList();
    protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
        try {
            return mPackageManager.getPackagesHoldingPermissions(new String[]{perm}, 0,
                    userId).getList();
        } catch (RemoteException e) {
            throw new IllegalStateException("Package manager has died", e);
        }
    }

}
+11 −23
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ public class AppsQueryHelperTests extends AndroidTestCase {
    @Override
    public void setUp() throws Exception {
        super.setUp();
        mAppsQueryHelper = new AppsQueryHelperTestable(getContext());
        mAppsQueryHelper = new AppsQueryHelperTestable();
    }

    public void testQueryAppsSystemAppsOnly() {
@@ -78,33 +78,20 @@ public class AppsQueryHelperTests extends AndroidTestCase {
        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps);
    }

    public void testQueryAppsDefaultIme() {
        // Test query default system IMEs
        List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES,
    public void testQueryAppsImes() {
        // Test query system IMEs
        List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_IMES,
                true, UserHandle.of(UserHandle.myUserId()));
        assertEqualsIgnoreOrder(Arrays.asList("sys_app1"), apps);

        // Test query default IMEs
        apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false,
        // Test query IMEs
        apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_IMES, false,
                UserHandle.of(UserHandle.myUserId()));
        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "app4"), apps);

        // Test that GET_DEFAULT_IMES cannot be used with a user id different from current process
        try {
            mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false,
                    UserHandle.of(UserHandle.USER_NULL));
            fail("queryApps must fail if wrong user was passed");
        } catch (IllegalArgumentException e) {
            // OK
        }
    }

    private class AppsQueryHelperTestable extends AppsQueryHelper {

        public AppsQueryHelperTestable(Context context) {
            super(context);
        }

        @Override
        protected List<ApplicationInfo> getAllApps(int userId) {
            final ApplicationInfo ai1 = new ApplicationInfo();
@@ -145,18 +132,19 @@ public class AppsQueryHelperTests extends AndroidTestCase {
        }

        @Override
        protected List<InputMethodInfo> getInputMethodList() {
        protected List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int userId) {
            final ResolveInfo sysApp1 = new ResolveInfo();
            sysApp1.serviceInfo = new ServiceInfo();
            sysApp1.serviceInfo.packageName = "sys_app1";
            sysApp1.serviceInfo.name = "name";
            InputMethodInfo imi1 = new InputMethodInfo(sysApp1, false, null, null, 0, true);
            sysApp1.serviceInfo.applicationInfo = new ApplicationInfo();
            sysApp1.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
            final ResolveInfo app4 = new ResolveInfo();
            app4.serviceInfo = new ServiceInfo();
            app4.serviceInfo.packageName = "app4";
            app4.serviceInfo.name = "name";
            InputMethodInfo imi2 = new InputMethodInfo(app4, false, null, null, 0, true);
            return Arrays.asList(imi1, imi2);
            app4.serviceInfo.applicationInfo = new ApplicationInfo();
            return Arrays.asList(sysApp1, app4);
        }
    }

+0 −39
Original line number Diff line number Diff line
@@ -12102,8 +12102,6 @@ public final class ActivityManagerService extends ActivityManagerNative
                }
            }
            enableSystemUserApps();
            // Start up initial activity.
            mBooting = true;
            startHomeActivityLocked(currentUserId, "systemReady");
@@ -12155,43 +12153,6 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
    }
    private void enableSystemUserApps() {
        // For system user, enable apps based on the following conditions:
        // - app is whitelisted; or has no launcher icons; or has INTERACT_ACROSS_USERS permission
        // - app is not in the blacklist
        if (UserManager.isSplitSystemUser()) {
            AppsQueryHelper queryHelper = new AppsQueryHelper(mContext);
            Set<String> enableApps = new HashSet<>();
            enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
                            | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM
                            | AppsQueryHelper.GET_DEFAULT_IMES,
                            /* systemAppsOnly */ true, UserHandle.SYSTEM));
            ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
            enableApps.addAll(wlApps);
            ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
            enableApps.removeAll(blApps);
            List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
                    UserHandle.SYSTEM);
            final int systemAppsSize = systemApps.size();
            for (int i = 0; i < systemAppsSize; i++) {
                String pName = systemApps.get(i);
                boolean enable = enableApps.contains(pName);
                try {
                    if (enable) {
                        AppGlobals.getPackageManager().installExistingPackageAsUser(pName,
                                UserHandle.USER_SYSTEM);
                    } else {
                        AppGlobals.getPackageManager().deletePackageAsUser(pName, null,
                                UserHandle.USER_SYSTEM, PackageManager.DELETE_SYSTEM_APP);
                    }
                } catch (RemoteException e) {
                    Slog.e(TAG, "Error occured when processing package " + pName, e);
                }
            }
        }
    }
    private boolean makeAppCrashingLocked(ProcessRecord app,
            String shortMsg, String longMsg, String stackTrace) {
        app.crashing = true;
+39 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ import android.content.IntentSender.SendIntentException;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AppsQueryHelper;
import android.content.pm.FeatureInfo;
import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IPackageDataObserver;
@@ -1810,10 +1811,48 @@ public class PackageManagerService extends IPackageManager.Stub {
            boolean factoryTest, boolean onlyCore) {
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        m.enableSystemUserApps();
        ServiceManager.addService("package", m);
        return m;
    }
    private void enableSystemUserApps() {
        if (!UserManager.isSplitSystemUser()) {
            return;
        }
        // For system user, enable apps based on the following conditions:
        // - app is whitelisted or belong to one of these groups:
        //   -- system app which has no launcher icons
        //   -- system app which has INTERACT_ACROSS_USERS permission
        //   -- system IME app
        // - app is not in the blacklist
        AppsQueryHelper queryHelper = new AppsQueryHelper(this);
        Set<String> enableApps = new ArraySet<>();
        enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
                | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM
                | AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM));
        ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
        enableApps.addAll(wlApps);
        ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
        enableApps.removeAll(blApps);
        List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
                UserHandle.SYSTEM);
        final int systemAppsSize = systemApps.size();
        synchronized (mPackages) {
            for (int i = 0; i < systemAppsSize; i++) {
                String pName = systemApps.get(i);
                PackageSetting pkgSetting = mSettings.mPackages.get(pName);
                // Should not happen, but we shouldn't be failing if it does
                if (pkgSetting == null) {
                    continue;
                }
                boolean installed = enableApps.contains(pName);
                pkgSetting.setInstalled(installed, UserHandle.USER_SYSTEM);
            }
        }
    }
    static String[] splitString(String str, char sep) {
        int count = 1;
        int i = 0;