Loading core/java/android/content/pm/PackageParser.java +23 −7 Original line number Diff line number Diff line Loading @@ -406,9 +406,15 @@ public class PackageParser { public final boolean extractNativeLibs; public final boolean isolatedSplits; public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, String[] splitCodePaths, int[] splitRevisionCodes) { // This does not represent the actual manifest structure since the 'profilable' tag // could be used with attributes other than 'shell'. Extend if necessary. public final boolean profilableByShell; public final boolean isSplitRequired; public final boolean useEmbeddedDex; public PackageLite(String codePath, String baseCodePath, ApkLite baseApk, String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, String[] splitCodePaths, int[] splitRevisionCodes) { this.packageName = baseApk.packageName; this.versionCode = baseApk.versionCode; this.versionCodeMajor = baseApk.versionCodeMajor; Loading @@ -418,8 +424,10 @@ public class PackageParser { this.isFeatureSplits = isFeatureSplits; this.usesSplitNames = usesSplitNames; this.configForSplit = configForSplit; // The following paths may be different from the path in ApkLite because we // move or rename the APK files. Use parameters to indicate the correct paths. this.codePath = codePath; this.baseCodePath = baseApk.codePath; this.baseCodePath = baseCodePath; this.splitCodePaths = splitCodePaths; this.baseRevisionCode = baseApk.revisionCode; this.splitRevisionCodes = splitRevisionCodes; Loading @@ -429,6 +437,9 @@ public class PackageParser { this.use32bitAbi = baseApk.use32bitAbi; this.extractNativeLibs = baseApk.extractNativeLibs; this.isolatedSplits = baseApk.isolatedSplits; this.useEmbeddedDex = baseApk.useEmbeddedDex; this.isSplitRequired = baseApk.isSplitRequired; this.profilableByShell = baseApk.profilableByShell; } public List<String> getAllCodePaths() { Loading @@ -439,6 +450,10 @@ public class PackageParser { } return paths; } public long getLongVersionCode() { return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); } } /** Loading Loading @@ -941,7 +956,8 @@ public class PackageParser { final ApkLite baseApk = parseApkLite(packageFile, flags); final String packagePath = packageFile.getAbsolutePath(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); return new PackageLite(packagePath, baseApk, null, null, null, null, null, null); return new PackageLite(packagePath, baseApk.codePath, baseApk, null, null, null, null, null, null); } static PackageLite parseClusterPackageLite(File packageDir, int flags) Loading Loading @@ -1031,8 +1047,8 @@ public class PackageParser { } final String codePath = packageDir.getAbsolutePath(); return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes); return new PackageLite(codePath, baseApk.codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes); } /** Loading core/java/android/content/pm/parsing/ApkLiteParseUtils.java +59 −10 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package android.content.pm.parsing; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import static android.content.pm.parsing.ParsingPackageUtils.validateName; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import android.annotation.NonNull; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; Loading Loading @@ -50,6 +52,7 @@ import java.security.PublicKey; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** @hide */ public class ApkLiteParseUtils { Loading Loading @@ -95,8 +98,8 @@ public class ApkLiteParseUtils { final PackageParser.ApkLite baseApk = result.getResult(); final String packagePath = packageFile.getAbsolutePath(); return input.success( new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null, null, null)); new PackageParser.PackageLite(packagePath, baseApk.codePath, baseApk, null, null, null, null, null, null)); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Loading Loading @@ -159,13 +162,43 @@ public class ApkLiteParseUtils { } final PackageParser.ApkLite baseApk = apks.remove(null); return composePackageLiteFromApks(input, packageDir, baseApk, apks); } /** * Utility method that retrieves lightweight details about the package by given location, * base APK, and split APKs. * * @param packageDir Path to the package * @param baseApk Parsed base APK * @param splitApks Parsed split APKs * @return PackageLite */ public static ParseResult<PackageParser.PackageLite> composePackageLiteFromApks( ParseInput input, File packageDir, PackageParser.ApkLite baseApk, ArrayMap<String, PackageParser.ApkLite> splitApks) { return composePackageLiteFromApks(input, packageDir, baseApk, splitApks, false); } /** * Utility method that retrieves lightweight details about the package by given location, * base APK, and split APKs. * * @param packageDir Path to the package * @param baseApk Parsed base APK * @param splitApks Parsed split APKs * @param apkRenamed Indicate whether the APKs are renamed after parsed. * @return PackageLite */ public static ParseResult<PackageParser.PackageLite> composePackageLiteFromApks( ParseInput input, File packageDir, PackageParser.ApkLite baseApk, ArrayMap<String, PackageParser.ApkLite> splitApks, boolean apkRenamed) { if (baseApk == null) { return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, "Missing base APK in " + packageDir); } // Always apply deterministic ordering based on splitName final int size = apks.size(); final int size = ArrayUtils.size(splitApks); String[] splitNames = null; boolean[] isFeatureSplits = null; Loading @@ -181,25 +214,41 @@ public class ApkLiteParseUtils { splitCodePaths = new String[size]; splitRevisionCodes = new int[size]; splitNames = apks.keySet().toArray(splitNames); splitNames = splitApks.keySet().toArray(splitNames); Arrays.sort(splitNames, PackageParser.sSplitNameComparator); for (int i = 0; i < size; i++) { final PackageParser.ApkLite apk = apks.get(splitNames[i]); final PackageParser.ApkLite apk = splitApks.get(splitNames[i]); usesSplitNames[i] = apk.usesSplitName; isFeatureSplits[i] = apk.isFeatureSplit; configForSplits[i] = apk.configForSplit; splitCodePaths[i] = apk.codePath; splitCodePaths[i] = apkRenamed ? new File(packageDir, splitNameToFileName(apk)).getAbsolutePath() : apk.codePath; splitRevisionCodes[i] = apk.revisionCode; } } final String codePath = packageDir.getAbsolutePath(); return input.success(new PackageParser.PackageLite(codePath, baseApk, splitNames, final String baseCodePath = apkRenamed ? new File(packageDir, splitNameToFileName(baseApk)).getAbsolutePath() : baseApk.codePath; return input.success( new PackageParser.PackageLite(codePath, baseCodePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes)); } /** * Utility method that retrieves canonical file name by given split name from parsed APK. * * @param apk Parsed APK * @return The canonical file name */ public static String splitNameToFileName(@NonNull PackageParser.ApkLite apk) { Objects.requireNonNull(apk); final String fileName = apk.splitName == null ? "base" : "split_" + apk.splitName; return fileName + APK_FILE_EXTENSION; } /** * Utility method that retrieves lightweight details about a single APK * file, including package name, split name, and install location. Loading core/java/com/android/internal/util/ArrayUtils.java +7 −0 Original line number Diff line number Diff line Loading @@ -207,6 +207,13 @@ public class ArrayUtils { return collection == null ? 0 : collection.size(); } /** * Length of the given map or 0 if it's null. */ public static int size(@Nullable Map<?, ?> map) { return map == null ? 0 : map.size(); } /** * Checks that value is present as at least one of the elements of the array. * @param array the array to check in Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +99 −51 Original line number Diff line number Diff line Loading @@ -31,22 +31,16 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE import static android.content.pm.PackageManager.INSTALL_STAGED; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageParser.APEX_FILE_EXTENSION; import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_WRONLY; import static com.android.internal.util.XmlUtils.readBitmapAttribute; import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readByteArrayAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; import static com.android.internal.util.XmlUtils.readLongAttribute; import static com.android.internal.util.XmlUtils.readStringAttribute; import static com.android.internal.util.XmlUtils.readUriAttribute; import static com.android.internal.util.XmlUtils.writeBooleanAttribute; import static com.android.internal.util.XmlUtils.writeByteArrayAttribute; import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.internal.util.XmlUtils.writeStringAttribute; import static com.android.internal.util.XmlUtils.writeUriAttribute; import static com.android.server.pm.PackageInstallerService.prepareStageDir; Loading Loading @@ -156,7 +150,6 @@ import libcore.util.EmptyArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayOutputStream; import java.io.File; Loading Loading @@ -483,6 +476,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private IncrementalFileStorages mIncrementalFileStorages; @GuardedBy("mLock") private PackageLite mPackageLite; private static final FileFilter sAddedApkFilter = new FileFilter() { @Override public boolean accept(File file) { Loading Loading @@ -2040,7 +2036,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // TODO(b/136257624): Some logic in this if block probably belongs in // makeInstallParams(). if (!params.isMultiPackage && !isApexSession()) { if (!isMultiPackage() && !isApexSession()) { Objects.requireNonNull(mPackageName); Objects.requireNonNull(mSigningDetails); Objects.requireNonNull(mResolvedBaseFile); Loading Loading @@ -2094,12 +2090,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "Failed to inherit existing install", e); } } // For mode inherit existing, it would link/copy existing files to stage dir in the // above block. Therefore, we need to parse the complete package in stage dir here. // Besides, PackageLite may be null for staged sessions that don't complete pre-reboot // verification. mPackageLite = getOrParsePackageLiteLocked(stageDir, /* flags */ 0); // TODO: surface more granular state from dexopt mInternalProgress = 0.5f; computeProgressLocked(true); extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs()); extractNativeLibraries(mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs()); } final IPackageInstallObserver2 localObserver; Loading Loading @@ -2142,7 +2144,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { copiedParams.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK; } return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams, mInstallSource, mInstallerUid, mSigningDetails, sessionId); mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite); } private void onVerificationComplete() { Loading Loading @@ -2215,10 +2217,37 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { params.installFlags |= INSTALL_STAGED; } if (!isMultiPackage() && !isApexSession()) { synchronized (mLock) { // This shouldn't be null, but have this code path just in case. if (mPackageLite == null) { Slog.wtf(TAG, "Session: " + sessionId + ". Don't have a valid PackageLite."); } mPackageLite = getOrParsePackageLiteLocked(stageDir, /* flags */ 0); } } synchronized (mLock) { return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user, mSigningDetails, mInstallerUid); mSigningDetails, mInstallerUid, mPackageLite); } } @GuardedBy("mLock") private PackageLite getOrParsePackageLiteLocked(File packageFile, int flags) throws PackageManagerException { if (mPackageLite != null) { return mPackageLite; } final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(input, packageFile, flags); if (result.isError()) { throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, result.getErrorMessage(), result.getException()); } return result.getResult(); } private static void maybeRenameFile(File from, File to) throws PackageManagerException { Loading Loading @@ -2366,13 +2395,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } private static String splitNameToFileName(String splitName) { if (splitName == null) { return "base"; } return "split_" + splitName; } /** * Validate install by confirming that all application packages are have * consistent package name, version code, and signing certificates. Loading @@ -2388,6 +2410,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private void validateApkInstallLocked() throws PackageManagerException { ApkLite baseApk = null; PackageLite packageLite = null; mPackageLite = null; mPackageName = null; mVersionCode = -1; mSigningDetails = PackageParser.SigningDetails.UNKNOWN; Loading Loading @@ -2431,6 +2455,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Verify that all staged packages are internally consistent final ArraySet<String> stagedSplits = new ArraySet<>(); final ArrayMap<String, PackageParser.ApkLite> splitApks = new ArrayMap<>(); ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); for (File addedFile : addedFiles) { ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(), Loading Loading @@ -2458,8 +2483,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertApkConsistentLocked(String.valueOf(addedFile), apk); // Take this opportunity to enforce uniform naming final String fileName = splitNameToFileName(apk.splitName); final String targetName = fileName + APK_FILE_EXTENSION; final String targetName = ApkLiteParseUtils.splitNameToFileName(apk); if (!FileUtils.isValidExtFilename(targetName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Invalid filename: " + targetName); Loading @@ -2483,6 +2507,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (apk.splitName == null) { mResolvedBaseFile = targetFile; baseApk = apk; } else { splitApks.put(apk.splitName, apk); } } Loading @@ -2506,14 +2532,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mVersionCode = pkgInfo.getLongVersionCode(); } if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) { try { mSigningDetails = ApkSignatureVerifier.unsafeGetCertsWithoutVerification( pkgInfo.applicationInfo.sourceDir, PackageParser.SigningDetails.SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Couldn't obtain signatures from base APK"); } mSigningDetails = unsafeGetCertsWithoutVerification( pkgInfo.applicationInfo.sourceDir); } } Loading Loading @@ -2548,6 +2568,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT, "Missing split for " + mPackageName); } // For mode full install, we compose package lite for future usage instead of // re-parsing it again and again. final ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.composePackageLiteFromApks(input.reset(), stageDir, baseApk, splitApks, true); if (pkgLiteResult.isError()) { throw new PackageManagerException(pkgLiteResult.getErrorCode(), pkgLiteResult.getErrorMessage(), pkgLiteResult.getException()); } mPackageLite = pkgLiteResult.getResult(); packageLite = mPackageLite; } else { final ApplicationInfo appInfo = pkgInfo.applicationInfo; ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite( Loading @@ -2557,22 +2588,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pkgLiteResult.getErrorMessage(), pkgLiteResult.getException()); } final PackageLite existing = pkgLiteResult.getResult(); ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(), new File(appInfo.getBaseCodePath()), PackageParser.PARSE_COLLECT_CERTIFICATES); if (apkLiteResult.isError()) { throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, apkLiteResult.getErrorMessage(), apkLiteResult.getException()); packageLite = existing; assertPackageConsistentLocked("Existing", existing.packageName, existing.getLongVersionCode()); final PackageParser.SigningDetails signingDetails = unsafeGetCertsWithoutVerification(existing.baseCodePath); if (!mSigningDetails.signaturesMatchExactly(signingDetails)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Existing signatures are inconsistent"); } final ApkLite existingBase = apkLiteResult.getResult(); assertApkConsistentLocked("Existing base", existingBase); // Inherit base if not overridden. if (mResolvedBaseFile == null) { mResolvedBaseFile = new File(appInfo.getBaseCodePath()); inheritFileLocked(mResolvedBaseFile); baseApk = existingBase; } // Inherit splits if not overridden. Loading Loading @@ -2659,7 +2688,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } // For the case of split required, failed if no splits existed if (baseApk.isSplitRequired) { if (packageLite.isSplitRequired) { final int existingSplits = ArrayUtils.size(existing.splitNames); final boolean allSplitsRemoved = (existingSplits == removeSplitList.size()); final boolean onlyBaseFileStaged = (stagedSplits.size() == 1 Loading @@ -2670,7 +2699,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } } if (baseApk.useEmbeddedDex) { if (packageLite.useEmbeddedDex) { for (File file : mResolvedStagedFiles) { if (file.getName().endsWith(".apk") && !DexManager.auditUncompressedDexInApk(file.getPath())) { Loading @@ -2683,7 +2712,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID); if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) { if (!baseApk.debuggable && !baseApk.profilableByShell) { if (!packageLite.debuggable && !packageLite.profilableByShell) { mIncrementalFileStorages.disableReadLogs(); } } Loading Loading @@ -2838,23 +2867,40 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private void assertApkConsistentLocked(String tag, ApkLite apk) throws PackageManagerException { if (!mPackageName.equals(apk.packageName)) { assertPackageConsistentLocked(tag, apk.packageName, apk.getLongVersionCode()); if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " signatures are inconsistent"); } } @GuardedBy("mLock") private void assertPackageConsistentLocked(String tag, String packageName, long versionCode) throws PackageManagerException { if (!mPackageName.equals(packageName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package " + apk.packageName + " inconsistent with " + mPackageName); + packageName + " inconsistent with " + mPackageName); } if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) { if (params.appPackageName != null && !params.appPackageName.equals(packageName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " specified package " + params.appPackageName + " inconsistent with " + apk.packageName); + " inconsistent with " + packageName); } if (mVersionCode != apk.getLongVersionCode()) { if (mVersionCode != versionCode) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " version code " + apk.versionCode + " inconsistent with " + " version code " + versionCode + " inconsistent with " + mVersionCode); } if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) { } private PackageParser.SigningDetails unsafeGetCertsWithoutVerification(String path) throws PackageManagerException { try { return ApkSignatureVerifier.unsafeGetCertsWithoutVerification(path, PackageParser.SigningDetails.SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " signatures are inconsistent"); "Couldn't obtain signatures from APK : " + path); } } Loading Loading @@ -2989,8 +3035,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir); } private void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit) private void extractNativeLibraries(PackageLite packageLite, File packageDir, String abiOverride, boolean inherit) throws PackageManagerException { Objects.requireNonNull(packageLite); final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME); if (!inherit) { // Start from a clean slate Loading @@ -2999,7 +3047,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { NativeLibraryHelper.Handle handle = null; try { handle = NativeLibraryHelper.Handle.create(packageDir); handle = NativeLibraryHelper.Handle.create(packageLite); final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir, abiOverride, isIncrementalInstallation()); if (res != INSTALL_SUCCEEDED) { Loading services/core/java/com/android/server/pm/PackageManagerService.java +13 −5 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/content/pm/PackageParser.java +23 −7 Original line number Diff line number Diff line Loading @@ -406,9 +406,15 @@ public class PackageParser { public final boolean extractNativeLibs; public final boolean isolatedSplits; public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, String[] splitCodePaths, int[] splitRevisionCodes) { // This does not represent the actual manifest structure since the 'profilable' tag // could be used with attributes other than 'shell'. Extend if necessary. public final boolean profilableByShell; public final boolean isSplitRequired; public final boolean useEmbeddedDex; public PackageLite(String codePath, String baseCodePath, ApkLite baseApk, String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, String[] splitCodePaths, int[] splitRevisionCodes) { this.packageName = baseApk.packageName; this.versionCode = baseApk.versionCode; this.versionCodeMajor = baseApk.versionCodeMajor; Loading @@ -418,8 +424,10 @@ public class PackageParser { this.isFeatureSplits = isFeatureSplits; this.usesSplitNames = usesSplitNames; this.configForSplit = configForSplit; // The following paths may be different from the path in ApkLite because we // move or rename the APK files. Use parameters to indicate the correct paths. this.codePath = codePath; this.baseCodePath = baseApk.codePath; this.baseCodePath = baseCodePath; this.splitCodePaths = splitCodePaths; this.baseRevisionCode = baseApk.revisionCode; this.splitRevisionCodes = splitRevisionCodes; Loading @@ -429,6 +437,9 @@ public class PackageParser { this.use32bitAbi = baseApk.use32bitAbi; this.extractNativeLibs = baseApk.extractNativeLibs; this.isolatedSplits = baseApk.isolatedSplits; this.useEmbeddedDex = baseApk.useEmbeddedDex; this.isSplitRequired = baseApk.isSplitRequired; this.profilableByShell = baseApk.profilableByShell; } public List<String> getAllCodePaths() { Loading @@ -439,6 +450,10 @@ public class PackageParser { } return paths; } public long getLongVersionCode() { return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); } } /** Loading Loading @@ -941,7 +956,8 @@ public class PackageParser { final ApkLite baseApk = parseApkLite(packageFile, flags); final String packagePath = packageFile.getAbsolutePath(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); return new PackageLite(packagePath, baseApk, null, null, null, null, null, null); return new PackageLite(packagePath, baseApk.codePath, baseApk, null, null, null, null, null, null); } static PackageLite parseClusterPackageLite(File packageDir, int flags) Loading Loading @@ -1031,8 +1047,8 @@ public class PackageParser { } final String codePath = packageDir.getAbsolutePath(); return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes); return new PackageLite(codePath, baseApk.codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes); } /** Loading
core/java/android/content/pm/parsing/ApkLiteParseUtils.java +59 −10 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package android.content.pm.parsing; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import static android.content.pm.parsing.ParsingPackageUtils.validateName; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import android.annotation.NonNull; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; Loading Loading @@ -50,6 +52,7 @@ import java.security.PublicKey; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** @hide */ public class ApkLiteParseUtils { Loading Loading @@ -95,8 +98,8 @@ public class ApkLiteParseUtils { final PackageParser.ApkLite baseApk = result.getResult(); final String packagePath = packageFile.getAbsolutePath(); return input.success( new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null, null, null)); new PackageParser.PackageLite(packagePath, baseApk.codePath, baseApk, null, null, null, null, null, null)); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Loading Loading @@ -159,13 +162,43 @@ public class ApkLiteParseUtils { } final PackageParser.ApkLite baseApk = apks.remove(null); return composePackageLiteFromApks(input, packageDir, baseApk, apks); } /** * Utility method that retrieves lightweight details about the package by given location, * base APK, and split APKs. * * @param packageDir Path to the package * @param baseApk Parsed base APK * @param splitApks Parsed split APKs * @return PackageLite */ public static ParseResult<PackageParser.PackageLite> composePackageLiteFromApks( ParseInput input, File packageDir, PackageParser.ApkLite baseApk, ArrayMap<String, PackageParser.ApkLite> splitApks) { return composePackageLiteFromApks(input, packageDir, baseApk, splitApks, false); } /** * Utility method that retrieves lightweight details about the package by given location, * base APK, and split APKs. * * @param packageDir Path to the package * @param baseApk Parsed base APK * @param splitApks Parsed split APKs * @param apkRenamed Indicate whether the APKs are renamed after parsed. * @return PackageLite */ public static ParseResult<PackageParser.PackageLite> composePackageLiteFromApks( ParseInput input, File packageDir, PackageParser.ApkLite baseApk, ArrayMap<String, PackageParser.ApkLite> splitApks, boolean apkRenamed) { if (baseApk == null) { return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, "Missing base APK in " + packageDir); } // Always apply deterministic ordering based on splitName final int size = apks.size(); final int size = ArrayUtils.size(splitApks); String[] splitNames = null; boolean[] isFeatureSplits = null; Loading @@ -181,25 +214,41 @@ public class ApkLiteParseUtils { splitCodePaths = new String[size]; splitRevisionCodes = new int[size]; splitNames = apks.keySet().toArray(splitNames); splitNames = splitApks.keySet().toArray(splitNames); Arrays.sort(splitNames, PackageParser.sSplitNameComparator); for (int i = 0; i < size; i++) { final PackageParser.ApkLite apk = apks.get(splitNames[i]); final PackageParser.ApkLite apk = splitApks.get(splitNames[i]); usesSplitNames[i] = apk.usesSplitName; isFeatureSplits[i] = apk.isFeatureSplit; configForSplits[i] = apk.configForSplit; splitCodePaths[i] = apk.codePath; splitCodePaths[i] = apkRenamed ? new File(packageDir, splitNameToFileName(apk)).getAbsolutePath() : apk.codePath; splitRevisionCodes[i] = apk.revisionCode; } } final String codePath = packageDir.getAbsolutePath(); return input.success(new PackageParser.PackageLite(codePath, baseApk, splitNames, final String baseCodePath = apkRenamed ? new File(packageDir, splitNameToFileName(baseApk)).getAbsolutePath() : baseApk.codePath; return input.success( new PackageParser.PackageLite(codePath, baseCodePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes)); } /** * Utility method that retrieves canonical file name by given split name from parsed APK. * * @param apk Parsed APK * @return The canonical file name */ public static String splitNameToFileName(@NonNull PackageParser.ApkLite apk) { Objects.requireNonNull(apk); final String fileName = apk.splitName == null ? "base" : "split_" + apk.splitName; return fileName + APK_FILE_EXTENSION; } /** * Utility method that retrieves lightweight details about a single APK * file, including package name, split name, and install location. Loading
core/java/com/android/internal/util/ArrayUtils.java +7 −0 Original line number Diff line number Diff line Loading @@ -207,6 +207,13 @@ public class ArrayUtils { return collection == null ? 0 : collection.size(); } /** * Length of the given map or 0 if it's null. */ public static int size(@Nullable Map<?, ?> map) { return map == null ? 0 : map.size(); } /** * Checks that value is present as at least one of the elements of the array. * @param array the array to check in Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +99 −51 Original line number Diff line number Diff line Loading @@ -31,22 +31,16 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE import static android.content.pm.PackageManager.INSTALL_STAGED; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageParser.APEX_FILE_EXTENSION; import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_WRONLY; import static com.android.internal.util.XmlUtils.readBitmapAttribute; import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readByteArrayAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; import static com.android.internal.util.XmlUtils.readLongAttribute; import static com.android.internal.util.XmlUtils.readStringAttribute; import static com.android.internal.util.XmlUtils.readUriAttribute; import static com.android.internal.util.XmlUtils.writeBooleanAttribute; import static com.android.internal.util.XmlUtils.writeByteArrayAttribute; import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.internal.util.XmlUtils.writeStringAttribute; import static com.android.internal.util.XmlUtils.writeUriAttribute; import static com.android.server.pm.PackageInstallerService.prepareStageDir; Loading Loading @@ -156,7 +150,6 @@ import libcore.util.EmptyArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayOutputStream; import java.io.File; Loading Loading @@ -483,6 +476,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private IncrementalFileStorages mIncrementalFileStorages; @GuardedBy("mLock") private PackageLite mPackageLite; private static final FileFilter sAddedApkFilter = new FileFilter() { @Override public boolean accept(File file) { Loading Loading @@ -2040,7 +2036,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // TODO(b/136257624): Some logic in this if block probably belongs in // makeInstallParams(). if (!params.isMultiPackage && !isApexSession()) { if (!isMultiPackage() && !isApexSession()) { Objects.requireNonNull(mPackageName); Objects.requireNonNull(mSigningDetails); Objects.requireNonNull(mResolvedBaseFile); Loading Loading @@ -2094,12 +2090,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "Failed to inherit existing install", e); } } // For mode inherit existing, it would link/copy existing files to stage dir in the // above block. Therefore, we need to parse the complete package in stage dir here. // Besides, PackageLite may be null for staged sessions that don't complete pre-reboot // verification. mPackageLite = getOrParsePackageLiteLocked(stageDir, /* flags */ 0); // TODO: surface more granular state from dexopt mInternalProgress = 0.5f; computeProgressLocked(true); extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs()); extractNativeLibraries(mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs()); } final IPackageInstallObserver2 localObserver; Loading Loading @@ -2142,7 +2144,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { copiedParams.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK; } return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams, mInstallSource, mInstallerUid, mSigningDetails, sessionId); mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite); } private void onVerificationComplete() { Loading Loading @@ -2215,10 +2217,37 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { params.installFlags |= INSTALL_STAGED; } if (!isMultiPackage() && !isApexSession()) { synchronized (mLock) { // This shouldn't be null, but have this code path just in case. if (mPackageLite == null) { Slog.wtf(TAG, "Session: " + sessionId + ". Don't have a valid PackageLite."); } mPackageLite = getOrParsePackageLiteLocked(stageDir, /* flags */ 0); } } synchronized (mLock) { return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user, mSigningDetails, mInstallerUid); mSigningDetails, mInstallerUid, mPackageLite); } } @GuardedBy("mLock") private PackageLite getOrParsePackageLiteLocked(File packageFile, int flags) throws PackageManagerException { if (mPackageLite != null) { return mPackageLite; } final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(input, packageFile, flags); if (result.isError()) { throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, result.getErrorMessage(), result.getException()); } return result.getResult(); } private static void maybeRenameFile(File from, File to) throws PackageManagerException { Loading Loading @@ -2366,13 +2395,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } private static String splitNameToFileName(String splitName) { if (splitName == null) { return "base"; } return "split_" + splitName; } /** * Validate install by confirming that all application packages are have * consistent package name, version code, and signing certificates. Loading @@ -2388,6 +2410,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private void validateApkInstallLocked() throws PackageManagerException { ApkLite baseApk = null; PackageLite packageLite = null; mPackageLite = null; mPackageName = null; mVersionCode = -1; mSigningDetails = PackageParser.SigningDetails.UNKNOWN; Loading Loading @@ -2431,6 +2455,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Verify that all staged packages are internally consistent final ArraySet<String> stagedSplits = new ArraySet<>(); final ArrayMap<String, PackageParser.ApkLite> splitApks = new ArrayMap<>(); ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); for (File addedFile : addedFiles) { ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(), Loading Loading @@ -2458,8 +2483,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertApkConsistentLocked(String.valueOf(addedFile), apk); // Take this opportunity to enforce uniform naming final String fileName = splitNameToFileName(apk.splitName); final String targetName = fileName + APK_FILE_EXTENSION; final String targetName = ApkLiteParseUtils.splitNameToFileName(apk); if (!FileUtils.isValidExtFilename(targetName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Invalid filename: " + targetName); Loading @@ -2483,6 +2507,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (apk.splitName == null) { mResolvedBaseFile = targetFile; baseApk = apk; } else { splitApks.put(apk.splitName, apk); } } Loading @@ -2506,14 +2532,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mVersionCode = pkgInfo.getLongVersionCode(); } if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) { try { mSigningDetails = ApkSignatureVerifier.unsafeGetCertsWithoutVerification( pkgInfo.applicationInfo.sourceDir, PackageParser.SigningDetails.SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Couldn't obtain signatures from base APK"); } mSigningDetails = unsafeGetCertsWithoutVerification( pkgInfo.applicationInfo.sourceDir); } } Loading Loading @@ -2548,6 +2568,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT, "Missing split for " + mPackageName); } // For mode full install, we compose package lite for future usage instead of // re-parsing it again and again. final ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.composePackageLiteFromApks(input.reset(), stageDir, baseApk, splitApks, true); if (pkgLiteResult.isError()) { throw new PackageManagerException(pkgLiteResult.getErrorCode(), pkgLiteResult.getErrorMessage(), pkgLiteResult.getException()); } mPackageLite = pkgLiteResult.getResult(); packageLite = mPackageLite; } else { final ApplicationInfo appInfo = pkgInfo.applicationInfo; ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite( Loading @@ -2557,22 +2588,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pkgLiteResult.getErrorMessage(), pkgLiteResult.getException()); } final PackageLite existing = pkgLiteResult.getResult(); ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(), new File(appInfo.getBaseCodePath()), PackageParser.PARSE_COLLECT_CERTIFICATES); if (apkLiteResult.isError()) { throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, apkLiteResult.getErrorMessage(), apkLiteResult.getException()); packageLite = existing; assertPackageConsistentLocked("Existing", existing.packageName, existing.getLongVersionCode()); final PackageParser.SigningDetails signingDetails = unsafeGetCertsWithoutVerification(existing.baseCodePath); if (!mSigningDetails.signaturesMatchExactly(signingDetails)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Existing signatures are inconsistent"); } final ApkLite existingBase = apkLiteResult.getResult(); assertApkConsistentLocked("Existing base", existingBase); // Inherit base if not overridden. if (mResolvedBaseFile == null) { mResolvedBaseFile = new File(appInfo.getBaseCodePath()); inheritFileLocked(mResolvedBaseFile); baseApk = existingBase; } // Inherit splits if not overridden. Loading Loading @@ -2659,7 +2688,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } // For the case of split required, failed if no splits existed if (baseApk.isSplitRequired) { if (packageLite.isSplitRequired) { final int existingSplits = ArrayUtils.size(existing.splitNames); final boolean allSplitsRemoved = (existingSplits == removeSplitList.size()); final boolean onlyBaseFileStaged = (stagedSplits.size() == 1 Loading @@ -2670,7 +2699,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } } if (baseApk.useEmbeddedDex) { if (packageLite.useEmbeddedDex) { for (File file : mResolvedStagedFiles) { if (file.getName().endsWith(".apk") && !DexManager.auditUncompressedDexInApk(file.getPath())) { Loading @@ -2683,7 +2712,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID); if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) { if (!baseApk.debuggable && !baseApk.profilableByShell) { if (!packageLite.debuggable && !packageLite.profilableByShell) { mIncrementalFileStorages.disableReadLogs(); } } Loading Loading @@ -2838,23 +2867,40 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private void assertApkConsistentLocked(String tag, ApkLite apk) throws PackageManagerException { if (!mPackageName.equals(apk.packageName)) { assertPackageConsistentLocked(tag, apk.packageName, apk.getLongVersionCode()); if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " signatures are inconsistent"); } } @GuardedBy("mLock") private void assertPackageConsistentLocked(String tag, String packageName, long versionCode) throws PackageManagerException { if (!mPackageName.equals(packageName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package " + apk.packageName + " inconsistent with " + mPackageName); + packageName + " inconsistent with " + mPackageName); } if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) { if (params.appPackageName != null && !params.appPackageName.equals(packageName)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " specified package " + params.appPackageName + " inconsistent with " + apk.packageName); + " inconsistent with " + packageName); } if (mVersionCode != apk.getLongVersionCode()) { if (mVersionCode != versionCode) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " version code " + apk.versionCode + " inconsistent with " + " version code " + versionCode + " inconsistent with " + mVersionCode); } if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) { } private PackageParser.SigningDetails unsafeGetCertsWithoutVerification(String path) throws PackageManagerException { try { return ApkSignatureVerifier.unsafeGetCertsWithoutVerification(path, PackageParser.SigningDetails.SignatureSchemeVersion.JAR); } catch (PackageParserException e) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " signatures are inconsistent"); "Couldn't obtain signatures from APK : " + path); } } Loading Loading @@ -2989,8 +3035,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir); } private void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit) private void extractNativeLibraries(PackageLite packageLite, File packageDir, String abiOverride, boolean inherit) throws PackageManagerException { Objects.requireNonNull(packageLite); final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME); if (!inherit) { // Start from a clean slate Loading @@ -2999,7 +3047,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { NativeLibraryHelper.Handle handle = null; try { handle = NativeLibraryHelper.Handle.create(packageDir); handle = NativeLibraryHelper.Handle.create(packageLite); final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir, abiOverride, isIncrementalInstallation()); if (res != INSTALL_SUCCEEDED) { Loading
services/core/java/com/android/server/pm/PackageManagerService.java +13 −5 File changed.Preview size limit exceeded, changes collapsed. Show changes