一. 签名分析
使用:
Auto-sign 执行命令
java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk
通过signapk.jar这个可执行jar包,以“testkey.x509.pem”这个公钥文件和“testkey.pk8”这个私钥文件对“update.apk”进行签名,签名后的文件保存为“update_signed.apk”
签名的APK差异:
MANIFEST.MF: 遍历所有文件entry 逐个生成SHA1的数字签名信息,再用Base64进行编码(build/tools/signapk/SignApk.java addDigestsToManifest)
SHA1数字签名。简单地说,它就是一种安全哈希算法,类似于MD5算法。它把任意长度的输入,通过散列算法变成固定长度的输出(摘要信息)
CERT.SF Manifest,使用SHA1-RSA算法,用私钥进行签名
CERT.RSA 公钥签名, 同时对比差异的位置。
获取签名的api:
frameworks/base/core/java/android/content/pm/PackageParser.java
//archiveFilePath指定APK文件路径;flags需设置PackageManager.GET_SIGNATURES
parsePackage(String archiveFilePath, int flags) {
....
//根据包名收集签名信息至PackageParser.Package 签名在PackageParser.Package.mSignatures
packageParser.collectCertificates(pkg, 0);
....
}
二.PMS分析
调用
PackageManagerService是通过使用Context的getPackageManager,在ContextImpl返回的PackageManager实际上是new的ApplicationPackageManager
概括
1.启动
和安装的重要变量 mInstaller(InstallerConnection) 和 mInstallerService (管理安装)
ApplicationPackageManager.installCommon {mPM.installPackage}-> PMS installPackageAsUser->PMS (doHandleMessage)INIT_COPY-> MCS_BOUND
startCopy->handleStartCopy()
2.Setting.java 解析 packages.xml 对包名信息解析。
3.解析安装APK
过程比较繁杂,整理一下调用关系更容易分析。从扫描开始:
1. PMS construction { scanDirLI } -> scanDirLI -> scanPackageLI -> scanPackageInternalLI
2. handleStartCopy-> Handler msg case:CHECK_PENDING_VERIFICATION -> processPendingInstall ->
installPackageLI -> installNewPackageLIF (安装新apk) -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
---------------------------------------------------------------------------------------------
installPackageLI -> replacePackageLI -> replaceNonSystemPackageLI -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
installPackageLI -> replacePackageLI -> replaceSystemPackageLI -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
---------------------------------------------------------------------------------------------
most of method invoke deletePackageLIF -> deleteSystemPackageLIF
---------------------------------------------------------------------------------------------
StorageEventListener onVolumeStateChanged ->
1.loadPrivatePackages -> loadPrivatePackagesInner -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
2.unloadPrivatePackages -> unloadPrivatePackagesInner -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
3.updateExternalMediaStatus -> updateExternalMediaStatusInner ->
1.loadMediaPackages -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
2.unloadMediaPackages -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
---------------------------------------------------------------------------------------------
三.修改
分析代码我们可以从调用关系入手 installNewPackageLIF 看起来比较合理,于是在:
installNewPackageLI
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
//checkSignature here ok
//2.后来修改在这里使用pkg.mSignatures 是可以的。
if (!checkSystemSignature(pkg.mSignatures)) {
res.setError(INSTALL_FAILED_INVALID_APK, "Can't install unsigned apk");
return;
}
//getDataUserPackageDirectory will new file in data/data/xxx.xxx(packageName)
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
final boolean dataDirExists = Environment
.getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists();
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
//checkSignature here only effect first time install
//1. 刚开始是在这里加入 使用newPackage.mSignatures check签名最后发现有问题: 只有第一次有效,第二次无法拦截。
//原因: getDataUserPackageDirectory 在data/data/目录创建了相应 apk的包名信息导致在 installPackageLI() 检查mPackages.containsKey(pkgName)
//已经包含了创建的包名导致replace = true 从而走到 replacePackageLIF
/* installPackageLI.java
if (replace) {
.......
replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, res, args.installReason);
} else {
installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, volumeUuid, res, args.installReason);
}
*/
检查签名:
在Android.mk 中有三种签名,默认是release 签名。
LOCAL_CERTIFICATE := platform
LOCAL_CERTIFICATE := shared
LOCAL_CERTIFICATE := media
需求是除了platform shared media外的的签名不安装
public boolean checkSystemSignature(Signature[] sig) {
synchronized (mPackages) {
final PackageParser.Package p2 = mPackages.get("com.android.xxx");
if (p2 == null || p2.mExtras == null) {
return false;
}
final PackageParser.Package p3 = mPackages.get("com.android.xxxxx");
if (p3 == null || p3.mExtras == null) {
return false;
}
final PackageParser.Package p4 = mPackages.get("com.android.xxxxxxx");
if (p4 == null || p4.mExtras == null) {
Log.d(TAG, "p4 = null");
return false;
}
if (compareSignatures(sig, p2.mSignatures) == PackageManager.SIGNATURE_MATCH
|| compareSignatures(sig, p3.mSignatures) == PackageManager.SIGNATURE_MATCH
|| compareSignatures(sig, p4.mSignatures) == PackageManager.SIGNATURE_MATCH) {
return true;
}else {
return false;
}
}
}
这样功能已经完成,最后优化下,在installPackageLI 中修改 可以更快的生效 因为 installPackageLI 调用的 installNewPackageLI.
参考: https://blog.csdn.net/long375577908/article/details/78550913