VerifyingSession 安装验证
VerifyingSession 位于 PackageInstallerSession 提交之后、真正安装之前。它把版本检查、APK 验证广播、Rollback 请求和最终 observer 回调组织到一个异步状态机中。Android 17 中,PackageSessionVerifier 负责创建它,PackageVerificationState 聚合验证器回应,MultiPackageVerifyingSession 再把多个子 session 汇合成一个结果。
1. 验证层次
| 层次 | 类 | 责任 |
|---|---|---|
| session 编排 | PackageSessionVerifier | APEX/APK 前置验证、创建 VerifyingSession |
| 单包状态 | VerifyingSession | 等待 APK verifier、Rollback、observer |
| 验证器聚合 | PackageVerificationState | required/sufficient 响应和超时 |
| 多包汇合 | MultiPackageVerifyingSession | 子包全部结束后回调父 session |
2. 验证入口
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageSessionVerifier.java
public void verify(PackageInstallerSession session, Callback callback) {
mHandler.post(() -> {
try {
storeSession(session.mStagedSession);
if (session.isMultiPackage()) {
for (PackageInstallerSession child :
session.getChildSessions()) {
checkApexUpdateAllowed(child);
checkRebootlessApex(child);
checkApexSignature(child);
}
} else {
checkApexUpdateAllowed(session);
checkRebootlessApex(session);
checkApexSignature(session);
}
verifyAPK(session, callback);
} catch (PackageManagerException e) {
session.setSessionFailed(e.error,
PackageManager.installStatusToString(
e.error, e.getMessage()));
callback.onResult(e.error, e.getMessage());
}
});
}验证在 handler 线程异步执行。APEX 更新限制和 APEX signer 检查先于 APK 验证;任意异常立即把 PackageInstallerSession 标记失败并回调。
3. APEX 签名
private SigningDetails getSigningDetails(
PackageInfo apexPkg) throws PackageManagerException {
final String apexPath = apexPkg.applicationInfo.sourceDir;
final int minSignatureScheme =
ApkSignatureVerifier
.getMinimumSignatureSchemeVersionForTargetSdk(
apexPkg.applicationInfo.targetSdkVersion);
final ParseResult<SigningDetails> result =
ApkSignatureVerifier.verify(
ParseTypeImpl.forDefaultParsing(),
apexPath, minSignatureScheme);
if (result.isError()) {
throw new PackageManagerException(
PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to verify APEX package " + apexPath);
}
return result.getResult();
}APEX 先取得最低 scheme 版本并验证签名,再与设备当前 APEX 的 SigningDetails 比较。这里的错误码是 verification failure,不是普通 APK 的 update incompatible。
4. 创建单包验证会话
private VerifyingSession createVerifyingSession(
PackageInstallerSession session,
IPackageInstallObserver2 observer) {
final UserHandle user;
if ((session.params.installFlags
& PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(session.userId);
}
return new VerifyingSession(
user, session.stageDir, observer, session.params,
session.getInstallSource(), session.getInstallerUid(),
session.getSigningDetails(), session.sessionId,
session.getPackageLite(),
session.getUserActionRequired(), mPm);
}VerifyingSession 保存安装用户、stage 目录、InstallSource、已收集的 SigningDetails、PackageLite、session ID 和 user-action 状态。INSTALL_ALL_USERS 使用 UserHandle.ALL,但不意味着验证器会为每个用户重复执行。
5. 启动与跳过
源码文件:frameworks/base/services/core/java/com/android/server/pm/VerifyingSession.java
public void handleStartVerify() {
PackageInfoLite pkgLite =
PackageManagerServiceUtils.getMinimalPackageInfo(
mPm.mContext, mPackageLite,
mOriginInfo.mResolvedPath,
mInstallFlags, mPackageAbiOverride);
Pair<Integer, String> ret = mPm.verifyReplacingVersionCode(
pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
setReturnCode(ret.first, ret.second);
if (mRet != INSTALL_SUCCEEDED) return;
if (!mOriginInfo.mExisting) {
final boolean verifyForRollback = !isARollback();
if (!isApex() && !isArchivedInstallation()
&& verifyForRollback) {
sendApkVerificationRequest(pkgLite);
}
if ((mInstallFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
sendEnableRollbackRequest();
}
}
}先做最小包信息和 replacing version code 检查。已有文件移动、APEX、归档安装和系统发起的 rollback 会跳过普通 APK verifier;INSTALL_ENABLE_ROLLBACK 仍可单独发起 rollback 请求。
6. 验证器状态
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageVerificationState.java
void addRequiredVerifierUid(int uid) {
mRequiredVerifierUids.put(uid, true);
mUnrespondedRequiredVerifierUids.put(uid, true);
}
void addSufficientVerifier(int uid) {
mSufficientVerifierUids.put(uid, true);
}
void setVerifierResponse(int uid, int code) {
if (mRequiredVerifierUids.get(uid)) {
switch (code) {
case PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT:
mSufficientVerifierUids.clear();
case PackageManager.VERIFICATION_ALLOW:
break;
default:
mRequiredVerificationPassed = false;
mUnrespondedRequiredVerifierUids.clear();
mSufficientVerifierUids.clear();
mExtendedTimeoutUids.clear();
}
mUnrespondedRequiredVerifierUids.delete(uid);
if (mUnrespondedRequiredVerifierUids.size() == 0) {
mRequiredVerificationComplete = true;
}
} else if (mSufficientVerifierUids.get(uid)) {
if (code == PackageManager.VERIFICATION_ALLOW) {
mSufficientVerificationPassed = true;
mSufficientVerificationComplete = true;
}
mSufficientVerifierUids.delete(uid);
if (mSufficientVerifierUids.size() == 0) {
mSufficientVerificationComplete = true;
}
}
}required verifier 必须全部回应且不能拒绝;sufficient verifier 只需一个允许,或所有 sufficient 都结束。ALLOW_WITHOUT_SUFFICIENT 会清空 sufficient 等待,表示 required verifier 已足够决定安装。
boolean isVerificationComplete() {
if (!mRequiredVerificationComplete) return false;
if (mSufficientVerifierUids.size() == 0) return true;
return mSufficientVerificationComplete;
}
boolean isInstallAllowed() {
if (!mRequiredVerificationComplete
|| !mRequiredVerificationPassed) return false;
if (mSufficientVerificationComplete) {
return mSufficientVerificationPassed;
}
return true;
}完成与允许是两个概念:required 完成后,若 sufficient 尚未结束,isVerificationComplete 仍为 false;只有完成后才应调用 isInstallAllowed。
7. 超时延长
boolean extendTimeout(int uid, long millisToDelay) {
if (!checkRequiredVerifierUid(uid)) return false;
if (timeoutExtended(uid)
&& !Flags.extendVerificationTimeoutMultipleTimes()) {
return false;
}
if (millisToDelay < 0) millisToDelay = 0;
long delay = millisToDelay + mExtendedTimeoutUids.get(uid);
if (delay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) {
delay = PackageManager.MAXIMUM_VERIFICATION_TIMEOUT;
}
mExtendedTimeoutUids.put(uid, delay);
return true;
}只有 required verifier 能延长超时;延长时间不能为负,也不能超过全局最大值。是否允许多次延长由 feature flag 控制。
8. 等待汇合
源码文件:frameworks/base/services/core/java/com/android/server/pm/VerifyingSession.java
void setReturnCode(int ret, String message) {
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
mRet = ret;
mErrorMessage = message;
}
}
void handleVerificationFinished() {
mWaitForVerificationToComplete = false;
handleReturnCode();
}
void handleRollbackEnabled() {
mWaitForEnableRollbackToComplete = false;
handleReturnCode();
}
void handleReturnCode() {
if (mWaitForVerificationToComplete
|| mWaitForEnableRollbackToComplete) return;
sendVerificationCompleteNotification();
}验证和 rollback 是两个独立等待条件。任意一个失败会写入返回码,但不会覆盖先前失败;只有两个等待标志都清除,才通知父 session 或 observer。
9. 多包 session
源码文件:frameworks/base/services/core/java/com/android/server/pm/MultiPackageVerifyingSession.java
public void start() {
for (VerifyingSession child : mChildVerifyingSessions) {
child.handleStartVerify();
}
for (VerifyingSession child : mChildVerifyingSessions) {
child.handleReturnCode();
}
}
public void trySendVerificationCompleteNotification(
VerifyingSession child) {
mVerificationState.add(child);
if (mVerificationState.size()
!= mChildVerifyingSessions.size()) return;
int completeStatus = PackageManager.INSTALL_SUCCEEDED;
String errorMsg = null;
for (VerifyingSession state : mVerificationState) {
if (state.getRet() != PackageManager.INSTALL_SUCCEEDED) {
completeStatus = state.getRet();
errorMsg = state.getErrorMessage();
break;
}
}
mObserver.onPackageInstalled(
null, completeStatus, errorMsg, new Bundle());
}父 session 创建一个 VerifyingSession 管理器,把 parent 引用注入每个 child。所有 child 都完成后,父 observer 才收到结果;任一 child 失败,父结果采用第一个失败状态。
10. 排查清单
INSTALL_FAILED_VERIFICATION_FAILURE:先看 APEX verifier 或 APK verifier,而不是签名兼容比较。- 验证卡住:检查 required UID 是否已注册、是否回应、是否延长超时。
- 批量安装结果异常:逐个查看 child VerifyingSession,父结果只在全部 child 回调后产生。
- 回滚安装跳过 verifier:确认
isARollback()的 install reason 和 initiating package。 - 验证成功但 session 未 ready:检查 rollback 等待标志是否仍为 true。
11. 源码阅读路线
PackageSessionVerifier.verify:验证线程和 APEX 前置检查。createVerifyingSession:session 参数如何封装。VerifyingSession.handleStartVerify:版本检查和跳过条件。PackageVerificationState:required/sufficient、超时和允许判断。VerifyingSession.handleReturnCode:多个异步条件的汇合。MultiPackageVerifyingSession:子 session 到父 observer 的汇合。
VerifyingSession 的核心不是发送一条验证广播,而是把“版本检查、验证器回应、超时、rollback 和多包回调”纳入同一个完成条件。只有把这些等待条件逐一对照源码,才能解释安装为什么提前失败、持续等待或成功进入下一阶段。
