7. 安装流程(上):ADB安装与PackageInstaller的发起流程,从Session创建到数据拷贝

各位同学,今天我们来啃一块硬骨头——Android应用的安装流程。说实话,这个流程涉及的东西非常多,从你敲下 adb install 命令,到应用图标出现在桌面上,中间经历了层层关卡。我个人习惯把这个过程拆成上下两讲,今天我们先聚焦上半场:从ADB发起安装,到Session创建,再到数据拷贝完成。

你想想看,一个APK文件是怎么从你的电脑跑到手机里的?又是怎么被系统“接纳”的?这里面门道不少。

7.1 起点:adb install 命令

我们先从最熟悉的 adb install 说起。你在终端敲下这个命令,背后发生了什么?

adb install myapp.apk

这条命令实际上触发了ADB客户端与服务端的通信。ADB客户端(你的电脑)会把APK文件推送到ADB服务端(手机上的adbd守护进程)。但这里有个关键点:ADB只负责传输,不负责安装。真正的安装工作,是由手机上的 PackageInstaller 完成的。

核心要点:ADB只是“快递员”,PackageInstaller才是“安装工”。

我曾经在调试一个安装失败的问题时,发现APK明明已经传到手机上了,但安装就是报错。后来定位到是ADB传输过程中文件损坏了。嗯,这里要注意:ADB传输虽然可靠,但也不是100%保险,尤其是大文件。

7.2 PackageInstaller的登场

ADB把APK文件推送到手机的临时目录后,会通过Binder调用 PackageManagerService(简称PMS)的安装接口。PMS收到请求后,会创建一个 PackageInstaller 实例。

PackageInstaller是Android 5.0引入的机制,它把安装过程抽象成了一个“会话”(Session)的概念。为什么要这么做?说白了,就是为了支持更灵活的安装场景,比如Google Play的增量更新、多Session并行安装等。

个人经验:我在做系统定制时,经常需要绕过PackageInstaller直接调用PMS的接口。但后来发现,直接调用PMS接口容易出问题,因为缺少了PackageInstaller的会话管理机制。所以,除非你非常清楚自己在做什么,否则还是走PackageInstaller这条路更稳妥。

7.3 Session的创建

Session是安装流程的核心抽象。我们来看看它是怎么创建的。

// PackageInstaller.java (简化版)
public int createSession(SessionParams params) {
    // 1. 校验参数
    // 2. 分配Session ID
    // 3. 创建Session状态
    // 4. 返回Session ID
}

创建Session时,需要传入 SessionParams 参数,它包含了安装模式、安装位置、权限等信息。我个人习惯把SessionParams看作是安装的“配置单”,你告诉系统你想怎么装这个应用。

Session创建成功后,会返回一个整数类型的Session ID。这个ID很重要,后续的所有操作都要靠它来定位。

Session状态 说明
CREATED Session刚创建,尚未写入数据
WRITING 正在写入APK数据
COMMITTED 数据写入完成,等待提交
SUCCESS 安装成功
FAILED 安装失败

注意:Session是有生命周期的。如果创建了Session但长时间不提交,系统会把它清理掉。我记得有一次调试时,创建了Session后去吃了个饭,回来发现Session已经被回收了。所以,Session创建后要尽快使用。

7.4 数据拷贝:从临时目录到安全存储

Session创建完成后,接下来就是数据拷贝阶段。ADB会把APK文件从临时目录拷贝到PackageInstaller管理的安全存储区域。

这个拷贝过程不是简单的文件复制,它涉及几个关键步骤:

  1. 文件校验:检查APK文件的完整性,防止传输过程中损坏
  2. 增量写入:支持断点续传,如果网络中断可以从中断处继续
  3. 权限检查:确保调用者有足够的权限进行安装操作

你可能会问:为什么要搞这么复杂?直接复制不就行了?

嗯,这里有个坑。Android系统对应用安装有严格的安全要求。如果APK文件被存放在普通目录,其他应用可能会篡改它。所以,系统必须把APK拷贝到只有系统服务才能访问的安全区域。

// 数据拷贝的核心逻辑
public void writeApk(int sessionId, InputStream in, long size) {
    // 1. 获取Session对应的文件描述符
    // 2. 创建临时文件
    // 3. 流式写入数据
    // 4. 校验文件完整性
    // 5. 重命名为正式文件
}

这段代码看起来简单,但实际实现要考虑很多边界情况。比如,写入过程中如果存储空间不足怎么办?如果写入一半断电了怎么办?这些都是我在项目中遇到过的问题。

7.5 核心流程图

为了让你更直观地理解整个流程,我画了一张图。这张图展示了从ADB命令到数据拷贝完成的完整链路。

ADB安装流程(上半场) ADB客户端 ADB服务端 PMS PackageInstaller Session创建 数据拷贝 安全存储 推送APK Binder调用 创建Session

从这张图你可以看到,整个流程是串行的。每一步都依赖上一步的结果。如果中间任何一环出了问题,安装就会失败。

7.6 避坑指南

最后,分享几个我在实际项目中踩过的坑:

  • 存储空间不足:数据拷贝阶段最容易出问题。我曾经遇到一个情况,APK只有50MB,但系统提示空间不足。后来发现是/data分区被日志文件占满了。所以,安装前最好检查一下可用空间。
  • Session ID冲突:在高并发场景下,Session ID可能会重复。虽然系统有重试机制,但偶尔还是会出问题。我建议在创建Session时加入超时重试逻辑。
  • 权限问题:有些第三方应用试图通过ADB安装应用,但权限不够。这时候系统会返回 INSTALL_FAILED_PERMISSION 错误。解决办法是确保调用者有 INSTALL_PACKAGES 权限。

总结一下:今天的内容主要讲了ADB安装的发起流程,从Session创建到数据拷贝。这些是安装流程的基础,理解了这些,你才能更好地理解后续的安装验证和提交阶段。

好了,上半场的内容就到这里。记住,安装流程不是一蹴而就的,它是一环扣一环的。下一讲我们会继续深入,看看数据拷贝完成后,系统是如何验证和提交安装的。


公众号:蓝海资料掘金营,微信deep3321