summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Winson Chiu <chiuwinson@google.com> 2020-09-15 16:22:37 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-09-15 16:22:37 +0000
commit40e1467fd0e7d02c59cd0b2db9599596e98bd4bc (patch)
tree96d3b779f7bd0022bdb593ae2920415e975e4d61
parentad9c3966184217c70264d92ce37853da2d503d9c (diff)
parentc086fe9ac1bd33ddc6c6aa681f7c92eababdceb0 (diff)
Merge "Optimize (Parsing)PackageImpl implementation"
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java91
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java3
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java537
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageRead.java2
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java3
-rw-r--r--core/java/android/os/Environment.java47
-rw-r--r--core/java/android/os/TEST_MAPPING9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java12
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java96
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java193
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt42
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/PackageInfoUserFieldsTest.kt145
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?
+ )
+}