finalinttinkerFlag= app.getTinkerFlags(); // 检查 tinker 是否开启 if (!ShareTinkerInternals.isTinkerEnabled(tinkerFlag)) { Log.w(TAG, "tryLoadPatchFiles: tinker is disable, just return"); ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_DISABLE); return; }
检查当前的进程
1 2 3 4 5 6
// 检查当前的进程,确保不是 :patch 进程 if (ShareTinkerInternals.isInPatchProcess(app)) { Log.w(TAG, "tryLoadPatchFiles: we don't load patch with :patch process itself, just return"); ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_DISABLE); return; }
获取 tinker 目录,检查目录是否存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// tinker 获取 tinker 目录,/data/data/tinker.sample.android/tinker FilepatchDirectoryFile= SharePatchFileUtil.getPatchDirectory(app); if (patchDirectoryFile == null) { Log.w(TAG, "tryLoadPatchFiles:getPatchDirectory == null"); //treat as not exist ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_DIRECTORY_NOT_EXIST); return; } StringpatchDirectoryPath= patchDirectoryFile.getAbsolutePath(); // 检查 tinker 目录是否存在 //check patch directory whether exist if (!patchDirectoryFile.exists()) { Log.w(TAG, "tryLoadPatchFiles:patch dir not exist:" + patchDirectoryPath); ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_DIRECTORY_NOT_EXIST); return; }
// So far new version is not loaded in main process and other processes. // We can remove new version directory safely. if (mainProcess && isRemoveNewVersion) { Log.w(TAG, "found clean patch mark and we are in main process, delete patch file now."); // 获取新的补丁文件夹,例如 patch-2c150d85 StringpatchName= SharePatchFileUtil.getPatchVersionDirectory(newVersion); if (patchName != null) { // 删除新的补丁文件夹 StringpatchVersionDirFullPath= patchDirectoryPath + "/" + patchName; SharePatchFileUtil.deleteDir(patchVersionDirFullPath); // 如果旧版本和新版本一致,就把 oldVersion 和 newVersion 设置为空来清除补丁 if (oldVersion.equals(newVersion)) { // !oldVersion.equals(newVersion) means new patch is applied, just fall back to old one in that case. // Or we will set oldVersion and newVersion to empty string to clean patch. oldVersion = ""; } // 如果 !oldVersion.equals(newVersion) 意味着新补丁已经应用了,需要回退到原来的旧版本 newVersion = oldVersion; patchInfo.oldVersion = oldVersion; patchInfo.newVersion = newVersion; // 把数据重新写入 patchInfo 文件中 SharePatchInfo.rewritePatchInfoFileWithLock(patchInfoFile, patchInfo, patchInfoLockFile); // 杀掉主进程以外的所有进程 ShareTinkerInternals.killProcessExceptMain(app); } }
// 根据版本变化和是否是主进程的条件决定是否允许加载最新的补丁 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; }
检查当前新版本补丁文件夹是否存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
//patch-641e634c StringpatchName= SharePatchFileUtil.getPatchVersionDirectory(version); if (patchName == null) { Log.w(TAG, "tryLoadPatchFiles:patchName is null"); //we may delete patch info file ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_VERSION_DIRECTORY_NOT_EXIST); return; } //tinker/patch.info/patch-641e634c StringpatchVersionDirectory= patchDirectoryPath + "/" + patchName;
if (!patchVersionDirectoryFile.exists()) { Log.w(TAG, "tryLoadPatchFiles:onPatchVersionDirectoryNotFound"); //we may delete patch info file ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_VERSION_DIRECTORY_NOT_EXIST); return; }
if (!SharePatchFileUtil.isLegalFile(patchVersionFile)) { 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 和基准包的 tinker id 是否一致。
注意,这里补丁文件的 tinker id 是当前补丁基准包的 tinker id ,也就是有 bug 的基准包 tinker id 。另外一个 new tinker id 是补丁加载完成后的 tinker id ,就是 bug 修复后的 tinker id 。
//only work for art platform oat,because of interpret, refuse 4.4 art oat //android o use quicken default, we don't need to use interpret mode booleanisSystemOTA= ShareTinkerInternals.isVmArt() && ShareTinkerInternals.isSystemOTA(patchInfo.fingerPrint) && Build.VERSION.SDK_INT >= 21 && !ShareTinkerInternals.isAfterAndroidO();
//we should first try rewrite patch info file, if there is a error, we can't load jar // 把patch.info的旧版本的值更新为新版本的值,写入 patch.info 中 if (mainProcess && (versionChanged || oatModeChanged)) { patchInfo.oldVersion = version; patchInfo.oatDir = oatDex;
//update old version to new if (!SharePatchInfo.rewritePatchInfoFileWithLock(patchInfoFile, patchInfo, patchInfoLockFile)) { ShareIntentUtil.setIntentReturnCode(resultIntent, ShareConstants.ERROR_LOAD_PATCH_REWRITE_PATCH_INFO_FAIL); Log.w(TAG, "tryLoadPatchFiles:onReWritePatchInfoCorrupted"); return; }
Log.i(TAG, "tryLoadPatchFiles:success to rewrite patch info, kill other process."); ShareTinkerInternals.killProcessExceptMain(app);
if (oatModeChanged) { // delete interpret odex // for android o, directory change. Fortunately, we don't need to support android o interpret mode any more Log.i(TAG, "tryLoadPatchFiles:oatModeChanged, try to delete interpret optimize files"); SharePatchFileUtil.deleteDir(patchVersionDirectory + "/" + ShareConstants.INTERPRET_DEX_OPTIMIZE_PATH); } }