Merge "Only parse an APK once" into nyc-dev

This commit is contained in:
Todd Kennedy
2016-04-07 16:51:10 +00:00
committed by Android (Google) Code Review
3 changed files with 87 additions and 24 deletions

View File

@@ -385,6 +385,7 @@ public class PackageParser {
public final int installLocation;
public final VerifierInfo[] verifiers;
public final Signature[] signatures;
public final Certificate[][] certificates;
public final boolean coreApp;
public final boolean multiArch;
public final boolean use32bitAbi;
@@ -392,8 +393,8 @@ public class PackageParser {
public ApkLite(String codePath, String packageName, String splitName, int versionCode,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
Signature[] signatures, boolean coreApp, boolean multiArch, boolean use32bitAbi,
boolean extractNativeLibs) {
Signature[] signatures, Certificate[][] certificates, boolean coreApp,
boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -402,6 +403,7 @@ public class PackageParser {
this.installLocation = installLocation;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
this.signatures = signatures;
this.certificates = certificates;
this.coreApp = coreApp;
this.multiArch = multiArch;
this.use32bitAbi = use32bitAbi;
@@ -1073,6 +1075,43 @@ public class PackageParser {
return APK_SIGNING_UNKNOWN;
}
/**
* Populates the correct packages fields with the given certificates.
* <p>
* This is useful when we've already processed the certificates [such as during package
* installation through an installer session]. We don't re-process the archive and
* simply populate the correct fields.
*/
public static void populateCertificates(Package pkg, Certificate[][] certificates)
throws PackageParserException {
pkg.mCertificates = null;
pkg.mSignatures = null;
pkg.mSigningKeys = null;
pkg.mCertificates = certificates;
try {
pkg.mSignatures = convertToSignatures(certificates);
} catch (CertificateEncodingException e) {
// certificates weren't encoded properly; something went wrong
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Failed to collect certificates from " + pkg.baseCodePath, e);
}
pkg.mSigningKeys = new ArraySet<>(certificates.length);
for (int i = 0; i < certificates.length; i++) {
Certificate[] signerCerts = certificates[i];
Certificate signerCert = signerCerts[0];
pkg.mSigningKeys.add(signerCert.getPublicKey());
}
// add signatures to child packages
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
Package childPkg = pkg.childPackages.get(i);
childPkg.mCertificates = pkg.mCertificates;
childPkg.mSignatures = pkg.mSignatures;
childPkg.mSigningKeys = pkg.mSigningKeys;
}
}
/**
* Collect certificates from all the APKs described in the given package,
* populating {@link Package#mSignatures}. Also asserts that all APK
@@ -1304,6 +1343,7 @@ public class PackageParser {
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final Signature[] signatures;
final Certificate[][] certificates;
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
// TODO: factor signature related items out of Package object
final Package tempPkg = new Package(null);
@@ -1314,12 +1354,14 @@ public class PackageParser {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
signatures = tempPkg.mSignatures;
certificates = tempPkg.mCertificates;
} else {
signatures = null;
certificates = null;
}
final AttributeSet attrs = parser;
return parseApkLite(apkPath, res, parser, attrs, flags, signatures);
return parseApkLite(apkPath, res, parser, attrs, flags, signatures, certificates);
} catch (XmlPullParserException | IOException | RuntimeException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -1405,8 +1447,8 @@ public class PackageParser {
}
private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser,
AttributeSet attrs, int flags, Signature[] signatures) throws IOException,
XmlPullParserException, PackageParserException {
AttributeSet attrs, int flags, Signature[] signatures, Certificate[][] certificates)
throws IOException, XmlPullParserException, PackageParserException {
final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs);
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
@@ -1466,8 +1508,8 @@ public class PackageParser {
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
use32bitAbi, extractNativeLibs);
revisionCode, installLocation, verifiers, signatures, certificates, coreApp,
multiArch, use32bitAbi, extractNativeLibs);
}
/**

View File

@@ -81,6 +81,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileFilter;
import java.io.IOException;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -151,6 +152,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private String mPackageName;
private int mVersionCode;
private Signature[] mSignatures;
private Certificate[][] mCertificates;
/**
* Path to the validated base APK for this session, which may point at an
@@ -633,7 +635,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mRelinquished = true;
mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
installerPackageName, installerUid, user);
installerPackageName, installerUid, user, mCertificates);
}
/**
@@ -695,6 +697,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
if (mSignatures == null) {
mSignatures = apk.signatures;
mCertificates = apk.certificates;
}
assertApkConsistent(String.valueOf(addedFile), apk);

View File

@@ -278,6 +278,7 @@ import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
@@ -10977,7 +10978,8 @@ public class PackageManagerService extends IPackageManager.Stub {
null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
null /*packageAbiOverride*/, null /*grantedPermissions*/);
null /*packageAbiOverride*/, null /*grantedPermissions*/,
null /*certificates*/);
params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -10991,7 +10993,8 @@ public class PackageManagerService extends IPackageManager.Stub {
void installStage(String packageName, File stagedDir, String stagedCid,
IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
String installerPackageName, int installerUid, UserHandle user) {
String installerPackageName, int installerUid, UserHandle user,
Certificate[][] certificates) {
if (DEBUG_EPHEMERAL) {
if ((sessionParams.installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {
Slog.d(TAG, "Ephemeral install of " + packageName);
@@ -11012,7 +11015,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final InstallParams params = new InstallParams(origin, null, observer,
sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
verificationInfo, user, sessionParams.abiOverride,
sessionParams.grantedRuntimePermissions);
sessionParams.grantedRuntimePermissions, certificates);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12107,11 +12110,12 @@ public class PackageManagerService extends IPackageManager.Stub {
final String packageAbiOverride;
final String[] grantedRuntimePermissions;
final VerificationInfo verificationInfo;
final Certificate[][] certificates;
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
String[] grantedPermissions) {
String[] grantedPermissions, Certificate[][] certificates) {
super(user);
this.origin = origin;
this.move = move;
@@ -12122,6 +12126,7 @@ public class PackageManagerService extends IPackageManager.Stub {
this.verificationInfo = verificationInfo;
this.packageAbiOverride = packageAbiOverride;
this.grantedRuntimePermissions = grantedPermissions;
this.certificates = certificates;
}
@Override
@@ -12590,6 +12595,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** If non-null, drop an async trace when the install completes */
final String traceMethod;
final int traceCookie;
final Certificate[][] certificates;
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -12600,7 +12606,7 @@ public class PackageManagerService extends IPackageManager.Stub {
int installFlags, String installerPackageName, String volumeUuid,
UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
String traceMethod, int traceCookie) {
String traceMethod, int traceCookie, Certificate[][] certificates) {
this.origin = origin;
this.move = move;
this.installFlags = installFlags;
@@ -12613,6 +12619,7 @@ public class PackageManagerService extends IPackageManager.Stub {
this.installGrantPermissions = installGrantPermissions;
this.traceMethod = traceMethod;
this.traceCookie = traceCookie;
this.certificates = certificates;
}
abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
@@ -12705,9 +12712,9 @@ public class PackageManagerService extends IPackageManager.Stub {
FileInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
params.traceMethod, params.traceCookie, params.certificates);
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
}
@@ -12716,7 +12723,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** Existing install */
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
null, null, null, 0);
null, null, null, 0, null /*certificates*/);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
@@ -12941,15 +12948,15 @@ public class PackageManagerService extends IPackageManager.Stub {
params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
params.traceMethod, params.traceCookie, params.certificates);
}
/** Existing install */
AsecInstallArgs(String fullCodePath, String[] instructionSets,
boolean isExternal, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, null, null, 0);
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, null, null, 0, null /*certificates*/);
// Hackily pretend we're still looking at a full code path
if (!fullCodePath.endsWith(RES_FILE_NAME)) {
fullCodePath = new File(fullCodePath, RES_FILE_NAME).getAbsolutePath();
@@ -12965,8 +12972,8 @@ public class PackageManagerService extends IPackageManager.Stub {
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, null, null, 0);
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, null, null, 0, null /*certificates*/);
this.cid = cid;
setMountPath(PackageHelper.getSdDir(cid));
}
@@ -13235,7 +13242,7 @@ public class PackageManagerService extends IPackageManager.Stub {
params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
params.traceMethod, params.traceCookie, params.certificates);
}
int copyApk(IMediaContainerService imcs, boolean temp) {
@@ -14274,7 +14281,18 @@ public class PackageManagerService extends IPackageManager.Stub {
}
try {
PackageParser.collectCertificates(pkg, parseFlags);
// either use what we've been given or parse directly from the APK
if (args.certificates != null) {
try {
PackageParser.populateCertificates(pkg, args.certificates);
} catch (PackageParserException e) {
// there was something wrong with the certificates we were given;
// try to pull them from the APK
PackageParser.collectCertificates(pkg, parseFlags);
}
} else {
PackageParser.collectCertificates(pkg, parseFlags);
}
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
@@ -19159,7 +19177,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
installerPackageName, volumeUuid, null /*verificationInfo*/, user,
packageAbiOverride, null);
packageAbiOverride, null /*grantedPermissions*/, null /*certificates*/);
params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;