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

Commit ad02f277 authored by Felipe Leme's avatar Felipe Leme Committed by Automerger Merge Worker
Browse files

Merge "Improved 'cmd user list-missing-system-packages'." into rvc-dev am:...

Merge "Improved 'cmd user list-missing-system-packages'." into rvc-dev am: 5ae8bbd6 am: 098e1aab

Change-Id: Ibc4a73569edfec9833fa33e48e7367fa01c4e491
parents d1105fa4 098e1aab
Loading
Loading
Loading
Loading
+25 −11
Original line number Original line Diff line number Diff line
@@ -4516,8 +4516,8 @@ public class UserManagerService extends IUserManager.Stub {
            switch(cmd) {
            switch(cmd) {
                case "list":
                case "list":
                    return runList(pw, shell);
                    return runList(pw, shell);
                case "list-missing-system-packages":
                case "report-system-user-package-whitelist-problems":
                    return runListMissingSystemPackages(pw, shell);
                    return runReportPackageWhitelistProblems(pw, shell);
                default:
                default:
                    return shell.handleDefaultCommands(cmd);
                    return shell.handleDefaultCommands(cmd);
            }
            }
@@ -4584,17 +4584,22 @@ public class UserManagerService extends IUserManager.Stub {
        }
        }
    }
    }


    private int runListMissingSystemPackages(PrintWriter pw, Shell shell) {
    private int runReportPackageWhitelistProblems(PrintWriter pw, Shell shell) {
        boolean verbose = false;
        boolean verbose = false;
        boolean force = false;
        boolean criticalOnly = false;
        int mode = UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_NONE;
        String opt;
        String opt;
        while ((opt = shell.getNextOption()) != null) {
        while ((opt = shell.getNextOption()) != null) {
            switch (opt) {
            switch (opt) {
                case "-v":
                case "-v":
                case "--verbose":
                    verbose = true;
                    verbose = true;
                    break;
                    break;
                case "--force":
                case "--critical-only":
                    force = true;
                    criticalOnly = true;
                    break;
                case "--mode":
                    mode = Integer.parseInt(shell.getNextArgRequired());
                    break;
                    break;
                default:
                default:
                    pw.println("Invalid option: " + opt);
                    pw.println("Invalid option: " + opt);
@@ -4602,8 +4607,12 @@ public class UserManagerService extends IUserManager.Stub {
            }
            }
        }
        }


        Slog.d(LOG_TAG, "runReportPackageWhitelistProblems(): verbose=" + verbose
                + ", criticalOnly=" + criticalOnly
                + ", mode=" + UserSystemPackageInstaller.modeToString(mode));

        try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ")) {
        try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ")) {
            mSystemPackageInstaller.dumpMissingSystemPackages(ipw, force, verbose);
            mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose, criticalOnly);
        }
        }
        return 0;
        return 0;
    }
    }
@@ -5176,13 +5185,18 @@ public class UserManagerService extends IUserManager.Stub {
            final PrintWriter pw = getOutPrintWriter();
            final PrintWriter pw = getOutPrintWriter();
            pw.println("User manager (user) commands:");
            pw.println("User manager (user) commands:");
            pw.println("  help");
            pw.println("  help");
            pw.println("    Print this help text.");
            pw.println("    Prints this help text.");
            pw.println("");
            pw.println("");
            pw.println("  list [-v] [-all]");
            pw.println("  list [-v] [-all]");
            pw.println("    Prints all users on the system.");
            pw.println("    Prints all users on the system.");
            pw.println("  list-missing-system-packages [-v] [--force]");
            pw.println("  report-system-user-package-whitelist-problems [-v | --verbose] "
            pw.println("    Prints all system packages that were not explicitly configured to be "
                    + "[--critical-only] [--mode MODE]");
                    + "installed.");
            pw.println("    Reports all issues on user-type package whitelist XML files. Options:");
            pw.println("    -v | --verbose : shows extra info, like number of issues");
            pw.println("    --critical-only: show only critical issues, excluding warnings");
            pw.println("    --mode MODE: shows what errors would be if device used mode MODE (where"
                    + " MODE is the whitelist mode integer as defined by "
                    + "config_userTypePackageWhitelistMode)");
        }
        }
    }
    }


