签名校验:APK 的身份证如何验证
2026/8/9大约 4 分钟PMS 专题Android 14PMS签名APK Signature
签名校验:APK 的身份证如何验证
上一章安装流程里,提交阶段会做签名校验。这一章回答:APK 为什么必须签名,v1/v2/v3 方案怎么工作,“签名不一致”为什么会拒绝更新?
APK 签名用于验证内容完整性并识别发布者,不对 APK 内容加密。更新场景还要验证新旧版本 签名身份是否兼容,否则相同包名无法取得旧应用的数据与权限身份。
签名证明身份,不隐藏 APK 内容
| 常见误解 | 正确理解 |
|---|---|
| 签名是“加密 APK” | 签名是“身份证明”,不加密内容,任何人可读 APK |
| 签名只影响安装 | 更新、签名级权限、系统应用身份都依赖签名一致性 |
| 签名在解析时就完成验证 | 解析读取签名信息,安装提交阶段才做完整验证 |
核心结论
- 签名用途三件套:防篡改、认身份、支撑签名级权限。
- v1 验证整个 JAR 条目;v2 在签名块中验证整个 APK;v3 在 v2 基础上支持密钥轮换。
- 安装时验证“APK 自洽”:签名有效且内容未被篡改。
- 更新时验证“新旧一致”:新签名必须与已安装版本匹配,否则拒绝更新。
- 签名证书可用于
signature级权限:只有同一签名的应用可申请。
校验主链
逐步解释:
- 读取签名块:从 APK 中提取证书与摘要信息。
- 比对摘要:确认 APK 内容与签名时一致,未被篡改。
- 安装场景:只需验证 APK 自身签名有效。
- 更新场景:还要与已安装版本的签名比对,不一致则拒绝。
v1、v2、v3 差异
| 方案 | 覆盖范围 | 特点 |
|---|---|---|
| v1(JAR) | 逐个文件条目 | 兼容旧系统,可被重打包攻击,性能一般 |
| v2 | 整个 APK | 更快更安全,校验在签名块 |
| v3 | 整个 APK | 在 v2 基础上支持密钥轮换与旧密钥继承 |
新应用默认同时带 v2/v3;需要兼容很老系统时才保留 v1。调试“签名不一致”时先确认新旧 APK 的签名证书是否来自同一密钥。
源码证据
阅读目标:确认校验入口与更新比对位置。
正文指针:PackageManagerService.java 中安装期签名校验与 Signature.java; apksig 在 external/apksig/。
// PackageManagerService.java(伪代码,行号以 r75 为准)
boolean verifySignatures(Package pkg, ...) {
// 安装:验证自洽;更新:与新签名比对
}这段代码证明: 安装与更新共用校验框架,但“更新比对”会单独比较新旧签名集; 不一致返回 INSTALL_FAILED_UPDATE_INCOMPATIBLE 一类错误。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell dumpsys package <包名> | grep -A2 "signatures"
adb shell pm install -r /data/local/tmp/app.apk先看已安装版本的签名证书,再对新 APK 用 apksigner verify --print-certs 对照;两者 证书不一致就是更新失败根因。注意:v2/v3 校验失败往往在安装早期就报错,日志关键字 通常是 INSTALL_FAILED_* 与 Signature 相关输出。
常见误区
- “签名 = 加密”:签名不加密内容。
- “更新失败一定是权限问题”:签名不一致是高频根因之一。
- “签名只在安装时检查”:运行期签名级权限、系统身份判断都会用到。
- “重新签名可以随便装”:换签名会破坏更新链,也影响依赖它的签名级权限。
延伸问题
- v3 密钥轮换如何让新旧密钥同时有效?
- 系统签名(platform key)与普通签名的应用如何区分?
- 增量安装的 v4 签名如何与 v2/v3 协作?
- 如何审计一个 APK 的签名证书是否可信?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
PackageManagerService.java | verifySignatures() | 安装/更新校验 |
Signature.java | 证书对象 | 签名表示 |
external/apksig/ | 验证实现 | v1/v2/v3 算法 |
PackageParser2.java | 解析期签名读取 | 提取签名信息 |
公共路径:Java 侧 frameworks/base/services/core/java/com/android/server/pm/ 与 frameworks/base/core/java/android/content/pm/;apksig 在 external/apksig/。 行号以 r75 检索为准。
签名身份如何影响授权,见 权限授予。