diff options
| -rw-r--r-- | services/core/java/com/android/server/pm/UserManagerService.java | 36 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/UserSystemPackageInstaller.java | 171 |
2 files changed, 134 insertions, 73 deletions
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index e6af86e52035..16d96d9a5574 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -4516,8 +4516,8 @@ public class UserManagerService extends IUserManager.Stub { switch(cmd) { case "list": return runList(pw, shell); - case "list-missing-system-packages": - return runListMissingSystemPackages(pw, shell); + case "report-system-user-package-whitelist-problems": + return runReportPackageWhitelistProblems(pw, shell); default: 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 force = false; + boolean criticalOnly = false; + int mode = UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_NONE; String opt; while ((opt = shell.getNextOption()) != null) { switch (opt) { case "-v": + case "--verbose": verbose = true; break; - case "--force": - force = true; + case "--critical-only": + criticalOnly = true; + break; + case "--mode": + mode = Integer.parseInt(shell.getNextArgRequired()); break; default: 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, " ")) { - mSystemPackageInstaller.dumpMissingSystemPackages(ipw, force, verbose); + mSystemPackageInstaller.dumpPackageWhitelistProblems(ipw, mode, verbose, criticalOnly); } return 0; } @@ -5176,13 +5185,18 @@ public class UserManagerService extends IUserManager.Stub { final PrintWriter pw = getOutPrintWriter(); pw.println("User manager (user) commands:"); pw.println(" help"); - pw.println(" Print this help text."); + pw.println(" Prints this help text."); pw.println(""); pw.println(" list [-v] [-all]"); pw.println(" Prints all users on the system."); - pw.println(" list-missing-system-packages [-v] [--force]"); - pw.println(" Prints all system packages that were not explicitly configured to be " - + "installed."); + pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] " + + "[--critical-only] [--mode MODE]"); + 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)"); } } diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java index cd1087f5fcd7..9ec03e5e8f5c 100644 --- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java +++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java @@ -27,7 +27,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.Pair; +import android.util.DebugUtils; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -41,6 +41,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -111,14 +112,20 @@ class UserSystemPackageInstaller { * frameworks/base/core/res/res/values/config.xml */ 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; - static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02; - static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04; - static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08; - static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10; + + // NOTE: flags below are public so they can used by DebugUtils.flagsToString. And this class + // itself is package-protected, so it doesn't matter... + public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00; + public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01; + 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; + // 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 = { USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE, USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE, @@ -266,58 +273,56 @@ class UserSystemPackageInstaller { if (!isLogMode(mode) && !isEnforceMode(mode)) { return; } - final List<Pair<Boolean, String>> warnings = checkSystemPackagesWhitelistWarnings(mode); - final int size = warnings.size(); - if (size == 0) { - Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + mode + "): no warnings"); - return; + Slog.v(TAG, "Checking that all system packages are whitelisted."); + + // Check whether all whitelisted packages are indeed on the system. + final List<String> warnings = getPackagesWhitelistWarnings(); + 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)) { - // Only shows whether all whitelisted packages are indeed on the system. - 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); - } - } return; } - Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + mode + "): " + size + " warnings"); + 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; + } + Slog.e(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode) + ") has " + + numberErrors + " errors:"); + boolean doWtf = !isImplicitWhitelistMode(mode); - for (int i = 0; i < size; i++) { - final Pair<Boolean, String> pair = warnings.get(i); - final boolean isSevere = pair.first; - final String msg = pair.second; - if (isSevere) { - if (doWtf) { - Slog.wtf(TAG, msg); - } else { - Slog.e(TAG, msg); - } + for (int i = 0; i < numberWarnings; i++) { + final String msg = errors.get(i); + if (doWtf) { + Slog.wtf(TAG, msg); } else { - Slog.w(TAG, msg); + Slog.e(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. - * - * @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. + * Gets packages that are listed in the whitelist XML but are not present on the system image. */ @NonNull - private List<Pair<Boolean, String>> checkSystemPackagesWhitelistWarnings( - @PackageWhitelistMode int mode) { + private List<String> getPackagesWhitelistWarnings() { 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); // Check whether all whitelisted packages are indeed on the system. @@ -326,25 +331,39 @@ class UserSystemPackageInstaller { for (String pkgName : allWhitelistedPackages) { final AndroidPackage pkg = pmInt.getPackage(pkgName); if (pkg == null) { - warnings.add(new Pair<>(false, String.format(notPresentFmt, pkgName))); + warnings.add(String.format(notPresentFmt, pkgName)); } 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. final String logMessageFmt = "System package %s is not whitelisted using " + "'install-in-user-type' in SystemConfig for any user types!"; - final boolean isSevere = isEnforceMode(mode); pmInt.forEachPackage(pkg -> { if (!pkg.isSystem()) return; final String pkgName = pkg.getManifestPackageName(); 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. */ @@ -420,10 +439,28 @@ class UserSystemPackageInstaller { if (runtimeMode != USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) { return runtimeMode; } + return getDeviceDefaultWhitelistMode(); + } + + /** Gets the PackageWhitelistMode as defined by {@code config_userTypePackageWhitelistMode}. */ + private @PackageWhitelistMode int getDeviceDefaultWhitelistMode() { return Resources.getSystem() .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. * See {@link #getInstallablePackagesForUserType(String)}. @@ -703,34 +740,44 @@ class UserSystemPackageInstaller { pw.decreaseIndent(); pw.decreaseIndent(); pw.increaseIndent(); - dumpMissingSystemPackages(pw, /* force= */ true, /* verbose= */ true); + dumpPackageWhitelistProblems(pw, mode, /* verbose= */ true, /* criticalOnly= */ false); pw.decreaseIndent(); } - void dumpMissingSystemPackages(IndentingPrintWriter pw, boolean force, boolean verbose) { - final int mode = getWhitelistMode(); - final boolean show = force || (isEnforceMode(mode) && !isImplicitWhitelistMode(mode)); - if (!show) return; + void dumpPackageWhitelistProblems(IndentingPrintWriter pw, @PackageWhitelistMode int mode, + boolean verbose, boolean criticalOnly) { + // Handle special cases first + 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); - final int size = warnings.size(); + if (criticalOnly) return; + 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 (verbose) { - pw.println("All system packages are accounted for"); + pw.print("No "); pw.println(issueType); } return; } - if (verbose) { - pw.print(size); pw.println(" warnings for system user:"); + pw.print(size); pw.print(' '); pw.println(issueType); pw.increaseIndent(); } for (int i = 0; i < size; i++) { - final Pair<Boolean, String> pair = warnings.get(i); - final String lvl = pair.first ? "WTF" : "WARN"; - final String msg = pair.second; - pw.print(lvl); pw.print(": "); pw.println(msg); + pw.println(issues.get(i)); } if (verbose) { pw.decreaseIndent(); |