1 /* 2 * Copyright (C) 2020 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.parsing; 18 19 import android.annotation.CheckResult; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.UserIdInt; 23 import android.apex.ApexInfo; 24 import android.content.pm.ActivityInfo; 25 import android.content.pm.ApplicationInfo; 26 import android.content.pm.ComponentInfo; 27 import android.content.pm.InstrumentationInfo; 28 import android.content.pm.PackageInfo; 29 import android.content.pm.PackageItemInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.PackageUserState; 32 import android.content.pm.PermissionGroupInfo; 33 import android.content.pm.PermissionInfo; 34 import android.content.pm.ProcessInfo; 35 import android.content.pm.ProviderInfo; 36 import android.content.pm.ServiceInfo; 37 import android.content.pm.SharedLibraryInfo; 38 import android.content.pm.parsing.PackageInfoWithoutStateUtils; 39 import android.content.pm.parsing.ParsingUtils; 40 import android.content.pm.parsing.component.ComponentParseUtils; 41 import android.content.pm.parsing.component.ParsedActivity; 42 import android.content.pm.parsing.component.ParsedComponent; 43 import android.content.pm.parsing.component.ParsedInstrumentation; 44 import android.content.pm.parsing.component.ParsedMainComponent; 45 import android.content.pm.parsing.component.ParsedPermission; 46 import android.content.pm.parsing.component.ParsedPermissionGroup; 47 import android.content.pm.parsing.component.ParsedProcess; 48 import android.content.pm.parsing.component.ParsedProvider; 49 import android.content.pm.parsing.component.ParsedService; 50 import android.os.UserHandle; 51 import android.util.ArrayMap; 52 import android.util.ArraySet; 53 import android.util.Pair; 54 import android.util.Slog; 55 56 import com.android.internal.util.ArrayUtils; 57 import com.android.server.pm.PackageSetting; 58 import com.android.server.pm.parsing.pkg.AndroidPackage; 59 import com.android.server.pm.parsing.pkg.AndroidPackageUtils; 60 import com.android.server.pm.parsing.pkg.PackageImpl; 61 import com.android.server.pm.pkg.PackageStateUnserialized; 62 63 import libcore.util.EmptyArray; 64 65 import java.util.Collections; 66 import java.util.List; 67 import java.util.Map; 68 import java.util.Set; 69 70 71 /** 72 * Methods that use a {@link PackageSetting} use it to override information provided from the raw 73 * package, or to provide information that would otherwise be missing. Null can be passed if none 74 * of the state values should be applied. 75 * 76 * @hide 77 **/ 78 public class PackageInfoUtils { 79 private static final String TAG = ParsingUtils.TAG; 80 81 /** 82 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 83 */ 84 @Nullable generate(AndroidPackage pkg, int[] gids, @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state, int userId, @Nullable PackageSetting pkgSetting)85 public static PackageInfo generate(AndroidPackage pkg, int[] gids, 86 @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, 87 Set<String> grantedPermissions, PackageUserState state, int userId, 88 @Nullable PackageSetting pkgSetting) { 89 return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime, 90 grantedPermissions, state, userId, null, pkgSetting); 91 } 92 93 /** 94 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 95 */ 96 @Nullable generate(AndroidPackage pkg, ApexInfo apexInfo, int flags, @Nullable PackageSetting pkgSetting)97 public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags, 98 @Nullable PackageSetting pkgSetting) { 99 return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(), 100 new PackageUserState(), UserHandle.getCallingUserId(), apexInfo, pkgSetting); 101 } 102 103 /** 104 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 105 */ generateWithComponents(AndroidPackage pkg, int[] gids, @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state, int userId, @Nullable ApexInfo apexInfo, @Nullable PackageSetting pkgSetting)106 private static PackageInfo generateWithComponents(AndroidPackage pkg, int[] gids, 107 @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, 108 Set<String> grantedPermissions, PackageUserState state, int userId, 109 @Nullable ApexInfo apexInfo, @Nullable PackageSetting pkgSetting) { 110 ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId, 111 pkgSetting); 112 if (applicationInfo == null) { 113 return null; 114 } 115 116 PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponentsUnchecked(pkg, 117 gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, 118 apexInfo, applicationInfo); 119 120 info.isStub = pkg.isStub(); 121 info.coreApp = pkg.isCoreApp(); 122 123 if ((flags & PackageManager.GET_ACTIVITIES) != 0) { 124 final int N = pkg.getActivities().size(); 125 if (N > 0) { 126 int num = 0; 127 final ActivityInfo[] res = new ActivityInfo[N]; 128 for (int i = 0; i < N; i++) { 129 final ParsedActivity a = pkg.getActivities().get(i); 130 if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), a, 131 flags)) { 132 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals( 133 a.getName())) { 134 continue; 135 } 136 res[num++] = generateActivityInfo(pkg, a, flags, state, 137 applicationInfo, userId, pkgSetting); 138 } 139 } 140 info.activities = ArrayUtils.trimToSize(res, num); 141 } 142 } 143 if ((flags & PackageManager.GET_RECEIVERS) != 0) { 144 final int size = pkg.getReceivers().size(); 145 if (size > 0) { 146 int num = 0; 147 final ActivityInfo[] res = new ActivityInfo[size]; 148 for (int i = 0; i < size; i++) { 149 final ParsedActivity a = pkg.getReceivers().get(i); 150 if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), a, 151 flags)) { 152 res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, 153 userId, pkgSetting); 154 } 155 } 156 info.receivers = ArrayUtils.trimToSize(res, num); 157 } 158 } 159 if ((flags & PackageManager.GET_SERVICES) != 0) { 160 final int size = pkg.getServices().size(); 161 if (size > 0) { 162 int num = 0; 163 final ServiceInfo[] res = new ServiceInfo[size]; 164 for (int i = 0; i < size; i++) { 165 final ParsedService s = pkg.getServices().get(i); 166 if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), s, 167 flags)) { 168 res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo, 169 userId, pkgSetting); 170 } 171 } 172 info.services = ArrayUtils.trimToSize(res, num); 173 } 174 } 175 if ((flags & PackageManager.GET_PROVIDERS) != 0) { 176 final int size = pkg.getProviders().size(); 177 if (size > 0) { 178 int num = 0; 179 final ProviderInfo[] res = new ProviderInfo[size]; 180 for (int i = 0; i < size; i++) { 181 final ParsedProvider pr = pkg.getProviders() 182 .get(i); 183 if (ComponentParseUtils.isMatch(state, pkg.isSystem(), pkg.isEnabled(), pr, 184 flags)) { 185 res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo, 186 userId, pkgSetting); 187 } 188 } 189 info.providers = ArrayUtils.trimToSize(res, num); 190 } 191 } 192 if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) { 193 int N = pkg.getInstrumentations().size(); 194 if (N > 0) { 195 info.instrumentation = new InstrumentationInfo[N]; 196 for (int i = 0; i < N; i++) { 197 info.instrumentation[i] = generateInstrumentationInfo( 198 pkg.getInstrumentations().get(i), pkg, flags, userId, pkgSetting); 199 } 200 } 201 } 202 203 return info; 204 } 205 206 /** 207 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 208 */ 209 @Nullable generateApplicationInfo(AndroidPackage pkg, @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId, @Nullable PackageSetting pkgSetting)210 public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg, 211 @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId, 212 @Nullable PackageSetting pkgSetting) { 213 if (pkg == null) { 214 return null; 215 } 216 217 if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags) 218 || !AndroidPackageUtils.isMatchForSystemOnly(pkg, flags)) { 219 return null; 220 } 221 222 ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfoUnchecked(pkg, 223 flags, state, userId, false /* assignUserFields */); 224 225 initForUser(info, pkg, userId); 226 227 if (pkgSetting != null) { 228 // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up 229 PackageStateUnserialized pkgState = pkgSetting.getPkgState(); 230 info.hiddenUntilInstalled = pkgState.isHiddenUntilInstalled(); 231 List<String> usesLibraryFiles = pkgState.getUsesLibraryFiles(); 232 List<SharedLibraryInfo> usesLibraryInfos = pkgState.getUsesLibraryInfos(); 233 info.sharedLibraryFiles = usesLibraryFiles.isEmpty() 234 ? null : usesLibraryFiles.toArray(new String[0]); 235 info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos; 236 } 237 238 info.seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting); 239 info.primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting); 240 info.secondaryCpuAbi = AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting); 241 242 info.flags |= appInfoFlags(info.flags, pkgSetting); 243 info.privateFlags |= appInfoPrivateFlags(info.privateFlags, pkgSetting); 244 info.privateFlagsExt |= appInfoPrivateFlagsExt(info.privateFlagsExt, pkgSetting); 245 246 return info; 247 } 248 249 /** 250 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 251 */ 252 @Nullable generateActivityInfo(AndroidPackage pkg, ParsedActivity a, @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId, @Nullable PackageSetting pkgSetting)253 public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, 254 @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId, 255 @Nullable PackageSetting pkgSetting) { 256 return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting); 257 } 258 259 /** 260 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 261 */ 262 @Nullable generateActivityInfo(AndroidPackage pkg, ParsedActivity a, @PackageManager.ComponentInfoFlags int flags, PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId, @Nullable PackageSetting pkgSetting)263 private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, 264 @PackageManager.ComponentInfoFlags int flags, PackageUserState state, 265 @Nullable ApplicationInfo applicationInfo, int userId, 266 @Nullable PackageSetting pkgSetting) { 267 if (a == null) return null; 268 if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) { 269 return null; 270 } 271 if (applicationInfo == null) { 272 applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); 273 } 274 275 if (applicationInfo == null) { 276 return null; 277 } 278 279 final ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfoUnchecked( 280 a, flags, applicationInfo); 281 assignSharedFieldsForComponentInfo(info, a, pkgSetting, userId); 282 return info; 283 } 284 285 /** 286 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 287 */ 288 @Nullable generateServiceInfo(AndroidPackage pkg, ParsedService s, @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId, @Nullable PackageSetting pkgSetting)289 public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s, 290 @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId, 291 @Nullable PackageSetting pkgSetting) { 292 return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting); 293 } 294 295 /** 296 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 297 */ 298 @Nullable generateServiceInfo(AndroidPackage pkg, ParsedService s, @PackageManager.ComponentInfoFlags int flags, PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId, @Nullable PackageSetting pkgSetting)299 private static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s, 300 @PackageManager.ComponentInfoFlags int flags, PackageUserState state, 301 @Nullable ApplicationInfo applicationInfo, int userId, 302 @Nullable PackageSetting pkgSetting) { 303 if (s == null) return null; 304 if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) { 305 return null; 306 } 307 if (applicationInfo == null) { 308 applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); 309 } 310 if (applicationInfo == null) { 311 return null; 312 } 313 314 final ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfoUnchecked( 315 s, flags, applicationInfo); 316 assignSharedFieldsForComponentInfo(info, s, pkgSetting, userId); 317 return info; 318 } 319 320 /** 321 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 322 */ 323 @Nullable generateProviderInfo(AndroidPackage pkg, ParsedProvider p, @PackageManager.ComponentInfoFlags int flags, PackageUserState state, @NonNull ApplicationInfo applicationInfo, int userId, @Nullable PackageSetting pkgSetting)324 public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p, 325 @PackageManager.ComponentInfoFlags int flags, PackageUserState state, 326 @NonNull ApplicationInfo applicationInfo, int userId, 327 @Nullable PackageSetting pkgSetting) { 328 if (p == null) return null; 329 if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) { 330 return null; 331 } 332 if (applicationInfo == null || !pkg.getPackageName().equals(applicationInfo.packageName)) { 333 Slog.wtf(TAG, "AppInfo's package name is different. Expected=" + pkg.getPackageName() 334 + " actual=" + (applicationInfo == null ? "(null AppInfo)" 335 : applicationInfo.packageName)); 336 applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); 337 } 338 if (applicationInfo == null) { 339 return null; 340 } 341 ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfoUnchecked(p, flags, 342 applicationInfo); 343 assignSharedFieldsForComponentInfo(info, p, pkgSetting, userId); 344 return info; 345 } 346 347 /** 348 * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. 349 */ 350 @Nullable generateInstrumentationInfo(ParsedInstrumentation i, AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId, @Nullable PackageSetting pkgSetting)351 public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i, 352 AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId, 353 @Nullable PackageSetting pkgSetting) { 354 if (i == null) return null; 355 356 InstrumentationInfo info = 357 PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId, 358 false /* assignUserFields */); 359 360 initForUser(info, pkg, userId); 361 362 if (info == null) { 363 return null; 364 } 365 366 info.primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting); 367 info.secondaryCpuAbi = AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting); 368 info.nativeLibraryDir = pkg.getNativeLibraryDir(); 369 info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir(); 370 371 assignStateFieldsForPackageItemInfo(info, i, pkgSetting, userId); 372 373 return info; 374 } 375 376 // TODO(b/135203078): Determine if permission methods need to pass in a non-null PackageSetting 377 // os that checkUseInstalledOrHidden filter can apply 378 @Nullable generatePermissionInfo(ParsedPermission p, @PackageManager.ComponentInfoFlags int flags)379 public static PermissionInfo generatePermissionInfo(ParsedPermission p, 380 @PackageManager.ComponentInfoFlags int flags) { 381 // TODO(b/135203078): Remove null checks and make all usages @NonNull 382 if (p == null) return null; 383 384 // For now, permissions don't have state-adjustable fields; return directly 385 return PackageInfoWithoutStateUtils.generatePermissionInfo(p, flags); 386 } 387 388 @Nullable generatePermissionGroupInfo(ParsedPermissionGroup pg, @PackageManager.ComponentInfoFlags int flags)389 public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg, 390 @PackageManager.ComponentInfoFlags int flags) { 391 if (pg == null) return null; 392 393 // For now, permissions don't have state-adjustable fields; return directly 394 return PackageInfoWithoutStateUtils.generatePermissionGroupInfo(pg, flags); 395 } 396 397 @Nullable generateProcessInfo( Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags int flags)398 public static ArrayMap<String, ProcessInfo> generateProcessInfo( 399 Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags int flags) { 400 if (procs == null) { 401 return null; 402 } 403 404 final int numProcs = procs.size(); 405 ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs); 406 for (String key : procs.keySet()) { 407 ParsedProcess proc = procs.get(key); 408 retProcs.put(proc.getName(), 409 new ProcessInfo(proc.getName(), new ArraySet<>(proc.getDeniedPermissions()), 410 proc.getGwpAsanMode(), proc.getMemtagMode(), 411 proc.getNativeHeapZeroInitialized())); 412 } 413 return retProcs; 414 } 415 416 /** 417 * Returns true if the package is installed and not hidden, or if the caller 418 * explicitly wanted all uninstalled and hidden packages as well. 419 */ checkUseInstalledOrHidden(AndroidPackage pkg, PackageSetting pkgSetting, PackageUserState state, @PackageManager.PackageInfoFlags int flags)420 private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, 421 PackageSetting pkgSetting, PackageUserState state, 422 @PackageManager.PackageInfoFlags int flags) { 423 // Returns false if the package is hidden system app until installed. 424 if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0 425 && !state.installed 426 && pkgSetting != null 427 && pkgSetting.getPkgState().isHiddenUntilInstalled()) { 428 return false; 429 } 430 431 // If available for the target user, or trying to match uninstalled packages and it's 432 // a system app. 433 return state.isAvailable(flags) 434 || (pkg.isSystem() 435 && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0 436 || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0)); 437 } 438 assignSharedFieldsForComponentInfo(@onNull ComponentInfo componentInfo, @NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting, int userId)439 private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo, 440 @NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting, 441 int userId) { 442 assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting, userId); 443 componentInfo.descriptionRes = mainComponent.getDescriptionRes(); 444 componentInfo.directBootAware = mainComponent.isDirectBootAware(); 445 componentInfo.enabled = mainComponent.isEnabled(); 446 componentInfo.splitName = mainComponent.getSplitName(); 447 componentInfo.attributionTags = mainComponent.getAttributionTags(); 448 } 449 assignStateFieldsForPackageItemInfo( @onNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component, @Nullable PackageSetting pkgSetting, int userId)450 private static void assignStateFieldsForPackageItemInfo( 451 @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component, 452 @Nullable PackageSetting pkgSetting, int userId) { 453 Pair<CharSequence, Integer> labelAndIcon = 454 ParsedComponentStateUtils.getNonLocalizedLabelAndIcon(component, pkgSetting, 455 userId); 456 packageItemInfo.nonLocalizedLabel = labelAndIcon.first; 457 packageItemInfo.icon = labelAndIcon.second; 458 } 459 460 @CheckResult flag(boolean hasFlag, int flag)461 private static int flag(boolean hasFlag, int flag) { 462 return hasFlag ? flag : 0; 463 } 464 465 /** @see ApplicationInfo#flags */ appInfoFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting)466 public static int appInfoFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) { 467 // @formatter:off 468 int pkgWithoutStateFlags = PackageInfoWithoutStateUtils.appInfoFlags(pkg) 469 | flag(pkg.isSystem(), ApplicationInfo.FLAG_SYSTEM) 470 | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST); 471 472 return appInfoFlags(pkgWithoutStateFlags, pkgSetting); 473 // @formatter:on 474 } 475 476 /** @see ApplicationInfo#flags */ appInfoFlags(int pkgWithoutStateFlags, @NonNull PackageSetting pkgSetting)477 public static int appInfoFlags(int pkgWithoutStateFlags, @NonNull PackageSetting pkgSetting) { 478 // @formatter:off 479 int flags = pkgWithoutStateFlags; 480 if (pkgSetting != null) { 481 flags |= flag(pkgSetting.getPkgState().isUpdatedSystemApp(), ApplicationInfo.FLAG_UPDATED_SYSTEM_APP); 482 } 483 return flags; 484 // @formatter:on 485 } 486 487 /** @see ApplicationInfo#privateFlags */ appInfoPrivateFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting)488 public static int appInfoPrivateFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) { 489 // @formatter:off 490 int pkgWithoutStateFlags = PackageInfoWithoutStateUtils.appInfoPrivateFlags(pkg) 491 | flag(pkg.isSystemExt(), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) 492 | flag(pkg.isPrivileged(), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) 493 | flag(pkg.isOem(), ApplicationInfo.PRIVATE_FLAG_OEM) 494 | flag(pkg.isVendor(), ApplicationInfo.PRIVATE_FLAG_VENDOR) 495 | flag(pkg.isProduct(), ApplicationInfo.PRIVATE_FLAG_PRODUCT) 496 | flag(pkg.isOdm(), ApplicationInfo.PRIVATE_FLAG_ODM) 497 | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY); 498 return appInfoPrivateFlags(pkgWithoutStateFlags, pkgSetting); 499 // @formatter:on 500 } 501 502 /** @see ApplicationInfo#privateFlags */ appInfoPrivateFlags(int pkgWithoutStateFlags, @Nullable PackageSetting pkgSetting)503 public static int appInfoPrivateFlags(int pkgWithoutStateFlags, @Nullable PackageSetting pkgSetting) { 504 // @formatter:off 505 // TODO: Add state specific flags 506 return pkgWithoutStateFlags; 507 // @formatter:on 508 } 509 510 /** @see ApplicationInfo#privateFlagsExt */ appInfoPrivateFlagsExt(AndroidPackage pkg, @Nullable PackageSetting pkgSetting)511 public static int appInfoPrivateFlagsExt(AndroidPackage pkg, 512 @Nullable PackageSetting pkgSetting) { 513 // @formatter:off 514 int pkgWithoutStateFlags = PackageInfoWithoutStateUtils.appInfoPrivateFlagsExt(pkg); 515 return appInfoPrivateFlagsExt(pkgWithoutStateFlags, pkgSetting); 516 // @formatter:on 517 } 518 519 /** @see ApplicationInfo#privateFlagsExt */ appInfoPrivateFlagsExt(int pkgWithoutStateFlags, @Nullable PackageSetting pkgSetting)520 public static int appInfoPrivateFlagsExt(int pkgWithoutStateFlags, 521 @Nullable PackageSetting pkgSetting) { 522 // @formatter:off 523 // TODO: Add state specific flags 524 return pkgWithoutStateFlags; 525 // @formatter:on 526 } 527 initForUser(ApplicationInfo output, AndroidPackage input, @UserIdInt int userId)528 private static void initForUser(ApplicationInfo output, AndroidPackage input, 529 @UserIdInt int userId) { 530 PackageImpl pkg = ((PackageImpl) input); 531 String packageName = input.getPackageName(); 532 output.uid = UserHandle.getUid(userId, UserHandle.getAppId(input.getUid())); 533 534 if ("android".equals(packageName)) { 535 output.dataDir = PackageInfoWithoutStateUtils.SYSTEM_DATA_PATH; 536 return; 537 } 538 539 // For performance reasons, all these paths are built as strings 540 if (userId == UserHandle.USER_SYSTEM) { 541 output.credentialProtectedDataDir = 542 pkg.getBaseAppDataCredentialProtectedDirForSystemUser() + packageName; 543 output.deviceProtectedDataDir = 544 pkg.getBaseAppDataDeviceProtectedDirForSystemUser() + packageName; 545 } else { 546 // Convert /data/user/0/ -> /data/user/1/com.example.app 547 String userIdString = String.valueOf(userId); 548 int credentialLength = pkg.getBaseAppDataCredentialProtectedDirForSystemUser().length(); 549 output.credentialProtectedDataDir = 550 new StringBuilder(pkg.getBaseAppDataCredentialProtectedDirForSystemUser()) 551 .replace(credentialLength - 2, credentialLength - 1, userIdString) 552 .append(packageName) 553 .toString(); 554 int deviceLength = pkg.getBaseAppDataDeviceProtectedDirForSystemUser().length(); 555 output.deviceProtectedDataDir = 556 new StringBuilder(pkg.getBaseAppDataDeviceProtectedDirForSystemUser()) 557 .replace(deviceLength - 2, deviceLength - 1, userIdString) 558 .append(packageName) 559 .toString(); 560 } 561 562 if (input.isDefaultToDeviceProtectedStorage() 563 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { 564 output.dataDir = output.deviceProtectedDataDir; 565 } else { 566 output.dataDir = output.credentialProtectedDataDir; 567 } 568 } 569 570 // This duplicates the ApplicationInfo variant because it uses field assignment and the classes 571 // don't inherit from each other, unfortunately. Consolidating logic would introduce overhead. initForUser(InstrumentationInfo output, AndroidPackage input, @UserIdInt int userId)572 private static void initForUser(InstrumentationInfo output, AndroidPackage input, 573 @UserIdInt int userId) { 574 PackageImpl pkg = ((PackageImpl) input); 575 String packageName = input.getPackageName(); 576 if ("android".equals(packageName)) { 577 output.dataDir = PackageInfoWithoutStateUtils.SYSTEM_DATA_PATH; 578 return; 579 } 580 581 // For performance reasons, all these paths are built as strings 582 if (userId == UserHandle.USER_SYSTEM) { 583 output.credentialProtectedDataDir = 584 pkg.getBaseAppDataCredentialProtectedDirForSystemUser() + packageName; 585 output.deviceProtectedDataDir = 586 pkg.getBaseAppDataDeviceProtectedDirForSystemUser() + packageName; 587 } else { 588 // Convert /data/user/0/ -> /data/user/1/com.example.app 589 String userIdString = String.valueOf(userId); 590 int credentialLength = pkg.getBaseAppDataCredentialProtectedDirForSystemUser().length(); 591 output.credentialProtectedDataDir = 592 new StringBuilder(pkg.getBaseAppDataCredentialProtectedDirForSystemUser()) 593 .replace(credentialLength - 2, credentialLength - 1, userIdString) 594 .append(packageName) 595 .toString(); 596 int deviceLength = pkg.getBaseAppDataDeviceProtectedDirForSystemUser().length(); 597 output.deviceProtectedDataDir = 598 new StringBuilder(pkg.getBaseAppDataDeviceProtectedDirForSystemUser()) 599 .replace(deviceLength - 2, deviceLength - 1, userIdString) 600 .append(packageName) 601 .toString(); 602 } 603 604 if (input.isDefaultToDeviceProtectedStorage() 605 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { 606 output.dataDir = output.deviceProtectedDataDir; 607 } else { 608 output.dataDir = output.credentialProtectedDataDir; 609 } 610 } 611 612 /** 613 * Wraps {@link PackageInfoUtils#generateApplicationInfo} with a cache. 614 */ 615 public static class CachedApplicationInfoGenerator { 616 // Map from a package name to the corresponding app info. 617 private ArrayMap<String, ApplicationInfo> mCache = new ArrayMap<>(); 618 619 /** 620 * {@link PackageInfoUtils#generateApplicationInfo} with a cache. 621 */ 622 @Nullable generate(AndroidPackage pkg, @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId, @Nullable PackageSetting pkgSetting)623 public ApplicationInfo generate(AndroidPackage pkg, 624 @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId, 625 @Nullable PackageSetting pkgSetting) { 626 ApplicationInfo appInfo = mCache.get(pkg.getPackageName()); 627 if (appInfo != null) { 628 return appInfo; 629 } 630 appInfo = PackageInfoUtils.generateApplicationInfo( 631 pkg, flags, state, userId, pkgSetting); 632 mCache.put(pkg.getPackageName(), appInfo); 633 return appInfo; 634 } 635 } 636 } 637