Important migration for new ParsingPackage/ParsedPackage split
Part of the Parsing/ParsedPackage split into core/server.
This splits all the "important" changes, or those which change
significant code/logic and that requires a closer look during
review.
Bug: 135203078
Test: enumerated in first commit of change ID
Ib4fe51d729a56bfb0ea1316e577358ba0dfceccf
Change-Id: Ie0e4394de2b3063121d850060fcd58622511c59d
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 76f6ef6..4ea6370 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -29,8 +29,10 @@
import android.content.pm.PackageManager.ComponentInfoFlags;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManager.ResolveInfoFlags;
-import android.content.pm.parsing.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
import android.content.pm.parsing.ComponentParseUtils;
+import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.ArrayMap;
@@ -763,8 +765,8 @@
throws IOException;
/** Returns {@code true} if the specified component is enabled and matches the given flags. */
- public abstract boolean isEnabledAndMatches(
- @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId);
+ public abstract boolean isEnabledAndMatches(@NonNull ParsedMainComponent component, int flags,
+ int userId);
/** Returns {@code true} if the given user requires extra badging for icons. */
public abstract boolean userNeedsBadging(int userId);
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index b9a30bb..72fae77 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -512,7 +512,7 @@
try {
ParsedPackage pkg = parser.parseParsedPackage(installationPath, 0, false);
int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA;
- ApkParseUtils.collectCertificates(pkg, false);
+ pkg.setSigningDetails(ApkParseUtils.collectCertificates(pkg, false));
return PackageInfoUtils.generate(pkg, null, flags, 0, 0, null, new PackageUserState(),
UserHandle.getCallingUserId());
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index a1250cb..6a582b1 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -207,14 +207,14 @@
/** Returns true if the querying package may query for the potential target package */
private static boolean canQueryViaComponents(AndroidPackage querying,
AndroidPackage potentialTarget) {
- if (querying.getQueriesIntents() != null) {
+ if (!querying.getQueriesIntents().isEmpty()) {
for (Intent intent : querying.getQueriesIntents()) {
if (matchesIntentFilters(intent, potentialTarget)) {
return true;
}
}
}
- if (querying.getQueriesProviders() != null
+ if (!querying.getQueriesProviders().isEmpty()
&& matchesProviders(querying.getQueriesProviders(), potentialTarget)) {
return true;
}
@@ -223,7 +223,7 @@
private static boolean canQueryViaPackage(AndroidPackage querying,
AndroidPackage potentialTarget) {
- return querying.getQueriesPackages() != null
+ return !querying.getQueriesPackages().isEmpty()
&& querying.getQueriesPackages().contains(potentialTarget.getPackageName());
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f6eb76b..d9cb212 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -209,20 +209,16 @@
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ApkParseUtils;
import android.content.pm.parsing.ComponentParseUtils;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
-import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
-import android.content.pm.parsing.PackageImpl;
-import android.content.pm.parsing.PackageInfoUtils;
-import android.content.pm.parsing.ParsedPackage;
-import android.content.pm.parsing.library.PackageBackwardCompatibility;
+import android.content.pm.parsing.ParsingPackageRead;
+import android.content.pm.parsing.ParsingPackageUtils;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
@@ -341,6 +337,13 @@
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.dex.ViewCompiler;
+import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.library.PackageBackwardCompatibility;
+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.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -1011,13 +1014,13 @@
private final AppsFilter mAppsFilter;
- class PackageParserCallback implements PackageParser.Callback {
+ class PackageParserCallback extends PackageParser2.Callback {
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
}
- final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
+ final PackageParser2.Callback mPackageParserCallback = new PackageParserCallback();
// Currently known shared libraries.
final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
@@ -2033,7 +2036,7 @@
mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers);
}
- final String packageName = res.pkg.getAppInfoPackageName();
+ final String packageName = res.pkg.getPackageName();
// Determine the set of users who are adding this package for
// the first time vs. those who are seeing an update.
@@ -2083,7 +2086,7 @@
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.uid);
- boolean isSystem = res.pkg.isSystemApp();
+ boolean isSystem = res.pkg.isSystem();
sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds);
@@ -2859,12 +2862,8 @@
final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
- PackageParser packageParser = new PackageParser();
- packageParser.setSeparateProcesses(mSeparateProcesses);
- packageParser.setOnlyCoreApps(mOnlyCore);
- packageParser.setDisplayMetrics(mMetrics);
- packageParser.setCacheDir(mCacheDir);
- packageParser.setCallback(mPackageParserCallback);
+ PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
+ mMetrics, mCacheDir, mPackageParserCallback);
ExecutorService executorService = ParallelPackageParser.makeExecutorService();
// Collect vendor/product/system_ext overlay packages. (Do this before scanning
@@ -2902,7 +2901,9 @@
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
- mOverlayConfig = OverlayConfig.initializeSystemInstance(mPmInternal::forEachPackage);
+ mOverlayConfig = OverlayConfig.initializeSystemInstance(
+ consumer -> mPmInternal.forEachPackage(
+ pkg -> consumer.accept(pkg, pkg.isSystem())));
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
@@ -3044,7 +3045,7 @@
// special privileges
removePackageLI(pkg, true);
try {
- final File codePath = new File(pkg.getAppInfoCodePath());
+ final File codePath = new File(pkg.getCodePath());
scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -4208,7 +4209,7 @@
throw new SecurityException("Package " + packageName + " is currently frozen!");
}
- if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) {
+ if (!userKeyUnlocked && !AndroidPackageUtils.isEncryptionAware(ps.pkg)) {
throw new SecurityException("Package " + packageName + " is not encryption aware!");
}
}
@@ -4574,7 +4575,7 @@
// reader
synchronized (mLock) {
final AndroidPackage p = mPackages.get(packageName);
- if (p != null && p.isMatch(flags)) {
+ if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
PackageSetting ps = getPackageSettingInternal(p.getPackageName(), callingUid);
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return -1;
@@ -4604,7 +4605,7 @@
// reader
synchronized (mLock) {
final AndroidPackage p = mPackages.get(packageName);
- if (p != null && p.isMatch(flags)) {
+ if (p != null && AndroidPackageUtils.isMatchForSystemOnly(p, flags)) {
PackageSetting ps = getPackageSetting(p.getPackageName());
if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
return null;
@@ -8563,7 +8564,7 @@
return null;
}
final ParsedInstrumentation i = mInstrumentation.get(component);
- return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags);
+ return PackageInfoUtils.generateInstrumentationInfo(i, pkg, flags, callingUserId);
}
}
@@ -8576,11 +8577,12 @@
if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) {
return ParceledListSlice.emptyList();
}
- return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
+ return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags,
+ callingUserId));
}
private @NonNull List<InstrumentationInfo> queryInstrumentationInternal(String targetPackage,
- int flags) {
+ int flags, int userId) {
ArrayList<InstrumentationInfo> finalList = new ArrayList<>();
// reader
@@ -8593,7 +8595,7 @@
AndroidPackage pkg = mPackages.get(p.getPackageName());
if (pkg != null) {
InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p,
- pkg, flags);
+ pkg, flags, userId);
if (ii != null) {
finalList.add(ii);
}
@@ -8606,7 +8608,7 @@
}
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
- long currentTime, PackageParser packageParser, ExecutorService executorService) {
+ long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
@@ -8616,7 +8618,7 @@
}
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
- PackageParser packageParser, ExecutorService executorService) {
+ PackageParser2 packageParser, ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + scanDir);
@@ -8720,7 +8722,8 @@
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
- ApkParseUtils.collectCertificates(parsedPackage, skipVerify);
+ parsedPackage.setSigningDetails(
+ ParsingPackageUtils.collectCertificates(parsedPackage, skipVerify));
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -8774,16 +8777,13 @@
private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
- PackageParser pp = new PackageParser();
- pp.setSeparateProcesses(mSeparateProcesses);
- pp.setOnlyCoreApps(mOnlyCore);
- pp.setDisplayMetrics(mMetrics);
- pp.setCallback(mPackageParserCallback);
+ PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null,
+ mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final ParsedPackage parsedPackage;
try {
- parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false);
+ parsedPackage = pp.parsePackage(scanFile, parseFlags, false);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -8869,18 +8869,6 @@
final boolean pkgAlreadyExists;
PackageSetting pkgSetting;
- // NOTE: installPackageLI() has the same code to setup the package's
- // application info. This probably should be done lower in the call
- // stack [such as scanPackageOnly()]. However, we verify the application
- // info prior to that [in scanPackageNew()] and thus have to setup
- // the application info early.
- // TODO(b/135203078): Remove all of these application info calls
- parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
- .setApplicationInfoCodePath(parsedPackage.getCodePath())
- .setApplicationInfoResourcePath(parsedPackage.getCodePath())
- .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
- .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
-
synchronized (mLock) {
renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
@@ -9957,7 +9945,7 @@
// Or:
// - Package manager is in a state where package isn't scanned yet. This will
// get called again after scanning to fix the dependencies.
- if (pkg.isLibrary()) {
+ if (AndroidPackageUtils.isLibrary(pkg)) {
if (pkg.getStaticSharedLibName() != null) {
SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion());
@@ -9994,7 +9982,7 @@
}
}
if (p != null) {
- usesLibraryFiles.addAll(p.getAllCodePaths());
+ usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(p));
// If the package provides libraries, add the dependency to them.
applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
definingLibrary.addDependency(dependency);
@@ -10026,18 +10014,18 @@
// that libraries are searched in the correct order) and must have no
// duplicates.
ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
- if (pkg.getUsesLibraries() != null) {
+ if (!pkg.getUsesLibraries().isEmpty()) {
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null,
pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null,
availablePackages, existingLibraries, newLibraries);
}
- if (pkg.getUsesStaticLibraries() != null) {
+ if (!pkg.getUsesStaticLibraries().isEmpty()) {
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(),
pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(),
pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos,
availablePackages, existingLibraries, newLibraries);
}
- if (pkg.getUsesOptionalLibraries() != null) {
+ if (!pkg.getUsesOptionalLibraries().isEmpty()) {
usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(),
null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(),
usesLibraryInfos, availablePackages, existingLibraries, newLibraries);
@@ -10607,7 +10595,7 @@
}
pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails;
- if (pkg.getAdoptPermissions() != null) {
+ if (!pkg.getAdoptPermissions().isEmpty()) {
// This package wants to adopt ownership of permissions from
// another package.
for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) {
@@ -10848,8 +10836,8 @@
}
// Initialize package source and resource directories
- final File destCodeFile = new File(parsedPackage.getAppInfoCodePath());
- final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath());
+ final File destCodeFile = new File(parsedPackage.getCodePath());
+ final File destResourceFile = new File(parsedPackage.getCodePath());
// We keep references to the derived CPU Abis from settings in oder to reuse
// them in the case where we're not upgrading or booting for the first time.
@@ -10878,7 +10866,7 @@
}
String[] usesStaticLibraries = null;
- if (parsedPackage.getUsesStaticLibraries() != null) {
+ if (!parsedPackage.getUsesStaticLibraries().isEmpty()) {
usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()];
parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries);
}
@@ -10898,8 +10886,7 @@
} else {
// make a deep copy to avoid modifying any existing system state.
pkgSetting = new PackageSetting(pkgSetting);
- // TODO(b/135203078): Remove entirely. Set package directly.
- parsedPackage.setPackageSettingCallback(pkgSetting);
+ pkgSetting.pkg = parsedPackage;
// REMOVE SharedUserSetting from method; update in a separate call.
//
@@ -10945,9 +10932,7 @@
.setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
injector.getCompatibility()))
.setSeInfoUser(SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState(
- userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)))
- .setProcessName(fixProcessName(parsedPackage.getPackageName(),
- parsedPackage.getProcessName()));
+ userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)));
if (!isPlatformPackage) {
// Get all of our default paths setup
@@ -10964,7 +10949,7 @@
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
- final boolean extractNativeLibs = !parsedPackage.isLibrary();
+ final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride,
extractNativeLibs);
@@ -11104,13 +11089,13 @@
}
pkgSetting.setTimeStamp(scanFileTime);
// TODO(b/135203078): Remove, move to constructor
- parsedPackage.setPackageSettingCallback(pkgSetting);
+ pkgSetting.pkg = parsedPackage;
pkgSetting.pkgFlags = parsedPackage.getFlags();
if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) {
pkgSetting.versionCode = parsedPackage.getLongVersionCode();
}
// Update volume if needed
- final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid();
+ final String volumeUuid = parsedPackage.getVolumeUuid();
if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) {
Slog.i(PackageManagerService.TAG,
"Update" + (pkgSetting.isSystem() ? " system" : "")
@@ -11122,14 +11107,15 @@
SharedLibraryInfo staticSharedLibraryInfo = null;
if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) {
- staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage);
+ staticSharedLibraryInfo =
+ AndroidPackageUtils.createSharedLibraryForStatic(parsedPackage);
}
List<SharedLibraryInfo> dynamicSharedLibraryInfos = null;
if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) {
dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size());
for (String name : parsedPackage.getLibraryNames()) {
dynamicSharedLibraryInfos.add(
- SharedLibraryInfo.createForDynamic(parsedPackage, name));
+ AndroidPackageUtils.createSharedLibraryForDynamic(parsedPackage, name));
}
}
@@ -11202,7 +11188,7 @@
parsedPackage.setAllComponentsDirectBootAware(true);
}
if (compressedFileExists(parsedPackage.getCodePath())) {
- parsedPackage.setIsStub(true);
+ parsedPackage.setStub(true);
}
} else {
parsedPackage
@@ -11257,7 +11243,7 @@
private <T extends ComponentParseUtils.ParsedMainComponent>
void assertPackageProcesses(AndroidPackage pkg, List<T> components,
- ArrayMap<String, ComponentParseUtils.ParsedProcess> procs, String compName)
+ Map<String, ComponentParseUtils.ParsedProcess> procs, String compName)
throws PackageManagerException {
if (components == null) {
return;
@@ -11291,8 +11277,7 @@
assertCodePolicy(pkg);
}
- if (pkg.getAppInfoCodePath() == null ||
- pkg.getAppInfoResourcePath() == null) {
+ if (pkg.getCodePath() == null) {
// Bail out. The resource and code paths haven't been set.
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Code and resource paths haven't been set correctly");
@@ -11375,49 +11360,49 @@
}
// Static shared libs cannot declare activities
- if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) {
+ if (!pkg.getActivities().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare activities");
}
// Static shared libs cannot declare services
- if (pkg.getServices() != null && !pkg.getServices().isEmpty()) {
+ if (!pkg.getServices().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare services");
}
// Static shared libs cannot declare providers
- if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) {
+ if (!pkg.getProviders().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare content providers");
}
// Static shared libs cannot declare receivers
- if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) {
+ if (!pkg.getReceivers().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare broadcast receivers");
}
// Static shared libs cannot declare permission groups
- if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) {
+ if (!pkg.getPermissionGroups().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare permission groups");
}
// Static shared libs cannot declare features
- if (pkg.getFeatures() != null && !pkg.getFeatures().isEmpty()) {
+ if (!pkg.getFeatures().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare features");
}
// Static shared libs cannot declare permissions
- if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
+ if (!pkg.getPermissions().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare permissions");
}
// Static shared libs cannot declare protected broadcasts
- if (pkg.getProtectedBroadcasts() != null) {
+ if (!pkg.getProtectedBroadcasts().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare protected broadcasts");
}
@@ -11479,12 +11464,11 @@
+ " and requiring known paths " + known.codePathString
+ " & " + known.resourcePathString);
}
- if (!pkg.getAppInfoCodePath().equals(known.codePathString)
- || !pkg.getAppInfoResourcePath().equals(
- known.resourcePathString)) {
+ if (!pkg.getCodePath().equals(known.codePathString)
+ || !pkg.getCodePath().equals(known.resourcePathString)) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
"Application package " + pkg.getPackageName()
- + " found at " + pkg.getAppInfoCodePath()
+ + " found at " + pkg.getCodePath()
+ " but expected at " + known.codePathString
+ "; ignoring.");
}
@@ -11506,8 +11490,8 @@
// If this package has defined explicit processes, then ensure that these are
// the only processes used by its components.
- final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
- if (procs != null) {
+ final Map<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
+ if (!procs.isEmpty()) {
if (!procs.containsKey(pkg.getProcessName())) {
throw new PackageManagerException(
INSTALL_FAILED_PROCESS_NOT_DEFINED,
@@ -11793,7 +11777,7 @@
if (clientLibPkgs != null) {
for (int i=0; i<clientLibPkgs.size(); i++) {
AndroidPackage clientPkg = clientLibPkgs.get(i);
- killApplication(clientPkg.getAppInfoPackageName(),
+ killApplication(clientPkg.getPackageName(),
clientPkg.getUid(), "update lib");
}
}
@@ -11807,7 +11791,7 @@
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
- mPackages.put(pkg.getAppInfoPackageName(), pkg);
+ mPackages.put(pkg.getPackageName(), pkg);
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
mApexManager.registerApkInApex(pkg);
}
@@ -11887,8 +11871,8 @@
// Set up information for custom user intent resolution activity.
mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState();
mResolveActivity.name = mCustomResolverComponentName.getClassName();
- mResolveActivity.packageName = pkg.getAppInfoPackageName();
- mResolveActivity.processName = pkg.getAppInfoProcessName();
+ mResolveActivity.packageName = pkg.getPackageName();
+ mResolveActivity.processName = pkg.getProcessName();
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
@@ -13727,7 +13711,7 @@
try {
if (bm.isUserReadyForBackup(userId)) {
bm.restoreAtInstallForUser(
- userId, res.pkg.getAppInfoPackageName(), token);
+ userId, res.pkg.getPackageName(), token);
} else {
Slog.w(TAG, "User " + userId + " is not ready. Restore at install "
+ "didn't take place.");
@@ -13755,7 +13739,7 @@
IRollbackManager rm = IRollbackManager.Stub.asInterface(
ServiceManager.getService(Context.ROLLBACK_SERVICE));
- final String packageName = res.pkg.getAppInfoPackageName();
+ final String packageName = res.pkg.getPackageName();
final String seInfo = res.pkg.getSeInfo();
final int[] allUsers = mUserManager.getUserIds();
final int[] installedUsers;
@@ -13815,7 +13799,7 @@
if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
continue;
}
- if (packageName.equals(data.res.pkg.getAppInfoPackageName())) {
+ if (packageName.equals(data.res.pkg.getPackageName())) {
// right package; but is it for the right user?
for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
if (userId == data.res.newUsers[uIndex]) {
@@ -15000,14 +14984,6 @@
parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, parsedPackage.getSplitCodePaths()));
- // Reflect the rename in app info
- // TODO(b/135203078): Remove all of these application info calls
- parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
- .setApplicationInfoCodePath(parsedPackage.getCodePath())
- .setApplicationInfoResourcePath(parsedPackage.getCodePath())
- .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
- .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
-
return true;
}
@@ -15117,14 +15093,6 @@
return false;
}
- // Reflect the move in app info
- // TODO(b/135203078): Remove all of these application info calls
- parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid())
- .setApplicationInfoCodePath(parsedPackage.getCodePath())
- .setApplicationInfoResourcePath(parsedPackage.getCodePath())
- .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath())
- .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths());
-
return true;
}
@@ -15922,8 +15890,8 @@
// which means we are replacing another update that is already
// installed. We need to make sure to delete the older one's .apk.
res.removedInfo.args = createInstallArgsForExisting(
- oldPackage.getAppInfoCodePath(),
- oldPackage.getAppInfoResourcePath(),
+ oldPackage.getCodePath(),
+ oldPackage.getCodePath(),
getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(),
oldPackage.getSecondaryCpuAbi()));
} else {
@@ -15944,14 +15912,14 @@
// If deleted package lived in a container, give users a chance to
// relinquish resources before killing.
- if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
+ if (isExternal(oldPackage)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + oldPackage
+ " is ASEC-hosted -> UNAVAILABLE");
}
final int[] uidArray = new int[]{oldPackage.getUid()};
final ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(oldPackage.getAppInfoPackageName());
+ pkgList.add(oldPackage.getPackageName());
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
}
@@ -16328,16 +16296,14 @@
| PackageParser.PARSE_ENFORCE_CODE
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
- PackageParser pp = new PackageParser();
- pp.setSeparateProcesses(mSeparateProcesses);
- pp.setDisplayMetrics(mMetrics);
- pp.setCallback(mPackageParserCallback);
+ PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
+ mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
ParsedPackage parsedPackage;
try {
- parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false);
- DexMetadataHelper.validatePackageDexMetadata(parsedPackage);
+ parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
+ AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
} catch (PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
@@ -16393,7 +16359,8 @@
parsedPackage.setSigningDetails(args.signingDetails);
} else {
// TODO(b/136132412): skip for Incremental installation
- ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */);
+ parsedPackage.setSigningDetails(
+ ParsingPackageUtils.collectCertificates(parsedPackage, false /* skipVerify */));
}
} catch (PackageParserException e) {
throw new PrepareFailure("Failed collect during installPackageLI", e);
@@ -16636,7 +16603,7 @@
try {
String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())
? args.abiOverride : parsedPackage.getCpuAbiOverride());
- final boolean extractNativeLibs = !parsedPackage.isLibrary();
+ final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
parsedPackage, abiOverride, extractNativeLibs);
@@ -19980,7 +19947,7 @@
// We're dealing with a component level state change
// First, verify that this is a valid class name.
AndroidPackage pkg = pkgSetting.pkg;
- if (pkg == null || !pkg.hasComponentClassName(className)) {
+ if (pkg == null || !AndroidPackageUtils.hasComponentClassName(pkg, className)) {
if (pkg != null &&
pkg.getTargetSdkVersion() >=
Build.VERSION_CODES.JELLY_BEAN) {
@@ -21336,7 +21303,7 @@
final int[] packageUids = new int[size];
for (int i = 0; i < size; i++) {
final AndroidPackage pkg = packages.get(i);
- packageNames[i] = pkg.getAppInfoPackageName();
+ packageNames[i] = pkg.getPackageName();
packageUids[i] = pkg.getUid();
}
sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
@@ -21801,7 +21768,7 @@
ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags,
appId, seInfo, pkg.getTargetSdkVersion());
} catch (InstallerException e) {
- if (pkg.isSystemApp()) {
+ if (pkg.isSystem()) {
logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName
+ ", but trying to recover: " + e);
destroyAppDataLeafLIF(pkg, userId, flags);
@@ -22054,7 +22021,7 @@
|| shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
}
- if (pkg.isSystemApp()) {
+ if (pkg.isSystem()) {
throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
"Cannot move system application");
}
@@ -22080,7 +22047,7 @@
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
"Package already moved to " + volumeUuid);
}
- if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
+ if (!pkg.isExternalStorage() && isPackageDeviceAdminOnAnyUser(packageName)) {
throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
"Device admin cannot be moved");
}
@@ -23352,7 +23319,7 @@
}
@Override
- public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) {
+ public boolean isEnabledAndMatches(ParsedMainComponent component, int flags, int userId) {
synchronized (mLock) {
AndroidPackage pkg = getPackage(component.getPackageName());
return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId);
@@ -24177,12 +24144,12 @@
if (p == null) {
return false;
}
- return p.canHaveOatDir();
+ return AndroidPackageUtils.canHaveOatDir(p, p.isUpdatedSystemApp());
}
}
private String getOatDir(AndroidPackage pkg) {
- if (!pkg.canHaveOatDir()) {
+ if (!AndroidPackageUtils.canHaveOatDir(pkg, pkg.isUpdatedSystemApp())) {
return null;
}
File codePath = new File(pkg.getCodePath());
@@ -24202,7 +24169,7 @@
}
instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(),
pkg.getSecondaryCpuAbi());
- codePaths = pkg.getAllCodePaths();
+ codePaths = AndroidPackageUtils.getAllCodePaths(pkg);
oatDir = getOatDir(pkg);
for (String codePath : codePaths) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index a9035b2..6040224 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -40,8 +40,7 @@
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.ParsingPackageUtils;
import android.os.Build;
import android.os.Debug;
import android.os.Environment;
@@ -66,6 +65,7 @@
import com.android.server.EventLogTags;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionsState;
import dalvik.system.VMRuntime;
@@ -544,7 +544,8 @@
private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
PackageSetting disabledPkgSetting) {
try {
- ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
+ disabledPkgSetting.pkg.mutate().setSigningDetails(
+ ParsingPackageUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */));
if (pkgSetting.signatures.mSigningDetails.checkCapability(
disabledPkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index d83e6f4..97342c0 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -20,13 +20,12 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-import android.content.pm.parsing.AndroidPackage;
-import android.content.pm.parsing.ParsedPackage;
import android.service.pm.PackageProto;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionsState;
import java.io.File;
@@ -39,8 +38,7 @@
/**
* Settings data for a particular package we know about.
*/
-public final class PackageSetting extends PackageSettingBase implements
- ParsedPackage.PackageSettingCallback {
+public final class PackageSetting extends PackageSettingBase {
int appId;
public AndroidPackage pkg;
@@ -323,10 +321,4 @@
Set<String> mimeGroupNames = other.mimeGroups != null ? other.mimeGroups.keySet() : null;
updateMimeGroups(mimeGroupNames);
}
-
- // TODO(b/135203078): Move to constructor
- @Override
- public void setAndroidPackage(AndroidPackage pkg) {
- this.pkg = pkg;
- }
}
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 448dad0..21334c0 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -19,12 +19,13 @@
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.content.pm.PackageParser;
-import android.content.pm.parsing.ParsedPackage;
import android.os.Process;
import android.os.Trace;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ConcurrentUtils;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
@@ -50,11 +51,11 @@
Process.THREAD_PRIORITY_FOREGROUND);
}
- private final PackageParser mPackageParser;
+ private final PackageParser2 mPackageParser;
private final ExecutorService mExecutorService;
- ParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
+ ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
mPackageParser = packageParser;
mExecutorService = executorService;
}
@@ -125,6 +126,6 @@
@VisibleForTesting
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageParser.PackageParserException {
- return mPackageParser.parseParsedPackage(scanFile, parseFlags, true);
+ return mPackageParser.parsePackage(scanFile, parseFlags, true);
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 60c8b94..5694428 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3155,7 +3155,7 @@
LocalServices.getService(PackageManagerInternal.class);
for (PackageSetting ps : mPackages.values()) {
if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null
- && ps.pkg.getPreferredActivityFilters() != null) {
+ && !ps.pkg.getPreferredActivityFilters().isEmpty()) {
List<ComponentParseUtils.ParsedActivityIntentInfo> intents
= ps.pkg.getPreferredActivityFilters();
for (int i=0; i<intents.size(); i++) {
@@ -4608,10 +4608,10 @@
pw.print(" (override=true)");
}
pw.println();
- if (ps.pkg.getQueriesPackages() != null) {
+ if (ps.pkg.getQueriesPackages().isEmpty()) {
pw.append(prefix).append(" queriesPackages=").println(ps.pkg.getQueriesPackages());
}
- if (ps.pkg.getQueriesIntents() != null) {
+ if (!ps.pkg.getQueriesIntents().isEmpty()) {
pw.append(prefix).append(" queriesIntents=").println(ps.pkg.getQueriesIntents());
}
pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.getDataDir());
@@ -4707,11 +4707,10 @@
pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles[i]);
}
}
- final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
- if (procs != null) {
+ final Map<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
+ if (!procs.isEmpty()) {
pw.print(prefix); pw.println(" processes:");
- for (int i = 0; i < procs.size(); i++) {
- final ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
+ for (ComponentParseUtils.ParsedProcess proc : procs.values()) {
pw.print(prefix); pw.print(" "); pw.println(proc.name);
if (proc.deniedPermissions != null) {
for (int j = 0; j < proc.deniedPermissions.size(); j++) {
@@ -4751,7 +4750,7 @@
pw.print(prefix); pw.print(" overlayCategory="); pw.println(pkg.getOverlayCategory());
}
- if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) {
+ if (pkg != null && !pkg.getPermissions().isEmpty()) {
final List<ParsedPermission> perms = pkg.getPermissions();
pw.print(prefix); pw.println(" declared permissions:");
for (int i=0; i<perms.size(); i++) {
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
new file mode 100644
index 0000000..e5e1b0b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -0,0 +1,200 @@
+/*
+ * 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.annotation.NonNull;
+import android.content.pm.PackageParserCacheHelper;
+import android.os.Parcel;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStat;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PackageCacher {
+
+ private static final String TAG = "PackageCacher";
+
+ /**
+ * Total number of packages that were read from the cache. We use it only for logging.
+ */
+ public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger();
+
+ @NonNull
+ private File mCacheDir;
+
+ public PackageCacher(@NonNull File cacheDir) {
+ this.mCacheDir = cacheDir;
+ }
+
+ /**
+ * Returns the cache key for a specified {@code packageFile} and {@code flags}.
+ */
+ private String getCacheKey(File packageFile, int flags) {
+ StringBuilder sb = new StringBuilder(packageFile.getName());
+ sb.append('-');
+ sb.append(flags);
+
+ return sb.toString();
+ }
+
+ @VisibleForTesting
+ protected ParsedPackage fromCacheEntry(byte[] bytes) {
+ return fromCacheEntryStatic(bytes);
+ }
+
+ /** static version of {@link #fromCacheEntry} for unit tests. */
+ @VisibleForTesting
+ public static ParsedPackage fromCacheEntryStatic(byte[] bytes) {
+ final Parcel p = Parcel.obtain();
+ p.unmarshall(bytes, 0, bytes.length);
+ p.setDataPosition(0);
+
+ final PackageParserCacheHelper.ReadHelper helper = new PackageParserCacheHelper.ReadHelper(p);
+ helper.startAndInstall();
+
+ // TODO(b/135203078): Hide PackageImpl constructor?
+ ParsedPackage pkg = new PackageImpl(p);
+
+ p.recycle();
+
+ sCachedPackageReadCount.incrementAndGet();
+
+ return pkg;
+ }
+
+ @VisibleForTesting
+ protected byte[] toCacheEntry(ParsedPackage pkg) {
+ return toCacheEntryStatic(pkg);
+
+ }
+
+ /** static version of {@link #toCacheEntry} for unit tests. */
+ @VisibleForTesting
+ public static byte[] toCacheEntryStatic(ParsedPackage pkg) {
+ final Parcel p = Parcel.obtain();
+ final PackageParserCacheHelper.WriteHelper helper = new PackageParserCacheHelper.WriteHelper(p);
+
+ pkg.writeToParcel(p, 0 /* flags */);
+
+ helper.finishAndUninstall();
+
+ byte[] serialized = p.marshall();
+ p.recycle();
+
+ return serialized;
+ }
+
+ /**
+ * Given a {@code packageFile} and a {@code cacheFile} returns whether the
+ * cache file is up to date based on the mod-time of both files.
+ */
+ private static boolean isCacheUpToDate(File packageFile, File cacheFile) {
+ try {
+ // NOTE: We don't use the File.lastModified API because it has the very
+ // non-ideal failure mode of returning 0 with no excepions thrown.
+ // The nio2 Files API is a little better but is considerably more expensive.
+ final StructStat pkg = Os.stat(packageFile.getAbsolutePath());
+ final StructStat cache = Os.stat(cacheFile.getAbsolutePath());
+ return pkg.st_mtime < cache.st_mtime;
+ } catch (ErrnoException ee) {
+ // The most common reason why stat fails is that a given cache file doesn't
+ // exist. We ignore that here. It's easy to reason that it's safe to say the
+ // cache isn't up to date if we see any sort of exception here.
+ //
+ // (1) Exception while stating the package file : This should never happen,
+ // and if it does, we do a full package parse (which is likely to throw the
+ // same exception).
+ // (2) Exception while stating the cache file : If the file doesn't exist, the
+ // cache is obviously out of date. If the file *does* exist, we can't read it.
+ // We will attempt to delete and recreate it after parsing the package.
+ if (ee.errno != OsConstants.ENOENT) {
+ Slog.w("Error while stating package cache : ", ee);
+ }
+
+ return false;
+ }
+ }
+
+ /**
+ * Returns the cached parse result for {@code packageFile} for parse flags {@code flags},
+ * or {@code null} if no cached result exists.
+ */
+ public ParsedPackage getCachedResult(File packageFile, int flags) {
+ final String cacheKey = getCacheKey(packageFile, flags);
+ final File cacheFile = new File(mCacheDir, cacheKey);
+
+ try {
+ // If the cache is not up to date, return null.
+ if (!isCacheUpToDate(packageFile, cacheFile)) {
+ return null;
+ }
+
+ final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
+ return fromCacheEntry(bytes);
+ } catch (Throwable e) {
+ Slog.w(TAG, "Error reading package cache: ", e);
+
+ // If something went wrong while reading the cache entry, delete the cache file
+ // so that we regenerate it the next time.
+ cacheFile.delete();
+ return null;
+ }
+ }
+
+ /**
+ * Caches the parse result for {@code packageFile} with flags {@code flags}.
+ */
+ public void cacheResult(File packageFile, int flags, ParsedPackage parsed) {
+ try {
+ final String cacheKey = getCacheKey(packageFile, flags);
+ final File cacheFile = new File(mCacheDir, cacheKey);
+
+ if (cacheFile.exists()) {
+ if (!cacheFile.delete()) {
+ Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
+ }
+ }
+
+ final byte[] cacheEntry = toCacheEntry(parsed);
+
+ if (cacheEntry == null) {
+ return;
+ }
+
+ try (FileOutputStream fos = new FileOutputStream(cacheFile)) {
+ fos.write(cacheEntry);
+ } catch (IOException ioe) {
+ Slog.w(TAG, "Error writing cache entry.", ioe);
+ cacheFile.delete();
+ }
+ } catch (Throwable e) {
+ Slog.w(TAG, "Error saving package cache.", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
new file mode 100644
index 0000000..3d56962
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -0,0 +1,419 @@
+/*
+ * 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.annotation.CheckResult;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.apex.ApexInfo;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProcessInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
+import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
+import android.content.pm.parsing.ComponentParseUtils.ParsedMainComponent;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
+import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProcess;
+import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
+import android.content.pm.parsing.ComponentParseUtils.ParsedService;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+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 libcore.util.EmptyArray;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/** @hide **/
+public class PackageInfoUtils {
+
+ @Nullable
+ public static PackageInfo generate(AndroidPackage pkg, int[] gids,
+ @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+ Set<String> grantedPermissions, PackageUserState state, int userId) {
+ PackageSetting pkgSetting = null;
+ return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime,
+ grantedPermissions, state, userId, null, pkgSetting);
+ }
+
+ @Nullable
+ public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags,
+ PackageSetting pkgSetting) {
+ return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
+ new PackageUserState(), UserHandle.getCallingUserId(), apexInfo, pkgSetting);
+ }
+
+ private static PackageInfo generateWithComponents(AndroidPackage pkg, int[] gids,
+ @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime,
+ Set<String> grantedPermissions, PackageUserState state, int userId,
+ @Nullable ApexInfo apexInfo, @Nullable PackageSetting pkgSetting) {
+ ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+ if (applicationInfo == null) {
+ return null;
+ }
+
+ PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponents(pkg, gids, flags,
+ firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, apexInfo,
+ applicationInfo);
+ if (info == null) {
+ return null;
+ }
+
+ info.isStub = pkg.isStub();
+ info.coreApp = pkg.isCoreApp();
+
+ if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+ final int N = pkg.getActivities().size();
+ if (N > 0) {
+ int num = 0;
+ final ActivityInfo[] res = new ActivityInfo[N];
+ for (int i = 0; i < N; i++) {
+ final ParsedActivity a = pkg.getActivities().get(i);
+ if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
+ a.getName())) {
+ continue;
+ }
+ res[num++] = generateActivityInfo(pkg, a, flags, state,
+ applicationInfo, userId, pkgSetting);
+ }
+ }
+ info.activities = ArrayUtils.trimToSize(res, num);
+ }
+ }
+ if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+ final int size = pkg.getReceivers().size();
+ if (size > 0) {
+ int num = 0;
+ final ActivityInfo[] res = new ActivityInfo[size];
+ for (int i = 0; i < size; i++) {
+ final ParsedActivity a = pkg.getReceivers().get(i);
+ if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) {
+ res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
+ userId, pkgSetting);
+ }
+ }
+ info.receivers = ArrayUtils.trimToSize(res, num);
+ }
+ }
+ if ((flags & PackageManager.GET_SERVICES) != 0) {
+ final int size = pkg.getServices().size();
+ if (size > 0) {
+ int num = 0;
+ final ServiceInfo[] res = new ServiceInfo[size];
+ for (int i = 0; i < size; i++) {
+ final ParsedService s = pkg.getServices().get(i);
+ if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) {
+ res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
+ userId, pkgSetting);
+ }
+ }
+ info.services = ArrayUtils.trimToSize(res, num);
+ }
+ }
+ if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+ final int size = pkg.getProviders().size();
+ if (size > 0) {
+ int num = 0;
+ final ProviderInfo[] res = new ProviderInfo[size];
+ for (int i = 0; i < size; i++) {
+ final ParsedProvider pr = pkg.getProviders()
+ .get(i);
+ if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) {
+ res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo,
+ userId, pkgSetting);
+ }
+ }
+ info.providers = ArrayUtils.trimToSize(res, num);
+ }
+ }
+ if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
+ int N = pkg.getInstrumentations().size();
+ if (N > 0) {
+ info.instrumentation = new InstrumentationInfo[N];
+ for (int i = 0; i < N; i++) {
+ info.instrumentation[i] = generateInstrumentationInfo(
+ pkg.getInstrumentations().get(i), pkg, flags, userId);
+ }
+ }
+ }
+
+ return info;
+ }
+
+ @Nullable
+ public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg,
+ @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) {
+ PackageSetting pkgSetting = null;
+ // TODO(b/135203078): Consider cases where we don't have a PkgSetting
+ if (pkg == null) {
+ return null;
+ }
+
+ if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)
+ || !AndroidPackageUtils.isMatchForSystemOnly(pkg, flags)) {
+ return null;
+ }
+
+ ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfo(pkg, flags,
+ state, userId);
+ if (info == null) {
+ return null;
+ }
+
+ info.flags |= appInfoFlags(pkg, pkgSetting);
+ info.privateFlags |= appInfoPrivateFlags(pkg, pkgSetting);
+ return info;
+ }
+
+ @Nullable
+ public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+ @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+ PackageSetting pkgSetting = null;
+ return generateActivityInfo(pkg, a, flags, state, null, userId, pkgSetting);
+ }
+
+ @Nullable
+ private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,
+ @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+ @Nullable ApplicationInfo applicationInfo, int userId,
+ @Nullable PackageSetting pkgSetting) {
+ if (a == null) return null;
+ if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+ return null;
+ }
+ if (applicationInfo == null) {
+ applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+ }
+ ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfo(pkg, a, flags, state,
+ applicationInfo, userId);
+ if (info == null) {
+ return null;
+ }
+
+ assignSharedFieldsForComponentInfo(info, a, pkgSetting);
+ return info;
+ }
+
+ @Nullable
+ public static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
+ @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+ PackageSetting pkgSetting = null;
+ return generateServiceInfo(pkg, s, flags, state, null, userId, pkgSetting);
+ }
+
+ @Nullable
+ private static ServiceInfo generateServiceInfo(AndroidPackage pkg, ParsedService s,
+ @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+ @Nullable ApplicationInfo applicationInfo, int userId,
+ @Nullable PackageSetting pkgSetting) {
+ if (s == null) return null;
+ if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+ return null;
+ }
+ if (applicationInfo == null) {
+ applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+ }
+ ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfo(pkg, s, flags, state,
+ applicationInfo, userId);
+ if (info == null) {
+ return null;
+ }
+
+ assignSharedFieldsForComponentInfo(info, s, pkgSetting);
+ return info;
+ }
+
+ @Nullable
+ public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
+ @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) {
+ PackageSetting pkgSetting = null;
+ return generateProviderInfo(pkg, p, flags, state, null, userId, pkgSetting);
+ }
+
+ @Nullable
+ private static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
+ @PackageManager.ComponentInfoFlags int flags, PackageUserState state,
+ @Nullable ApplicationInfo applicationInfo, int userId,
+ @Nullable PackageSetting pkgSetting) {
+ if (p == null) return null;
+ if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) {
+ return null;
+ }
+ if (applicationInfo == null) {
+ applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
+ }
+ ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state,
+ applicationInfo, userId);
+ if (info == null) {
+ return null;
+ }
+
+ assignSharedFieldsForComponentInfo(info, p, pkgSetting);
+ return info;
+ }
+
+ @Nullable
+ public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
+ AndroidPackage pkg, @PackageManager.ComponentInfoFlags int flags, int userId) {
+ PackageSetting pkgSetting = null;
+ if (i == null) return null;
+
+ InstrumentationInfo info =
+ PackageInfoWithoutStateUtils.generateInstrumentationInfo(i, pkg, flags, userId);
+ if (info == null) {
+ return null;
+ }
+
+ // TODO(b/135203078): Add setting related state
+ info.primaryCpuAbi = pkg.getPrimaryCpuAbi();
+ info.secondaryCpuAbi = pkg.getSecondaryCpuAbi();
+ info.nativeLibraryDir = pkg.getNativeLibraryDir();
+ info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
+
+ assignStateFieldsForPackageItemInfo(info, i, pkgSetting);
+
+ return info;
+ }
+
+ // TODO(b/135203078): Determine if permission methods need to pass in a non-null PackageSetting
+ // os that checkUseInstalledOrHidden filter can apply
+ @Nullable
+ public static PermissionInfo generatePermissionInfo(ParsedPermission p,
+ @PackageManager.ComponentInfoFlags int flags) {
+ // TODO(b/135203078): Remove null checks and make all usages @NonNull
+ if (p == null) return null;
+
+ // For now, permissions don't have state-adjustable fields; return directly
+ return PackageInfoWithoutStateUtils.generatePermissionInfo(p, flags);
+ }
+
+ @Nullable
+ public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg,
+ @PackageManager.ComponentInfoFlags int flags) {
+ if (pg == null) return null;
+
+ // For now, permissions don't have state-adjustable fields; return directly
+ return PackageInfoWithoutStateUtils.generatePermissionGroupInfo(pg, flags);
+ }
+
+ @Nullable
+ public static ArrayMap<String, ProcessInfo> generateProcessInfo(
+ Map<String, ParsedProcess> procs, @PackageManager.ComponentInfoFlags int flags) {
+ if (procs == null) {
+ return null;
+ }
+
+ final int numProcs = procs.size();
+ ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs);
+ for (String key : procs.keySet()) {
+ ParsedProcess proc = procs.get(key);
+ retProcs.put(proc.name, new ProcessInfo(proc.name,
+ proc.deniedPermissions != null
+ ? new ArraySet<>(proc.deniedPermissions) : null));
+ }
+ return retProcs;
+ }
+
+ /**
+ * Returns true if the package is installed and not hidden, or if the caller
+ * explicitly wanted all uninstalled and hidden packages as well.
+ */
+ private static boolean checkUseInstalledOrHidden(AndroidPackage pkg,
+ PackageSetting pkgSetting, PackageUserState state,
+ @PackageManager.PackageInfoFlags int flags) {
+ // Returns false if the package is hidden system app until installed.
+ if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
+ && !state.installed
+ && pkg.isHiddenUntilInstalled()) {
+ return false;
+ }
+
+ // If available for the target user, or trying to match uninstalled packages and it's
+ // a system app.
+ return state.isAvailable(flags)
+ || (pkg.isSystem()
+ && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
+ || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
+ }
+
+ private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
+ @NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting) {
+ assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting);
+ componentInfo.descriptionRes = mainComponent.descriptionRes;
+ componentInfo.directBootAware = mainComponent.isDirectBootAware();
+ componentInfo.enabled = mainComponent.isEnabled();
+ componentInfo.splitName = mainComponent.getSplitName();
+ }
+
+ private static void assignStateFieldsForPackageItemInfo(
+ @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component,
+ @Nullable PackageSetting pkgSetting) {
+ // TODO(b/135203078): Add setting related state
+ }
+
+ @CheckResult
+ private static int flag(boolean hasFlag, int flag) {
+ return hasFlag ? flag : 0;
+ }
+
+ /** @see ApplicationInfo#flags */
+ public static int appInfoFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
+ // TODO(b/135203078): Add setting related state
+ // @formatter:off
+ return PackageInfoWithoutStateUtils.appInfoFlags(pkg)
+ | flag(pkg.isSystem(), ApplicationInfo.FLAG_SYSTEM)
+ | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST)
+ | flag(pkg.isUpdatedSystemApp(), ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
+ // @formatter:on
+ }
+
+ /** @see ApplicationInfo#privateFlags */
+ public static int appInfoPrivateFlags(AndroidPackage pkg, @Nullable PackageSetting pkgSetting) {
+ // TODO(b/135203078): Add setting related state
+ // @formatter:off
+ return PackageInfoWithoutStateUtils.appInfoPrivateFlags(pkg)
+ | flag(pkg.isSystemExt(), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
+ | flag(pkg.isPrivileged(), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ | flag(pkg.isOem(), ApplicationInfo.PRIVATE_FLAG_OEM)
+ | flag(pkg.isVendor(), ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ | flag(pkg.isProduct(), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
+ | flag(pkg.isOdm(), ApplicationInfo.PRIVATE_FLAG_ODM)
+ | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
+ // @formatter:on
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
new file mode 100644
index 0000000..804f110
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -0,0 +1,128 @@
+/*
+ * 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.annotation.AnyThread;
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import java.io.File;
+
+/**
+ * The v2 of {@link PackageParser} for use when parsing is initiated in the server and must
+ * contain state contained by the server.
+ */
+public class PackageParser2 {
+
+ private static final String TAG = "PackageParser2";
+
+ private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
+ private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
+
+ private ThreadLocal<ParsingPackageUtils.ParseResult> mSharedResult = ThreadLocal.withInitial(
+ ParsingPackageUtils.ParseResult::new);
+
+ private final String[] mSeparateProcesses;
+ private final boolean mOnlyCoreApps;
+ private final DisplayMetrics mDisplayMetrics;
+ private final Callback mCallback;
+
+ @Nullable
+ protected PackageCacher mCacher;
+
+ /**
+ * @param onlyCoreApps Flag indicating this parser should only consider apps with
+ * {@code coreApp} manifest attribute to be valid apps. This is useful when
+ * creating a minimalist boot environment.
+ */
+ public PackageParser2(String[] separateProcesses, boolean onlyCoreApps,
+ DisplayMetrics displayMetrics, @Nullable File cacheDir, Callback callback) {
+ mSeparateProcesses = separateProcesses;
+ mOnlyCoreApps = onlyCoreApps;
+
+ if (displayMetrics == null) {
+ mDisplayMetrics = new DisplayMetrics();
+ mDisplayMetrics.setToDefaults();
+ } else {
+ mDisplayMetrics = displayMetrics;
+ }
+
+ mCacher = cacheDir == null ? null : new PackageCacher(cacheDir);
+ // TODO(b/135203078): Remove nullability of callback
+ mCallback = callback != null ? callback : new Callback() {
+ @Override
+ public boolean hasFeature(String feature) {
+ return false;
+ }
+ };
+ }
+
+ /**
+ * TODO(b/135203078): Document new package parsing
+ */
+ @AnyThread
+ public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
+ throws PackageParser.PackageParserException {
+ if (useCaches && mCacher != null) {
+ ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
+ if (parsed != null) {
+ return parsed;
+ }
+ }
+
+ long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
+ ParsingPackageUtils.ParseInput parseInput = mSharedResult.get().reset();
+ ParsedPackage parsed = (ParsedPackage) ParsingPackageUtils.parsePackage(parseInput,
+ mSeparateProcesses, mCallback, mDisplayMetrics, mOnlyCoreApps, packageFile, flags)
+ .hideAsParsed();
+
+ long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
+ if (mCacher != null) {
+ mCacher.cacheResult(packageFile, flags, parsed);
+ }
+ if (LOG_PARSE_TIMINGS) {
+ parseTime = cacheTime - parseTime;
+ cacheTime = SystemClock.uptimeMillis() - cacheTime;
+ if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
+ Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+ + "ms, update_cache=" + cacheTime + " ms");
+ }
+ }
+
+ return parsed;
+ }
+
+ public static abstract class Callback implements ParsingPackageUtils.Callback {
+
+ @Override
+ public final ParsingPackage startParsingPackage(String packageName, String baseCodePath,
+ String codePath, TypedArray manifestArray, boolean isCoreApp) {
+ return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray,
+ isCoreApp);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index 239cf9d..d0ec969 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -187,7 +187,7 @@
@NonNull
List<ParsedPermissionGroup> getPermissionGroups();
- @Nullable
+ @NonNull
List<ParsedFeature> getFeatures();
/**
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 36697f9..e1d1a1a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3612,7 +3612,7 @@
return EmptyArray.INT;
}
for (AndroidPackage pkg : pkgList) {
- if (pkg.getRequestedPermissions() == null) {
+ if (pkg.getRequestedPermissions().isEmpty()) {
continue;
}
final int requestedPermCount = pkg.getRequestedPermissions().size();
@@ -4246,7 +4246,7 @@
}
private static boolean hasPermission(AndroidPackage pkg, String permName) {
- if (pkg.getPermissions() == null) {
+ if (pkg.getPermissions().isEmpty()) {
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index da5986f7..20f3f3e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -17,11 +17,13 @@
package com.android.server.pm;
import android.content.pm.PackageParser;
-import android.content.pm.parsing.ParsedPackage;
import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
import junit.framework.Assert;
import org.junit.Before;
@@ -44,7 +46,7 @@
@Before
public void setUp() {
- mParser = new TestParallelPackageParser(new PackageParser(),
+ mParser = new TestParallelPackageParser(new PackageParser2(null, false, null, null, null),
ParallelPackageParser.makeExecutorService());
}
@@ -72,7 +74,7 @@
private class TestParallelPackageParser extends ParallelPackageParser {
- TestParallelPackageParser(PackageParser packageParser, ExecutorService executorService) {
+ TestParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
super(packageParser, executorService);
}