private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “parsePackage”);
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
DexMetadataHelper.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
res.setError(“Failed parse during installPackageLI”, e);
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
// either use what we’ve been given or parse directly from the APK
if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
pkg.setSigningDetails(args.signingDetails);
} else {
PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
} catch (PackageParserException e) {
res.setError(“Failed collect during installPackageLI”, e);
return;
}
}
-
首先实例化一个PackageParser的对象pp,利用这个对象的parsePackage()方法,返回一个位于PackageParser类中的内部类Package的实例对象pkg,其中包含着要安装的应用的一些信息
-
利用PackageParser的一个静态方法collectCertificates(pkg,false)收集证书,这里就是验签的入口了
PackageParser.collectCertificates()
frameworks/base/core/java/android/content/pm/PackageParser.java
public static void collectCertificates(Package pkg, boolean skipVerify)
throws PackageParserException {
collectCertificatesInternal(pkg, skipVerify);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
Package childPkg = pkg.childPackages.get(i);
childPkg.mSigningDetails = pkg.mSigningDetails;
}
}
private static void collectCertificatesInternal(Package pkg, boolean skipVerify)
throws PackageParserException {
pkg.mSigningDetails = SigningDetails.UNKNOWN;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “collectCertificates”);
try {
collectCertificates(pkg, new File(pkg.baseCodePath), skipVerify);
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
for (int i = 0; i < pkg.splitCodePaths.length; i++) {
collectCertificates(pkg, new File(pkg.splitCodePaths[i]), skipVerify);
}
}
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
private static void collectCertificates(Package pkg, File apkFile, boolean skipVerify)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
// must use v2 signing scheme
minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
SigningDetails verified;
if (skipVerify) {
// systemDir APKs are already trusted, save time by not verifying
verified = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
apkPath, minSignatureScheme);
} else {
verified = ApkSignatureVerifier.verify(apkPath, minSignatureScheme);
}
// Verify that entries are signed consistently with the first pkg
// we encountered. Note that for splits, certificates may have
// already been populated during an earlier parse of a base APK.
if (pkg.mSigningDetails == SigningDetails.UNKNOWN) {
pkg.mSigningDetails = verified;
} else {
if (!Signature.areExactMatch(pkg.mSigningDetails.signatures, verified.signatures)) {
throw new PackageParserException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
apkPath + " has mismatched certificates");
}
}
}
- collectCertificates重载到三个参数的方法,因为跳过检查的参数为false,最终调用ApkSignatureVerifier类中的verify方法
ApkSignatureVerifier.verify()
frameworks/base/core/java/android/util/apk/ApkSignatureVerifier.java
public static PackageParser.SigningDetails verify(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion)
throws PackageParserException {
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
// V3 and before are older than the requested minimum signing version
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
- " or newer for package " + apkPath);
}
// first try v3
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, “verifyV3”);
try {
ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
ApkSignatureSchemeV3Verifier.verify(apkPath);
Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
Signature[] signerSigs = convertToSignatures(signerCerts);
Signature[] pastSignerSigs = null;
int[] pastSignerSigsFlags = null;
if (vSigner.por != null) {
// populate proof-of-rotation information
pastSignerSigs = new Signature[vSigner.por.certs.size()];
pastSignerSigsFlags = new int[vSigner.por.flagsList.size()];
for (int i = 0; i < pastSignerSigs.length; i++) {
pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded());
pastSignerSigsFlags[i] = vSigner.por.flagsList.get(i);
}
}
return new PackageParser.SigningDetails(
signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3,
pastSignerSigs, pastSignerSigsFlags);
-
这里会首先尝试v3的签名方案,然后v2v1依次尝试,这里只给出v3的部分,最终返回一个PackageParser类中的内部类SigningDetails的对象
-
检查v3版本签名调用ApkSignatureSchemeV3Verifier类中的verify()方法
ApkSignatureSchemeV3Verifier.verify()
frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0;
public static VerifiedSigner verify(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
return verify(apkFile, true);
}
/**
-
Returns the certificates associated with each signer for the given APK without verification.
-
This method is dangerous and should not be used, unless the caller is absolutely certain the
-
APK is trusted. Specifically, verification is only done for the APK Signature Scheme v3
-
Block while gathering signer information. The APK contents are not verified.
-
@throws SignatureNotFoundException if the APK is not signed using APK Signature Scheme v3.
-
@throws IOException if an I/O error occurs while reading the APK file.
*/
public static VerifiedSigner plsCertsNoVerifyOnlyCerts(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
return verify(apkFile, false);
}
private static VerifiedSigner verify(String apkFile, boolean verifyIntegrity)
throws SignatureNotFoundException, SecurityException, IOException {
try (RandomAccessFile apk = new RandomAccessFile(apkFile, “r”)) {
return verify(apk, verifyI