在app安装时,系统会采集app的签名进行保存,不了解的请看https://blog.csdn.net/Cailand/article/details/103870784
手机签名的用处就是方尺防止安装的apk是非法来源的,那么系统是怎么进行校验的呢,下面我们通过Android9.0的源码进行分析
查看installPackageLI方法如下
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
..........................
..........................
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
pp.setCallback(mPackageParserCallback);
..............................
..............................
//解析apk中的签名文件
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;
}
.............................
.............................
//获取已安装的信息
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
// Static shared libs have same package with different versions where
// we internally use a synthetic package name to allow multiple versions
// of the same package, therefore we need to compare signatures against
// the package setting for the latest library version.
PackageSetting signatureCheckPs = ps;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
if (libraryEntry != null) {
signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
}
}
// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
return;
}
} else {
try {
final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
// We don't care about disabledPkgSetting on install for now.
//此处去比较两个apk的签名文件
final boolean compatMatch = verifySignatures( signatureCheckPs, null, pkg.mSigningDetails, compareCompat, compareRecover);
// The new KeySets will be re-added later in the scanning process.
if (compatMatch) {
synchronized (mPackages) {
ksms.removeAppKeySetDataLPw(pkg.packageName);
}
}
} catch (PackageManagerException e) {
res.setError(e.error, e.getMessage());
return;
}
}
oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
}
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
............
...................
}
接下来看verifySignatures方法
public static boolean verifySignatures(PackageSetting pkgSetting,
PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures,
boolean compareCompat, boolean compareRecover)
throws PackageManagerException {
final String packageName = pkgSetting.name;
boolean compatMatch = false;
if (pkgSetting.signatures.mSigningDetails.signatures != null) {
// Already existing package. Make sure signatures match
boolean match = parsedSignatures.checkCapability(
pkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
|| pkgSetting.signatures.mSigningDetails.checkCapability(
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
if (!match && compareCompat) {
match = matchSignaturesCompat(packageName, pkgSetting.signatures,
parsedSignatures);
compatMatch = match;
}
if (!match && compareRecover) {
match = matchSignaturesRecover(
packageName,
pkgSetting.signatures.mSigningDetails,
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
|| matchSignaturesRecover(
packageName,
parsedSignatures,
pkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
}
if (!match && isApkVerificationForced(disabledPkgSetting)) {
match = matchSignatureInSystem(pkgSetting, disabledPkgSetting);
}
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + packageName +
" signatures do not match previously installed version; ignoring!");
}
}
// Check for shared user signatures
if (pkgSetting.sharedUser != null
&& pkgSetting.sharedUser.signatures.mSigningDetails
!= PackageParser.SigningDetails.UNKNOWN) {
// Already existing package. Make sure signatures match. In case of signing certificate
// rotation, the packages with newer certs need to be ok with being sharedUserId with
// the older ones. We check to see if either the new package is signed by an older cert
// with which the current sharedUser is ok, or if it is signed by a newer one, and is ok
// with being sharedUser with the existing signing cert.
boolean match =
parsedSignatures.checkCapability(
pkgSetting.sharedUser.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
|| pkgSetting.sharedUser.signatures.mSigningDetails.checkCapability(
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
if (!match && compareCompat) {
match = matchSignaturesCompat(
packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
}
if (!match && compareRecover) {
match =
matchSignaturesRecover(packageName,
pkgSetting.sharedUser.signatures.mSigningDetails,
parsedSignatures,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID)
|| matchSignaturesRecover(packageName,
parsedSignatures,
pkgSetting.sharedUser.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID);
compatMatch |= match;
}
if (!match) {
throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
"Package " + packageName
+ " has no signatures that match those in shared user "
+ pkgSetting.sharedUser.name + "; ignoring!");
}
}
return compatMatch;
}
调用了SigningDetails的checkCapability的方法,继续深入
public boolean signaturesMatchExactly(SigningDetails other) {
return Signature.areExactMatch(this.signatures, other.signatures);
}
查看Signature.areExactMatch
public static boolean areExactMatch(Signature[] a, Signature[] b) {
return (a.length == b.length) && ArrayUtils.containsAll(a, b)
&& ArrayUtils.containsAll(b, a);
}
从这里可以看到,只有传入的两个签名数据(Certificate)完全一样才返回true,下面的判断同理,而最后如果match还是false就会抛出异常.