+109 −62
Original line number Original line Diff line number Diff line
@@ -27,7 +27,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.Pair;
import android.util.DebugUtils;
import android.util.Slog;
import android.util.Slog;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
@@ -41,6 +41,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Set;
import java.util.Set;
@@ -111,14 +112,20 @@ class UserSystemPackageInstaller {
     * frameworks/base/core/res/res/values/config.xml
     * frameworks/base/core/res/res/values/config.xml
     */
     */
    static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
    static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00;

    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01;
    // NOTE: flags below are public so they can used by DebugUtils.flagsToString. And this class
    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02;
    // itself is package-protected, so it doesn't matter...
    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04;
    public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00;
    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08;
    public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01;
    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10;
    public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02;
    public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04;
    public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08;
    public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10;
    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;


    // Used by Shell command only
    static final int USER_TYPE_PACKAGE_WHITELIST_MODE_NONE = -1000;

    @IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
    @IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
            USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE,
            USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE,
            USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
            USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
@@ -266,58 +273,56 @@ class UserSystemPackageInstaller {
        if (!isLogMode(mode) && !isEnforceMode(mode)) {
        if (!isLogMode(mode) && !isEnforceMode(mode)) {
            return;
            return;
        }
        }
        final List<Pair<Boolean, String>> warnings = checkSystemPackagesWhitelistWarnings(mode);
        Slog.v(TAG,  "Checking that all system packages are whitelisted.");
        final int size = warnings.size();

        if (size == 0) {
        // Check whether all whitelisted packages are indeed on the system.
            Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + mode + "): no warnings");
        final List<String> warnings = getPackagesWhitelistWarnings();
            return;
        final int numberWarnings = warnings.size();
        if (numberWarnings == 0) {
            Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
                    + ") has no warnings");
        } else {
            Slog.w(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
                    + ") has " + numberWarnings + " warnings:");
            for (int i = 0; i < numberWarnings; i++) {
                Slog.w(TAG, warnings.get(i));
            }
        }
        }


        // Check whether all system packages are indeed whitelisted.
        if (isImplicitWhitelistMode(mode) && !isLogMode(mode)) {
        if (isImplicitWhitelistMode(mode) && !isLogMode(mode)) {
            // Only shows whether all whitelisted packages are indeed on the system.
            return;
            for (int i = 0; i < size; i++) {
                final Pair<Boolean, String> pair = warnings.get(i);
                final boolean isSevere = pair.first;
                if (!isSevere) {
                    final String msg = pair.second;
                    Slog.w(TAG, msg);
                }
        }
        }

        final List<String> errors = getPackagesWhitelistErrors(mode);
        final int numberErrors = errors.size();

        if (numberErrors == 0) {
            Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode)
                    + ") has no errors");
            return;
            return;
        }
        }
        Slog.e(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode) + ") has "
                + numberErrors + " errors:");


        Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + mode + "): " + size + " warnings");
        boolean doWtf = !isImplicitWhitelistMode(mode);
        boolean doWtf = !isImplicitWhitelistMode(mode);
        for (int i = 0; i < size; i++) {
        for (int i = 0; i < numberWarnings; i++) {
            final Pair<Boolean, String> pair = warnings.get(i);
            final String msg = errors.get(i);
            final boolean isSevere = pair.first;
            final String msg = pair.second;
            if (isSevere) {
            if (doWtf) {
            if (doWtf) {
                Slog.wtf(TAG, msg);
                Slog.wtf(TAG, msg);
            } else {
            } else {
                Slog.e(TAG, msg);
                Slog.e(TAG, msg);
            }
            }
            } else {
                Slog.w(TAG, msg);
            }
        }
        }
    }
    }


    // TODO: method below was created to refactor the one-time logging logic so it can be used on
    // dump / cmd as well. It could to be further refactored (for example, creating a new
    // structure for the warnings so it doesn't need a Pair).
    /**
    /**
     * Gets warnings for system user whitelisting.
     * Gets packages that are listed in the whitelist XML but are not present on the system image.
     *
     * @return list of warnings, where {@code Pair.first} is the severity ({@code true} for WTF,
     * {@code false} for WARN) and {@code Pair.second} the message.
     */
     */
    @NonNull
    @NonNull
    private List<Pair<Boolean, String>> checkSystemPackagesWhitelistWarnings(
    private List<String> getPackagesWhitelistWarnings() {
            @PackageWhitelistMode int mode) {
        final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages();
        final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages();
        final List<Pair<Boolean, String>> warnings = new ArrayList<>();
        final List<String> warnings = new ArrayList<>();
        final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
        final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);


        // Check whether all whitelisted packages are indeed on the system.
        // Check whether all whitelisted packages are indeed on the system.
@@ -326,25 +331,39 @@ class UserSystemPackageInstaller {
        for (String pkgName : allWhitelistedPackages) {
        for (String pkgName : allWhitelistedPackages) {
            final AndroidPackage pkg = pmInt.getPackage(pkgName);
            final AndroidPackage pkg = pmInt.getPackage(pkgName);
            if (pkg == null) {
            if (pkg == null) {
                warnings.add(new Pair<>(false, String.format(notPresentFmt, pkgName)));
                warnings.add(String.format(notPresentFmt, pkgName));
            } else if (!pkg.isSystem()) {
            } else if (!pkg.isSystem()) {
                warnings.add(new Pair<>(false, String.format(notSystemFmt, pkgName)));
                warnings.add(String.format(notSystemFmt, pkgName));
            }
        }
        return warnings;
    }
    }

    /**
     * Gets packages that are not listed in the whitelist XMLs when they should be.
     */
    @NonNull
    private List<String> getPackagesWhitelistErrors(@PackageWhitelistMode int mode) {
        if ((!isEnforceMode(mode) || isImplicitWhitelistMode(mode)) && !isLogMode(mode)) {
            return Collections.emptyList();
        }
        }


        final List<String> errors = new ArrayList<>();
        final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages();
        final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);

        // Check whether all system packages are indeed whitelisted.
        // Check whether all system packages are indeed whitelisted.
        final String logMessageFmt = "System package %s is not whitelisted using "
        final String logMessageFmt = "System package %s is not whitelisted using "
                + "'install-in-user-type' in SystemConfig for any user types!";
                + "'install-in-user-type' in SystemConfig for any user types!";
        final boolean isSevere = isEnforceMode(mode);
        pmInt.forEachPackage(pkg -> {
        pmInt.forEachPackage(pkg -> {
            if (!pkg.isSystem()) return;
            if (!pkg.isSystem()) return;
            final String pkgName = pkg.getManifestPackageName();
            final String pkgName = pkg.getManifestPackageName();
            if (!allWhitelistedPackages.contains(pkgName)) {
            if (!allWhitelistedPackages.contains(pkgName)) {
                warnings.add(new Pair<>(isSevere, String.format(logMessageFmt, pkgName)));
                errors.add(String.format(logMessageFmt, pkgName));
            }
            }
        });
        });


        return warnings;
        return errors;
    }
    }


    /** Whether to only install system packages in new users for which they are whitelisted. */
    /** Whether to only install system packages in new users for which they are whitelisted. */
