use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class ResDiffPatchInternal method extractResourceDiffInternals.
private static boolean extractResourceDiffInternals(Context context, String dir, String meta, File patchFile, int type) {
ShareResPatchInfo resPatchInfo = new ShareResPatchInfo();
ShareResPatchInfo.parseAllResPatchInfo(meta, resPatchInfo);
TinkerLog.i(TAG, "res dir: %s, meta: %s", dir, resPatchInfo.toString());
Tinker manager = Tinker.with(context);
if (!SharePatchFileUtil.checkIfMd5Valid(resPatchInfo.resArscMd5)) {
TinkerLog.w(TAG, "resource meta file md5 mismatch, type:%s, md5: %s", ShareTinkerInternals.getTypeString(type), resPatchInfo.resArscMd5);
manager.getPatchReporter().onPatchPackageCheckFail(patchFile, BasePatchInternal.getMetaCorruptedCode(type));
return false;
}
File directory = new File(dir);
File resOutput = new File(directory, ShareConstants.RES_NAME);
//check result file whether already exist
if (resOutput.exists()) {
if (SharePatchFileUtil.checkResourceArscMd5(resOutput, resPatchInfo.resArscMd5)) {
//it is ok, just continue
TinkerLog.w(TAG, "resource file %s is already exist, and md5 match, just return true", resOutput.getPath());
return true;
} else {
TinkerLog.w(TAG, "have a mismatch corrupted resource " + resOutput.getPath());
resOutput.delete();
}
} else {
resOutput.getParentFile().mkdirs();
}
try {
ApplicationInfo applicationInfo = context.getApplicationInfo();
if (applicationInfo == null) {
//Looks like running on a test Context, so just return without patching.
TinkerLog.w(TAG, "applicationInfo == null!!!!");
return false;
}
String apkPath = applicationInfo.sourceDir;
if (!checkAndExtractResourceLargeFile(context, apkPath, directory, patchFile, resPatchInfo, type)) {
return false;
}
TinkerZipOutputStream out = null;
TinkerZipFile oldApk = null;
TinkerZipFile newApk = null;
int totalEntryCount = 0;
try {
out = new TinkerZipOutputStream(new BufferedOutputStream(new FileOutputStream(resOutput)));
oldApk = new TinkerZipFile(apkPath);
newApk = new TinkerZipFile(patchFile);
final Enumeration<? extends TinkerZipEntry> entries = oldApk.entries();
while (entries.hasMoreElements()) {
TinkerZipEntry zipEntry = entries.nextElement();
if (zipEntry == null) {
throw new TinkerRuntimeException("zipEntry is null when get from oldApk");
}
String name = zipEntry.getName();
if (name.contains("../")) {
continue;
}
if (ShareResPatchInfo.checkFileInPattern(resPatchInfo.patterns, name)) {
//won't contain in add set.
if (!resPatchInfo.deleteRes.contains(name) && !resPatchInfo.modRes.contains(name) && !resPatchInfo.largeModRes.contains(name) && !name.equals(ShareConstants.RES_MANIFEST)) {
ResUtil.extractTinkerEntry(oldApk, zipEntry, out);
totalEntryCount++;
}
}
}
//process manifest
TinkerZipEntry manifestZipEntry = oldApk.getEntry(ShareConstants.RES_MANIFEST);
if (manifestZipEntry == null) {
TinkerLog.w(TAG, "manifest patch entry is null. path:" + ShareConstants.RES_MANIFEST);
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, resOutput, ShareConstants.RES_MANIFEST, type);
return false;
}
ResUtil.extractTinkerEntry(oldApk, manifestZipEntry, out);
totalEntryCount++;
for (String name : resPatchInfo.largeModRes) {
TinkerZipEntry largeZipEntry = oldApk.getEntry(name);
if (largeZipEntry == null) {
TinkerLog.w(TAG, "large patch entry is null. path:" + name);
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, resOutput, name, type);
return false;
}
ShareResPatchInfo.LargeModeInfo largeModeInfo = resPatchInfo.largeModMap.get(name);
ResUtil.extractLargeModifyFile(largeZipEntry, largeModeInfo.file, largeModeInfo.crc, out);
totalEntryCount++;
}
for (String name : resPatchInfo.addRes) {
TinkerZipEntry addZipEntry = newApk.getEntry(name);
if (addZipEntry == null) {
TinkerLog.w(TAG, "add patch entry is null. path:" + name);
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, resOutput, name, type);
return false;
}
ResUtil.extractTinkerEntry(newApk, addZipEntry, out);
totalEntryCount++;
}
for (String name : resPatchInfo.modRes) {
TinkerZipEntry modZipEntry = newApk.getEntry(name);
if (modZipEntry == null) {
TinkerLog.w(TAG, "mod patch entry is null. path:" + name);
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, resOutput, name, type);
return false;
}
ResUtil.extractTinkerEntry(newApk, modZipEntry, out);
totalEntryCount++;
}
} finally {
if (out != null) {
out.close();
}
if (oldApk != null) {
oldApk.close();
}
if (newApk != null) {
newApk.close();
}
//delete temp files
for (ShareResPatchInfo.LargeModeInfo largeModeInfo : resPatchInfo.largeModMap.values()) {
SharePatchFileUtil.safeDeleteFile(largeModeInfo.file);
}
}
boolean result = SharePatchFileUtil.checkResourceArscMd5(resOutput, resPatchInfo.resArscMd5);
if (!result) {
TinkerLog.i(TAG, "check final new resource file fail path:%s, entry count:%d, size:%d", resOutput.getAbsolutePath(), totalEntryCount, resOutput.length());
SharePatchFileUtil.safeDeleteFile(resOutput);
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, resOutput, ShareConstants.RES_NAME, type);
return false;
}
TinkerLog.i(TAG, "final new resource file:%s, entry count:%d, size:%d", resOutput.getAbsolutePath(), totalEntryCount, resOutput.length());
} catch (Throwable e) {
// e.printStackTrace();
throw new TinkerRuntimeException("patch " + ShareTinkerInternals.getTypeString(type) + " extract failed (" + e.getMessage() + ").", e);
}
return true;
}
use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class UpgradePatch method tryPatch.
@Override
public boolean tryPatch(Context context, String tempPatchPath, PatchResult patchResult) {
Tinker manager = Tinker.with(context);
final File patchFile = new File(tempPatchPath);
if (!manager.isTinkerEnabled() || !ShareTinkerInternals.isTinkerEnableWithSharedPreferences(context)) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:patch is disabled, just return");
return false;
}
if (!SharePatchFileUtil.isLegalFile(patchFile)) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:patch file is not found, just return");
return false;
}
//check the signature, we should create a new checker
ShareSecurityCheck signatureCheck = new ShareSecurityCheck(context);
int returnCode = ShareTinkerInternals.checkTinkerPackage(context, manager.getTinkerFlags(), patchFile, signatureCheck);
if (returnCode != ShareConstants.ERROR_PACKAGE_CHECK_OK) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:onPatchPackageCheckFail");
manager.getPatchReporter().onPatchPackageCheckFail(patchFile, returnCode);
return false;
}
//it is a new patch, so we should not find a exist
SharePatchInfo oldInfo = manager.getTinkerLoadResultIfPresent().patchInfo;
String patchMd5 = SharePatchFileUtil.getMD5(patchFile);
if (patchMd5 == null) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:patch md5 is null, just return");
return false;
}
//use md5 as version
patchResult.patchVersion = patchMd5;
SharePatchInfo newInfo;
//already have patch
if (oldInfo != null) {
if (oldInfo.oldVersion == null || oldInfo.newVersion == null) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:onPatchInfoCorrupted");
manager.getPatchReporter().onPatchInfoCorrupted(patchFile, oldInfo.oldVersion, oldInfo.newVersion);
return false;
}
if (!SharePatchFileUtil.checkIfMd5Valid(patchMd5)) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:onPatchVersionCheckFail md5 %s is valid", patchMd5);
manager.getPatchReporter().onPatchVersionCheckFail(patchFile, oldInfo, patchMd5);
return false;
}
newInfo = new SharePatchInfo(oldInfo.oldVersion, patchMd5, Build.FINGERPRINT);
} else {
newInfo = new SharePatchInfo("", patchMd5, Build.FINGERPRINT);
}
//check ok, we can real recover a new patch
final String patchDirectory = manager.getPatchDirectory().getAbsolutePath();
TinkerLog.i(TAG, "UpgradePatch tryPatch:patchMd5:%s", patchMd5);
final String patchName = SharePatchFileUtil.getPatchVersionDirectory(patchMd5);
final String patchVersionDirectory = patchDirectory + "/" + patchName;
TinkerLog.i(TAG, "UpgradePatch tryPatch:patchVersionDirectory:%s", patchVersionDirectory);
//it is a new patch, we first delete if there is any files
//don't delete dir for faster retry
// SharePatchFileUtil.deleteDir(patchVersionDirectory);
//copy file
File destPatchFile = new File(patchVersionDirectory + "/" + SharePatchFileUtil.getPatchVersionFile(patchMd5));
try {
// check md5 first
if (!patchMd5.equals(SharePatchFileUtil.getMD5(destPatchFile))) {
SharePatchFileUtil.copyFileUsingStream(patchFile, destPatchFile);
TinkerLog.w(TAG, "UpgradePatch copy patch file, src file: %s size: %d, dest file: %s size:%d", patchFile.getAbsolutePath(), patchFile.length(), destPatchFile.getAbsolutePath(), destPatchFile.length());
}
} catch (IOException e) {
// e.printStackTrace();
TinkerLog.e(TAG, "UpgradePatch tryPatch:copy patch file fail from %s to %s", patchFile.getPath(), destPatchFile.getPath());
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, destPatchFile, patchFile.getName(), ShareConstants.TYPE_PATCH_FILE);
return false;
}
//we use destPatchFile instead of patchFile, because patchFile may be deleted during the patch process
if (!DexDiffPatchInternal.tryRecoverDexFiles(manager, signatureCheck, context, patchVersionDirectory, destPatchFile)) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:new patch recover, try patch dex failed");
return false;
}
if (!BsDiffPatchInternal.tryRecoverLibraryFiles(manager, signatureCheck, context, patchVersionDirectory, destPatchFile)) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:new patch recover, try patch library failed");
return false;
}
if (!ResDiffPatchInternal.tryRecoverResourceFiles(manager, signatureCheck, context, patchVersionDirectory, destPatchFile)) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:new patch recover, try patch resource failed");
return false;
}
// just warn
if (!DexDiffPatchInternal.waitDexOptFile()) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:new patch recover, check dex opt file failed");
}
final File patchInfoFile = manager.getPatchInfoFile();
if (!SharePatchInfo.rewritePatchInfoFileWithLock(patchInfoFile, newInfo, SharePatchFileUtil.getPatchInfoLockFile(patchDirectory))) {
TinkerLog.e(TAG, "UpgradePatch tryPatch:new patch recover, rewrite patch info failed");
manager.getPatchReporter().onPatchInfoCorrupted(patchFile, newInfo.oldVersion, newInfo.newVersion);
return false;
}
TinkerLog.w(TAG, "UpgradePatch tryPatch: done, it is ok");
return true;
}
use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class DefaultLoadReporter method checkAndCleanPatch.
/**
* other process may have installed old patch version,
* if we try to clean patch, we should kill other process first
*/
public void checkAndCleanPatch() {
Tinker tinker = Tinker.with(context);
//only main process can load a new patch
if (tinker.isMainProcess()) {
TinkerLoadResult tinkerLoadResult = tinker.getTinkerLoadResultIfPresent();
//if versionChange and the old patch version is not ""
if (tinkerLoadResult.versionChanged) {
SharePatchInfo sharePatchInfo = tinkerLoadResult.patchInfo;
if (sharePatchInfo != null && !ShareTinkerInternals.isNullOrNil(sharePatchInfo.oldVersion)) {
TinkerLog.w(TAG, "checkAndCleanPatch, oldVersion %s is not null, try kill all other process", sharePatchInfo.oldVersion);
ShareTinkerInternals.killAllOtherProcess(context);
}
}
}
tinker.cleanPatch();
}
use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class TinkerPatchService method onHandleIntent.
@Override
protected void onHandleIntent(Intent intent) {
final Context context = getApplicationContext();
Tinker tinker = Tinker.with(context);
tinker.getPatchReporter().onPatchServiceStart(intent);
if (intent == null) {
TinkerLog.e(TAG, "TinkerPatchService received a null intent, ignoring.");
return;
}
String path = getPatchPathExtra(intent);
if (path == null) {
TinkerLog.e(TAG, "TinkerPatchService can't get the path extra, ignoring.");
return;
}
File patchFile = new File(path);
long begin = SystemClock.elapsedRealtime();
boolean result;
long cost;
Throwable e = null;
increasingPriority();
PatchResult patchResult = new PatchResult();
try {
if (upgradePatchProcessor == null) {
throw new TinkerRuntimeException("upgradePatchProcessor is null.");
}
result = upgradePatchProcessor.tryPatch(context, path, patchResult);
} catch (Throwable throwable) {
e = throwable;
result = false;
tinker.getPatchReporter().onPatchException(patchFile, e);
}
cost = SystemClock.elapsedRealtime() - begin;
tinker.getPatchReporter().onPatchResult(patchFile, result, cost);
patchResult.isSuccess = result;
patchResult.rawPatchFilePath = path;
patchResult.costTime = cost;
patchResult.e = e;
AbstractResultService.runResultService(context, patchResult, getPatchResultExtra(intent));
}
use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class SampleApplicationLike method onBaseContextAttached.
/**
* install multiDex before install tinker
* so we don't need to put the tinker lib classes in the main dex
*
* @param base
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public void onBaseContextAttached(Context base) {
super.onBaseContextAttached(base);
//you must install multiDex whatever tinker is installed!
MultiDex.install(base);
SampleApplicationContext.application = getApplication();
SampleApplicationContext.context = getApplication();
TinkerManager.setTinkerApplicationLike(this);
TinkerManager.initFastCrashProtect();
//should set before tinker is installed
TinkerManager.setUpgradeRetryEnable(true);
//optional set logIml, or you can use default debug log
TinkerInstaller.setLogIml(new MyLogImp());
//installTinker after load multiDex
//or you can put com.tencent.tinker.** to main dex
TinkerManager.installTinker(this);
Tinker tinker = Tinker.with(getApplication());
}
Aggregations