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管理的安全存储区域。
这个拷贝过程不是简单的文件复制,它涉及几个关键步骤:
- 文件校验:检查APK文件的完整性,防止传输过程中损坏
- 增量写入:支持断点续传,如果网络中断可以从中断处继续
- 权限检查:确保调用者有足够的权限进行安装操作
你可能会问:为什么要搞这么复杂?直接复制不就行了?
嗯,这里有个坑。Android系统对应用安装有严格的安全要求。如果APK文件被存放在普通目录,其他应用可能会篡改它。所以,系统必须把APK拷贝到只有系统服务才能访问的安全区域。
// 数据拷贝的核心逻辑
public void writeApk(int sessionId, InputStream in, long size) {
// 1. 获取Session对应的文件描述符
// 2. 创建临时文件
// 3. 流式写入数据
// 4. 校验文件完整性
// 5. 重命名为正式文件
}
这段代码看起来简单,但实际实现要考虑很多边界情况。比如,写入过程中如果存储空间不足怎么办?如果写入一半断电了怎么办?这些都是我在项目中遇到过的问题。
7.5 核心流程图
为了让你更直观地理解整个流程,我画了一张图。这张图展示了从ADB命令到数据拷贝完成的完整链路。
从这张图你可以看到,整个流程是串行的。每一步都依赖上一步的结果。如果中间任何一环出了问题,安装就会失败。
7.6 避坑指南
最后,分享几个我在实际项目中踩过的坑:
- 存储空间不足:数据拷贝阶段最容易出问题。我曾经遇到一个情况,APK只有50MB,但系统提示空间不足。后来发现是/data分区被日志文件占满了。所以,安装前最好检查一下可用空间。
- Session ID冲突:在高并发场景下,Session ID可能会重复。虽然系统有重试机制,但偶尔还是会出问题。我建议在创建Session时加入超时重试逻辑。
- 权限问题:有些第三方应用试图通过ADB安装应用,但权限不够。这时候系统会返回
INSTALL_FAILED_PERMISSION错误。解决办法是确保调用者有INSTALL_PACKAGES权限。
总结一下:今天的内容主要讲了ADB安装的发起流程,从Session创建到数据拷贝。这些是安装流程的基础,理解了这些,你才能更好地理解后续的安装验证和提交阶段。
好了,上半场的内容就到这里。记住,安装流程不是一蹴而就的,它是一环扣一环的。下一讲我们会继续深入,看看数据拷贝完成后,系统是如何验证和提交安装的。
公众号:蓝海资料掘金营,微信deep3321