Search in sources :

Example 16 with Tinker

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;
}
Also used : TinkerRuntimeException(com.tencent.tinker.loader.TinkerRuntimeException) ApplicationInfo(android.content.pm.ApplicationInfo) TinkerZipEntry(com.tencent.tinker.commons.ziputil.TinkerZipEntry) Tinker(com.tencent.tinker.lib.tinker.Tinker) TinkerZipOutputStream(com.tencent.tinker.commons.ziputil.TinkerZipOutputStream) ShareResPatchInfo(com.tencent.tinker.loader.shareutil.ShareResPatchInfo) FileOutputStream(java.io.FileOutputStream) TinkerZipFile(com.tencent.tinker.commons.ziputil.TinkerZipFile) File(java.io.File) ZipFile(java.util.zip.ZipFile) BufferedOutputStream(java.io.BufferedOutputStream) TinkerZipFile(com.tencent.tinker.commons.ziputil.TinkerZipFile)

Example 17 with Tinker

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;
}
Also used : SharePatchInfo(com.tencent.tinker.loader.shareutil.SharePatchInfo) ShareSecurityCheck(com.tencent.tinker.loader.shareutil.ShareSecurityCheck) IOException(java.io.IOException) Tinker(com.tencent.tinker.lib.tinker.Tinker) File(java.io.File)

Example 18 with Tinker

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();
}
Also used : SharePatchInfo(com.tencent.tinker.loader.shareutil.SharePatchInfo) TinkerLoadResult(com.tencent.tinker.lib.tinker.TinkerLoadResult) Tinker(com.tencent.tinker.lib.tinker.Tinker)

Example 19 with Tinker

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));
}
Also used : Context(android.content.Context) TinkerRuntimeException(com.tencent.tinker.loader.TinkerRuntimeException) Tinker(com.tencent.tinker.lib.tinker.Tinker) File(java.io.File)

Example 20 with Tinker

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());
}
Also used : MyLogImp(tinker.sample.android.Log.MyLogImp) Tinker(com.tencent.tinker.lib.tinker.Tinker) TargetApi(android.annotation.TargetApi)

Aggregations

Tinker (com.tencent.tinker.lib.tinker.Tinker)21 File (java.io.File)16 TinkerRuntimeException (com.tencent.tinker.loader.TinkerRuntimeException)8 TinkerLoadResult (com.tencent.tinker.lib.tinker.TinkerLoadResult)5 ZipFile (java.util.zip.ZipFile)5 ApplicationInfo (android.content.pm.ApplicationInfo)3 ZipEntry (java.util.zip.ZipEntry)3 SharedPreferences (android.content.SharedPreferences)2 TinkerZipEntry (com.tencent.tinker.commons.ziputil.TinkerZipEntry)2 TinkerZipFile (com.tencent.tinker.commons.ziputil.TinkerZipFile)2 SharePatchInfo (com.tencent.tinker.loader.shareutil.SharePatchInfo)2 ShareResPatchInfo (com.tencent.tinker.loader.shareutil.ShareResPatchInfo)2 DexFile (dalvik.system.DexFile)2 InputStream (java.io.InputStream)2 ArrayList (java.util.ArrayList)2 Properties (java.util.Properties)2 TargetApi (android.annotation.TargetApi)1 AlertDialog (android.app.AlertDialog)1 Context (android.content.Context)1 ViewGroup (android.view.ViewGroup)1