Android16 应用安装流程源码分析
2026/5/9 23:48:37 网站建设 项目流程

基于 AN16(Android 16)代码


一、整体流程总览

用户点击 APK │ ▼ InstallStart 入口 Activity,权限检查 + 路由分发 │ ├── content:// URI │ ▼ │ InstallStaging 异步拷贝 APK 到 Session 临时目录 │ │ └── package:// URI ▼ PackageInstallerActivity 解析 APK,显示安装确认对话框 │ 用户点击"安装" ▼ InstallInstalling 创建/打开 Session,commit 到 PMS │ session.commit() ▼ PackageInstallerSession 验证 → seal → verify → install │ installNonStaged() ▼ InstallingSession 准备安装参数,检查存储空间 │ installPackagesTraced() ▼ InstallPackageHelper PMS 核心五步安装 │ ┌───────┴───────┐ ▼ ▼ InstallSuccess InstallFailed 显示打开/完成 显示错误信息

二、各阶段详解

阶段一:InstallStart(入口路由)

文件packages/PackageInstaller/src/.../InstallStart.java

职责:权限校验 + 路由分发

步骤内容
获取调用者信息getLaunchedFromPackage()/getLaunchedFromUid()
权限检查是否持有INSTALL_PACKAGES,是否声明REQUEST_INSTALL_PACKAGES
设备策略检查DISALLOW_INSTALL_APPSDISALLOW_INSTALL_UNKNOWN_SOURCES
SKG 定制检查persist.sys.skg.is3rdNotAllowInstall,为 true 则拒绝并 Toast
路由分发content://InstallStagingpackage://PackageInstallerActivity

阶段二:InstallStaging(文件暂存)

文件packages/PackageInstaller/src/.../InstallStaging.java

触发条件:APK 来自content://URI(如文件管理器分享)

目的:将文件拷贝到 PackageInstaller 的 Session 目录,防止安装过程中源文件被篡改。

onCreate() └── 显示拷贝进度对话框 onResume() └── 创建 PackageInstaller.Session,设置 SessionParams StagingAsyncTask.doInBackground() ├── installer.openSession(stagedSessionId) ├── getContentResolver().openInputStream(packageUri) ├── session.openWrite() 获取输出流 ├── 循环读写(1MB buffer),更新进度 └── session.fsync() 确保落盘 onPostExecute() └── 跳转 DeleteStagedFileOnResult → PackageInstallerActivity

阶段三:PackageInstallerActivity(安装确认)

文件packages/PackageInstaller/src/.../PackageInstallerActivity.java

职责:解析 APK 信息,显示"是否安装"确认界面。

onCreate() ├── 解析 APK(包名、版本、图标、权限列表) └── processAppSnippet() onResume() → checkIfAllowedAndInitiateInstall() ├── [SKG] getFileManagerPermission() 对 com.skg.filemanager 特殊处理 ├── 受信任来源 → 直接 initiateInstall() └── 未知来源 → 检查 OP_REQUEST_INSTALL_PACKAGES app op ├── MODE_ALLOWED → initiateInstall() └── MODE_ERRORED → 弹出"开启未知来源"对话框 用户点击"安装" ├── Session 安装:mInstaller.setPermissionsResult(sessionId, true) └── 非 Session 安装:startInstall() → 跳转 InstallInstalling

阶段四:InstallInstalling(提交安装)

文件packages/PackageInstaller/src/.../InstallInstalling.java

职责:将 Session 提交给 PMS,显示"正在安装…"。

onCreate() ├── 注册 InstallEventReceiver 监听安装结果广播 └── 获取 stagedSessionId,验证 Session 有效性 onResume() → InstallingAsyncTask └── doInBackground() └── openSession(mSessionId) └── onPostExecute() ├── 构建 PendingIntent(接收结果广播) └── session.commit(pendingIntent.getIntentSender()) ↑ 进入 Framework 层

阶段五:PackageInstallerSession(Framework 调度)

文件services/core/.../pm/PackageInstallerSession.java

职责:验证 APK 完整性、协调安装时序。

commit(statusReceiver) ├── markAsSealed() 标记 Session 不再接受写入 │ ├── dispatchStreamValidateAndCommit() │ └── handleStreamValidateAndCommit() │ └── validateApkInstallLocked() 校验签名、包名、版本、split │ └── handleInstall() ├── prepareInheritedFiles() 继承已安装包文件 ├── parseApk() 解析 APK └── verify() ├── runExtractNativeLibraries() 提取 native 库 └── onVerificationComplete() └── install() └── installNonStaged() └── 创建 InstallingSession

阶段六:InstallingSession(参数准备)

文件services/core/.../pm/InstallingSession.java

职责:准备安装参数,检查存储空间,进入 PMS 安装。

