本系列 Tinker 源码解析基于 Tinker v1.9.12
前一篇讲到了利用反射执行的是 TinkerLoader.tryLoad 方法
tryLoad
1 | @Override |
加载的流程主要在 tryLoadPatchFilesInternal 里面。tryLoadPatchFilesInternal 方法很长,我们需要分段来看。
tryLoadPatchFilesInternal
一开始是各种校验
检查 tinker 是否开启
1 | final int tinkerFlag = app.getTinkerFlags(); |
检查当前的进程
1 | // 检查当前的进程,确保不是 :patch 进程 |
获取 tinker 目录,检查目录是否存在
1 | // tinker 获取 tinker 目录,/data/data/tinker.sample.android/tinker |
检查 patch.info 文件是否存在, patch.info 是补丁信息文件,里面记录着新旧两个补丁版本的 md5 值
1 | // 文件目录 /data/data/tinker.sample.android/tinker/patch.info |
读取 patch.info 文件,并包装成一个 SharePatchInfo ,并检查 patchInfo 是否为空 (先加锁 file lock 再解锁)
1 | //old = 641e634c5b8f1649c75caf73794acbdf |
检查读取出来的 patchInfo 补丁版本信息
1 | String oldVersion = patchInfo.oldVersion; |
如果发现 patchInfo 中的 isRemoveNewVersion 为 true 并且在主进程中运行的话,就代表需要清除补丁了
1 | boolean mainProcess = ShareTinkerInternals.isInMainProcess(app); |
根据版本变化和是否是主进程的条件决定是否允许加载最新的补丁
1 | boolean versionChanged = !(oldVersion.equals(newVersion)); |
检查当前新版本补丁文件夹是否存在
1 | //patch-641e634c |
检查补丁文件是否存在并且可读
1 | //tinker/patch.info/patch-641e634c/patch-641e634c.apk |
检查补丁文件签名以及补丁文件中的 tinker id 和基准包的 tinker id 是否一致。
注意,这里补丁文件的 tinker id 是当前补丁基准包的 tinker id ,也就是有 bug 的基准包 tinker id 。另外一个 new tinker id 是补丁加载完成后的 tinker id ,就是 bug 修复后的 tinker id 。
1 | ShareSecurityCheck securityCheck = new ShareSecurityCheck(app); |
下面是 checkTinkerPackage 方法的具体代码
1 | public static int checkTinkerPackage(Context context, int tinkerFlag, File patchFile, ShareSecurityCheck securityCheck) { |
根据不同的情况,最多有四个文件是以meta.txt结尾的:
- package_meta.txt 补丁包的基本信息
- dex_meta.txt dex补丁的信息
- so_meta.txt so补丁的信息
- res_meta.txt 资源补丁的信息
如果开启了支持 dex 热修复,检查 dex_meta.txt 文件中记录的dex文件信息对应的dex文件是否存在
1 | final boolean isEnabledForDex = ShareTinkerInternals.isTinkerEnabledForDex(tinkerFlag); |
如果开启了支持 so 热修复,检查 so_meta.txt 文件中记录的so文件信息对应的so文件是否存在
1 | final boolean isEnabledForNativeLib = ShareTinkerInternals.isTinkerEnabledForNativeLib(tinkerFlag); |
如果开启了支持 res 热修复,检查 res_meta.txt 文件中记录的res文件信息对应的res文件是否存在
1 | //check resource |
符合条件的话就更新版本信息,并将最新的patch info更新入文件.在v1.7.5的版本开始有了isSystemOTA判断,
只要用户是ART环境并且做了OTA升级,则在加载dex补丁的时候就会先把最近一次的补丁全部DexFile.loadDex一遍重新生成odex,再加载dex补丁。否则会报错
1 | //only work for art platform oat,because of interpret, refuse 4.4 art oat |
加载补丁的安全次数最多三次
1 | if (!checkSafeModeCount(app)) { |
加载补丁 jar ,这一部分的代码我们后面会详细展开
1 | //now we can load patch jar |
加载补丁资源,这一部分的代码我们后面会详细展开
1 | //now we can load patch resource |
补丁加载流程结束
1 | // Init component hotplug support. |