Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.server.pm; |
| 18 | |
| 19 | import android.annotation.IntDef; |
| 20 | import android.annotation.NonNull; |
| 21 | import android.annotation.Nullable; |
| 22 | import android.annotation.UserIdInt; |
Adam Bookatz | 1efd27cd | 2020-03-19 18:37:36 -0700 | [diff] [blame] | 23 | import android.content.pm.PackageManager; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 24 | import android.content.pm.PackageManagerInternal; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 25 | import android.content.res.Resources; |
| 26 | import android.os.SystemProperties; |
| 27 | import android.os.UserHandle; |
| 28 | import android.util.ArrayMap; |
| 29 | import android.util.ArraySet; |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 30 | import android.util.DebugUtils; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 31 | import android.util.Slog; |
| 32 | |
| 33 | import com.android.internal.annotations.VisibleForTesting; |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 34 | import com.android.internal.util.IndentingPrintWriter; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 35 | import com.android.server.LocalServices; |
| 36 | import com.android.server.SystemConfig; |
Winson | 5e0a1d5 | 2020-01-24 12:00:33 -0800 | [diff] [blame] | 37 | import com.android.server.pm.parsing.pkg.AndroidPackage; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 38 | |
| 39 | import java.io.PrintWriter; |
| 40 | import java.lang.annotation.Retention; |
| 41 | import java.lang.annotation.RetentionPolicy; |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 42 | import java.util.ArrayList; |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 43 | import java.util.Arrays; |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 44 | import java.util.Collections; |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 45 | import java.util.List; |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 46 | import java.util.Map; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 47 | import java.util.Set; |
| 48 | |
| 49 | /** |
| 50 | * Responsible for un/installing system packages based on user type. |
| 51 | * |
| 52 | * <p>Uses the SystemConfig's install-in-user-type whitelist; |
| 53 | * see {@link SystemConfig#getAndClearPackageToUserTypeWhitelist} and |
| 54 | * {@link SystemConfig#getAndClearPackageToUserTypeBlacklist}. |
| 55 | * |
| 56 | * <p>If {@link #isEnforceMode()} is false, then all system packages are always installed for all |
| 57 | * users. The following applies when it is true. |
| 58 | * |
Felipe Leme | 7d4d728 | 2019-10-25 10:03:18 -0700 | [diff] [blame] | 59 | * <p>Any package can be in one of three states in the {@code SystemConfig} whitelist |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 60 | * <ol> |
| 61 | * <li>Explicitly blacklisted for a particular user type</li> |
| 62 | * <li>Explicitly whitelisted for a particular user type</li> |
| 63 | * <li>Not mentioned at all, for any user type (neither whitelisted nor blacklisted)</li> |
| 64 | * </ol> |
Felipe Leme | 7d4d728 | 2019-10-25 10:03:18 -0700 | [diff] [blame] | 65 | * |
| 66 | * <p>Blacklisting always takes precedence - if a package is blacklisted for a particular user, |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 67 | * it won't be installed on that type of user (even if it is also whitelisted for that user). |
| 68 | * Next comes whitelisting - if it is whitelisted for a particular user, it will be installed on |
| 69 | * that type of user (as long as it isn't blacklisted). |
| 70 | * Finally, if the package is not mentioned at all (i.e. neither whitelisted nor blacklisted for |
| 71 | * any user types) in the SystemConfig 'install-in-user-type' lists |
| 72 | * then: |
| 73 | * <ul> |
| 74 | * <li>If {@link #isImplicitWhitelistMode()}, the package is implicitly treated as whitelisted |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 75 | * for <b>all</b> users</li> |
| 76 | * <li>Otherwise, if {@link #isImplicitWhitelistSystemMode()}, the package is implicitly treated |
| 77 | * as whitelisted for the <b>{@link UserHandle#USER_SYSTEM}</b> user (not other users), |
| 78 | * which is useful for local development purposes</li> |
| 79 | * <li>Otherwise, the package is implicitly treated as blacklisted for all users</li> |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 80 | * </ul> |
Felipe Leme | 7d4d728 | 2019-10-25 10:03:18 -0700 | [diff] [blame] | 81 | * |
Adam Bookatz | 1efd27cd | 2020-03-19 18:37:36 -0700 | [diff] [blame] | 82 | * <p>Packages are only installed/uninstalled by this mechanism when a new user is created or during |
| 83 | * an update. In the case of updates:<ul> |
| 84 | * <li>new packages are (un)installed per the whitelist/blacklist</li> |
| 85 | * <li>pre-existing installed blacklisted packages are never uninstalled</li> |
| 86 | * <li>pre-existing not-installed whitelisted packages are only installed if the reason why they |
| 87 | * had been previously uninstalled was due to UserSystemPackageInstaller</li> |
| 88 | * </ul> |
| 89 | * |
Felipe Leme | 7d4d728 | 2019-10-25 10:03:18 -0700 | [diff] [blame] | 90 | * <p><b>NOTE:</b> the {@code SystemConfig} state is only updated on first boot or after a system |
| 91 | * update. So, to verify changes during development, you can emulate the latter by calling: |
| 92 | * <pre><code> |
| 93 | * adb shell setprop persist.pm.mock-upgrade true |
| 94 | * </code></pre> |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 95 | */ |
| 96 | class UserSystemPackageInstaller { |
| 97 | private static final String TAG = "UserManagerService"; |
| 98 | |
| 99 | /** |
| 100 | * System Property whether to only install system packages on a user if they're whitelisted for |
| 101 | * that user type. These are flags and can be freely combined. |
| 102 | * <ul> |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 103 | * <li> 0 - disable whitelist (install all system packages; no logging)</li> |
| 104 | * <li> 1 - enforce (only install system packages if they are whitelisted)</li> |
Adam Bookatz | 3483914 | 2020-02-10 13:56:46 -0800 | [diff] [blame] | 105 | * <li> 2 - log (log non-whitelisted packages)</li> |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 106 | * <li> 4 - for all users: implicitly whitelist any package not mentioned in the whitelist</li> |
| 107 | * <li> 8 - for SYSTEM: implicitly whitelist any package not mentioned in the whitelist</li> |
| 108 | * <li> 16 - ignore OTAs (don't install system packages during OTAs)</li> |
| 109 | * <li>-1 - use device default (as defined in res/res/values/config.xml)</li> |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 110 | * </ul> |
| 111 | * Note: This list must be kept current with config_userTypePackageWhitelistMode in |
| 112 | * frameworks/base/core/res/res/values/config.xml |
| 113 | */ |
| 114 | static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode"; |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 115 | |
| 116 | // NOTE: flags below are public so they can used by DebugUtils.flagsToString. And this class |
| 117 | // itself is package-protected, so it doesn't matter... |
| 118 | public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0x00; |
| 119 | public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0x01; |
| 120 | public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0x02; |
| 121 | public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0x04; |
| 122 | public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM = 0x08; |
| 123 | public static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0x10; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 124 | static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1; |
| 125 | |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 126 | // Used by Shell command only |
| 127 | static final int USER_TYPE_PACKAGE_WHITELIST_MODE_NONE = -1000; |
| 128 | |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 129 | @IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = { |
| 130 | USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE, |
| 131 | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE, |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 132 | USER_TYPE_PACKAGE_WHITELIST_MODE_LOG, |
| 133 | USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST, |
Bookatz | 0274a6e | 2019-11-25 15:31:39 -0800 | [diff] [blame] | 134 | USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA, |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 135 | }) |
| 136 | @Retention(RetentionPolicy.SOURCE) |
| 137 | public @interface PackageWhitelistMode {} |
| 138 | |
| 139 | /** |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 140 | * Maps system package manifest names to a bitset representing (via {@link #getUserTypeMask}) |
| 141 | * the user types on which they should be initially installed. |
| 142 | * <p> |
| 143 | * E.g. if package "pkg1" should be installed on "usertype_d", which is the user type for which |
| 144 | * {@link #getUserTypeMask}("usertype_d") returns (1 << 3) |
| 145 | * then mWhitelistedPackagesForUserTypes.get("pkg1") will be a Long whose |
| 146 | * bit in position 3 will equal 1. |
| 147 | * <p> |
| 148 | * Packages that are whitelisted, but then blacklisted so that they aren't to be installed on |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 149 | * any user, are purposefully still present in this list. |
| 150 | */ |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 151 | private final ArrayMap<String, Long> mWhitelistedPackagesForUserTypes; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 152 | |
| 153 | private final UserManagerService mUm; |
| 154 | |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 155 | /** |
| 156 | * Alphabetically sorted list of user types. |
| 157 | * Throughout this class, a long (functioning as a bitset) has its ith bit representing |
| 158 | * the user type stored in mUserTypes[i]. |
| 159 | * mUserTypes cannot exceed Long.SIZE (since we are using long for our bitset). |
| 160 | */ |
| 161 | private final String[] mUserTypes; |
| 162 | |
| 163 | UserSystemPackageInstaller(UserManagerService um, ArrayMap<String, UserTypeDetails> userTypes) { |
| 164 | mUm = um; |
| 165 | mUserTypes = getAndSortKeysFromMap(userTypes); |
| 166 | if (mUserTypes.length > Long.SIZE) { |
| 167 | throw new IllegalArgumentException("Device contains " + userTypes.size() |
| 168 | + " user types. However, UserSystemPackageInstaller does not work if there are" |
| 169 | + " more than " + Long.SIZE + " user types."); |
| 170 | // UserSystemPackageInstaller could use a BitSet instead of Long in this case. |
| 171 | // But, currently, 64 user types is far beyond expectations, so we have not done so. |
| 172 | } |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 173 | mWhitelistedPackagesForUserTypes = |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 174 | determineWhitelistedPackagesForUserTypes(SystemConfig.getInstance()); |
| 175 | } |
| 176 | |
| 177 | /** Constructor for testing purposes. */ |
| 178 | @VisibleForTesting |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 179 | UserSystemPackageInstaller(UserManagerService ums, ArrayMap<String, Long> whitelist, |
| 180 | String[] sortedUserTypes) { |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 181 | mUm = ums; |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 182 | mUserTypes = sortedUserTypes; |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 183 | mWhitelistedPackagesForUserTypes = whitelist; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 184 | } |
| 185 | |
| 186 | /** |
| 187 | * During OTAs and first boot, install/uninstall all system packages for all users based on the |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 188 | * user's user type and the SystemConfig whitelist. |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 189 | * We do NOT uninstall packages during an OTA though. |
| 190 | * |
| 191 | * This is responsible for enforcing the whitelist for pre-existing users (i.e. USER_SYSTEM); |
| 192 | * enforcement for new users is done when they are created in UserManagerService.createUser(). |
Adam Bookatz | 1efd27cd | 2020-03-19 18:37:36 -0700 | [diff] [blame] | 193 | * |
| 194 | * @param preExistingPackages list of packages on the device prior to the upgrade. Cannot be |
| 195 | * null if isUpgrade is true. |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 196 | */ |
Adam Bookatz | 1efd27cd | 2020-03-19 18:37:36 -0700 | [diff] [blame] | 197 | boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade, |
| 198 | @Nullable ArraySet<String> preExistingPackages) { |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 199 | final int mode = getWhitelistMode(); |
| 200 | checkWhitelistedSystemPackages(mode); |
Bookatz | 0274a6e | 2019-11-25 15:31:39 -0800 | [diff] [blame] | 201 | final boolean isConsideredUpgrade = isUpgrade && !isIgnoreOtaMode(mode); |
| 202 | if (!isConsideredUpgrade && !isFirstBoot) { |
| 203 | return false; |
| 204 | } |
| 205 | if (isFirstBoot && !isEnforceMode(mode)) { |
| 206 | // Note that if !isEnforceMode, we nonetheless still install packages if isUpgrade |
| 207 | // in order to undo any previous non-installing. isFirstBoot lacks this requirement. |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 208 | return false; |
| 209 | } |
| 210 | Slog.i(TAG, "Reviewing whitelisted packages due to " |
Bookatz | 0274a6e | 2019-11-25 15:31:39 -0800 | [diff] [blame] | 211 | + (isFirstBoot ? "[firstBoot]" : "") + (isConsideredUpgrade ? "[upgrade]" : "")); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 212 | final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); |
| 213 | // Install/uninstall system packages per user. |
| 214 | for (int userId : mUm.getUserIds()) { |
| 215 | final Set<String> userWhitelist = getInstallablePackagesForUserId(userId); |
Winson | e075629 | 2020-01-31 12:21:54 -0800 | [diff] [blame] | 216 | pmInt.forEachPackageSetting(pkgSetting -> { |
| 217 | AndroidPackage pkg = pkgSetting.pkg; |
| 218 | if (pkg == null || !pkg.isSystem()) { |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 219 | return; |
| 220 | } |
| 221 | final boolean install = |
Winson | 655a5b9 | 2019-10-23 10:49:32 -0700 | [diff] [blame] | 222 | (userWhitelist == null || userWhitelist.contains(pkg.getPackageName())) |
Winson | e075629 | 2020-01-31 12:21:54 -0800 | [diff] [blame] | 223 | && !pkgSetting.getPkgState().isHiddenUntilInstalled(); |
Adam Bookatz | 1efd27cd | 2020-03-19 18:37:36 -0700 | [diff] [blame] | 224 | if (pkgSetting.getInstalled(userId) == install |
| 225 | || !shouldChangeInstallationState(pkgSetting, install, userId, isFirstBoot, |
| 226 | isConsideredUpgrade, preExistingPackages)) { |
| 227 | return; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 228 | } |
Adam Bookatz | 1efd27cd | 2020-03-19 18:37:36 -0700 | [diff] [blame] | 229 | pkgSetting.setInstalled(install, userId); |
| 230 | pkgSetting.setUninstallReason( |
| 231 | install ? PackageManager.UNINSTALL_REASON_UNKNOWN : |
| 232 | PackageManager.UNINSTALL_REASON_USER_TYPE, |
| 233 | userId); |
| 234 | Slog.i(TAG, (install ? "Installed " : "Uninstalled ") |
| 235 | + pkg.getPackageName() + " for user " + userId); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 236 | }); |
| 237 | } |
| 238 | return true; |
| 239 | } |
| 240 | |
| 241 | /** |
Adam Bookatz | 1efd27cd | 2020-03-19 18:37:36 -0700 | [diff] [blame] | 242 | * Returns whether to proceed with install/uninstall for the given package. |
| 243 | * In particular, do not install a package unless it was only uninstalled due to the user type; |
| 244 | * and do not uninstall a package if it previously was installed (prior to the OTA). |
| 245 | * |
| 246 | * Should be called only within PackageManagerInternal.forEachPackageSetting() since it |
| 247 | * requires the LP lock. |
| 248 | * |
| 249 | * @param preOtaPkgs list of packages on the device prior to the upgrade. |
| 250 | * Cannot be null if isUpgrade is true. |
| 251 | */ |
| 252 | private static boolean shouldChangeInstallationState(PackageSetting pkgSetting, |
| 253 | boolean install, |
| 254 | @UserIdInt int userId, |
| 255 | boolean isFirstBoot, |
| 256 | boolean isUpgrade, |
| 257 | @Nullable ArraySet<String> preOtaPkgs) { |
| 258 | if (install) { |
| 259 | // Only proceed with install if we are the only reason why it had been uninstalled. |
| 260 | return pkgSetting.getUninstallReason(userId) |
| 261 | == PackageManager.UNINSTALL_REASON_USER_TYPE; |
| 262 | } else { |
| 263 | // Only proceed with uninstall if the package is new to the device. |
| 264 | return isFirstBoot || (isUpgrade && !preOtaPkgs.contains(pkgSetting.name)); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | /** |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 269 | * Checks whether the system packages and the mWhitelistedPackagesForUserTypes whitelist are |
| 270 | * in 1-to-1 correspondence. |
| 271 | */ |
| 272 | private void checkWhitelistedSystemPackages(@PackageWhitelistMode int mode) { |
| 273 | if (!isLogMode(mode) && !isEnforceMode(mode)) { |
| 274 | return; |
| 275 | } |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 276 | Slog.v(TAG, "Checking that all system packages are whitelisted."); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 277 | |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 278 | // Check whether all whitelisted packages are indeed on the system. |
| 279 | final List<String> warnings = getPackagesWhitelistWarnings(); |
| 280 | final int numberWarnings = warnings.size(); |
| 281 | if (numberWarnings == 0) { |
| 282 | Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode) |
| 283 | + ") has no warnings"); |
| 284 | } else { |
| 285 | Slog.w(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode) |
| 286 | + ") has " + numberWarnings + " warnings:"); |
| 287 | for (int i = 0; i < numberWarnings; i++) { |
| 288 | Slog.w(TAG, warnings.get(i)); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 289 | } |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 290 | } |
| 291 | |
| 292 | // Check whether all system packages are indeed whitelisted. |
| 293 | if (isImplicitWhitelistMode(mode) && !isLogMode(mode)) { |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 294 | return; |
| 295 | } |
| 296 | |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 297 | final List<String> errors = getPackagesWhitelistErrors(mode); |
| 298 | final int numberErrors = errors.size(); |
| 299 | |
| 300 | if (numberErrors == 0) { |
| 301 | Slog.v(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode) |
| 302 | + ") has no errors"); |
| 303 | return; |
| 304 | } |
| 305 | Slog.e(TAG, "checkWhitelistedSystemPackages(mode=" + modeToString(mode) + ") has " |
| 306 | + numberErrors + " errors:"); |
| 307 | |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 308 | boolean doWtf = !isImplicitWhitelistMode(mode); |
felipeal | c0f1286 | 2020-05-08 08:25:24 -0700 | [diff] [blame] | 309 | for (int i = 0; i < numberErrors; i++) { |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 310 | final String msg = errors.get(i); |
| 311 | if (doWtf) { |
| 312 | Slog.wtf(TAG, msg); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 313 | } else { |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 314 | Slog.e(TAG, msg); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 315 | } |
| 316 | } |
| 317 | } |
| 318 | |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 319 | /** |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 320 | * Gets packages that are listed in the whitelist XML but are not present on the system image. |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 321 | */ |
| 322 | @NonNull |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 323 | private List<String> getPackagesWhitelistWarnings() { |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 324 | final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages(); |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 325 | final List<String> warnings = new ArrayList<>(); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 326 | final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); |
| 327 | |
| 328 | // Check whether all whitelisted packages are indeed on the system. |
| 329 | final String notPresentFmt = "%s is whitelisted but not present."; |
| 330 | final String notSystemFmt = "%s is whitelisted and present but not a system package."; |
| 331 | for (String pkgName : allWhitelistedPackages) { |
| 332 | final AndroidPackage pkg = pmInt.getPackage(pkgName); |
| 333 | if (pkg == null) { |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 334 | warnings.add(String.format(notPresentFmt, pkgName)); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 335 | } else if (!pkg.isSystem()) { |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 336 | warnings.add(String.format(notSystemFmt, pkgName)); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 337 | } |
| 338 | } |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 339 | return warnings; |
| 340 | } |
| 341 | |
| 342 | /** |
| 343 | * Gets packages that are not listed in the whitelist XMLs when they should be. |
| 344 | */ |
| 345 | @NonNull |
| 346 | private List<String> getPackagesWhitelistErrors(@PackageWhitelistMode int mode) { |
| 347 | if ((!isEnforceMode(mode) || isImplicitWhitelistMode(mode)) && !isLogMode(mode)) { |
| 348 | return Collections.emptyList(); |
| 349 | } |
| 350 | |
| 351 | final List<String> errors = new ArrayList<>(); |
| 352 | final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages(); |
| 353 | final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 354 | |
| 355 | // Check whether all system packages are indeed whitelisted. |
| 356 | final String logMessageFmt = "System package %s is not whitelisted using " |
| 357 | + "'install-in-user-type' in SystemConfig for any user types!"; |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 358 | pmInt.forEachPackage(pkg -> { |
| 359 | if (!pkg.isSystem()) return; |
| 360 | final String pkgName = pkg.getManifestPackageName(); |
| 361 | if (!allWhitelistedPackages.contains(pkgName)) { |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 362 | errors.add(String.format(logMessageFmt, pkgName)); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 363 | } |
| 364 | }); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 365 | |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 366 | return errors; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 367 | } |
| 368 | |
| 369 | /** Whether to only install system packages in new users for which they are whitelisted. */ |
| 370 | boolean isEnforceMode() { |
| 371 | return isEnforceMode(getWhitelistMode()); |
| 372 | } |
| 373 | |
| 374 | /** |
Bookatz | 0274a6e | 2019-11-25 15:31:39 -0800 | [diff] [blame] | 375 | * Whether to ignore OTAs, and therefore not install missing system packages during OTAs. |
| 376 | * <p>Note: |
| 377 | * If in this mode, old system packages will not be installed on pre-existing users during OTAs. |
| 378 | * Any system packages that had not been installed at the time of the user's creation, |
| 379 | * due to {@link UserSystemPackageInstaller}'s previous actions, will therefore continue to |
| 380 | * remain uninstalled, even if the whitelist (or enforcement mode) now declares that they should |
| 381 | * be. |
| 382 | */ |
| 383 | boolean isIgnoreOtaMode() { |
| 384 | return isIgnoreOtaMode(getWhitelistMode()); |
| 385 | } |
| 386 | |
| 387 | /** |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 388 | * Whether to log a warning concerning potential problems with the user-type package whitelist. |
| 389 | */ |
| 390 | boolean isLogMode() { |
| 391 | return isLogMode(getWhitelistMode()); |
| 392 | } |
| 393 | |
| 394 | /** |
| 395 | * Whether to treat all packages that are not mentioned at all in the whitelist to be implicitly |
| 396 | * whitelisted for all users. |
| 397 | */ |
| 398 | boolean isImplicitWhitelistMode() { |
| 399 | return isImplicitWhitelistMode(getWhitelistMode()); |
| 400 | } |
| 401 | |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 402 | /** |
| 403 | * Whether to treat all packages that are not mentioned at all in the whitelist to be implicitly |
| 404 | * whitelisted for the SYSTEM user. |
| 405 | */ |
| 406 | boolean isImplicitWhitelistSystemMode() { |
| 407 | return isImplicitWhitelistSystemMode(getWhitelistMode()); |
| 408 | } |
| 409 | |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 410 | /** See {@link #isEnforceMode()}. */ |
| 411 | private static boolean isEnforceMode(int whitelistMode) { |
| 412 | return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0; |
| 413 | } |
| 414 | |
Bookatz | 0274a6e | 2019-11-25 15:31:39 -0800 | [diff] [blame] | 415 | /** See {@link #isIgnoreOtaMode()}. */ |
| 416 | private static boolean isIgnoreOtaMode(int whitelistMode) { |
| 417 | return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA) != 0; |
| 418 | } |
| 419 | |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 420 | /** See {@link #isLogMode()}. */ |
| 421 | private static boolean isLogMode(int whitelistMode) { |
| 422 | return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_LOG) != 0; |
| 423 | } |
| 424 | |
| 425 | /** See {@link #isImplicitWhitelistMode()}. */ |
| 426 | private static boolean isImplicitWhitelistMode(int whitelistMode) { |
| 427 | return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST) != 0; |
| 428 | } |
| 429 | |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 430 | /** See {@link #isImplicitWhitelistSystemMode()}. */ |
| 431 | private static boolean isImplicitWhitelistSystemMode(int whitelistMode) { |
| 432 | return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM) != 0; |
| 433 | } |
| 434 | |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 435 | /** Gets the PackageWhitelistMode for use of {@link #mWhitelistedPackagesForUserTypes}. */ |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 436 | private @PackageWhitelistMode int getWhitelistMode() { |
| 437 | final int runtimeMode = SystemProperties.getInt( |
| 438 | PACKAGE_WHITELIST_MODE_PROP, USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT); |
| 439 | if (runtimeMode != USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) { |
| 440 | return runtimeMode; |
| 441 | } |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 442 | return getDeviceDefaultWhitelistMode(); |
| 443 | } |
| 444 | |
| 445 | /** Gets the PackageWhitelistMode as defined by {@code config_userTypePackageWhitelistMode}. */ |
| 446 | private @PackageWhitelistMode int getDeviceDefaultWhitelistMode() { |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 447 | return Resources.getSystem() |
| 448 | .getInteger(com.android.internal.R.integer.config_userTypePackageWhitelistMode); |
| 449 | } |
| 450 | |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 451 | static @NonNull String modeToString(@PackageWhitelistMode int mode) { |
| 452 | // Must handle some types separately because they're not bitwise flags |
| 453 | switch (mode) { |
| 454 | case USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT: |
| 455 | return "DEVICE_DEFAULT"; |
| 456 | case USER_TYPE_PACKAGE_WHITELIST_MODE_NONE: |
| 457 | return "NONE"; |
| 458 | default: |
| 459 | return DebugUtils.flagsToString(UserSystemPackageInstaller.class, |
| 460 | "USER_TYPE_PACKAGE_WHITELIST_MODE_", mode); |
| 461 | } |
| 462 | } |
| 463 | |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 464 | /** |
| 465 | * Gets the system packages names that should be installed on the given user. |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 466 | * See {@link #getInstallablePackagesForUserType(String)}. |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 467 | */ |
| 468 | private @Nullable Set<String> getInstallablePackagesForUserId(@UserIdInt int userId) { |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 469 | return getInstallablePackagesForUserType(mUm.getUserInfo(userId).userType); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | /** |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 473 | * Gets the system package names that should be installed on users of the given user type, as |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 474 | * determined by SystemConfig, the whitelist mode, and the apps actually on the device. |
| 475 | * Names are the {@link PackageParser.Package#packageName}, not necessarily the manifest names. |
| 476 | * |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 477 | * Returns null if all system packages should be installed (due to enforce-mode being off). |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 478 | */ |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 479 | @Nullable Set<String> getInstallablePackagesForUserType(String userType) { |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 480 | final int mode = getWhitelistMode(); |
| 481 | if (!isEnforceMode(mode)) { |
| 482 | return null; |
| 483 | } |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 484 | final boolean implicitlyWhitelist = isImplicitWhitelistMode(mode) |
| 485 | || (isImplicitWhitelistSystemMode(mode) && mUm.isUserTypeSubtypeOfSystem(userType)); |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 486 | final Set<String> whitelistedPackages = getWhitelistedPackagesForUserType(userType); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 487 | |
| 488 | final Set<String> installPackages = new ArraySet<>(); |
| 489 | final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); |
| 490 | pmInt.forEachPackage(pkg -> { |
| 491 | if (!pkg.isSystem()) { |
| 492 | return; |
| 493 | } |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 494 | if (shouldInstallPackage(pkg, mWhitelistedPackagesForUserTypes, |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 495 | whitelistedPackages, implicitlyWhitelist)) { |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 496 | // Although the whitelist uses manifest names, this function returns packageNames. |
Winson | 14ff717 | 2019-10-23 10:42:27 -0700 | [diff] [blame] | 497 | installPackages.add(pkg.getPackageName()); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 498 | } |
| 499 | }); |
| 500 | return installPackages; |
| 501 | } |
| 502 | |
| 503 | /** |
| 504 | * Returns whether the given system package should be installed on the given user, based on the |
| 505 | * the given whitelist of system packages. |
| 506 | * |
| 507 | * @param sysPkg the system package. Must be a system package; no verification for this is done. |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 508 | * @param userTypeWhitelist map of package manifest names to user types on which they should be |
| 509 | * installed. This is only used for overriding the userWhitelist in |
| 510 | * certain situations (based on its keyset). |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 511 | * @param userWhitelist set of package manifest names that should be installed on this |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 512 | * <b>particular</b> user. This must be consistent with userTypeWhitelist, |
| 513 | * but is passed in separately to avoid repeatedly calculating it from |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 514 | * userTypeWhitelist. |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 515 | * @param implicitlyWhitelist whether non-mentioned packages are implicitly whitelisted. |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 516 | */ |
| 517 | @VisibleForTesting |
Winson | 655a5b9 | 2019-10-23 10:49:32 -0700 | [diff] [blame] | 518 | static boolean shouldInstallPackage(AndroidPackage sysPkg, |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 519 | @NonNull ArrayMap<String, Long> userTypeWhitelist, |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 520 | @NonNull Set<String> userWhitelist, boolean implicitlyWhitelist) { |
Winson | 14ff717 | 2019-10-23 10:42:27 -0700 | [diff] [blame] | 521 | final String pkgName = sysPkg.getManifestPackageName(); |
Bookatz | eac923e | 2019-12-17 12:30:20 -0800 | [diff] [blame] | 522 | return (implicitlyWhitelist && !userTypeWhitelist.containsKey(pkgName)) |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 523 | || userWhitelist.contains(pkgName); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 524 | } |
| 525 | |
| 526 | /** |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 527 | * Gets the package manifest names that are whitelisted for users of the given user type, |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 528 | * as determined by SystemConfig. |
| 529 | */ |
| 530 | @VisibleForTesting |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 531 | @NonNull Set<String> getWhitelistedPackagesForUserType(String userType) { |
| 532 | final long userTypeMask = getUserTypeMask(userType); |
| 533 | final Set<String> installablePkgs = new ArraySet<>(mWhitelistedPackagesForUserTypes.size()); |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 534 | for (int i = 0; i < mWhitelistedPackagesForUserTypes.size(); i++) { |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 535 | final String pkgName = mWhitelistedPackagesForUserTypes.keyAt(i); |
| 536 | final long whitelistedUserTypes = mWhitelistedPackagesForUserTypes.valueAt(i); |
| 537 | if ((userTypeMask & whitelistedUserTypes) != 0) { |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 538 | installablePkgs.add(pkgName); |
| 539 | } |
| 540 | } |
| 541 | return installablePkgs; |
| 542 | } |
| 543 | |
| 544 | /** |
| 545 | * Set of package manifest names that are included anywhere in the package-to-user-type |
| 546 | * whitelist, as determined by SystemConfig. |
| 547 | * |
| 548 | * Packages that are whitelisted, but then blacklisted so that they aren't to be installed on |
| 549 | * any user, are still present in this list, since that is a valid scenario (e.g. if an OEM |
| 550 | * completely blacklists an AOSP app). |
| 551 | */ |
| 552 | private Set<String> getWhitelistedSystemPackages() { |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 553 | return mWhitelistedPackagesForUserTypes.keySet(); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 554 | } |
| 555 | |
| 556 | /** |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 557 | * Returns a map of package manifest names to the bit set representing (via |
| 558 | * {@link #getUserTypeMask}) the user types on which they are to be installed. |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 559 | * Also, clears this data from SystemConfig where it was stored inefficiently (and therefore |
| 560 | * should be called exactly once, even if the data isn't useful). |
| 561 | * |
| 562 | * Any system packages not present in this map should not even be on the device at all. |
| 563 | * To enforce this: |
| 564 | * <ul> |
| 565 | * <li>Illegal user types are ignored.</li> |
| 566 | * <li>Packages that never whitelisted at all (even if they are explicitly blacklisted) are |
| 567 | * ignored.</li> |
| 568 | * <li>Packages that are blacklisted whenever they are whitelisted will be stored with the |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 569 | * value 0 (since this is a valid scenario, e.g. if an OEM completely blacklists an |
| 570 | * AOSP app).</li> |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 571 | * </ul> |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 572 | * |
| 573 | * @see #mWhitelistedPackagesForUserTypes |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 574 | */ |
| 575 | @VisibleForTesting |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 576 | ArrayMap<String, Long> determineWhitelistedPackagesForUserTypes(SystemConfig sysConfig) { |
| 577 | // We first get the list of user types that correspond to FULL, SYSTEM, and PROFILE. |
| 578 | final Map<String, Long> baseTypeBitSets = getBaseTypeBitSets(); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 579 | |
| 580 | final ArrayMap<String, Set<String>> whitelist = |
| 581 | sysConfig.getAndClearPackageToUserTypeWhitelist(); |
| 582 | // result maps packageName -> userTypes on which the package should be installed. |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 583 | final ArrayMap<String, Long> result = new ArrayMap<>(whitelist.size() + 1); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 584 | // First, do the whitelisted user types. |
| 585 | for (int i = 0; i < whitelist.size(); i++) { |
Bookatz | 12c292e | 2019-11-14 11:00:13 -0800 | [diff] [blame] | 586 | final String pkgName = whitelist.keyAt(i).intern(); |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 587 | final long typesBitSet = getTypesBitSet(whitelist.valueAt(i), baseTypeBitSets); |
| 588 | if (typesBitSet != 0) { |
| 589 | result.put(pkgName, typesBitSet); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 590 | } |
| 591 | } |
| 592 | // Then, un-whitelist any blacklisted user types. |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 593 | final ArrayMap<String, Set<String>> blacklist = |
| 594 | sysConfig.getAndClearPackageToUserTypeBlacklist(); |
| 595 | for (int i = 0; i < blacklist.size(); i++) { |
Bookatz | 12c292e | 2019-11-14 11:00:13 -0800 | [diff] [blame] | 596 | final String pkgName = blacklist.keyAt(i).intern(); |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 597 | final long nonTypesBitSet = getTypesBitSet(blacklist.valueAt(i), baseTypeBitSets); |
| 598 | final Long typesBitSet = result.get(pkgName); |
| 599 | if (typesBitSet != null) { |
| 600 | result.put(pkgName, typesBitSet & ~nonTypesBitSet); |
| 601 | } else if (nonTypesBitSet != 0) { |
| 602 | // Package was never whitelisted but is validly blacklisted. |
| 603 | result.put(pkgName, 0L); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 604 | } |
| 605 | } |
| 606 | // Regardless of the whitelists/blacklists, ensure mandatory packages. |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 607 | result.put("android", ~0L); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 608 | return result; |
| 609 | } |
| 610 | |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 611 | /** |
| 612 | * Returns the bitmask (with exactly one 1) corresponding to the given userType. |
| 613 | * Returns 0 if no such userType exists. |
| 614 | */ |
| 615 | @VisibleForTesting |
| 616 | long getUserTypeMask(String userType) { |
| 617 | final int userTypeIndex = Arrays.binarySearch(mUserTypes, userType); |
| 618 | final long userTypeMask = userTypeIndex >= 0 ? (1 << userTypeIndex) : 0; |
| 619 | return userTypeMask; |
| 620 | } |
| 621 | |
| 622 | /** |
| 623 | * Returns the mapping from the name of each base type to the bitset (as defined by |
| 624 | * {@link #getUserTypeMask}) of user types to which it corresponds (i.e. the base's subtypes). |
| 625 | * <p> |
| 626 | * E.g. if "android.type.ex" is a FULL user type for which getUserTypeMask() returns (1 << 3), |
| 627 | * then getBaseTypeBitSets().get("FULL") will contain true (1) in position 3. |
| 628 | */ |
| 629 | private Map<String, Long> getBaseTypeBitSets() { |
| 630 | long typesBitSetFull = 0; |
| 631 | long typesBitSetSystem = 0; |
| 632 | long typesBitSetProfile = 0; |
| 633 | for (int idx = 0; idx < mUserTypes.length; idx++) { |
| 634 | if (mUm.isUserTypeSubtypeOfFull(mUserTypes[idx])) { |
| 635 | typesBitSetFull |= (1 << idx); |
| 636 | } |
| 637 | if (mUm.isUserTypeSubtypeOfSystem(mUserTypes[idx])) { |
| 638 | typesBitSetSystem |= (1 << idx); |
| 639 | } |
| 640 | if (mUm.isUserTypeSubtypeOfProfile(mUserTypes[idx])) { |
| 641 | typesBitSetProfile |= (1 << idx); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 642 | } |
| 643 | } |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 644 | |
| 645 | Map<String, Long> result = new ArrayMap<>(3); |
| 646 | result.put("FULL", typesBitSetFull); |
| 647 | result.put("SYSTEM", typesBitSetSystem); |
| 648 | result.put("PROFILE", typesBitSetProfile); |
| 649 | return result; |
| 650 | } |
| 651 | |
| 652 | /** |
| 653 | * Converts a list of user types and base types, as used in SystemConfig, to a bit set |
| 654 | * representing (via {@link #getUserTypeMask}) user types. |
| 655 | * |
| 656 | * Returns 0 if userTypes does not contain any valid user or base types. |
| 657 | * |
| 658 | * @param baseTypeBitSets a map from the base types (FULL/SYSTEM/PROFILE) to their subtypes |
| 659 | * (represented as a bitset, as defined by {@link #getUserTypeMask}). |
| 660 | * (This can be created by {@link #getBaseTypeBitSets}.) |
| 661 | */ |
| 662 | private long getTypesBitSet(Iterable<String> userTypes, Map<String, Long> baseTypeBitSets) { |
| 663 | long resultBitSet = 0; |
| 664 | for (String type : userTypes) { |
| 665 | // See if userType is a base type, like FULL. |
| 666 | final Long baseTypeBitSet = baseTypeBitSets.get(type); |
| 667 | if (baseTypeBitSet != null) { |
| 668 | resultBitSet |= baseTypeBitSet; |
| 669 | continue; |
| 670 | } |
| 671 | // userType wasn't a base type, so it should be the name of a specific user type. |
| 672 | final long userTypeBitSet = getUserTypeMask(type); |
| 673 | if (userTypeBitSet != 0) { |
| 674 | resultBitSet |= userTypeBitSet; |
| 675 | continue; |
| 676 | } |
| 677 | Slog.w(TAG, "SystemConfig contained an invalid user type: " + type); |
| 678 | } |
| 679 | return resultBitSet; |
| 680 | } |
| 681 | |
| 682 | /** Returns a sorted array consisting of the keyset of the provided map. */ |
| 683 | private static String[] getAndSortKeysFromMap(ArrayMap<String, ?> map) { |
| 684 | final String[] userTypeList = new String[map.size()]; |
| 685 | for (int i = 0; i < map.size(); i++) { |
| 686 | userTypeList[i] = map.keyAt(i); |
| 687 | } |
| 688 | Arrays.sort(userTypeList); |
| 689 | return userTypeList; |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 690 | } |
| 691 | |
| 692 | void dump(PrintWriter pw) { |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 693 | try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) { |
| 694 | dumpIndented(ipw); |
| 695 | } |
| 696 | } |
| 697 | |
| 698 | private void dumpIndented(IndentingPrintWriter pw) { |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 699 | final int mode = getWhitelistMode(); |
| 700 | pw.println("Whitelisted packages per user type"); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 701 | |
| 702 | pw.increaseIndent(); |
| 703 | pw.print("Mode: "); |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 704 | pw.print(mode); |
| 705 | pw.print(isEnforceMode(mode) ? " (enforced)" : ""); |
| 706 | pw.print(isLogMode(mode) ? " (logged)" : ""); |
| 707 | pw.print(isImplicitWhitelistMode(mode) ? " (implicit)" : ""); |
Bookatz | 0274a6e | 2019-11-25 15:31:39 -0800 | [diff] [blame] | 708 | pw.print(isIgnoreOtaMode(mode) ? " (ignore OTAs)" : ""); |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 709 | pw.println(); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 710 | pw.decreaseIndent(); |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 711 | |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 712 | pw.increaseIndent(); |
| 713 | pw.println("Legend"); |
| 714 | pw.increaseIndent(); |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 715 | for (int idx = 0; idx < mUserTypes.length; idx++) { |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 716 | pw.println(idx + " -> " + mUserTypes[idx]); |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 717 | } |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 718 | pw.decreaseIndent(); pw.decreaseIndent(); |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 719 | |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 720 | pw.increaseIndent(); |
Felipe Leme | 1fbe9b5 | 2019-10-21 14:20:08 -0700 | [diff] [blame] | 721 | final int size = mWhitelistedPackagesForUserTypes.size(); |
Felipe Leme | 2b8c51b | 2019-10-09 17:21:33 -0700 | [diff] [blame] | 722 | if (size == 0) { |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 723 | pw.println("No packages"); |
| 724 | pw.decreaseIndent(); |
Felipe Leme | 2b8c51b | 2019-10-09 17:21:33 -0700 | [diff] [blame] | 725 | return; |
| 726 | } |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 727 | pw.print(size); pw.println(" packages:"); |
| 728 | pw.increaseIndent(); |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 729 | for (int pkgIdx = 0; pkgIdx < size; pkgIdx++) { |
| 730 | final String pkgName = mWhitelistedPackagesForUserTypes.keyAt(pkgIdx); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 731 | pw.print(pkgName); pw.print(": "); |
Bookatz | a8c2d2a | 2019-11-13 10:10:18 -0800 | [diff] [blame] | 732 | final long userTypesBitSet = mWhitelistedPackagesForUserTypes.valueAt(pkgIdx); |
| 733 | for (int idx = 0; idx < mUserTypes.length; idx++) { |
| 734 | if ((userTypesBitSet & (1 << idx)) != 0) { |
| 735 | pw.print(idx); pw.print(" "); |
| 736 | } |
| 737 | } |
| 738 | pw.println(); |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 739 | } |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 740 | pw.decreaseIndent(); pw.decreaseIndent(); |
| 741 | |
| 742 | pw.increaseIndent(); |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 743 | dumpPackageWhitelistProblems(pw, mode, /* verbose= */ true, /* criticalOnly= */ false); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 744 | pw.decreaseIndent(); |
| 745 | } |
| 746 | |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 747 | void dumpPackageWhitelistProblems(IndentingPrintWriter pw, @PackageWhitelistMode int mode, |
| 748 | boolean verbose, boolean criticalOnly) { |
| 749 | // Handle special cases first |
| 750 | if (mode == USER_TYPE_PACKAGE_WHITELIST_MODE_NONE) { |
| 751 | mode = getWhitelistMode(); |
| 752 | } else if (mode == USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) { |
| 753 | mode = getDeviceDefaultWhitelistMode(); |
| 754 | } |
| 755 | Slog.v(TAG, "dumpPackageWhitelistProblems(): using mode " + modeToString(mode)); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 756 | |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 757 | final List<String> errors = getPackagesWhitelistErrors(mode); |
| 758 | showIssues(pw, verbose, errors, "errors"); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 759 | |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 760 | if (criticalOnly) return; |
| 761 | |
| 762 | final List<String> warnings = getPackagesWhitelistWarnings(); |
| 763 | showIssues(pw, verbose, warnings, "warnings"); |
| 764 | } |
| 765 | |
| 766 | private static void showIssues(IndentingPrintWriter pw, boolean verbose, List<String> issues, |
| 767 | String issueType) { |
| 768 | final int size = issues.size(); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 769 | if (size == 0) { |
| 770 | if (verbose) { |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 771 | pw.print("No "); pw.println(issueType); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 772 | } |
| 773 | return; |
| 774 | } |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 775 | if (verbose) { |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 776 | pw.print(size); pw.print(' '); pw.println(issueType); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 777 | pw.increaseIndent(); |
| 778 | } |
| 779 | for (int i = 0; i < size; i++) { |
felipeal | 60aabe6 | 2020-04-21 13:20:35 -0700 | [diff] [blame] | 780 | pw.println(issues.get(i)); |
felipeal | a2f45ef | 2020-04-15 08:39:36 -0700 | [diff] [blame] | 781 | } |
| 782 | if (verbose) { |
| 783 | pw.decreaseIndent(); |
| 784 | } |
Bookatz | 04d7ae5 | 2019-08-05 14:07:12 -0700 | [diff] [blame] | 785 | } |
| 786 | } |