-
检查tinkerFlag是否设置了enable ? continue : 记录ERROR_LOAD_DISABLE
到result中,return.
if (!ShareTinkerInternals.isTinkerEnabled(tinkerFlag)) {
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_DISABLE)
return
}
-
检查补丁工作空间/tinker是否已经存在 ? continue : 记录ERROR_LOAD_PATCH_DIRECTORY_NOT_EXIST
到result中,return.
File patchDirectoryFile = SharePatchFileUtil.getPatchDirectory(app);
if (patchDirectoryFile == null) {
Log.w(TAG, "tryLoadPatchFiles:getPatchDirectory == null");
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_DIRECTORY_NOT_EXIST);
return;
}
String patchDirectoryPath = patchDirectoryFile.getAbsolutePath();
if (!patchDirectoryFile.exists()) {
Log.w(TAG, "tryLoadPatchFiles:patch dir not exist:" + patchDirectoryPath);
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_DIRECTORY_NOT_EXIST);
return;
}
-
检查/tinker/patch.info 补丁信息文件是否存在 ? continue : 记录ERROR_LOAD_PATCH_INFO_NOT_EXIST
到result中,return.
//tinker/patch.info
File patchInfoFile = SharePatchFileUtil.getPatchInfoFile(patchDirectoryPath)
//check patch info file whether exist
if (!patchInfoFile.exists()) {
Log.w(TAG, "tryLoadPatchFiles:patch info not exist:" + patchInfoFile.getAbsolutePath())
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_INFO_NOT_EXIST)
return
}
-
patch.info文件中存储了如下新旧两个版本补丁的MD5.先用lock文件加锁,然后检查patch info能否读出有效的补丁信息 ? continue : 记录ERROR_LOAD_PATCH_INFO_CORRUPTED
到result中,return.
File patchInfoLockFile = SharePatchFileUtil.getPatchInfoLockFile(patchDirectoryPath);
patchInfo = SharePatchInfo.readAndCheckPropertyWithLock(patchInfoFile, patchInfoLockFile);
if (patchInfo == null) {
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_INFO_CORRUPTED);
return;
}
-
检查补丁信息中的数据是否有效? 将信息记录到result中,continue : 记录ERROR_LOAD_PATCH_INFO_CORRUPTED
到result中,return.
String oldVersion = patchInfo.oldVersion
String newVersion = patchInfo.newVersion
if (oldVersion == null || newVersion == null) {
//it is nice to clean patch
Log.w(TAG, "tryLoadPatchFiles:onPatchInfoCorrupted")
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_INFO_CORRUPTED)
return
}
resultIntent.putExtra(ShareIntentUtil.INTENT_PATCH_OLD_VERSION, oldVersion)
resultIntent.putExtra(ShareIntentUtil.INTENT_PATCH_NEW_VERSION, newVersion)
-
根据版本变化和是否是主进程的条件决定是否允许加载最新的补丁,并检查该补丁的MD5标识是否不为空 ? continue : 记录ERROR_LOAD_PATCH_INFO_BLANK
到result中,return.
boolean mainProcess = ShareTinkerInternals.isInMainProcess(app);
boolean versionChanged = !(oldVersion.equals(newVersion));
String version = oldVersion;
if (versionChanged && mainProcess) {
version = newVersion;
}
if (ShareTinkerInternals.isNullOrNil(version)) {
Log.w(TAG, "tryLoadPatchFiles:version is blank, wait main process to restart");
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_INFO_BLANK);
return;
}
-
检查当前版本补丁路径是否存在 ? continue : 记录ERROR_LOAD_PATCH_VERSION_DIRECTORY_NOT_EXIST
到result中,return.
String patchName = SharePatchFileUtil.getPatchVersionDirectory(version);
String patchVersionDirectory = patchDirectoryPath + "/" + patchName;
File patchVersionDirectoryFile = new File(patchVersionDirectory);
if (!patchVersionDirectoryFile.exists()) {
Log.w(TAG, "tryLoadPatchFiles:onPatchVersionDirectoryNotFound");
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_VERSION_DIRECTORY_NOT_EXIST);
return;
}
-
检查补丁文件是否存在 ? continue : 记录ERROR_LOAD_PATCH_VERSION_FILE_NOT_EXIST
到result中,return.
//tinker/patch.info/patch-641e634c/patch-641e634c.apk
File patchVersionFile = new File(patchVersionDirectoryFile.getAbsolutePath(), SharePatchFileUtil.getPatchVersionFile(version))
//检查补丁文件是否存在
if (!patchVersionFile.exists()) {
Log.w(TAG, "tryLoadPatchFiles:onPatchVersionFileNotFound")
//we may delete patch info file
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_VERSION_FILE_NOT_EXIST)
return
}
-
检查补丁文件签名和Tinker id是否一致 ? 将补丁的相关信息存入resultIntent,continue : 记录ERROR_LOAD_PATCH_PACKAGE_CHECK_FAIL
和检查结果到result中,return.
ShareSecurityCheck securityCheck = new ShareSecurityCheck(app)
//检查补丁文件签名和Tinker id是否一致
int returnCode = ShareTinkerInternals.checkTinkerPackage(app, tinkerFlag, patchVersionFile, securityCheck)
if (returnCode != ShareConstants.ERROR_PACKAGE_CHECK_OK) {
Log.w(TAG, "tryLoadPatchFiles:checkTinkerPackage")
resultIntent.putExtra(ShareIntentUtil.INTENT_PATCH_PACKAGE_PATCH_CHECK, returnCode)
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_PACKAGE_CHECK_FAIL)
return
}
resultIntent.putExtra(ShareIntentUtil.INTENT_PATCH_PACKAGE_CONFIG, securityCheck.getPackagePropertiesIfPresent())
这里为了快速校验,就只检验补丁包内部以meta.txt结尾的文件的签名. 其他的文件的合法性则通过校验过的meta.txt文件内部的补丁文件Md5校验.这里只是把meta.txt的内容分别存入到metaContentMap
中,以供外部使用.
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (jarEntry == null) {
continue;
}
final String name = jarEntry.getName();
if (name.startsWith("META-INF/")) {
continue;
}
if (!name.endsWith(ShareConstants.META_SUFFIX)) {
continue;
}
metaContentMap.put(name, SharePatchFileUtil.loadDigestes(jarFile, jarEntry));
Certificate[] certs = jarEntry.getCertificates();
if (certs == null) {
return false;
}
if (!check(path, certs)) {
return false;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
根据不同的情况,最多有四个文件是以meta.txt结尾的:
- package_meta.txt 补丁包的基本信息
- dex_meta.txt 所有dex文件的信息
- so_meta.txt 所有so文件的信息
- res_meta.txt 所有资源文件的信息
-
如果支持dex修复 则继续检查dex补丁文件是否存在 ? continue : log, return.
final boolean isEnabledForDex = ShareTinkerInternals.isTinkerEnabledForDex(tinkerFlag);
if (isEnabledForDex) {
//tinker/patch.info/patch-641e634c/dex
boolean dexCheck = TinkerDexLoader.checkComplete(patchVersionDirectory, securityCheck, resultIntent);
if (!dexCheck) {
//file not found, do not load patch
Log.w(TAG, "tryLoadPatchFiles:dex check fail");
return;
}
}
至于checkComplete
都校验了哪些东西?可以继续往里面看.先根据第9步中读取到内存中的dex_meta.txt
数据,在parseDexDiffPatchInfo
内部将字符串以dex为单位切割出每个dex文件的详细信息.
String meta = securityCheck.getMetaContentMap().get(DEX_MEAT_FILE);
if (meta == null) {
return true;
}
dexList.clear();
ShareDexDiffPatchInfo.parseDexDiffPatchInfo(meta, dexList);
if (dexList.isEmpty()) {
return true;
}
将dex摘要信息有效的item过滤出来,再遍历过滤出来的dex,去/tinker/patch.info/patch-xxx/dex和/tinker/patch.info/patch-xxx/odex下验证物理文件是否存在.
HashMap<String, String> dexes = new HashMap<>();
for (ShareDexDiffPatchInfo info : dexList) {
if (isJustArtSupportDex(info)) {
continue;
}
if (!ShareDexDiffPatchInfo.checkDexDiffPatchInfo(info)) {
intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_PACKAGE_PATCH_CHECK, ShareConstants.ERROR_PACKAGE_CHECK_DEX_META_CORRUPTED);
ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_PACKAGE_CHECK_FAIL);
return false;
}
dexes.put(info.realName, info.destMd5InDvm);
}
-
如果支持so修复 则继续检查so补丁文件是否存在,校验的方式同第10步.
final boolean isEnabledForNativeLib = ShareTinkerInternals.isTinkerEnabledForNativeLib(tinkerFlag);
if (isEnabledForNativeLib) {
//tinker/patch.info/patch-641e634c/lib
boolean libCheck = TinkerSoLoader.checkComplete(patchVersionDirectory, securityCheck, resultIntent);
if (!libCheck) {
//file not found, do not load patch
Log.w(TAG, "tryLoadPatchFiles:native lib check fail");
return;
}
}
-
如果支持资源修复 则继续检查资源补丁文件是否存在,校验的方式同第10步.
final boolean isEnabledForResource = ShareTinkerInternals.isTinkerEnabledForResource(tinkerFlag);
Log.w(TAG, "tryLoadPatchFiles:isEnabledForResource:" + isEnabledForResource);
if (isEnabledForResource) {
boolean resourceCheck = TinkerResourceLoader.checkComplete(app, patchVersionDirectory, securityCheck, resultIntent);
if (!resourceCheck) {
Log.w(TAG, "tryLoadPatchFiles:resource check fail");
return;
}
}
-
符合条件的话就更新版本信息,并将最新的patch info更新入文件.在v1.7.5的版本开始有了isSystemOTA
判断,只要用户是ART环境并且做了OTA升级则在加载dex补丁的时候就会先把最近一次的补丁全部DexFile.loadDex
一遍重新生成odex.再加载dex补丁.
boolean isSystemOTA = ShareTinkerInternals.isVmArt() && ShareTinkerInternals.isSystemOTA(patchInfo.fingerPrint);
if (isSystemOTA || (mainProcess && versionChanged)) {
patchInfo.oldVersion = version;
if (!SharePatchInfo.rewritePatchInfoFileWithLock(patchInfoFile, patchInfo, patchInfoLockFile)) {
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_REWRITE_PATCH_INFO_FAIL);
Log.w(TAG, "tryLoadPatchFiles:onReWritePatchInfoCorrupted");
return;
}
}
-
检查safe mode计数是否超过三次
if (!checkSafeModeCount(app)) {
resultIntent.putExtra(ShareIntentUtil.INTENT_PATCH_EXCEPTION, new TinkerRuntimeException("checkSafeModeCount fail"))
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_UNCAUGHT_EXCEPTION)
Log.w(TAG, "tryLoadPatchFiles:checkSafeModeCount fail")
return
}
-
在符合条件的情况下加载dex,res补丁.并记录成功状态.
if (isEnabledForDex) {
boolean loadTinkerJars = TinkerDexLoader.loadTinkerJars(app, tinkerLoadVerifyFlag, patchVersionDirectory, resultIntent);
if (!loadTinkerJars) {
Log.w(TAG, "tryLoadPatchFiles:onPatchLoadDexesFail");
return;
}
}
if (isEnabledForResource) {
boolean loadTinkerResources = TinkerResourceLoader.loadTinkerResources(app, tinkerLoadVerifyFlag, patchVersionDirectory, resultIntent);
if (!loadTinkerResources) {
Log.w(TAG, "tryLoadPatchFiles:onPatchLoadResourcesFail");
return;
}
}
ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_OK);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
接下来详细分析dex,so和资源补丁更新的原理.