本系列 Tinker 源码解析基于 Tinker v1.9.12
补丁合成流程
下发的补丁包其实并不能直接加载,因为补丁包只是差异包,需要和本地的 dex 、资源等进行合成后,得到全量的 dex 才能被完整地使用。这样也就避免了热修复中 dex 的 pre-verify 问题,也减少了补丁包的体积,方便用户下载。
补丁合成的入口在 TinkerInstaller.onReceiveUpgradePatch 方法
TinkerInstaller.onReceiveUpgradePatch
1 | public static void onReceiveUpgradePatch(Context context, String patchLocation) { |
这里的 PatchListener 有默认实现类,即 DefaultPatchListener 。
DefaultPatchListener.onPatchReceived
1 | @Override |
我们直接来看 TinkerPatchService.runPatchService 方法
TinkerPatchService.runPatchService
1 | public static void runPatchService(final Context context, final String path) { |
在 runPatchService 中去启动了 TinkerPatchService 。TinkerPatchService 是跑在 :patch
进程中的。
TinkerPatchService 主要做的事情都在 onHandleWork 中
1 | @Override |
首先是 increasingPriority 方法,目的就是提高 service 的优先级,具体的方案就是设置为前台服务
1 | private void increasingPriority() { |
接着是 doApplyPatch 方法,在这里做补丁合成的事
1 | private static void doApplyPatch(Context context, Intent intent) { |
upgradePatchProcessor 是一个接口,具体的实现类是 UpgradePatch 。
UpgradePatch.tryPatch
那么来看看 UpgradePatch.tryPatch ,方法比较长,分段来看吧。
首先是对 Tinker 自身开关的校验,然后对补丁文件的合法性进行校验。
1 | @Override |
然后检查补丁包的签名以及 tinkerId , 这里的操作和加载补丁是一样的。
然后就是获取补丁文件的 md5 值
1 | //check the signature, we should create a new checker |
接着,校验完成后,我们就来构造一个新的 patch.info 文件了。
1 | //check ok, we can real recover a new patch |
再接下来,就是把补丁包复制到私有目录中
具体的路径也就是之前在加载补丁中遇到的 /data/data/应用包名/tinker/patch-xxxxxx/patch-xxxxxx.apk
1 | //it is a new patch, we first delete if there is any files |
复制好之后,就是把补丁包和基准包进行整合了
1 | //we use destPatchFile instead of patchFile, because patchFile may be deleted during the patch process |
这里面的三个合成代码我们到后面的章节再分析,这里先跳过了。
合成完后,还要对 dex 进行opt优化
1 | // check dex opt file at last, some phone such as VIVO/OPPO like to change dex2oat to interpreted |
最后,就是把结果重新写入到 patch.info ,这样在加载补丁的流程中就能加载新补丁了。
1 | if (!SharePatchInfo.rewritePatchInfoFileWithLock(patchInfoFile, newInfo, patchInfoLockFile)) { |
over ,整个合成补丁的流程讲完了,这里还留了三个坑:
- dex 文件的合成
- so 文件的合成
- 资源文件的合成
到后面再讲吧。