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; |
| 23 | import android.content.pm.PackageManagerInternal; |
| 24 | import android.content.pm.PackageParser; |
| 25 | import android.content.pm.UserInfo; |
| 26 | import android.content.res.Resources; |
| 27 | import android.os.SystemProperties; |
| 28 | import android.os.UserHandle; |
| 29 | import android.util.ArrayMap; |
| 30 | import android.util.ArraySet; |
| 31 | import android.util.Slog; |
| 32 | |
| 33 | import com.android.internal.annotations.VisibleForTesting; |
| 34 | import com.android.server.LocalServices; |
| 35 | import com.android.server.SystemConfig; |
| 36 | |
| 37 | import java.io.PrintWriter; |
| 38 | import java.lang.annotation.Retention; |
| 39 | import java.lang.annotation.RetentionPolicy; |
| 40 | import java.util.Set; |
| 41 | |
| 42 | /** |
| 43 | * Responsible for un/installing system packages based on user type. |
| 44 | * |
| 45 | * <p>Uses the SystemConfig's install-in-user-type whitelist; |
| 46 | * see {@link SystemConfig#getAndClearPackageToUserTypeWhitelist} and |
| 47 | * {@link SystemConfig#getAndClearPackageToUserTypeBlacklist}. |
| 48 | * |
| 49 | * <p>If {@link #isEnforceMode()} is false, then all system packages are always installed for all |
| 50 | * users. The following applies when it is true. |
| 51 | * |
| 52 | * Any package can be in one of three states in the SystemConfig whitelist |
| 53 | * <ol> |
| 54 | * <li>Explicitly blacklisted for a particular user type</li> |
| 55 | * <li>Explicitly whitelisted for a particular user type</li> |
| 56 | * <li>Not mentioned at all, for any user type (neither whitelisted nor blacklisted)</li> |
| 57 | * </ol> |
| 58 | * Blacklisting always takes precedence - if a package is blacklisted for a particular user, |
| 59 | * it won't be installed on that type of user (even if it is also whitelisted for that user). |
| 60 | * Next comes whitelisting - if it is whitelisted for a particular user, it will be installed on |
| 61 | * that type of user (as long as it isn't blacklisted). |
| 62 | * Finally, if the package is not mentioned at all (i.e. neither whitelisted nor blacklisted for |
| 63 | * any user types) in the SystemConfig 'install-in-user-type' lists |
| 64 | * then: |
| 65 | * <ul> |
| 66 | * <li>If {@link #isImplicitWhitelistMode()}, the package is implicitly treated as whitelisted |
| 67 | * for all users</li> |
| 68 | * <li>Otherwise, the package is implicitly treated as blacklisted for all non-SYSTEM users</li> |
| 69 | * <li>Either way, for {@link UserHandle#USER_SYSTEM}, the package will be implicitly |
| 70 | * whitelisted so that it can be used for local development purposes.</li> |
| 71 | * </ul> |
| 72 | */ |
| 73 | class UserSystemPackageInstaller { |
| 74 | private static final String TAG = "UserManagerService"; |
| 75 | |
| 76 | /** |
| 77 | * System Property whether to only install system packages on a user if they're whitelisted for |
| 78 | * that user type. These are flags and can be freely combined. |
| 79 | * <ul> |
| 80 | * <li> 0 (0b000) - disable whitelist (install all system packages; no logging)</li> |
| 81 | * <li> 1 (0b001) - enforce (only install system packages if they are whitelisted)</li> |
| 82 | * <li> 2 (0b010) - log (log when a non-whitelisted package is run)</li> |
| 83 | * <li> 4 (0b100) - implicitly whitelist any package not mentioned in the whitelist</li> |
| 84 | * <li>-1 - use device default (as defined in res/res/values/config.xml)</li> |
| 85 | * </ul> |
| 86 | * Note: This list must be kept current with config_userTypePackageWhitelistMode in |
| 87 | * frameworks/base/core/res/res/values/config.xml |
| 88 | */ |
| 89 | static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode"; |
| 90 | static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0; |
| 91 | static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001; |
| 92 | static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b010; |
| 93 | static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100; |
| 94 | static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1; |
| 95 | |
| 96 | @IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = { |
| 97 | USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE, |
| 98 | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE, |
| 99 | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE, |
| 100 | USER_TYPE_PACKAGE_WHITELIST_MODE_LOG, |
| 101 | USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST, |
| 102 | }) |
| 103 | @Retention(RetentionPolicy.SOURCE) |
| 104 | public @interface PackageWhitelistMode {} |
| 105 | |
| 106 | /** |
| 107 | * Maps system package manifest names to the user flags on which they should be initially |
| 108 | * installed. |
| 109 | * <p>Packages that are whitelisted, but then blacklisted so that they aren't to be installed on |
| 110 | * any user, are purposefully still present in this list. |
| 111 | */ |
| 112 | private final ArrayMap<String, Integer> mWhitelitsedPackagesForUserTypes; |
| 113 | |
| 114 | private final UserManagerService mUm; |
| 115 | |
| 116 | UserSystemPackageInstaller(UserManagerService ums) { |
| 117 | mUm = ums; |
| 118 | mWhitelitsedPackagesForUserTypes = |
| 119 | determineWhitelistedPackagesForUserTypes(SystemConfig.getInstance()); |
| 120 | } |
| 121 | |
| 122 | /** Constructor for testing purposes. */ |
| 123 | @VisibleForTesting |
| 124 | UserSystemPackageInstaller(UserManagerService ums, ArrayMap<String, Integer> whitelist) { |
| 125 | mUm = ums; |
| 126 | mWhitelitsedPackagesForUserTypes = whitelist; |
| 127 | } |
| 128 | |
| 129 | /** |
| 130 | * During OTAs and first boot, install/uninstall all system packages for all users based on the |
| 131 | * user's UserInfo flags and the SystemConfig whitelist. |
| 132 | * We do NOT uninstall packages during an OTA though. |
| 133 | * |
| 134 | * This is responsible for enforcing the whitelist for pre-existing users (i.e. USER_SYSTEM); |
| 135 | * enforcement for new users is done when they are created in UserManagerService.createUser(). |
| 136 | */ |
| 137 | boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade) { |
| 138 | final int mode = getWhitelistMode(); |
| 139 | checkWhitelistedSystemPackages(mode); |
| 140 | if (!isUpgrade && !isFirstBoot) { |
| 141 | return false; |
| 142 | } |
| 143 | Slog.i(TAG, "Reviewing whitelisted packages due to " |
| 144 | + (isFirstBoot ? "[firstBoot]" : "") + (isUpgrade ? "[upgrade]" : "")); |
| 145 | final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); |
| 146 | // Install/uninstall system packages per user. |
| 147 | for (int userId : mUm.getUserIds()) { |
| 148 | final Set<String> userWhitelist = getInstallablePackagesForUserId(userId); |
| 149 | pmInt.forEachPackage(pkg -> { |
| 150 | if (!pkg.isSystem()) { |
| 151 | return; |
| 152 | } |
| 153 | final boolean install = |
| 154 | (userWhitelist == null || userWhitelist.contains(pkg.packageName)) |
| 155 | && !pkg.applicationInfo.hiddenUntilInstalled; |
| 156 | if (isUpgrade && !isFirstBoot && !install) { |
| 157 | return; // To be careful, we don’t uninstall apps during OTAs |
| 158 | } |
| 159 | final boolean changed = pmInt.setInstalled(pkg, userId, install); |
| 160 | if (changed) { |
| 161 | Slog.i(TAG, (install ? "Installed " : "Uninstalled ") |
| 162 | + pkg.packageName + " for user " + userId); |
| 163 | } |
| 164 | }); |
| 165 | } |
| 166 | return true; |
| 167 | } |
| 168 | |
| 169 | /** |
| 170 | * Checks whether the system packages and the mWhitelistedPackagesForUserTypes whitelist are |
| 171 | * in 1-to-1 correspondence. |
| 172 | */ |
| 173 | private void checkWhitelistedSystemPackages(@PackageWhitelistMode int mode) { |
| 174 | if (!isLogMode(mode) && !isEnforceMode(mode)) { |
| 175 | return; |
| 176 | } |
| 177 | Slog.v(TAG, "Checking that all system packages are whitelisted."); |
| 178 | final Set<String> allWhitelistedPackages = getWhitelistedSystemPackages(); |
| 179 | PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); |
| 180 | |
| 181 | // Check whether all whitelisted packages are indeed on the system. |
| 182 | for (String pkgName : allWhitelistedPackages) { |
| 183 | PackageParser.Package pkg = pmInt.getPackage(pkgName); |
| 184 | if (pkg == null) { |
| 185 | Slog.w(TAG, pkgName + " is whitelisted but not present."); |
| 186 | } else if (!pkg.isSystem()) { |
| 187 | Slog.w(TAG, pkgName + " is whitelisted and present but not a system package."); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | // Check whether all system packages are indeed whitelisted. |
| 192 | if (isImplicitWhitelistMode(mode) && !isLogMode(mode)) { |
| 193 | return; |
| 194 | } |
| 195 | final boolean doWtf = isEnforceMode(mode); |
| 196 | pmInt.forEachPackage(pkg -> { |
| 197 | if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.manifestPackageName)) { |
| 198 | final String msg = "System package " + pkg.manifestPackageName |
| 199 | + " is not whitelisted using 'install-in-user-type' in SystemConfig " |
| 200 | + "for any user types!"; |
| 201 | if (doWtf) { |
| 202 | Slog.wtf(TAG, msg); |
| 203 | } else { |
| 204 | Slog.e(TAG, msg); |
| 205 | } |
| 206 | } |
| 207 | }); |
| 208 | } |
| 209 | |
| 210 | /** Whether to only install system packages in new users for which they are whitelisted. */ |
| 211 | boolean isEnforceMode() { |
| 212 | return isEnforceMode(getWhitelistMode()); |
| 213 | } |
| 214 | |
| 215 | /** |
| 216 | * Whether to log a warning concerning potential problems with the user-type package whitelist. |
| 217 | */ |
| 218 | boolean isLogMode() { |
| 219 | return isLogMode(getWhitelistMode()); |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Whether to treat all packages that are not mentioned at all in the whitelist to be implicitly |
| 224 | * whitelisted for all users. |
| 225 | */ |
| 226 | boolean isImplicitWhitelistMode() { |
| 227 | return isImplicitWhitelistMode(getWhitelistMode()); |
| 228 | } |
| 229 | |
| 230 | /** See {@link #isEnforceMode()}. */ |
| 231 | private static boolean isEnforceMode(int whitelistMode) { |
| 232 | return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0; |
| 233 | } |
| 234 | |
| 235 | /** See {@link #isLogMode()}. */ |
| 236 | private static boolean isLogMode(int whitelistMode) { |
| 237 | return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_LOG) != 0; |
| 238 | } |
| 239 | |
| 240 | /** See {@link #isImplicitWhitelistMode()}. */ |
| 241 | private static boolean isImplicitWhitelistMode(int whitelistMode) { |
| 242 | return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST) != 0; |
| 243 | } |
| 244 | |
| 245 | /** Gets the PackageWhitelistMode for use of {@link #mWhitelitsedPackagesForUserTypes}. */ |
| 246 | private @PackageWhitelistMode int getWhitelistMode() { |
| 247 | final int runtimeMode = SystemProperties.getInt( |
| 248 | PACKAGE_WHITELIST_MODE_PROP, USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT); |
| 249 | if (runtimeMode != USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT) { |
| 250 | return runtimeMode; |
| 251 | } |
| 252 | return Resources.getSystem() |
| 253 | .getInteger(com.android.internal.R.integer.config_userTypePackageWhitelistMode); |
| 254 | } |
| 255 | |
| 256 | /** |
| 257 | * Gets the system packages names that should be installed on the given user. |
| 258 | * See {@link #getInstallablePackagesForUserType(int)}. |
| 259 | */ |
| 260 | private @Nullable Set<String> getInstallablePackagesForUserId(@UserIdInt int userId) { |
| 261 | return getInstallablePackagesForUserType(mUm.getUserInfo(userId).flags); |
| 262 | } |
| 263 | |
| 264 | /** |
| 265 | * Gets the system package names that should be installed on a user with the given flags, as |
| 266 | * determined by SystemConfig, the whitelist mode, and the apps actually on the device. |
| 267 | * Names are the {@link PackageParser.Package#packageName}, not necessarily the manifest names. |
| 268 | * |
| 269 | * Returns null if all system packages should be installed (due enforce-mode being off). |
| 270 | */ |
| 271 | @Nullable Set<String> getInstallablePackagesForUserType(int flags) { |
| 272 | final int mode = getWhitelistMode(); |
| 273 | if (!isEnforceMode(mode)) { |
| 274 | return null; |
| 275 | } |
| 276 | final boolean isSystemUser = (flags & UserInfo.FLAG_SYSTEM) != 0; |
| 277 | final boolean isImplicitWhitelistMode = isImplicitWhitelistMode(mode); |
| 278 | final Set<String> whitelistedPackages = getWhitelistedPackagesForUserType(flags); |
| 279 | |
| 280 | final Set<String> installPackages = new ArraySet<>(); |
| 281 | final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); |
| 282 | pmInt.forEachPackage(pkg -> { |
| 283 | if (!pkg.isSystem()) { |
| 284 | return; |
| 285 | } |
| 286 | if (shouldInstallPackage(pkg, mWhitelitsedPackagesForUserTypes, |
| 287 | whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) { |
| 288 | // Although the whitelist uses manifest names, this function returns packageNames. |
| 289 | installPackages.add(pkg.packageName); |
| 290 | } |
| 291 | }); |
| 292 | return installPackages; |
| 293 | } |
| 294 | |
| 295 | /** |
| 296 | * Returns whether the given system package should be installed on the given user, based on the |
| 297 | * the given whitelist of system packages. |
| 298 | * |
| 299 | * @param sysPkg the system package. Must be a system package; no verification for this is done. |
| 300 | * @param userTypeWhitelist map of package manifest names to user flags on which they should be |
| 301 | * installed |
| 302 | * @param userWhitelist set of package manifest names that should be installed on this |
| 303 | * particular user. This must be consistent with userTypeWhitelist, but is |
| 304 | * passed in separately to avoid repeatedly calculating it from |
| 305 | * userTypeWhitelist. |
| 306 | * @param isImplicitWhitelistMode whether non-mentioned packages are implicitly whitelisted. |
| 307 | * @param isSystemUser whether the user is USER_SYSTEM (which gets special treatment). |
| 308 | */ |
| 309 | @VisibleForTesting |
| 310 | static boolean shouldInstallPackage(PackageParser.Package sysPkg, |
| 311 | @NonNull ArrayMap<String, Integer> userTypeWhitelist, |
| 312 | @NonNull Set<String> userWhitelist, boolean isImplicitWhitelistMode, |
| 313 | boolean isSystemUser) { |
| 314 | |
| 315 | final String pkgName = sysPkg.manifestPackageName; |
| 316 | boolean install = (isImplicitWhitelistMode && !userTypeWhitelist.containsKey(pkgName)) |
| 317 | || userWhitelist.contains(pkgName); |
| 318 | |
| 319 | // For the purposes of local development, any package that isn't even mentioned in the |
| 320 | // whitelist at all is implicitly treated as whitelisted for the SYSTEM user. |
| 321 | if (!install && isSystemUser && !userTypeWhitelist.containsKey(pkgName)) { |
| 322 | install = true; |
| 323 | Slog.e(TAG, "System package " + pkgName + " is not mentioned " |
| 324 | + "in SystemConfig's 'install-in-user-type' but we are " |
| 325 | + "implicitly treating it as whitelisted for the SYSTEM user."); |
| 326 | } |
| 327 | return install; |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Gets the package manifest names that are whitelisted for a user with the given flags, |
| 332 | * as determined by SystemConfig. |
| 333 | */ |
| 334 | @VisibleForTesting |
| 335 | @NonNull Set<String> getWhitelistedPackagesForUserType(int flags) { |
| 336 | Set<String> installablePkgs = new ArraySet<>(mWhitelitsedPackagesForUserTypes.size()); |
| 337 | for (int i = 0; i < mWhitelitsedPackagesForUserTypes.size(); i++) { |
| 338 | String pkgName = mWhitelitsedPackagesForUserTypes.keyAt(i); |
| 339 | int whitelistedUserTypes = mWhitelitsedPackagesForUserTypes.valueAt(i); |
| 340 | if ((flags & whitelistedUserTypes) != 0) { |
| 341 | installablePkgs.add(pkgName); |
| 342 | } |
| 343 | } |
| 344 | return installablePkgs; |
| 345 | } |
| 346 | |
| 347 | /** |
| 348 | * Set of package manifest names that are included anywhere in the package-to-user-type |
| 349 | * whitelist, as determined by SystemConfig. |
| 350 | * |
| 351 | * Packages that are whitelisted, but then blacklisted so that they aren't to be installed on |
| 352 | * any user, are still present in this list, since that is a valid scenario (e.g. if an OEM |
| 353 | * completely blacklists an AOSP app). |
| 354 | */ |
| 355 | private Set<String> getWhitelistedSystemPackages() { |
| 356 | return mWhitelitsedPackagesForUserTypes.keySet(); |
| 357 | } |
| 358 | |
| 359 | /** |
| 360 | * Returns a map of package manifest names to the user flags on which it is to be installed. |
| 361 | * Also, clears this data from SystemConfig where it was stored inefficiently (and therefore |
| 362 | * should be called exactly once, even if the data isn't useful). |
| 363 | * |
| 364 | * Any system packages not present in this map should not even be on the device at all. |
| 365 | * To enforce this: |
| 366 | * <ul> |
| 367 | * <li>Illegal user types are ignored.</li> |
| 368 | * <li>Packages that never whitelisted at all (even if they are explicitly blacklisted) are |
| 369 | * ignored.</li> |
| 370 | * <li>Packages that are blacklisted whenever they are whitelisted will be stored with the |
| 371 | * flag 0 (since this is a valid scenario, e.g. if an OEM completely blacklists an AOSP |
| 372 | * app).</li> |
| 373 | * </ul> |
| 374 | */ |
| 375 | @VisibleForTesting |
| 376 | static ArrayMap<String, Integer> determineWhitelistedPackagesForUserTypes( |
| 377 | SystemConfig sysConfig) { |
| 378 | |
| 379 | final ArrayMap<String, Set<String>> whitelist = |
| 380 | sysConfig.getAndClearPackageToUserTypeWhitelist(); |
| 381 | // result maps packageName -> userTypes on which the package should be installed. |
| 382 | final ArrayMap<String, Integer> result = new ArrayMap<>(whitelist.size() + 1); |
| 383 | // First, do the whitelisted user types. |
| 384 | for (int i = 0; i < whitelist.size(); i++) { |
| 385 | final String pkgName = whitelist.keyAt(i); |
| 386 | final int flags = getFlagsFromUserTypes(whitelist.valueAt(i)); |
| 387 | if (flags != 0) { |
| 388 | result.put(pkgName, flags); |
| 389 | } |
| 390 | } |
| 391 | // Then, un-whitelist any blacklisted user types. |
| 392 | // TODO(b/141370854): Right now, the blacklist is actually just an 'unwhitelist'. Which |
| 393 | // direction we go depends on how we design user subtypes, which is still |
| 394 | // being designed. For now, unwhitelisting works for current use-cases. |
| 395 | final ArrayMap<String, Set<String>> blacklist = |
| 396 | sysConfig.getAndClearPackageToUserTypeBlacklist(); |
| 397 | for (int i = 0; i < blacklist.size(); i++) { |
| 398 | final String pkgName = blacklist.keyAt(i); |
| 399 | final int nonFlags = getFlagsFromUserTypes(blacklist.valueAt(i)); |
| 400 | final Integer flags = result.get(pkgName); |
| 401 | if (flags != null) { |
| 402 | result.put(pkgName, flags & ~nonFlags); |
| 403 | } |
| 404 | } |
| 405 | // Regardless of the whitelists/blacklists, ensure mandatory packages. |
| 406 | result.put("android", |
| 407 | UserInfo.FLAG_SYSTEM | UserInfo.FLAG_FULL | UserInfo.PROFILE_FLAGS_MASK); |
| 408 | return result; |
| 409 | } |
| 410 | |
| 411 | /** Converts a user types, as used in SystemConfig, to a UserInfo flag. */ |
| 412 | private static int getFlagsFromUserTypes(Iterable<String> userTypes) { |
| 413 | int flags = 0; |
| 414 | for (String type : userTypes) { |
| 415 | switch (type) { |
| 416 | case "GUEST": |
| 417 | flags |= UserInfo.FLAG_GUEST; |
| 418 | break; |
| 419 | case "RESTRICTED": |
| 420 | flags |= UserInfo.FLAG_RESTRICTED; |
| 421 | break; |
| 422 | case "MANAGED_PROFILE": |
| 423 | flags |= UserInfo.FLAG_MANAGED_PROFILE; |
| 424 | break; |
| 425 | case "EPHEMERAL": |
| 426 | flags |= UserInfo.FLAG_EPHEMERAL; |
| 427 | break; |
| 428 | case "DEMO": |
| 429 | flags |= UserInfo.FLAG_DEMO; |
| 430 | break; |
| 431 | case "FULL": |
| 432 | flags |= UserInfo.FLAG_FULL; |
| 433 | break; |
| 434 | case "SYSTEM": |
| 435 | flags |= UserInfo.FLAG_SYSTEM; |
| 436 | break; |
| 437 | case "PROFILE": |
| 438 | flags |= UserInfo.PROFILE_FLAGS_MASK; |
| 439 | break; |
| 440 | default: |
| 441 | Slog.w(TAG, "SystemConfig contained an invalid user type: " + type); |
| 442 | break; |
| 443 | // Other UserInfo flags are forbidden. |
| 444 | // In particular, FLAG_INITIALIZED, FLAG_DISABLED, FLAG_QUIET_MODE are inapplicable. |
| 445 | // The following are invalid now, but are reconsiderable: FLAG_PRIMARY, FLAG_ADMIN. |
| 446 | } |
| 447 | } |
| 448 | return flags; |
| 449 | } |
| 450 | |
| 451 | void dump(PrintWriter pw) { |
| 452 | for (int i = 0; i < mWhitelitsedPackagesForUserTypes.size(); i++) { |
| 453 | final String pkgName = mWhitelitsedPackagesForUserTypes.keyAt(i); |
| 454 | final String whitelistedUserTypes = |
| 455 | UserInfo.flagsToString(mWhitelitsedPackagesForUserTypes.valueAt(i)); |
| 456 | pw.println(" " + pkgName + ": " + whitelistedUserTypes); |
| 457 | } |
| 458 | } |
| 459 | } |