Skip to content

VerifyingSession 安装验证

分析 VerifyingSession 的安装验证、验证器状态聚合、超时和多包 session 回调。

AndroidPMS安装签名

VerifyingSession 安装验证 ​

VerifyingSession 位于 PackageInstallerSession 提交之后、真正安装之前。它把版本检查、APK 验证广播、Rollback 请求和最终 observer 回调组织到一个异步状态机中。Android 17 中,PackageSessionVerifier 负责创建它,PackageVerificationState 聚合验证器回应,MultiPackageVerifyingSession 再把多个子 session 汇合成一个结果。

1. 验证层次 ​

层次类责任
session 编排PackageSessionVerifierAPEX/APK 前置验证、创建 VerifyingSession
单包状态VerifyingSession等待 APK verifier、Rollback、observer
验证器聚合PackageVerificationStaterequired/sufficient 响应和超时
多包汇合MultiPackageVerifyingSession子包全部结束后回调父 session

2. 验证入口 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageSessionVerifier.java

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 签名 ​

java
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. 创建单包验证会话 ​

java
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

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

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 已足够决定安装。

java
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. 超时延长 ​

java
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

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

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. 排查清单 ​

  1. INSTALL_FAILED_VERIFICATION_FAILURE:先看 APEX verifier 或 APK verifier,而不是签名兼容比较。
  2. 验证卡住:检查 required UID 是否已注册、是否回应、是否延长超时。
  3. 批量安装结果异常:逐个查看 child VerifyingSession,父结果只在全部 child 回调后产生。
  4. 回滚安装跳过 verifier:确认 isARollback() 的 install reason 和 initiating package。
  5. 验证成功但 session 未 ready:检查 rollback 等待标志是否仍为 true。

11. 源码阅读路线 ​

  1. PackageSessionVerifier.verify:验证线程和 APEX 前置检查。
  2. createVerifyingSession:session 参数如何封装。
  3. VerifyingSession.handleStartVerify:版本检查和跳过条件。
  4. PackageVerificationState:required/sufficient、超时和允许判断。
  5. VerifyingSession.handleReturnCode:多个异步条件的汇合。
  6. MultiPackageVerifyingSession:子 session 到父 observer 的汇合。

VerifyingSession 的核心不是发送一条验证广播,而是把“版本检查、验证器回应、超时、rollback 和多包回调”纳入同一个完成条件。只有把这些等待条件逐一对照源码,才能解释安装为什么提前失败、持续等待或成功进入下一阶段。