SickWorm的博客

Android Apply Changes 源码 Deployer 解析

Android, Android 编译  ·  

源码链接

https://android.googlesource.com/platform/tools/base/+/37d63d4040a41987551704400d471793285f1c85/deploy/deployer/src/main/java/com/android/tools/deployer/Deployer.java

一般代码直接看 studio-master-dev 分支就好,此处为了溯源指定了具体 commit。

功能:

IDE 上面的三个按钮对应三个方法
Run -> Deployer::install
Apply Code Changes -> Deployer::codeSwap
Apply Changes and Restart Activity -> Deployer::fullSwap

参数分析:

Deployer::install

/**
 * 对应 IDE 中的 Run 按钮。
 * 
 * @param packageName 包名
 * @param apks 待安装的 apk 文件列表
 * @param options 设置 adb install 的参数
 * @param installMode 安装模式,分为三种:发送整个 APK 安装;只发送变化部分进行安装,只发送变化部分进行安装且如果 APK 无变化也不跳过安装
 */
public Result install(String packageName, List<String> apks, InstallOptions options, InstallMode installMode)

Deployer::codeSwap

/**
 * 对应 IDE 中的 Apply Code Changes 按钮。
 * 
 * @param apks 待安装的 apk 文件列表
 * @param redefiners 类重定义实现类。从源码来看,主要是未 debug attached 时传入 DebuggerRedefiner,其他情况传入empty map
 */
public Result codeSwap(List<String> apks, Map<Integer, ClassRedefiner> redefiners)

Deployer::fullSwap

/**
 * 对应 IDE 中的 Apply Changes and Restart Activity 按钮。
 * 对比可以发现,fullSwap 和 codeSwap 区别只有两点:
 * 1. 是否支持传入 redefiners(codeSwap 支持,fullSwap 不支持)
 * 2. 是否重启 Activity(codeSwap 不重启,fullSwap 重启)
 * 
 * @param apks 待安装的 apk 文件列表
 */
public Result fullSwap(List<String> apks)

流程分析

版本区别

Deployer::install

调用 ApkInstaller 安装 apk,如果设备 supportsNewPipeline,则讲 apk 录入到数据库中,用于后续 codeSwap 和 fullSwap

Deployer::codeSwap

如果支持 supportsNewPipeline 且开启 useOptimisticResourceSwap,则调用 optimisticSwap;否则调用 swap

Deployer::fullSwap

如果支持 supportsNewPipeline 且开启 useOptimisticResourceSwap,则调用 optimisticSwap;否则调用 swap

fullSwap 和 codeSwap 区别只有两点:

  1. 是否支持传入 redefiners
  2. 是否重启 Activity(codeSwap 不重启,fullSwap 重启)

Deployer::swap

runner.create 会将创建的 Task 加入队列,随后调用 run/runAsync 时会将任务队列拷贝一份然后清空,然后按顺序执行拷贝的任务队列。
Task 命名方式是以 Task 运行完后返回的结果命名

  1. paths: (参数)Apk 路径
  2. restart: 重启
  3. splitter: (参数)拆分 Dex 实现类 CachedDexSplitter
  4. newFiles: 解析新 apk 的 zip entries
  5. dumps: 从设备上拉取已安装的同包名 apk 的 zip entries
  6. diffs: 对以上两个列表做 diff,得出变更文件的列表
  7. sessionId: 通过 ApkPreInstaller 安装 apk
  8. dexDiffs: 过滤掉不支持 swap 的文件
  9. toSwap: 比较本地和设备上的 dex 文件,根据文件列表 dexDiffs 验证是否支持 apply changes(是否改动 dex,资源之外的内容),如果不支持则退出。不支持的情况如:新增了类,改变了方法签名等。
  10. swapper: 开始 swap dex 和资源
  11. (如果成功)CACHE, DEPLOY_CACHE_STORE: 异步将变更文件列表存储在数据库

Deployer::optimisticSwap

  1. paths: (参数)Apk 路径
  2. restart: 重启任务
  3. splitter: (参数)拆分 Dex 实现
  4. newFiles: 解析新 apk 的 zip entries
  5. packageName,pids,arch,获取包名,进程 id,架构
  6. speculativeDump: 从设备上拉取已安装的同包名 apk 的 zip entries,假设本地 cache 是正确的
  7. dumper: (参数)ApplicationDumper
  8. verifyDump: 校验拉取的 apk 的 zip entries
  9. diffs: 对以上两个列表做 diff,得出变更文件的列表,并推测本地 cache 是正确性
  10. extractedFiles: 解压 apk 的res 和 assets 资源
  11. dexDiffs: 过滤掉不支持 swap 的文件
  12. changedClasses: 比较本地和设备上的 dex 文件,根据文件列表 dexDiffs 验证是否支持 apply changes(是否改动 dex,资源之外的内容),如果不支持则退出。不支持的情况如:新增了类,改变了方法签名等。
  13. swapper: 开始 swap dex 和资源
  14. overlayUpdate: 收集更新资源列表
  15. nextOverlayId: 更新资源
  16. (如果成功)CACHE, DEPLOY_CACHE_STORE: 异步将变更文件列表存储在数据库

可以看到 optimisticSwap 和 swap 区别是:

  1. 从设备拉取变更文件列表的流程不同了
  2. 支持资源 overlay

附录

参考资料:Android Studio Apply Changes

版权所有,转载请注明出处:
https://sickworm.com/?p=1861

# # # #