签名权限
signature 权限的授予条件不是简单比较两个证书字节。Android 17 的 AppIdPermissionPolicy 同时考虑权限定义包的签名、请求包的签名 lineage、PERMISSION capability、平台包 lineage,以及平台签名权限的 allowlist。knownSigner 则走证书摘要集合,和普通 signature capability 是两条不同路径。
1. 授予条件分层
| 层 | 判断 |
|---|---|
| 基础类型 | permission.isSignature |
| 定义包关系 | sourceSigningDetails 与请求包 signer |
| lineage 能力 | PERMISSION |
| 平台关系 | platform package signer/capability |
| 额外保护 | platform signature allowlist、knownSigner |
2. 类型与标志
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/Permission.kt
inline val isSignature: Boolean
get() = protection == PermissionInfo.PROTECTION_SIGNATURE
inline val isKnownSigner: Boolean
get() = protectionFlags.hasBits(
PermissionInfo.PROTECTION_FLAG_KNOWN_SIGNER)
inline val knownCerts: Set<String>
get() = permissionInfo.knownCertsisSignature 只看基础 protection,knownSigner 是附加 flag。一个 permission 可以是 signature 基础级别并附加 privileged、knownSigner 等策略;代码必须分别读取这两个属性。
3. 签名关系主函数
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
private fun MutateStateScope.shouldGrantPermissionBySignature(
packageState: PackageState,
permission: Permission,
): Boolean {
val packageSigningDetails =
packageState.androidPackage!!.signingDetails
val sourceSigningDetails =
newState.externalState.packageStates[permission.packageName]
?.androidPackage?.signingDetails
val platformSigningDetails =
newState.externalState.packageStates[PLATFORM_PACKAGE_NAME]!!
.androidPackage!!.signingDetails
val hasCommonSigner =
sourceSigningDetails?.hasCommonSignerWithCapability(
packageSigningDetails,
SigningDetails.CertCapabilities.PERMISSION,
) == true ||
packageSigningDetails.hasAncestorOrSelf(
platformSigningDetails) ||
platformSigningDetails.checkCapability(
packageSigningDetails,
SigningDetails.CertCapabilities.PERMISSION,
)允许来源有三类:定义包与请求包共享具备 PERMISSION 的 signer;请求包 lineage 包含平台 signer;平台 signer 对请求包授予 PERMISSION capability。未知定义包签名时,第一项为空,后两项仍可能决定结果。
4. 能力与精确匹配
hasCommonSignerWithCapability 允许在 lineage 中寻找共同 signer;checkCapability 则要求目标旧 signer 出现在当前对象的 lineage,并且历史 Signature.flags 包含所需能力。多 signer 包不支持 rotation,最终退化为 exact match。
boolean matchFound = hasCertificate(
oldDetails.mSignatures[0], flags);
if (oldDetails.mSignatures.length > 1) {
return signaturesMatchExactly(oldDetails);
}因此签名权限问题不能只看“当前证书不同”。应继续检查旧证书是否位于 lineage,以及新 signer 是否仍授予 PERMISSION。
5. 平台权限白名单
if (!Flags.signaturePermissionAllowlistEnabled()) {
return hasCommonSigner
}
if (!hasCommonSigner) {
return false
}
if (permission.packageName == PLATFORM_PACKAGE_NAME) {
val isRequestedByFactoryApp =
if (packageState.isSystem) {
if (packageState.isUpdatedSystemApp) {
val disabledSystemPackage =
newState.externalState.disabledSystemPackageStates[
packageState.packageName]?.androidPackage
disabledSystemPackage != null &&
permission.name in
disabledSystemPackage.requestedPermissions
} else {
true
}
} else {
false
}
if (!(isRequestedByFactoryApp ||
getSignaturePermissionAllowlistState(
packageState, permission.name) == true
)) {
if (!Build.isDebuggable()
|| isSignaturePermissionAllowlistForceEnforced) {
return false
}
}
}
return trueallowlist flag 关闭时,签名关系足够;开启后,平台包定义的 signature permission 还要求出厂 system app 请求过,或签名 allowlist 明确为 true。debuggable 构建默认可只告警,user 构建或 force-enforced 则拒绝。
6. knownSigner 路径
源码文件:frameworks/base/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
if (
permission.isKnownSigner &&
androidPackage.signingDetails.hasAncestorOrSelfWithDigest(
permission.knownCerts)
) {
return true
}knownSigner 不要求请求包与定义包拥有同一 signer,而是检查请求包当前/历史证书的 SHA-256 digest 是否落在 permission 的 knownCerts 集合。摘要匹配成功后即可满足该附加策略,但仍处在整体权限授予重算流程中。
7. 其他保护标志
签名关系通过后,policy 还会处理 installer、verifier、preInstalled、setup、module、role 等附加 flag。它们依据 known package、系统分区或角色 holder 判断,不应与 PERMISSION capability 混为一谈。
8. 权限重算时机
val shouldGrantBySignature =
permission.isSignature &&
requestingPackageStates.anyIndexed { _, packageState ->
shouldGrantPermissionBySignature(
packageState, permission)
}
if (mayGrantByPrivileged &&
(shouldGrantBySignature || shouldGrantByProtectionFlags)
) {
PermissionFlags.PROTECTION_GRANTED
}签名权限不是在每次 checkPermission 时重新比较证书,而是在包扫描、安装更新和权限状态 reconcile 时计算 flags。之后运行时检查读取已计算的 PROTECTION_GRANTED,签名变更会触发下一次重算和必要的状态清理。
9. 排查清单
- 确认 permission 基础 protection 是否为 signature,附加 flag 是否包含 knownSigner/privileged。
- 对比定义包、请求包和 platform 包的
SigningDetails。 - 检查 lineage 中旧 signer 的
PERMISSIONflags,而不是只看当前证书。 - 多 signer 包按 exact match 排查,不套用 rotation。
- 平台 signature permission 检查 factory app 请求和分区 allowlist。
- knownSigner 权限检查
knownCertsdigest 是否包含当前/历史证书。 - 确认权限状态是否经历了包更新后的 reconcile;旧 flags 可能尚未被清理或重算。
10. 源码阅读路线
Permission.isSignature/isKnownSigner/knownCerts:确认类型与附加标志。AppIdPermissionPolicy.shouldGrantPermissionBySignature:主授予路径。SigningDetails.hasCommonSignerWithCapability:定义包与请求包的共同 signer。SigningDetails.checkCapability:lineage capability 判定。AppIdPermissionPolicy的 knownSigner 和平台 allowlist 分支。- 权限 reconcile 中
PROTECTION_GRANTED写入:确认何时把签名关系变成用户状态。
签名权限的核心不是“证书相等”,而是 signer 身份、lineage 方向、PERMISSION capability、平台 allowlist 和 knownCerts 共同决定的策略。把这些条件拆开阅读,才能解释密钥轮换后权限为何继续保留、被撤销或只在特定构建中失败。
