基于 AN16Android 16代码一、整体流程总览用户点击 APK │ ▼ InstallStart 入口 Activity权限检查 路由分发 │ ├── content:// URI │ ▼ │ InstallStaging 异步拷贝 APK 到 Session 临时目录 │ │ └── package:// URI ▼ PackageInstallerActivity 解析 APK显示安装确认对话框 │ 用户点击安装 ▼ InstallInstalling 创建/打开 Sessioncommit 到 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_APPS、DISALLOW_INSTALL_UNKNOWN_SOURCESSKG 定制检查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 层阶段五PackageInstallerSessionFramework 调度文件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 核心阶段七InstallPackageHelperPMS 核心五步安装文件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.vendingGoogle Play Store的升级安装四、关键源码文件索引文件路径作用InstallStartpackages/PackageInstaller/src/.../InstallStart.java入口权限检查路由InstallStagingpackages/PackageInstaller/src/.../InstallStaging.javacontent:// URI 文件暂存PackageInstallerActivitypackages/PackageInstaller/src/.../PackageInstallerActivity.javaAPK 解析安装确认 UIInstallInstallingpackages/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五、核心知识点速记为什么需要 InstallStagingcontent://URI 属于另一个进程的文件安装过程中源文件可能被修改必须先拷贝到 PackageInstaller 控制的 Session 目录确保完整性。为什么 commit() 后还要等广播session.commit()只是提交任务PMS 在独立 Handler 线程异步执行结果通过PendingIntent广播异步通知InstallInstalling 监听广播后再跳转结果页。packages.xml 是什么/data/system/packages.xmlPMS 的包信息数据库记录所有已安装包的签名、权限、安装路径等系统启动时从这里恢复包信息。DEX 优化在哪一步在commitInstallPackages()的executePostCommitStepsLIF()中执行performDexOpt()是安装最后阶段这也是为什么大 APK 安装时间较长。
Android16 应用安装流程源码分析
发布时间:2026/6/25 8:18:37
基于 AN16Android 16代码一、整体流程总览用户点击 APK │ ▼ InstallStart 入口 Activity权限检查 路由分发 │ ├── content:// URI │ ▼ │ InstallStaging 异步拷贝 APK 到 Session 临时目录 │ │ └── package:// URI ▼ PackageInstallerActivity 解析 APK显示安装确认对话框 │ 用户点击安装 ▼ InstallInstalling 创建/打开 Sessioncommit 到 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_APPS、DISALLOW_INSTALL_UNKNOWN_SOURCESSKG 定制检查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 层阶段五PackageInstallerSessionFramework 调度文件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 核心阶段七InstallPackageHelperPMS 核心五步安装文件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.vendingGoogle Play Store的升级安装四、关键源码文件索引文件路径作用InstallStartpackages/PackageInstaller/src/.../InstallStart.java入口权限检查路由InstallStagingpackages/PackageInstaller/src/.../InstallStaging.javacontent:// URI 文件暂存PackageInstallerActivitypackages/PackageInstaller/src/.../PackageInstallerActivity.javaAPK 解析安装确认 UIInstallInstallingpackages/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五、核心知识点速记为什么需要 InstallStagingcontent://URI 属于另一个进程的文件安装过程中源文件可能被修改必须先拷贝到 PackageInstaller 控制的 Session 目录确保完整性。为什么 commit() 后还要等广播session.commit()只是提交任务PMS 在独立 Handler 线程异步执行结果通过PendingIntent广播异步通知InstallInstalling 监听广播后再跳转结果页。packages.xml 是什么/data/system/packages.xmlPMS 的包信息数据库记录所有已安装包的签名、权限、安装路径等系统启动时从这里恢复包信息。DEX 优化在哪一步在commitInstallPackages()的executePostCommitStepsLIF()中执行performDexOpt()是安装最后阶段这也是为什么大 APK 安装时间较长。