@@ -420,10 +439,28 @@ class UserSystemPackageInstaller {
        if (runtimeMode != USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) {
        if (runtimeMode != USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) {
            return runtimeMode;
            return runtimeMode;
        }
        }
        return getDeviceDefaultWhitelistMode();
    }

    /** Gets the PackageWhitelistMode as defined by {@code config_userTypePackageWhitelistMode}. */
    private @PackageWhitelistMode int getDeviceDefaultWhitelistMode() {
        return Resources.getSystem()
        return Resources.getSystem()
                .getInteger(com.android.internal.R.integer.config_userTypePackageWhitelistMode);
                .getInteger(com.android.internal.R.integer.config_userTypePackageWhitelistMode);
    }
    }


    static @NonNull String modeToString(@PackageWhitelistMode int mode) {
        // Must handle some types separately because they're not bitwise flags
        switch (mode) {
            case USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT:
                return "DEVICE_DEFAULT";
            case USER_TYPE_PACKAGE_WHITELIST_MODE_NONE:
                return "NONE";
            default:
                return DebugUtils.flagsToString(UserSystemPackageInstaller.class,
                        "USER_TYPE_PACKAGE_WHITELIST_MODE_", mode);
        }
    }

    /**
    /**
     * Gets the system packages names that should be installed on the given user.
     * Gets the system packages names that should be installed on the given user.
     * See {@link #getInstallablePackagesForUserType(String)}.
     * See {@link #getInstallablePackagesForUserType(String)}.
@@ -703,34 +740,44 @@ class UserSystemPackageInstaller {
        pw.decreaseIndent(); pw.decreaseIndent();
        pw.decreaseIndent(); pw.decreaseIndent();


        pw.increaseIndent();
        pw.increaseIndent();
        dumpMissingSystemPackages(pw, /* force= */ true, /* verbose= */ true);
        dumpPackageWhitelistProblems(pw, mode, /* verbose= */ true, /* criticalOnly= */ false);
        pw.decreaseIndent();
        pw.decreaseIndent();
    }
    }


    void dumpMissingSystemPackages(IndentingPrintWriter pw, boolean force, boolean verbose) {
    void dumpPackageWhitelistProblems(IndentingPrintWriter pw, @PackageWhitelistMode int mode,
        final int mode = getWhitelistMode();
            boolean verbose, boolean criticalOnly) {
        final boolean show = force || (isEnforceMode(mode) && !isImplicitWhitelistMode(mode));
        // Handle special cases first
        if (!show) return;
        if (mode == USER_TYPE_PACKAGE_WHITELIST_MODE_NONE) {
            mode = getWhitelistMode();
        } else if (mode == USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) {
            mode = getDeviceDefaultWhitelistMode();
        }
        Slog.v(TAG, "dumpPackageWhitelistProblems(): using mode " + modeToString(mode));

        final List<String> errors = getPackagesWhitelistErrors(mode);
        showIssues(pw, verbose, errors, "errors");


        final List<Pair<Boolean, String>> warnings = checkSystemPackagesWhitelistWarnings(mode);
        if (criticalOnly) return;
        final int size = warnings.size();


        final List<String> warnings = getPackagesWhitelistWarnings();
        showIssues(pw, verbose, warnings, "warnings");
    }

    private static void showIssues(IndentingPrintWriter pw, boolean verbose, List<String> issues,
            String issueType) {
        final int size = issues.size();
        if (size == 0) {
        if (size == 0) {
            if (verbose) {
            if (verbose) {
                pw.println("All system packages are accounted for");
                pw.print("No "); pw.println(issueType);
            }
            }
            return;
            return;
        }
        }

        if (verbose) {
        if (verbose) {
            pw.print(size); pw.println(" warnings for system user:");
            pw.print(size); pw.print(' '); pw.println(issueType);
            pw.increaseIndent();
            pw.increaseIndent();
        }
        }
        for (int i = 0; i < size; i++) {
        for (int i = 0; i < size; i++) {
            final Pair<Boolean, String> pair = warnings.get(i);
            pw.println(issues.get(i));
            final String lvl = pair.first ? "WTF" : "WARN";
            final String msg = pair.second;
            pw.print(lvl); pw.print(": "); pw.println(msg);
        }
        }
        if (verbose) {
        if (verbose) {
            pw.decreaseIndent();
            pw.decreaseIndent();