diff options
| author | 2020-09-15 16:22:37 +0000 | |
|---|---|---|
| committer | 2020-09-15 16:22:37 +0000 | |
| commit | 40e1467fd0e7d02c59cd0b2db9599596e98bd4bc (patch) | |
| tree | 96d3b779f7bd0022bdb593ae2920415e975e4d61 | |
| parent | ad9c3966184217c70264d92ce37853da2d503d9c (diff) | |
| parent | c086fe9ac1bd33ddc6c6aa681f7c92eababdceb0 (diff) | |
Merge "Optimize (Parsing)PackageImpl implementation"
17 files changed, 792 insertions, 412 deletions
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java index e57353922115..c5240c2814e8 100644 --- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java +++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java @@ -63,6 +63,9 @@ import java.util.Set; /** @hide **/ public class PackageInfoWithoutStateUtils { + public static final String SYSTEM_DATA_PATH = + Environment.getDataDirectoryPath() + File.separator + "system"; + @Nullable public static PackageInfo generate(ParsingPackageRead pkg, int[] gids, @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, @@ -168,7 +171,8 @@ public class PackageInfoWithoutStateUtils { info.instrumentation = new InstrumentationInfo[N]; for (int i = 0; i < N; i++) { info.instrumentation[i] = generateInstrumentationInfo( - pkg.getInstrumentations().get(i), pkg, flags, userId); + pkg.getInstrumentations().get(i), pkg, flags, userId, + true /* assignUserFields */); } } } @@ -332,7 +336,8 @@ public class PackageInfoWithoutStateUtils { return null; } - return generateApplicationInfoUnchecked(pkg, flags, state, userId); + return generateApplicationInfoUnchecked(pkg, flags, state, userId, + true /* assignUserFields */); } /** @@ -340,15 +345,23 @@ public class PackageInfoWithoutStateUtils { * system server. * * Prefer {@link #generateApplicationInfo(ParsingPackageRead, int, PackageUserState, int)}. + * + * @param assignUserFields whether to fill the returned {@link ApplicationInfo} with user + * specific fields. This can be skipped when building from a system + * server package, as there are cached strings which can be used rather + * than querying and concatenating the comparatively expensive + * {@link Environment#getDataDirectory(String)}}. */ @NonNull public static ApplicationInfo generateApplicationInfoUnchecked(@NonNull ParsingPackageRead pkg, - @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) { + @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId, + boolean assignUserFields) { // Make shallow copy so we can store the metadata/libraries safely ApplicationInfo ai = pkg.toAppInfoWithoutState(); - // Init handles data directories - // TODO(b/135203078): Consolidate the data directory logic, remove initForUser - ai.initForUser(userId); + + if (assignUserFields) { + assignUserFields(pkg, ai, userId); + } if ((flags & PackageManager.GET_META_DATA) == 0) { ai.metaData = null; @@ -567,9 +580,14 @@ public class PackageInfoWithoutStateUtils { return generateProviderInfo(pkg, p, flags, state, null, userId); } + /** + * @param assignUserFields see {@link #generateApplicationInfoUnchecked(ParsingPackageRead, int, + * PackageUserState, int, boolean)} + */ @Nullable public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i, - ParsingPackageRead pkg, @PackageManager.ComponentInfoFlags int flags, int userId) { + ParsingPackageRead pkg, @PackageManager.ComponentInfoFlags int flags, int userId, + boolean assignUserFields) { if (i == null) return null; InstrumentationInfo ii = new InstrumentationInfo(); @@ -585,10 +603,10 @@ public class PackageInfoWithoutStateUtils { ii.splitSourceDirs = pkg.getSplitCodePaths(); ii.splitPublicSourceDirs = pkg.getSplitCodePaths(); ii.splitDependencies = pkg.getSplitDependencies(); - ii.dataDir = getDataDir(pkg, userId).getAbsolutePath(); - ii.deviceProtectedDataDir = getDeviceProtectedDataDir(pkg, userId).getAbsolutePath(); - ii.credentialProtectedDataDir = getCredentialProtectedDataDir(pkg, - userId).getAbsolutePath(); + + if (assignUserFields) { + assignUserFields(pkg, ii, userId); + } if ((flags & PackageManager.GET_META_DATA) == 0) { return ii; @@ -770,4 +788,55 @@ public class PackageInfoWithoutStateUtils { return Environment.getDataUserCePackageDirectory(pkg.getVolumeUuid(), userId, pkg.getPackageName()); } + + private static void assignUserFields(ParsingPackageRead pkg, ApplicationInfo info, int userId) { + // This behavior is undefined for no-state ApplicationInfos when called by a public API, + // since the uid is never assigned by the system. It will always effectively be appId 0. + info.uid = UserHandle.getUid(userId, UserHandle.getAppId(info.uid)); + + String pkgName = pkg.getPackageName(); + if ("android".equals(pkgName)) { + info.dataDir = SYSTEM_DATA_PATH; + return; + } + + // For performance reasons, all these paths are built as strings + String baseDataDirPrefix = + Environment.getDataDirectoryPath(pkg.getVolumeUuid()) + File.separator; + String userIdPkgSuffix = File.separator + userId + File.separator + pkgName; + info.credentialProtectedDataDir = baseDataDirPrefix + Environment.DIR_USER_CE + + userIdPkgSuffix; + info.deviceProtectedDataDir = baseDataDirPrefix + Environment.DIR_USER_DE + userIdPkgSuffix; + + if (pkg.isDefaultToDeviceProtectedStorage() + && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { + info.dataDir = info.deviceProtectedDataDir; + } else { + info.dataDir = info.credentialProtectedDataDir; + } + } + + private static void assignUserFields(ParsingPackageRead pkg, InstrumentationInfo info, + int userId) { + String pkgName = pkg.getPackageName(); + if ("android".equals(pkgName)) { + info.dataDir = SYSTEM_DATA_PATH; + return; + } + + // For performance reasons, all these paths are built as strings + String baseDataDirPrefix = + Environment.getDataDirectoryPath(pkg.getVolumeUuid()) + File.separator; + String userIdPkgSuffix = File.separator + userId + File.separator + pkgName; + info.credentialProtectedDataDir = baseDataDirPrefix + Environment.DIR_USER_CE + + userIdPkgSuffix; + info.deviceProtectedDataDir = baseDataDirPrefix + Environment.DIR_USER_DE + userIdPkgSuffix; + + if (pkg.isDefaultToDeviceProtectedStorage() + && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { + info.dataDir = info.deviceProtectedDataDir; + } else { + info.dataDir = info.credentialProtectedDataDir; + } + } } diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java index 872098c8689e..9cda4d33503b 100644 --- a/core/java/android/content/pm/parsing/ParsingPackage.java +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -16,6 +16,7 @@ package android.content.pm.parsing; +import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; @@ -343,6 +344,6 @@ public interface ParsingPackage extends ParsingPackageRead { // TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement // for moving to the next step - @Deprecated + @CallSuper Object hideAsParsed(); } diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index ed12a17ad493..2a15e0260c1a 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -20,6 +20,8 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; +import android.annotation.CallSuper; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; @@ -73,6 +75,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; /** * The backing data for a package that was parsed from disk. @@ -147,7 +150,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @NonNull protected String mBaseApkPath; - private boolean requiredForAllUsers; @Nullable @DataClass.ParcelWith(ForInternedString.class) private String restrictedAccountType; @@ -165,7 +167,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @DataClass.ParcelWith(ForInternedString.class) private String overlayCategory; private int overlayPriority; - private boolean overlayIsStatic; @NonNull @DataClass.ParcelWith(ForInternedStringValueMap.class) private Map<String, String> overlayables = emptyMap(); @@ -282,11 +283,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @DataClass.ParcelWith(ForInternedString.class) protected String mPath; - private boolean use32BitAbi; - private boolean visibleToInstantApps; - - private boolean forceQueryable; - @NonNull @DataClass.ParcelWith(ForInternedStringList.class) private List<Intent> queriesIntents = emptyList(); @@ -331,12 +327,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { private int compatibleWidthLimitDp; private int descriptionRes; - // Usually there's code to set this to true during parsing, but it's possible to install an APK - // targeting <R that doesn't contain an <application> tag. That code would be skipped and never - // assign this, so initialize this to true for those cases. - private boolean enabled = true; - - private boolean crossProfile; private int fullBackupContent; private int iconRes; private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION; @@ -374,26 +364,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @DataClass.ParcelWith(ForInternedString.class) private String zygotePreloadName; - private boolean externalStorage; - private boolean baseHardwareAccelerated; - private boolean allowBackup; - private boolean killAfterRestore; - private boolean restoreAnyVersion; - private boolean fullBackupOnly; - private boolean persistent; - private boolean debuggable; - private boolean vmSafeMode; - private boolean hasCode; - private boolean allowTaskReparenting; - private boolean allowClearUserData; - private boolean largeHeap; - private boolean usesCleartextTraffic; - private boolean supportsRtl; - private boolean testOnly; - private boolean multiArch; - private boolean extractNativeLibs; - private boolean game; - /** * @see ParsingPackageRead#getResizeableActivity() */ @@ -401,26 +371,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @DataClass.ParcelWith(ForBoolean.class) private Boolean resizeableActivity; - private boolean staticSharedLibrary; - private boolean overlay; - private boolean isolatedSplitLoading; - private boolean hasDomainUrls; - private boolean profileableByShell; - private boolean backupInForeground; - private boolean useEmbeddedDex; - private boolean defaultToDeviceProtectedStorage; - private boolean directBootAware; - private boolean partiallyDirectBootAware; - private boolean resizeableActivityViaSdkVersion; - private boolean allowClearUserDataOnFailedRestore; - private boolean allowAudioPlaybackCapture; - private boolean requestLegacyExternalStorage; - private boolean usesNonSdkApi; - private boolean hasFragileUserData; - private boolean cantSaveState; - private boolean allowNativeHeapPointerTagging; private int autoRevokePermissions; - private boolean preserveLegacyExternalStorage; protected int gwpAsanMode; @@ -428,6 +379,130 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Nullable private ArraySet<String> mimeGroups; + // Usually there's code to set enabled to true during parsing, but it's possible to install + // an APK targeting <R that doesn't contain an <application> tag. That code would be skipped + // and never assign this, so initialize this to true for those cases. + private long mBooleans = Booleans.ENABLED; + + /** + * Flags used for a internal bitset. These flags should never be persisted or exposed outside + * of this class. It is expected that PackageCacher explicitly clears itself whenever the + * Parcelable implementation changes such that all these flags can be re-ordered or invalidated. + */ + protected static class Booleans { + @LongDef({ + EXTERNAL_STORAGE, + BASE_HARDWARE_ACCELERATED, + ALLOW_BACKUP, + KILL_AFTER_RESTORE, + RESTORE_ANY_VERSION, + FULL_BACKUP_ONLY, + PERSISTENT, + DEBUGGABLE, + VM_SAFE_MODE, + HAS_CODE, + ALLOW_TASK_REPARENTING, + ALLOW_CLEAR_USER_DATA, + LARGE_HEAP, + USES_CLEARTEXT_TRAFFIC, + SUPPORTS_RTL, + TEST_ONLY, + MULTI_ARCH, + EXTRACT_NATIVE_LIBS, + GAME, + STATIC_SHARED_LIBRARY, + OVERLAY, + ISOLATED_SPLIT_LOADING, + HAS_DOMAIN_URLS, + PROFILEABLE_BY_SHELL, + BACKUP_IN_FOREGROUND, + USE_EMBEDDED_DEX, + DEFAULT_TO_DEVICE_PROTECTED_STORAGE, + DIRECT_BOOT_AWARE, + PARTIALLY_DIRECT_BOOT_AWARE, + RESIZEABLE_ACTIVITY_VIA_SDK_VERSION, + ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, + ALLOW_AUDIO_PLAYBACK_CAPTURE, + REQUEST_LEGACY_EXTERNAL_STORAGE, + USES_NON_SDK_API, + HAS_FRAGILE_USER_DATA, + CANT_SAVE_STATE, + ALLOW_NATIVE_HEAP_POINTER_TAGGING, + PRESERVE_LEGACY_EXTERNAL_STORAGE, + REQUIRED_FOR_ALL_USERS, + OVERLAY_IS_STATIC, + USE_32_BIT_ABI, + VISIBLE_TO_INSTANT_APPS, + FORCE_QUERYABLE, + CROSS_PROFILE, + ENABLED, + }) + public @interface Values {} + private static final long EXTERNAL_STORAGE = 1L; + private static final long BASE_HARDWARE_ACCELERATED = 1L << 1; + private static final long ALLOW_BACKUP = 1L << 2; + private static final long KILL_AFTER_RESTORE = 1L << 3; + private static final long RESTORE_ANY_VERSION = 1L << 4; + private static final long FULL_BACKUP_ONLY = 1L << 5; + private static final long PERSISTENT = 1L << 6; + private static final long DEBUGGABLE = 1L << 7; + private static final long VM_SAFE_MODE = 1L << 8; + private static final long HAS_CODE = 1L << 9; + private static final long ALLOW_TASK_REPARENTING = 1L << 10; + private static final long ALLOW_CLEAR_USER_DATA = 1L << 11; + private static final long LARGE_HEAP = 1L << 12; + private static final long USES_CLEARTEXT_TRAFFIC = 1L << 13; + private static final long SUPPORTS_RTL = 1L << 14; + private static final long TEST_ONLY = 1L << 15; + private static final long MULTI_ARCH = 1L << 16; + private static final long EXTRACT_NATIVE_LIBS = 1L << 17; + private static final long GAME = 1L << 18; + private static final long STATIC_SHARED_LIBRARY = 1L << 19; + private static final long OVERLAY = 1L << 20; + private static final long ISOLATED_SPLIT_LOADING = 1L << 21; + private static final long HAS_DOMAIN_URLS = 1L << 22; + private static final long PROFILEABLE_BY_SHELL = 1L << 23; + private static final long BACKUP_IN_FOREGROUND = 1L << 24; + private static final long USE_EMBEDDED_DEX = 1L << 25; + private static final long DEFAULT_TO_DEVICE_PROTECTED_STORAGE = 1L << 26; + private static final long DIRECT_BOOT_AWARE = 1L << 27; + private static final long PARTIALLY_DIRECT_BOOT_AWARE = 1L << 28; + private static final long RESIZEABLE_ACTIVITY_VIA_SDK_VERSION = 1L << 29; + private static final long ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE = 1L << 30; + private static final long ALLOW_AUDIO_PLAYBACK_CAPTURE = 1L << 31; + private static final long REQUEST_LEGACY_EXTERNAL_STORAGE = 1L << 32; + private static final long USES_NON_SDK_API = 1L << 33; + private static final long HAS_FRAGILE_USER_DATA = 1L << 34; + private static final long CANT_SAVE_STATE = 1L << 35; + private static final long ALLOW_NATIVE_HEAP_POINTER_TAGGING = 1L << 36; + private static final long PRESERVE_LEGACY_EXTERNAL_STORAGE = 1L << 37; + private static final long REQUIRED_FOR_ALL_USERS = 1L << 38; + private static final long OVERLAY_IS_STATIC = 1L << 39; + private static final long USE_32_BIT_ABI = 1L << 40; + private static final long VISIBLE_TO_INSTANT_APPS = 1L << 41; + private static final long FORCE_QUERYABLE = 1L << 42; + private static final long CROSS_PROFILE = 1L << 43; + private static final long ENABLED = 1L << 44; + } + + private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) { + if (value) { + mBooleans |= flag; + } else { + mBooleans &= ~flag; + } + return this; + } + + private boolean getBoolean(@Booleans.Values long flag) { + return (mBooleans & flag) != 0; + } + + // Derived fields + @NonNull + private UUID mStorageUuid; + private long mLongVersionCode; + @VisibleForTesting public ParsingPackageImpl(@NonNull String packageName, @NonNull String baseApkPath, @NonNull String path, @Nullable TypedArray manifestArray) { @@ -517,10 +592,16 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { return this; } + @CallSuper @Override public Object hideAsParsed() { - // There is no equivalent for core-only parsing - throw new UnsupportedOperationException(); + assignDerivedFields(); + return this; + } + + private void assignDerivedFields() { + mStorageUuid = StorageManager.convert(volumeUuid); + mLongVersionCode = PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); } @Override @@ -862,6 +943,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { return this; } + @Override + public ParsingPackageImpl setNonLocalizedLabel(@Nullable CharSequence value) { + nonLocalizedLabel = value == null ? null : value.toString().trim(); + return this; + } + @NonNull @Override public String getProcessName() { @@ -905,7 +992,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { // appInfo.dataDir appInfo.descriptionRes = descriptionRes; // appInfo.deviceProtectedDataDir - appInfo.enabled = enabled; + appInfo.enabled = getBoolean(Booleans.ENABLED); // appInfo.enabledSetting appInfo.fullBackupContent = fullBackupContent; // TODO(b/135203078): See ParsingPackageImpl#getHiddenApiEnforcementPolicy @@ -924,17 +1011,11 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { appInfo.minAspectRatio = minAspectRatio; appInfo.minSdkVersion = minSdkVersion; appInfo.name = className; - if (appInfo.name != null) { - appInfo.name = appInfo.name.trim(); - } // appInfo.nativeLibraryDir // appInfo.nativeLibraryRootDir // appInfo.nativeLibraryRootRequiresIsa appInfo.networkSecurityConfigRes = networkSecurityConfigRes; appInfo.nonLocalizedLabel = nonLocalizedLabel; - if (appInfo.nonLocalizedLabel != null) { - appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim(); - } appInfo.packageName = packageName; appInfo.permission = permission; // appInfo.primaryCpuAbi @@ -951,7 +1032,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { appInfo.splitClassLoaderNames = splitClassLoaderNames; appInfo.splitDependencies = splitDependencies; appInfo.splitNames = splitNames; - appInfo.storageUuid = StorageManager.convert(volumeUuid); + appInfo.storageUuid = mStorageUuid; appInfo.targetSandboxVersion = targetSandboxVersion; appInfo.targetSdkVersion = targetSdkVersion; appInfo.taskAffinity = taskAffinity; @@ -967,7 +1048,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { appInfo.setResourcePath(mPath); appInfo.setSplitCodePaths(splitCodePaths); appInfo.setSplitResourcePaths(splitCodePaths); - appInfo.setVersionCode(PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode)); + appInfo.setVersionCode(mLongVersionCode); return appInfo; } @@ -994,14 +1075,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { sForInternedString.parcel(this.packageName, dest, flags); dest.writeString(this.realPackage); dest.writeString(this.mBaseApkPath); - dest.writeBoolean(this.requiredForAllUsers); dest.writeString(this.restrictedAccountType); dest.writeString(this.requiredAccountType); sForInternedString.parcel(this.overlayTarget, dest, flags); dest.writeString(this.overlayTargetName); dest.writeString(this.overlayCategory); dest.writeInt(this.overlayPriority); - dest.writeBoolean(this.overlayIsStatic); sForInternedStringValueMap.parcel(this.overlayables, dest, flags); sForInternedString.parcel(this.staticSharedLibName, dest, flags); dest.writeLong(this.staticSharedLibVersion); @@ -1049,9 +1128,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { sForInternedString.parcel(this.volumeUuid, dest, flags); dest.writeParcelable(this.signingDetails, flags); dest.writeString(this.mPath); - dest.writeBoolean(this.use32BitAbi); - dest.writeBoolean(this.visibleToInstantApps); - dest.writeBoolean(this.forceQueryable); dest.writeParcelableList(this.queriesIntents, flags); sForInternedStringList.parcel(this.queriesPackages, dest, flags); dest.writeString(this.appComponentFactory); @@ -1062,8 +1138,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { dest.writeString(this.className); dest.writeInt(this.compatibleWidthLimitDp); dest.writeInt(this.descriptionRes); - dest.writeBoolean(this.enabled); - dest.writeBoolean(this.crossProfile); dest.writeInt(this.fullBackupContent); dest.writeInt(this.iconRes); dest.writeInt(this.installLocation); @@ -1092,52 +1166,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { dest.writeIntArray(this.splitFlags); dest.writeStringArray(this.splitNames); dest.writeIntArray(this.splitRevisionCodes); - - dest.writeBoolean(this.externalStorage); - dest.writeBoolean(this.baseHardwareAccelerated); - dest.writeBoolean(this.allowBackup); - dest.writeBoolean(this.killAfterRestore); - dest.writeBoolean(this.restoreAnyVersion); - dest.writeBoolean(this.fullBackupOnly); - dest.writeBoolean(this.persistent); - dest.writeBoolean(this.debuggable); - dest.writeBoolean(this.vmSafeMode); - dest.writeBoolean(this.hasCode); - dest.writeBoolean(this.allowTaskReparenting); - dest.writeBoolean(this.allowClearUserData); - dest.writeBoolean(this.largeHeap); - dest.writeBoolean(this.usesCleartextTraffic); - dest.writeBoolean(this.supportsRtl); - dest.writeBoolean(this.testOnly); - dest.writeBoolean(this.multiArch); - dest.writeBoolean(this.extractNativeLibs); - dest.writeBoolean(this.game); - sForBoolean.parcel(this.resizeableActivity, dest, flags); - - dest.writeBoolean(this.staticSharedLibrary); - dest.writeBoolean(this.overlay); - dest.writeBoolean(this.isolatedSplitLoading); - dest.writeBoolean(this.hasDomainUrls); - dest.writeBoolean(this.profileableByShell); - dest.writeBoolean(this.backupInForeground); - dest.writeBoolean(this.useEmbeddedDex); - dest.writeBoolean(this.defaultToDeviceProtectedStorage); - dest.writeBoolean(this.directBootAware); - dest.writeBoolean(this.partiallyDirectBootAware); - dest.writeBoolean(this.resizeableActivityViaSdkVersion); - dest.writeBoolean(this.allowClearUserDataOnFailedRestore); - dest.writeBoolean(this.allowAudioPlaybackCapture); - dest.writeBoolean(this.requestLegacyExternalStorage); - dest.writeBoolean(this.usesNonSdkApi); - dest.writeBoolean(this.hasFragileUserData); - dest.writeBoolean(this.cantSaveState); - dest.writeBoolean(this.allowNativeHeapPointerTagging); dest.writeInt(this.autoRevokePermissions); - dest.writeBoolean(this.preserveLegacyExternalStorage); dest.writeArraySet(this.mimeGroups); dest.writeInt(this.gwpAsanMode); dest.writeSparseIntArray(this.minExtensionVersions); + dest.writeLong(this.mBooleans); } public ParsingPackageImpl(Parcel in) { @@ -1158,14 +1192,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.packageName = sForInternedString.unparcel(in); this.realPackage = in.readString(); this.mBaseApkPath = in.readString(); - this.requiredForAllUsers = in.readBoolean(); this.restrictedAccountType = in.readString(); this.requiredAccountType = in.readString(); this.overlayTarget = sForInternedString.unparcel(in); this.overlayTargetName = in.readString(); this.overlayCategory = in.readString(); this.overlayPriority = in.readInt(); - this.overlayIsStatic = in.readBoolean(); this.overlayables = sForInternedStringValueMap.unparcel(in); this.staticSharedLibName = sForInternedString.unparcel(in); this.staticSharedLibVersion = in.readLong(); @@ -1213,9 +1245,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.volumeUuid = sForInternedString.unparcel(in); this.signingDetails = in.readParcelable(boot); this.mPath = in.readString(); - this.use32BitAbi = in.readBoolean(); - this.visibleToInstantApps = in.readBoolean(); - this.forceQueryable = in.readBoolean(); this.queriesIntents = in.createTypedArrayList(Intent.CREATOR); this.queriesPackages = sForInternedStringList.unparcel(in); this.appComponentFactory = in.readString(); @@ -1226,8 +1255,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.className = in.readString(); this.compatibleWidthLimitDp = in.readInt(); this.descriptionRes = in.readInt(); - this.enabled = in.readBoolean(); - this.crossProfile = in.readBoolean(); this.fullBackupContent = in.readInt(); this.iconRes = in.readInt(); this.installLocation = in.readInt(); @@ -1256,50 +1283,15 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.splitFlags = in.createIntArray(); this.splitNames = in.createStringArray(); this.splitRevisionCodes = in.createIntArray(); - this.externalStorage = in.readBoolean(); - this.baseHardwareAccelerated = in.readBoolean(); - this.allowBackup = in.readBoolean(); - this.killAfterRestore = in.readBoolean(); - this.restoreAnyVersion = in.readBoolean(); - this.fullBackupOnly = in.readBoolean(); - this.persistent = in.readBoolean(); - this.debuggable = in.readBoolean(); - this.vmSafeMode = in.readBoolean(); - this.hasCode = in.readBoolean(); - this.allowTaskReparenting = in.readBoolean(); - this.allowClearUserData = in.readBoolean(); - this.largeHeap = in.readBoolean(); - this.usesCleartextTraffic = in.readBoolean(); - this.supportsRtl = in.readBoolean(); - this.testOnly = in.readBoolean(); - this.multiArch = in.readBoolean(); - this.extractNativeLibs = in.readBoolean(); - this.game = in.readBoolean(); this.resizeableActivity = sForBoolean.unparcel(in); - this.staticSharedLibrary = in.readBoolean(); - this.overlay = in.readBoolean(); - this.isolatedSplitLoading = in.readBoolean(); - this.hasDomainUrls = in.readBoolean(); - this.profileableByShell = in.readBoolean(); - this.backupInForeground = in.readBoolean(); - this.useEmbeddedDex = in.readBoolean(); - this.defaultToDeviceProtectedStorage = in.readBoolean(); - this.directBootAware = in.readBoolean(); - this.partiallyDirectBootAware = in.readBoolean(); - this.resizeableActivityViaSdkVersion = in.readBoolean(); - this.allowClearUserDataOnFailedRestore = in.readBoolean(); - this.allowAudioPlaybackCapture = in.readBoolean(); - this.requestLegacyExternalStorage = in.readBoolean(); - this.usesNonSdkApi = in.readBoolean(); - this.hasFragileUserData = in.readBoolean(); - this.cantSaveState = in.readBoolean(); - this.allowNativeHeapPointerTagging = in.readBoolean(); this.autoRevokePermissions = in.readInt(); - this.preserveLegacyExternalStorage = in.readBoolean(); this.mimeGroups = (ArraySet<String>) in.readArraySet(boot); this.gwpAsanMode = in.readInt(); this.minExtensionVersions = in.readSparseIntArray(); + this.mBooleans = in.readLong(); + + assignDerivedFields(); } public static final Parcelable.Creator<ParsingPackageImpl> CREATOR = @@ -1367,7 +1359,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public boolean isRequiredForAllUsers() { - return requiredForAllUsers; + return getBoolean(Booleans.REQUIRED_FOR_ALL_USERS); } @Nullable @@ -1407,7 +1399,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public boolean isOverlayIsStatic() { - return overlayIsStatic; + return getBoolean(Booleans.OVERLAY_IS_STATIC); } @NonNull @@ -1653,17 +1645,17 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public boolean isUse32BitAbi() { - return use32BitAbi; + return getBoolean(Booleans.USE_32_BIT_ABI); } @Override public boolean isVisibleToInstantApps() { - return visibleToInstantApps; + return getBoolean(Booleans.VISIBLE_TO_INSTANT_APPS); } @Override public boolean isForceQueryable() { - return forceQueryable; + return getBoolean(Booleans.FORCE_QUERYABLE); } @NonNull @@ -1766,12 +1758,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public boolean isEnabled() { - return enabled; + return getBoolean(Booleans.ENABLED); } @Override public boolean isCrossProfile() { - return crossProfile; + return getBoolean(Booleans.CROSS_PROFILE); } @Override @@ -1892,97 +1884,97 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public boolean isExternalStorage() { - return externalStorage; + return getBoolean(Booleans.EXTERNAL_STORAGE); } @Override public boolean isBaseHardwareAccelerated() { - return baseHardwareAccelerated; + return getBoolean(Booleans.BASE_HARDWARE_ACCELERATED); } @Override public boolean isAllowBackup() { - return allowBackup; + return getBoolean(Booleans.ALLOW_BACKUP); } @Override public boolean isKillAfterRestore() { - return killAfterRestore; + return getBoolean(Booleans.KILL_AFTER_RESTORE); } @Override public boolean isRestoreAnyVersion() { - return restoreAnyVersion; + return getBoolean(Booleans.RESTORE_ANY_VERSION); } @Override public boolean isFullBackupOnly() { - return fullBackupOnly; + return getBoolean(Booleans.FULL_BACKUP_ONLY); } @Override public boolean isPersistent() { - return persistent; + return getBoolean(Booleans.PERSISTENT); } @Override public boolean isDebuggable() { - return debuggable; + return getBoolean(Booleans.DEBUGGABLE); } @Override public boolean isVmSafeMode() { - return vmSafeMode; + return getBoolean(Booleans.VM_SAFE_MODE); } @Override public boolean isHasCode() { - return hasCode; + return getBoolean(Booleans.HAS_CODE); } @Override public boolean isAllowTaskReparenting() { - return allowTaskReparenting; + return getBoolean(Booleans.ALLOW_TASK_REPARENTING); } @Override public boolean isAllowClearUserData() { - return allowClearUserData; + return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA); } @Override public boolean isLargeHeap() { - return largeHeap; + return getBoolean(Booleans.LARGE_HEAP); } @Override public boolean isUsesCleartextTraffic() { - return usesCleartextTraffic; + return getBoolean(Booleans.USES_CLEARTEXT_TRAFFIC); } @Override public boolean isSupportsRtl() { - return supportsRtl; + return getBoolean(Booleans.SUPPORTS_RTL); } @Override public boolean isTestOnly() { - return testOnly; + return getBoolean(Booleans.TEST_ONLY); } @Override public boolean isMultiArch() { - return multiArch; + return getBoolean(Booleans.MULTI_ARCH); } @Override public boolean isExtractNativeLibs() { - return extractNativeLibs; + return getBoolean(Booleans.EXTRACT_NATIVE_LIBS); } @Override public boolean isGame() { - return game; + return getBoolean(Booleans.GAME); } /** @@ -1996,47 +1988,47 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public boolean isStaticSharedLibrary() { - return staticSharedLibrary; + return getBoolean(Booleans.STATIC_SHARED_LIBRARY); } @Override public boolean isOverlay() { - return overlay; + return getBoolean(Booleans.OVERLAY); } @Override public boolean isIsolatedSplitLoading() { - return isolatedSplitLoading; + return getBoolean(Booleans.ISOLATED_SPLIT_LOADING); } @Override public boolean isHasDomainUrls() { - return hasDomainUrls; + return getBoolean(Booleans.HAS_DOMAIN_URLS); } @Override public boolean isProfileableByShell() { - return profileableByShell; + return getBoolean(Booleans.PROFILEABLE_BY_SHELL); } @Override public boolean isBackupInForeground() { - return backupInForeground; + return getBoolean(Booleans.BACKUP_IN_FOREGROUND); } @Override public boolean isUseEmbeddedDex() { - return useEmbeddedDex; + return getBoolean(Booleans.USE_EMBEDDED_DEX); } @Override public boolean isDefaultToDeviceProtectedStorage() { - return defaultToDeviceProtectedStorage; + return getBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE); } @Override public boolean isDirectBootAware() { - return directBootAware; + return getBoolean(Booleans.DIRECT_BOOT_AWARE); } @Override @@ -2046,47 +2038,47 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public boolean isPartiallyDirectBootAware() { - return partiallyDirectBootAware; + return getBoolean(Booleans.PARTIALLY_DIRECT_BOOT_AWARE); } @Override public boolean isResizeableActivityViaSdkVersion() { - return resizeableActivityViaSdkVersion; + return getBoolean(Booleans.RESIZEABLE_ACTIVITY_VIA_SDK_VERSION); } @Override public boolean isAllowClearUserDataOnFailedRestore() { - return allowClearUserDataOnFailedRestore; + return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE); } @Override public boolean isAllowAudioPlaybackCapture() { - return allowAudioPlaybackCapture; + return getBoolean(Booleans.ALLOW_AUDIO_PLAYBACK_CAPTURE); } @Override public boolean isRequestLegacyExternalStorage() { - return requestLegacyExternalStorage; + return getBoolean(Booleans.REQUEST_LEGACY_EXTERNAL_STORAGE); } @Override public boolean isUsesNonSdkApi() { - return usesNonSdkApi; + return getBoolean(Booleans.USES_NON_SDK_API); } @Override public boolean isHasFragileUserData() { - return hasFragileUserData; + return getBoolean(Booleans.HAS_FRAGILE_USER_DATA); } @Override public boolean isCantSaveState() { - return cantSaveState; + return getBoolean(Booleans.CANT_SAVE_STATE); } @Override public boolean isAllowNativeHeapPointerTagging() { - return allowNativeHeapPointerTagging; + return getBoolean(Booleans.ALLOW_NATIVE_HEAP_POINTER_TAGGING); } @Override @@ -2096,7 +2088,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public boolean hasPreserveLegacyExternalStorage() { - return preserveLegacyExternalStorage; + return getBoolean(Booleans.PRESERVE_LEGACY_EXTERNAL_STORAGE); } @Override @@ -2113,8 +2105,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setRequiredForAllUsers(boolean value) { - requiredForAllUsers = value; - return this; + return setBoolean(Booleans.REQUIRED_FOR_ALL_USERS, value); } @Override @@ -2125,8 +2116,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setOverlayIsStatic(boolean value) { - overlayIsStatic = value; - return this; + return setBoolean(Booleans.OVERLAY_IS_STATIC, value); } @Override @@ -2173,20 +2163,17 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setUse32BitAbi(boolean value) { - use32BitAbi = value; - return this; + return setBoolean(Booleans.USE_32_BIT_ABI, value); } @Override public ParsingPackageImpl setVisibleToInstantApps(boolean value) { - visibleToInstantApps = value; - return this; + return setBoolean(Booleans.VISIBLE_TO_INSTANT_APPS, value); } @Override public ParsingPackageImpl setForceQueryable(boolean value) { - forceQueryable = value; - return this; + return setBoolean(Booleans.FORCE_QUERYABLE, value); } @Override @@ -2215,14 +2202,12 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setEnabled(boolean value) { - enabled = value; - return this; + return setBoolean(Booleans.ENABLED, value); } @Override public ParsingPackageImpl setCrossProfile(boolean value) { - crossProfile = value; - return this; + return setBoolean(Booleans.CROSS_PROFILE, value); } @Override @@ -2292,12 +2277,6 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { } @Override - public ParsingPackageImpl setNonLocalizedLabel(@Nullable CharSequence value) { - nonLocalizedLabel = value; - return this; - } - - @Override public ParsingPackageImpl setRequiresSmallestWidthDp(int value) { requiresSmallestWidthDp = value; return this; @@ -2335,116 +2314,97 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setExternalStorage(boolean value) { - externalStorage = value; - return this; + return setBoolean(Booleans.EXTERNAL_STORAGE, value); } @Override public ParsingPackageImpl setBaseHardwareAccelerated(boolean value) { - baseHardwareAccelerated = value; - return this; + return setBoolean(Booleans.BASE_HARDWARE_ACCELERATED, value); } @Override public ParsingPackageImpl setAllowBackup(boolean value) { - allowBackup = value; - return this; + return setBoolean(Booleans.ALLOW_BACKUP, value); } @Override public ParsingPackageImpl setKillAfterRestore(boolean value) { - killAfterRestore = value; - return this; + return setBoolean(Booleans.KILL_AFTER_RESTORE, value); } @Override public ParsingPackageImpl setRestoreAnyVersion(boolean value) { - restoreAnyVersion = value; - return this; + return setBoolean(Booleans.RESTORE_ANY_VERSION, value); } @Override public ParsingPackageImpl setFullBackupOnly(boolean value) { - fullBackupOnly = value; - return this; + return setBoolean(Booleans.FULL_BACKUP_ONLY, value); } @Override public ParsingPackageImpl setPersistent(boolean value) { - persistent = value; - return this; + return setBoolean(Booleans.PERSISTENT, value); } @Override public ParsingPackageImpl setDebuggable(boolean value) { - debuggable = value; - return this; + return setBoolean(Booleans.DEBUGGABLE, value); } @Override public ParsingPackageImpl setVmSafeMode(boolean value) { - vmSafeMode = value; - return this; + return setBoolean(Booleans.VM_SAFE_MODE, value); } @Override public ParsingPackageImpl setHasCode(boolean value) { - hasCode = value; - return this; + return setBoolean(Booleans.HAS_CODE, value); } @Override public ParsingPackageImpl setAllowTaskReparenting(boolean value) { - allowTaskReparenting = value; - return this; + return setBoolean(Booleans.ALLOW_TASK_REPARENTING, value); } @Override public ParsingPackageImpl setAllowClearUserData(boolean value) { - allowClearUserData = value; - return this; + return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA, value); } @Override public ParsingPackageImpl setLargeHeap(boolean value) { - largeHeap = value; - return this; + return setBoolean(Booleans.LARGE_HEAP, value); } @Override public ParsingPackageImpl setUsesCleartextTraffic(boolean value) { - usesCleartextTraffic = value; - return this; + return setBoolean(Booleans.USES_CLEARTEXT_TRAFFIC, value); } @Override public ParsingPackageImpl setSupportsRtl(boolean value) { - supportsRtl = value; - return this; + return setBoolean(Booleans.SUPPORTS_RTL, value); } @Override public ParsingPackageImpl setTestOnly(boolean value) { - testOnly = value; - return this; + return setBoolean(Booleans.TEST_ONLY, value); } @Override public ParsingPackageImpl setMultiArch(boolean value) { - multiArch = value; - return this; + return setBoolean(Booleans.MULTI_ARCH, value); } @Override public ParsingPackageImpl setExtractNativeLibs(boolean value) { - extractNativeLibs = value; - return this; + return setBoolean(Booleans.EXTRACT_NATIVE_LIBS, value); } @Override public ParsingPackageImpl setGame(boolean value) { - game = value; - return this; + return setBoolean(Booleans.GAME, value); } /** @@ -2458,56 +2418,47 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setStaticSharedLibrary(boolean value) { - staticSharedLibrary = value; - return this; + return setBoolean(Booleans.STATIC_SHARED_LIBRARY, value); } @Override public ParsingPackageImpl setOverlay(boolean value) { - overlay = value; - return this; + return setBoolean(Booleans.OVERLAY, value); } @Override public ParsingPackageImpl setIsolatedSplitLoading(boolean value) { - isolatedSplitLoading = value; - return this; + return setBoolean(Booleans.ISOLATED_SPLIT_LOADING, value); } @Override public ParsingPackageImpl setHasDomainUrls(boolean value) { - hasDomainUrls = value; - return this; + return setBoolean(Booleans.HAS_DOMAIN_URLS, value); } @Override public ParsingPackageImpl setProfileableByShell(boolean value) { - profileableByShell = value; - return this; + return setBoolean(Booleans.PROFILEABLE_BY_SHELL, value); } @Override public ParsingPackageImpl setBackupInForeground(boolean value) { - backupInForeground = value; - return this; + return setBoolean(Booleans.BACKUP_IN_FOREGROUND, value); } @Override public ParsingPackageImpl setUseEmbeddedDex(boolean value) { - useEmbeddedDex = value; - return this; + return setBoolean(Booleans.USE_EMBEDDED_DEX, value); } @Override public ParsingPackageImpl setDefaultToDeviceProtectedStorage(boolean value) { - defaultToDeviceProtectedStorage = value; - return this; + return setBoolean(Booleans.DEFAULT_TO_DEVICE_PROTECTED_STORAGE, value); } @Override public ParsingPackageImpl setDirectBootAware(boolean value) { - directBootAware = value; - return this; + return setBoolean(Booleans.DIRECT_BOOT_AWARE, value); } @Override @@ -2518,56 +2469,47 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setPartiallyDirectBootAware(boolean value) { - partiallyDirectBootAware = value; - return this; + return setBoolean(Booleans.PARTIALLY_DIRECT_BOOT_AWARE, value); } @Override public ParsingPackageImpl setResizeableActivityViaSdkVersion(boolean value) { - resizeableActivityViaSdkVersion = value; - return this; + return setBoolean(Booleans.RESIZEABLE_ACTIVITY_VIA_SDK_VERSION, value); } @Override public ParsingPackageImpl setAllowClearUserDataOnFailedRestore(boolean value) { - allowClearUserDataOnFailedRestore = value; - return this; + return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, value); } @Override public ParsingPackageImpl setAllowAudioPlaybackCapture(boolean value) { - allowAudioPlaybackCapture = value; - return this; + return setBoolean(Booleans.ALLOW_AUDIO_PLAYBACK_CAPTURE, value); } @Override public ParsingPackageImpl setRequestLegacyExternalStorage(boolean value) { - requestLegacyExternalStorage = value; - return this; + return setBoolean(Booleans.REQUEST_LEGACY_EXTERNAL_STORAGE, value); } @Override public ParsingPackageImpl setUsesNonSdkApi(boolean value) { - usesNonSdkApi = value; - return this; + return setBoolean(Booleans.USES_NON_SDK_API, value); } @Override public ParsingPackageImpl setHasFragileUserData(boolean value) { - hasFragileUserData = value; - return this; + return setBoolean(Booleans.HAS_FRAGILE_USER_DATA, value); } @Override public ParsingPackageImpl setCantSaveState(boolean value) { - cantSaveState = value; - return this; + return setBoolean(Booleans.CANT_SAVE_STATE, value); } @Override public ParsingPackageImpl setAllowNativeHeapPointerTagging(boolean value) { - allowNativeHeapPointerTagging = value; - return this; + return setBoolean(Booleans.ALLOW_NATIVE_HEAP_POINTER_TAGGING, value); } @Override @@ -2578,8 +2520,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setPreserveLegacyExternalStorage(boolean value) { - preserveLegacyExternalStorage = value; - return this; + return setBoolean(Booleans.PRESERVE_LEGACY_EXTERNAL_STORAGE, value); } @Override @@ -2644,7 +2585,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { @Override public ParsingPackageImpl setClassName(@Nullable String className) { - this.className = className; + this.className = className == null ? null : className.trim(); return this; } diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java index dbd15f544bcd..acd6305a1442 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageRead.java +++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java @@ -867,7 +867,7 @@ public interface ParsingPackageRead extends Parcelable { * @see ApplicationInfo#gwpAsanMode * @see R.styleable#AndroidManifest_gwpAsanMode */ - public int getGwpAsanMode(); + int getGwpAsanMode(); // TODO(b/135203078): Hide and enforce going through PackageInfoUtils ApplicationInfo toAppInfoWithoutState(); diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index bce75cde20c2..9197020e1fce 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -185,6 +185,9 @@ public class ParsingPackageUtils { ParsingPackageUtils.getSigningDetails(pkg, false /* skipVerify */)); } + // Need to call this to finish the parsing stage + pkg.hideAsParsed(); + return input.success(pkg); } catch (PackageParser.PackageParserException e) { return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index eaf6198b67ad..085681d412e9 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -29,6 +29,7 @@ import android.compat.annotation.Disabled; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; @@ -73,12 +74,29 @@ public class Environment { private static final String DIR_FILES = "files"; private static final String DIR_CACHE = "cache"; + /** + * The folder name prefix for the user credential protected data directory. This is exposed for + * use in string path caching for {@link ApplicationInfo} objects, and should not be accessed + * directly otherwise. Prefer {@link #getDataUserCeDirectory(String, int)}. + * {@hide} + */ + public static final String DIR_USER_CE = "user"; + + /** + * The folder name prefix for the user device protected data directory. This is exposed for use + * in string path caching for {@link ApplicationInfo} objects, and should not be accessed + * directly otherwise. Prefer {@link #getDataUserDeDirectory(String, int)}. + * {@hide} + */ + public static final String DIR_USER_DE = "user_de"; + /** {@hide} */ @Deprecated public static final String DIRECTORY_ANDROID = DIR_ANDROID; private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system"); - private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data"); + private static final String DIR_ANDROID_DATA_PATH = getDirectoryPath(ENV_ANDROID_DATA, "/data"); + private static final File DIR_ANDROID_DATA = new File(DIR_ANDROID_DATA_PATH); private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand"); private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage"); private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache"); @@ -357,6 +375,14 @@ public class Environment { return DIR_ANDROID_DATA; } + /** + * @see #getDataDirectory() + * @hide + */ + public static String getDataDirectoryPath() { + return DIR_ANDROID_DATA_PATH; + } + /** {@hide} */ public static File getDataDirectory(String volumeUuid) { if (TextUtils.isEmpty(volumeUuid)) { @@ -366,6 +392,15 @@ public class Environment { } } + /** @hide */ + public static String getDataDirectoryPath(String volumeUuid) { + if (TextUtils.isEmpty(volumeUuid)) { + return DIR_ANDROID_DATA_PATH; + } else { + return getExpandDirectory().getAbsolutePath() + File.separator + volumeUuid; + } + } + /** {@hide} */ public static File getExpandDirectory() { return DIR_ANDROID_EXPAND; @@ -489,7 +524,7 @@ public class Environment { /** {@hide} */ public static File getDataUserCeDirectory(String volumeUuid) { - return new File(getDataDirectory(volumeUuid), "user"); + return new File(getDataDirectory(volumeUuid), DIR_USER_CE); } /** {@hide} */ @@ -506,7 +541,7 @@ public class Environment { /** {@hide} */ public static File getDataUserDeDirectory(String volumeUuid) { - return new File(getDataDirectory(volumeUuid), "user_de"); + return new File(getDataDirectory(volumeUuid), DIR_USER_DE); } /** {@hide} */ @@ -1372,6 +1407,12 @@ public class Environment { return path == null ? new File(defaultPath) : new File(path); } + @NonNull + static String getDirectoryPath(@NonNull String variableName, @NonNull String defaultPath) { + String path = System.getenv(variableName); + return path == null ? defaultPath : path; + } + /** {@hide} */ public static void setUserRequired(boolean userRequired) { sUserRequired = userRequired; diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING index 39c196d1a06c..1bdc82a82c6c 100644 --- a/core/java/android/os/TEST_MAPPING +++ b/core/java/android/os/TEST_MAPPING @@ -29,6 +29,15 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" } ] + }, + { + "file_patterns": ["Environment\\.java"], + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.pm.parsing.PackageInfoUserFieldsTest" + } + ] } ], "postsubmit": [ diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5850dc012226..35648dabb86d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9531,10 +9531,16 @@ public class PackageManagerService extends IPackageManager.Stub } } + // The version of the application on the /system partition is less than or + // equal to the version on the /data partition. Throw an exception and use + // the application already installed on the /data partition. if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) { - // The version of the application on the /system partition is less than or - // equal to the version on the /data partition. Throw an exception and use - // the application already installed on the /data partition. + // In the case of a skipped package, commitReconciledScanResultLocked is not called to + // add the object to the "live" data structures, so this is the final mutation step + // for the package. Which means it needs to be finalized here to cache derived fields. + // This is relevant for cases where the disabled system package is used for flags or + // other metadata. + ((ParsedPackage) parsedPackage).hideAsFinal(); throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName() + " at " + parsedPackage.getPath() + " ignored: updated version " + pkgSetting.versionCode + " better than this " diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 4476e8ac8d90..276f88082df0 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -42,7 +42,9 @@ import java.util.Set; * Settings data for a particular package we know about. */ public class PackageSetting extends PackageSettingBase { - int appId; + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public int appId; /** * This can be null whenever a physical APK on device is missing. This can be the result of diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java index d695a01109ff..2d2e72a3facb 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java +++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java @@ -19,6 +19,7 @@ package com.android.server.pm.parsing; import android.annotation.CheckResult; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.apex.ApexInfo; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -56,6 +57,7 @@ import com.android.internal.util.ArrayUtils; import com.android.server.pm.PackageSetting; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.pkg.PackageStateUnserialized; import libcore.util.EmptyArray; @@ -218,7 +220,9 @@ public class PackageInfoUtils { } ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfoUnchecked(pkg, - flags, state, userId); + flags, state, userId, false /* assignUserFields */); + + initForUser(info, pkg, userId); if (pkgSetting != null) { // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up @@ -349,7 +353,11 @@ public class PackageInfoUtils { if (i == null) return null; InstrumentationInfo info = - PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId); + PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId, + false /* assignUserFields */); + + initForUser(info, pkg, userId); + if (info == null) { return null; } @@ -496,6 +504,90 @@ public class PackageInfoUtils { // @formatter:on } + private static void initForUser(ApplicationInfo output, AndroidPackage input, + @UserIdInt int userId) { + PackageImpl pkg = ((PackageImpl) input); + String packageName = input.getPackageName(); + output.uid = UserHandle.getUid(userId, UserHandle.getAppId(input.getUid())); + + if ("android".equals(packageName)) { + output.dataDir = PackageInfoWithoutStateUtils.SYSTEM_DATA_PATH; + return; + } + + // For performance reasons, all these paths are built as strings + if (userId == UserHandle.USER_SYSTEM) { + output.credentialProtectedDataDir = + pkg.getBaseAppDataCredentialProtectedDirForSystemUser() + packageName; + output.deviceProtectedDataDir = + pkg.getBaseAppDataDeviceProtectedDirForSystemUser() + packageName; + } else { + // Convert /data/user/0/ -> /data/user/1/com.example.app + String userIdString = String.valueOf(userId); + int credentialLength = pkg.getBaseAppDataCredentialProtectedDirForSystemUser().length(); + output.credentialProtectedDataDir = + new StringBuilder(pkg.getBaseAppDataCredentialProtectedDirForSystemUser()) + .replace(credentialLength - 2, credentialLength - 1, userIdString) + .append(packageName) + .toString(); + int deviceLength = pkg.getBaseAppDataDeviceProtectedDirForSystemUser().length(); + output.deviceProtectedDataDir = + new StringBuilder(pkg.getBaseAppDataDeviceProtectedDirForSystemUser()) + .replace(deviceLength - 2, deviceLength - 1, userIdString) + .append(packageName) + .toString(); + } + + if (input.isDefaultToDeviceProtectedStorage() + && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { + output.dataDir = output.deviceProtectedDataDir; + } else { + output.dataDir = output.credentialProtectedDataDir; + } + } + + // This duplicates the ApplicationInfo variant because it uses field assignment and the classes + // don't inherit from each other, unfortunately. Consolidating logic would introduce overhead. + private static void initForUser(InstrumentationInfo output, AndroidPackage input, + @UserIdInt int userId) { + PackageImpl pkg = ((PackageImpl) input); + String packageName = input.getPackageName(); + if ("android".equals(packageName)) { + output.dataDir = PackageInfoWithoutStateUtils.SYSTEM_DATA_PATH; + return; + } + + // For performance reasons, all these paths are built as strings + if (userId == UserHandle.USER_SYSTEM) { + output.credentialProtectedDataDir = + pkg.getBaseAppDataCredentialProtectedDirForSystemUser() + packageName; + output.deviceProtectedDataDir = + pkg.getBaseAppDataDeviceProtectedDirForSystemUser() + packageName; + } else { + // Convert /data/user/0/ -> /data/user/1/com.example.app + String userIdString = String.valueOf(userId); + int credentialLength = pkg.getBaseAppDataCredentialProtectedDirForSystemUser().length(); + output.credentialProtectedDataDir = + new StringBuilder(pkg.getBaseAppDataCredentialProtectedDirForSystemUser()) + .replace(credentialLength - 2, credentialLength - 1, userIdString) + .append(packageName) + .toString(); + int deviceLength = pkg.getBaseAppDataDeviceProtectedDirForSystemUser().length(); + output.deviceProtectedDataDir = + new StringBuilder(pkg.getBaseAppDataDeviceProtectedDirForSystemUser()) + .replace(deviceLength - 2, deviceLength - 1, userIdString) + .append(packageName) + .toString(); + } + + if (input.isDefaultToDeviceProtectedStorage() + && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { + output.dataDir = output.deviceProtectedDataDir; + } else { + output.dataDir = output.credentialProtectedDataDir; + } + } + /** * Wraps {@link PackageInfoUtils#generateApplicationInfo} with a cache. */ diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java index 0e3e110bdc56..b4c6e9d99751 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java @@ -16,6 +16,7 @@ package com.android.server.pm.parsing.pkg; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.ActivityInfo; @@ -28,7 +29,9 @@ import android.content.pm.parsing.component.ParsedActivity; import android.content.pm.parsing.component.ParsedProvider; import android.content.pm.parsing.component.ParsedService; import android.content.res.TypedArray; +import android.os.Environment; import android.os.Parcel; +import android.os.UserHandle; import android.os.storage.StorageManager; import android.text.TextUtils; @@ -38,6 +41,7 @@ import com.android.internal.util.DataClass; import com.android.internal.util.Parcelling.BuiltIn.ForInternedString; import com.android.server.pm.parsing.PackageInfoUtils; +import java.io.File; import java.util.UUID; /** @@ -87,8 +91,6 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka @DataClass.ParcelWith(ForInternedString.class) private final String manifestPackageName; - private boolean stub; - @Nullable @DataClass.ParcelWith(ForInternedString.class) protected String nativeLibraryDir; @@ -97,8 +99,6 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka @DataClass.ParcelWith(ForInternedString.class) protected String nativeLibraryRootDir; - private boolean nativeLibraryRootRequiresIsa; - @Nullable @DataClass.ParcelWith(ForInternedString.class) protected String primaryCpuAbi; @@ -116,44 +116,102 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka @DataClass.ParcelWith(ForInternedString.class) protected String seInfoUser; - private boolean coreApp; - - private boolean system; - private boolean factoryTest; + /** + * This is an appId, the uid if the userId is == USER_SYSTEM + */ + private int uid = -1; - private boolean systemExt; - private boolean privileged; - private boolean oem; - private boolean vendor; - private boolean product; - private boolean odm; + // This is kept around as a boolean to avoid flag calculation + // during ApplicationInfo generation. + private boolean nativeLibraryRootRequiresIsa; - private boolean signedWithPlatformKey; + private int mBooleans; /** - * This is an appId, the uid if the userId is == USER_SYSTEM + * @see ParsingPackageImpl.Booleans */ - private int uid = -1; + private static class Booleans { + @IntDef({ + CORE_APP, + SYSTEM, + FACTORY_TEST, + SYSTEM_EXT, + PRIVILEGED, + OEM, + VENDOR, + PRODUCT, + ODM, + SIGNED_WITH_PLATFORM_KEY, + NATIVE_LIBRARY_ROOT_REQUIRES_ISA, + STUB, + }) + public @interface Flags {} + + private static final int CORE_APP = 1; + private static final int SYSTEM = 1 << 1; + private static final int FACTORY_TEST = 1 << 2; + private static final int SYSTEM_EXT = 1 << 3; + private static final int PRIVILEGED = 1 << 4; + private static final int OEM = 1 << 5; + private static final int VENDOR = 1 << 6; + private static final int PRODUCT = 1 << 7; + private static final int ODM = 1 << 8; + private static final int SIGNED_WITH_PLATFORM_KEY = 1 << 9; + private static final int NATIVE_LIBRARY_ROOT_REQUIRES_ISA = 1 << 10; + private static final int STUB = 1 << 11; + } + + private ParsedPackage setBoolean(@Booleans.Flags int flag, boolean value) { + if (value) { + mBooleans |= flag; + } else { + mBooleans &= ~flag; + } + return this; + } + + private boolean getBoolean(@Booleans.Flags int flag) { + return (mBooleans & flag) != 0; + } + + // Derived fields + private int mBaseAppInfoFlags; + private int mBaseAppInfoPrivateFlags; + private String mBaseAppDataCredentialProtectedDirForSystemUser; + private String mBaseAppDataDeviceProtectedDirForSystemUser; @VisibleForTesting public PackageImpl(@NonNull String packageName, @NonNull String baseApkPath, @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp) { super(packageName, baseApkPath, path, manifestArray); this.manifestPackageName = this.packageName; - this.coreApp = isCoreApp; + setBoolean(Booleans.CORE_APP, isCoreApp); } @Override public ParsedPackage hideAsParsed() { + super.hideAsParsed(); return this; } @Override public AndroidPackage hideAsFinal() { // TODO(b/135203078): Lock as immutable + assignDerivedFields(); return this; } + private void assignDerivedFields() { + mBaseAppInfoFlags = PackageInfoUtils.appInfoFlags(this, null); + mBaseAppInfoPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null); + String baseAppDataDir = Environment.getDataDirectoryPath(getVolumeUuid()) + File.separator; + String systemUserSuffix = File.separator + UserHandle.USER_SYSTEM + File.separator; + mBaseAppDataCredentialProtectedDirForSystemUser = TextUtils.safeIntern( + baseAppDataDir + Environment.DIR_USER_CE + systemUserSuffix); + mBaseAppDataDeviceProtectedDirForSystemUser = TextUtils.safeIntern( + baseAppDataDir + Environment.DIR_USER_DE + systemUserSuffix); + } + @Override public long getLongVersionCode() { return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); @@ -437,8 +495,7 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka @Override public ParsedPackage setCoreApp(boolean coreApp) { - this.coreApp = coreApp; - return this; + return setBoolean(Booleans.CORE_APP, coreApp); } @Override @@ -456,8 +513,8 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka @Override public ApplicationInfo toAppInfoWithoutState() { ApplicationInfo appInfo = super.toAppInfoWithoutStateWithoutFlags(); - appInfo.flags = PackageInfoUtils.appInfoFlags(this, null); - appInfo.privateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null); + appInfo.flags = mBaseAppInfoFlags; + appInfo.privateFlags = mBaseAppInfoPrivateFlags; appInfo.nativeLibraryDir = nativeLibraryDir; appInfo.nativeLibraryRootDir = nativeLibraryRootDir; appInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; @@ -479,7 +536,6 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); sForInternedString.parcel(this.manifestPackageName, dest, flags); - dest.writeBoolean(this.stub); dest.writeString(this.nativeLibraryDir); dest.writeString(this.nativeLibraryRootDir); dest.writeBoolean(this.nativeLibraryRootRequiresIsa); @@ -489,22 +545,12 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka dest.writeString(this.seInfo); dest.writeString(this.seInfoUser); dest.writeInt(this.uid); - dest.writeBoolean(this.coreApp); - dest.writeBoolean(this.system); - dest.writeBoolean(this.factoryTest); - dest.writeBoolean(this.systemExt); - dest.writeBoolean(this.privileged); - dest.writeBoolean(this.oem); - dest.writeBoolean(this.vendor); - dest.writeBoolean(this.product); - dest.writeBoolean(this.odm); - dest.writeBoolean(this.signedWithPlatformKey); + dest.writeInt(this.mBooleans); } public PackageImpl(Parcel in) { super(in); this.manifestPackageName = sForInternedString.unparcel(in); - this.stub = in.readBoolean(); this.nativeLibraryDir = in.readString(); this.nativeLibraryRootDir = in.readString(); this.nativeLibraryRootRequiresIsa = in.readBoolean(); @@ -514,16 +560,9 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka this.seInfo = in.readString(); this.seInfoUser = in.readString(); this.uid = in.readInt(); - this.coreApp = in.readBoolean(); - this.system = in.readBoolean(); - this.factoryTest = in.readBoolean(); - this.systemExt = in.readBoolean(); - this.privileged = in.readBoolean(); - this.oem = in.readBoolean(); - this.vendor = in.readBoolean(); - this.product = in.readBoolean(); - this.odm = in.readBoolean(); - this.signedWithPlatformKey = in.readBoolean(); + this.mBooleans = in.readInt(); + + assignDerivedFields(); } public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() { @@ -544,9 +583,8 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka return manifestPackageName; } - @DataClass.Generated.Member public boolean isStub() { - return stub; + return getBoolean(Booleans.STUB); } @Nullable @@ -598,52 +636,52 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka @Override public boolean isCoreApp() { - return coreApp; + return getBoolean(Booleans.CORE_APP); } @Override public boolean isSystem() { - return system; + return getBoolean(Booleans.SYSTEM); } @Override public boolean isFactoryTest() { - return factoryTest; + return getBoolean(Booleans.FACTORY_TEST); } @Override public boolean isSystemExt() { - return systemExt; + return getBoolean(Booleans.SYSTEM_EXT); } @Override public boolean isPrivileged() { - return privileged; + return getBoolean(Booleans.PRIVILEGED); } @Override public boolean isOem() { - return oem; + return getBoolean(Booleans.OEM); } @Override public boolean isVendor() { - return vendor; + return getBoolean(Booleans.VENDOR); } @Override public boolean isProduct() { - return product; + return getBoolean(Booleans.PRODUCT); } @Override public boolean isOdm() { - return odm; + return getBoolean(Booleans.ODM); } @Override public boolean isSignedWithPlatformKey() { - return signedWithPlatformKey; + return getBoolean(Booleans.SIGNED_WITH_PLATFORM_KEY); } /** @@ -656,7 +694,7 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka @DataClass.Generated.Member public PackageImpl setStub(boolean value) { - stub = value; + setBoolean(Booleans.STUB, value); return this; } @@ -668,77 +706,72 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka @Override public PackageImpl setSystem(boolean value) { - system = value; + setBoolean(Booleans.SYSTEM, value); return this; } @Override public PackageImpl setFactoryTest(boolean value) { - factoryTest = value; + setBoolean(Booleans.FACTORY_TEST, value); return this; } @Override public PackageImpl setSystemExt(boolean value) { - systemExt = value; + setBoolean(Booleans.SYSTEM_EXT, value); return this; } @Override public PackageImpl setPrivileged(boolean value) { - privileged = value; + setBoolean(Booleans.PRIVILEGED, value); return this; } @Override public PackageImpl setOem(boolean value) { - oem = value; + setBoolean(Booleans.OEM, value); return this; } @Override public PackageImpl setVendor(boolean value) { - vendor = value; + setBoolean(Booleans.VENDOR, value); return this; } @Override public PackageImpl setProduct(boolean value) { - product = value; + setBoolean(Booleans.PRODUCT, value); return this; } @Override public PackageImpl setOdm(boolean value) { - odm = value; + setBoolean(Booleans.ODM, value); return this; } @Override public PackageImpl setSignedWithPlatformKey(boolean value) { - signedWithPlatformKey = value; + setBoolean(Booleans.SIGNED_WITH_PLATFORM_KEY, value); return this; } - /** - * This is an appId, the uid if the userId is == USER_SYSTEM - */ @Override public PackageImpl setUid(int value) { uid = value; return this; } - @DataClass.Generated( - time = 1580517688900L, - codegenVersion = "1.0.14", - sourceFile = "frameworks/base/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java", - inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String manifestPackageName\nprivate boolean stub\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String nativeLibraryDir\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String nativeLibraryRootDir\nprivate boolean nativeLibraryRootRequiresIsa\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String primaryCpuAbi\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String secondaryCpuAbi\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String secondaryNativeLibraryDir\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String seInfo\nprotected @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String seInfoUser\nprivate boolean system\nprivate boolean factoryTest\nprivate boolean systemExt\nprivate boolean privileged\nprivate boolean oem\nprivate boolean vendor\nprivate boolean product\nprivate boolean odm\nprivate boolean signedWithPlatformKey\nprivate int uid\npublic static final com.android.server.pm.parsing.pkg.Creator<com.android.server.pm.parsing.pkg.PackageImpl> CREATOR\npublic static com.android.server.pm.parsing.pkg.PackageImpl forParsing(java.lang.String,java.lang.String,java.lang.String,android.content.res.TypedArray,boolean)\npublic static com.android.server.pm.parsing.pkg.AndroidPackage buildFakeForDeletion(java.lang.String,java.lang.String)\npublic static @com.android.internal.annotations.VisibleForTesting android.content.pm.parsing.ParsingPackage forTesting(java.lang.String)\npublic static @com.android.internal.annotations.VisibleForTesting android.content.pm.parsing.ParsingPackage forTesting(java.lang.String,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage hideAsParsed()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.AndroidPackage hideAsFinal()\npublic @java.lang.Override long getLongVersionCode()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removePermission(int)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl addUsesOptionalLibrary(int,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl addUsesLibrary(int,java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removeUsesLibrary(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl removeUsesOptionalLibrary(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSigningDetails(android.content.pm.PackageParser.SigningDetails)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setRestrictUpdateHash(byte)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setRealPackage(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPersistent(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setDefaultToDeviceProtectedStorage(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setDirectBootAware(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearProtectedBroadcasts()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearOriginalPackages()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl clearAdoptPermissions()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setCodePath(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPackageName(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setAllComponentsDirectBootAware(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setBaseCodePath(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setNativeLibraryDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setNativeLibraryRootDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setPrimaryCpuAbi(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSecondaryCpuAbi(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSecondaryNativeLibraryDir(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSeInfo(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSeInfoUser(java.lang.String)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl setSplitCodePaths(java.lang.String[])\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl capPermissionPriorities()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.PackageImpl markNotActivitiesAsNotExportedIfSingleUser()\npublic @java.lang.Override java.util.UUID getStorageUuid()\npublic @java.lang.Deprecated @java.lang.Override java.lang.String toAppInfoToString()\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setCoreApp(boolean)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setVersionCode(int)\npublic @java.lang.Override com.android.server.pm.parsing.pkg.ParsedPackage setVersionCodeMajor(int)\npublic @java.lang.Override android.content.pm.ApplicationInfo toAppInfoWithoutState()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass PackageImpl extends android.content.pm.parsing.ParsingPackageImpl implements [com.android.server.pm.parsing.pkg.ParsedPackage, com.android.server.pm.parsing.pkg.AndroidPackage]\n@com.android.internal.util.DataClass(genConstructor=false, genParcelable=false, genAidl=false, genBuilder=false, genHiddenConstructor=false, genCopyConstructor=false)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code + // The following methods are explicitly not inside any interface. These are hidden under + // PackageImpl which is only accessible to the system server. This is to prevent/discourage + // usage of these fields outside of the utility classes. + public String getBaseAppDataCredentialProtectedDirForSystemUser() { + return mBaseAppDataCredentialProtectedDirForSystemUser; + } + public String getBaseAppDataDeviceProtectedDirForSystemUser() { + return mBaseAppDataDeviceProtectedDirForSystemUser; + } } diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java index 2660f2bda23b..657f32c25a89 100644 --- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java +++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java @@ -105,6 +105,9 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir); + /** + * This is an appId, the uid if the userId is == USER_SYSTEM + */ ParsedPackage setUid(int uid); ParsedPackage setVersionCode(int versionCode); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index 1d384e961dc3..dc9d1ac5240d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -155,8 +155,8 @@ public class PackageParserTest { @Test public void test_serializePackage() throws Exception { try (PackageParser2 pp = PackageParser2.forParsingFileWithDefaults()) { - ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, - true /* useCaches */); + AndroidPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, + true /* useCaches */).hideAsFinal(); Parcel p = Parcel.obtain(); pkg.writeToParcel(p, 0 /* flags */); @@ -591,7 +591,7 @@ public class PackageParserTest { null ) .setUse32BitAbi(true) - .setVolumeUuid("foo3") + .setVolumeUuid("d52ef59a-7def-4541-bf21-4c28ed4b65a0") .addPermission(permission) .addPermissionGroup(new ParsedPermissionGroup()) .addActivity(new ParsedActivity()) diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java index 4d8cc4647271..1ca3c7488f32 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java @@ -470,11 +470,16 @@ public class ScanTests { private PackageManagerService.ScanResult executeScan( PackageManagerService.ScanRequest scanRequest) throws PackageManagerException { - return PackageManagerService.scanPackageOnlyLI( + PackageManagerService.ScanResult result = PackageManagerService.scanPackageOnlyLI( scanRequest, mMockInjector, false /*isUnderFactoryTest*/, System.currentTimeMillis()); + + // Need to call hideAsFinal to cache derived fields. This is normally done in PMS, but not + // in this cut down flow used for the test. + ((ParsedPackage) result.pkgSetting.pkg).hideAsFinal(); + return result; } private static String createCodePath(String packageName) { diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt index d36dcce800eb..fb82b1d3d3f6 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt @@ -59,7 +59,9 @@ class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() { fun appInfo(flag: Int, fieldFunction: (ApplicationInfo) -> List<Any?>) = Param( flag, ApplicationInfo::class.java.simpleName, - ::oldAppInfo, ::newAppInfo, fieldFunction + { pkg, flags -> oldAppInfo(pkg, flags) }, + { pkg, flags -> newAppInfo(pkg, flags) }, + fieldFunction ) } diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt index 0f5f0af8f838..61252c473530 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt @@ -32,6 +32,7 @@ import android.content.pm.ServiceInfo import android.os.Bundle import android.os.Debug import android.os.Environment +import android.os.Process import android.util.SparseArray import androidx.test.platform.app.InstrumentationRegistry import com.android.server.pm.PackageManagerService @@ -54,7 +55,7 @@ open class AndroidPackageParsingTestBase { private const val VERIFY_ALL_APKS = true - /** For auditing memory usage differences */ + // For auditing memory usage differences to /sdcard/AndroidPackageParsingTestBase.hprof private const val DUMP_HPROF_TO_EXTERNAL = false val context: Context = InstrumentationRegistry.getInstrumentation().getContext() @@ -104,10 +105,12 @@ open class AndroidPackageParsingTestBase { @JvmStatic @BeforeClass fun setUpPackages() { + var uid = Process.FIRST_APPLICATION_UID apks.mapNotNull { try { packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) to - packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) + packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, + false) } catch (ignored: Exception) { // It is intentional that a failure of either call here will result in failing // both. Having null on one side would mean nothing to compare. Due to the @@ -117,8 +120,15 @@ open class AndroidPackageParsingTestBase { null } }.forEach { (old, new) -> + // Assign an arbitrary UID. This is normally done after parsing completes, inside + // PackageManagerService, but since that code isn't run here, need to mock it. This + // is equivalent to what the system would assign. + old.applicationInfo.uid = uid + new.uid = uid + uid++ + oldPackages += old - newPackages += new + newPackages += new.hideAsFinal() } if (DUMP_HPROF_TO_EXTERNAL) { @@ -131,12 +141,29 @@ open class AndroidPackageParsingTestBase { } } - fun oldAppInfo(pkg: PackageParser.Package, flags: Int = 0): ApplicationInfo? { - return PackageParser.generateApplicationInfo(pkg, flags, dummyUserState, 0) + fun oldAppInfo( + pkg: PackageParser.Package, + flags: Int = 0, + userId: Int = 0 + ): ApplicationInfo? { + return PackageParser.generateApplicationInfo(pkg, flags, dummyUserState, userId) + } + + fun newAppInfo( + pkg: AndroidPackage, + flags: Int = 0, + userId: Int = 0 + ): ApplicationInfo? { + return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyUserState, userId, + mockPkgSetting(pkg)) } - fun newAppInfo(pkg: AndroidPackage, flags: Int = 0): ApplicationInfo? { - return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyUserState, 0, + fun newAppInfoWithoutState( + pkg: AndroidPackage, + flags: Int = 0, + userId: Int = 0 + ): ApplicationInfo? { + return PackageInfoUtils.generateApplicationInfo(pkg, flags, dummyUserState, userId, mockPkgSetting(pkg)) } @@ -152,6 +179,7 @@ open class AndroidPackageParsingTestBase { private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> { this.pkg = aPkg + this.appId = aPkg.uid whenever(pkgState) { PackageStateUnserialized() } whenever(readUserState(anyInt())) { dummyUserState } } diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageInfoUserFieldsTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageInfoUserFieldsTest.kt new file mode 100644 index 000000000000..67b5d683de9a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageInfoUserFieldsTest.kt @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing + +import android.content.pm.ApplicationInfo +import android.content.pm.PackageParser +import android.os.Environment +import android.os.UserHandle +import android.platform.test.annotations.Presubmit +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Test + +/** + * As a performance optimization, the new parsing code builds the user data directories manually + * using string concatenation. This tries to mirror the logic that [Environment] uses, but it is + * still fragile to changes and potentially different device configurations. + * + * This compares the resultant values against the old [PackageParser] outputs as well as + * [ApplicationInfo]'s own [ApplicationInfo.initForUser]. + */ +@Presubmit +class PackageInfoUserFieldsTest : AndroidPackageParsingTestBase() { + + @Test + fun userEnvironmentValues() { + // Specifically use a large user ID to test assumptions about single character IDs + val userId = 110 + + oldPackages.zip(newPackages) + .map { (old, new) -> + (old to oldAppInfo(pkg = old, userId = userId)!!) to + (new to newAppInfo(pkg = new, userId = userId)!!) + } + .forEach { (oldPair, newPair) -> + val (oldPkg, oldInfo) = oldPair + val (newPkg, newInfo) = newPair + + val oldValuesActual = extractActual(oldInfo) + val newValuesActual = extractActual(newInfo) + val oldValuesExpected: Values + val newValuesExpected: Values + + val packageName = oldPkg.packageName + if (packageName == "android") { + val systemDataDir = Environment.getDataSystemDirectory().absolutePath + oldValuesExpected = Values( + uid = UserHandle.getUid(userId, + UserHandle.getAppId(oldPkg.applicationInfo.uid)), + userDe = null, + userCe = null, + dataDir = systemDataDir + ) + newValuesExpected = Values( + uid = UserHandle.getUid(userId, UserHandle.getAppId(newPkg.uid)), + userDe = null, + userCe = null, + dataDir = systemDataDir + ) + } else { + oldValuesExpected = extractExpected(oldInfo, oldInfo.uid, userId) + newValuesExpected = extractExpected(newInfo, newPkg.uid, userId) + } + + // Calls the internal ApplicationInfo logic to compare against. This must be + // done after saving the original values, since this will overwrite them. + oldInfo.initForUser(userId) + newInfo.initForUser(userId) + + val oldInitValues = extractActual(oldInfo) + val newInitValues = extractActual(newInfo) + + // The optimization is also done for the no state API that isn't used by the + // system. This API is still exposed publicly, so for this test we should + // verify it. + val newNoStateValues = extractActual( + newAppInfoWithoutState(newPkg, 0, userId)!!) + + assertAllEquals(packageName, + oldValuesActual, oldValuesExpected, oldInitValues, + newValuesActual, newValuesExpected, newInitValues, newNoStateValues) + } + } + + private fun assertAllEquals(packageName: String, vararg values: Values) { + // Local function to avoid accidentally calling wrong type + fun assertAllEquals(message: String, vararg values: Any?) { + values.forEachIndexed { index, value -> + if (index == 0) return@forEachIndexed + assertWithMessage("$message $index").that(values[0]).isEqualTo(value) + } + } + + assertAllEquals("$packageName mismatched uid", values.map { it.uid }) + assertAllEquals("$packageName mismatched userDe", values.map { it.userDe }) + assertAllEquals("$packageName mismatched userCe", values.map { it.userCe }) + assertAllEquals("$packageName mismatched dataDir", values.map { it.dataDir }) + } + + private fun extractActual(appInfo: ApplicationInfo) = Values( + uid = appInfo.uid, + userDe = appInfo.deviceProtectedDataDir, + userCe = appInfo.credentialProtectedDataDir, + dataDir = appInfo.dataDir + ) + + private fun extractExpected(appInfo: ApplicationInfo, appIdUid: Int, userId: Int): Values { + val userDe = Environment.getDataUserDePackageDirectory(appInfo.volumeUuid, userId, + appInfo.packageName).absolutePath + val userCe = Environment.getDataUserCePackageDirectory(appInfo.volumeUuid, userId, + appInfo.packageName).absolutePath + val dataDir = if (appInfo.isDefaultToDeviceProtectedStorage) { + appInfo.deviceProtectedDataDir + } else { + appInfo.credentialProtectedDataDir + } + + return Values( + uid = UserHandle.getUid(userId, UserHandle.getAppId(appIdUid)), + userDe = userDe, + userCe = userCe, + dataDir = dataDir + ) + } + + data class Values( + val uid: Int, + val userDe: String?, + val userCe: String?, + val dataDir: String? + ) +} |