installStage() └── mPm.mHandler.post(this::start) 投递到 PMS Handler 线程 start() ├── handleStartCopy(installRequest) │ ├── [SKG] 检查 is3rdNotAllowInstall,为 true 则拒绝 │ ├── [SKG] 拦截 com.android.vending 升级安装 │ ├── getMinimalPackageInfo() 检查存储空间,确定安装位置 │ └── freeCacheForInstallation() 空间不足时尝试清理缓存 │ └── handleReturnCode(installRequest) └── processApkInstallRequests() └── mPm.installPackagesTraced() 进入 PMS 核心

阶段七:InstallPackageHelper(PMS 核心五步安装)

文件services/core/.../pm/InstallPackageHelper.java

职责:APK 的实际安装,从文件处理到数据库写入。

installPackagesTraced() │ ├── 第1步 prepareInstallPackages() │ 解析 APK 完整信息,校验签名兼容性 │ 检查是否允许降级,处理权限和依赖 │ ├── 第2步 scanInstallPackages() │ 扫描 APK,生成 PackageSetting │ 分配 UID / appId,注册到 PMS 内部数据结构 │ ├── 第3步 reconcileInstallPackages() │ 处理包替换逻辑,签名一致性校验 │ shared user 处理,权限继承 │ ├── 第4步 renameAndUpdatePaths() │ Stage 目录重命名为最终安装目录 │ /data/app/~~random~~/com.example.app-random/ │ └── 第5步 commitInstallPackages() freezePackageForInstall() 冻结应用 commitPackagesLocked() 写入 packages.xml executePostCommitStepsLIF() ├── prepareAppDataAfterInstallLIF() 创建应用数据目录 ├── performDexOpt() DEX 优化 └── 发送 PACKAGE_ADDED / PACKAGE_REPLACED 广播

阶段八:安装结果回调

InstallPackageHelper 安装完成 ↓ InstallingSession.IPackageInstallObserver2.onPackageInstalled() ↓ PackageInstallerSession.dispatchSessionFinished() ↓ sendOnPackageInstalled() → 通过 IntentSender 发送广播 ↓ InstallEventReceiver 收到广播 ↓ InstallInstalling.launchFinishBasedOnResult() ├── 成功 → InstallSuccess(显示"打开"/"完成") └── 失败 → InstallFailed(显示错误原因)

三、SKG 定制点汇总

位置定制内容
InstallStart.javapersist.sys.skg.is3rdNotAllowInstall为 true 时,Toast 提示并拒绝安装
PackageInstallerActivity.javacom.skg.filemanager特殊处理,视为已知来源,跳过未知来源校验
PackageInstallerActivity.javagetFileManagerPermission()自定义文件管理器安装权限检查
InstallingSession.javahandleStartCopy()中二次检查is3rdNotAllowInstall(防绕过)
InstallingSession.java拦截com.android.vending(Google Play Store)的升级安装

四、关键源码文件索引

文件路径作用
InstallStartpackages/PackageInstaller/src/.../InstallStart.java入口,权限检查,路由
InstallStagingpackages/PackageInstaller/src/.../InstallStaging.javacontent:// URI 文件暂存
PackageInstallerActivitypackages/PackageInstaller/src/.../PackageInstallerActivity.javaAPK 解析,安装确认 UI
InstallInstallingpackages/PackageInstaller/src/.../InstallInstalling.javaSession commit,等待结果
InstallSuccesspackages/PackageInstaller/src/.../InstallSuccess.java安装成功界面
InstallFailedpackages/PackageInstaller/src/.../InstallFailed.java安装失败界面
PackageInstallerSessionservices/core/.../pm/PackageInstallerSession.javaSession 管理,验证,调度
InstallingSessionservices/core/.../pm/InstallingSession.java安装参数准备,空间检查
InstallPackageHelperservices/core/.../pm/InstallPackageHelper.javaPMS 核心五步安装
PackageManagerServiceservices/core/.../pm/PackageManagerService.javaPMS 入口,转发到 Helper

五、核心知识点速记

为什么需要 InstallStaging?
content://URI 属于另一个进程的文件,安装过程中源文件可能被修改,必须先拷贝到 PackageInstaller 控制的 Session 目录确保完整性。

为什么 commit() 后还要等广播?
session.commit()只是提交任务,PMS 在独立 Handler 线程异步执行,结果通过PendingIntent广播异步通知,InstallInstalling 监听广播后再跳转结果页。

packages.xml 是什么?
/data/system/packages.xml,PMS 的包信息数据库,记录所有已安装包的签名、权限、安装路径等,系统启动时从这里恢复包信息。

DEX 优化在哪一步?
commitInstallPackages()executePostCommitStepsLIF()中执行performDexOpt(),是安装最后阶段,这也是为什么大 APK 安装时间较长。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询