Search in sources :

Example 1 with ShareDexDiffPatchInfo

use of com.tencent.tinker.loader.shareutil.ShareDexDiffPatchInfo in project tinker by Tencent.

the class TinkerDexLoader method checkComplete.

/**
     * all the dex files in meta file exist?
     * fast check, only check whether exist
     *
     * @param directory
     * @return boolean
     */
public static boolean checkComplete(String directory, ShareSecurityCheck securityCheck, Intent intentResult) {
    String meta = securityCheck.getMetaContentMap().get(DEX_MEAT_FILE);
    //not found dex
    if (meta == null) {
        return true;
    }
    dexList.clear();
    ShareDexDiffPatchInfo.parseDexDiffPatchInfo(meta, dexList);
    if (dexList.isEmpty()) {
        return true;
    }
    HashMap<String, String> dexes = new HashMap<>();
    for (ShareDexDiffPatchInfo info : dexList) {
        //for dalvik, ignore art support dex
        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);
    }
    //tinker/patch.info/patch-641e634c/dex
    String dexDirectory = directory + "/" + DEX_PATH + "/";
    File dexDir = new File(dexDirectory);
    if (!dexDir.exists() || !dexDir.isDirectory()) {
        ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_DIRECTORY_NOT_EXIST);
        return false;
    }
    String optimizeDexDirectory = directory + "/" + DEX_OPTIMIZE_PATH + "/";
    File optimizeDexDirectoryFile = new File(optimizeDexDirectory);
    //fast check whether there is any dex files missing
    for (String name : dexes.keySet()) {
        File dexFile = new File(dexDirectory + name);
        if (!SharePatchFileUtil.isLegalFile(dexFile)) {
            intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_MISSING_DEX_PATH, dexFile.getAbsolutePath());
            ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_FILE_NOT_EXIST);
            return false;
        }
        //check dex opt whether complete also
        File dexOptFile = new File(SharePatchFileUtil.optimizedPathFor(dexFile, optimizeDexDirectoryFile));
        if (!SharePatchFileUtil.isLegalFile(dexOptFile)) {
            intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_MISSING_DEX_PATH, dexOptFile.getAbsolutePath());
            ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_OPT_FILE_NOT_EXIST);
            return false;
        }
    }
    //if is ok, add to result intent
    intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_DEXES_PATH, dexes);
    return true;
}
Also used : HashMap(java.util.HashMap) File(java.io.File) ShareDexDiffPatchInfo(com.tencent.tinker.loader.shareutil.ShareDexDiffPatchInfo)

Example 2 with ShareDexDiffPatchInfo

use of com.tencent.tinker.loader.shareutil.ShareDexDiffPatchInfo in project tinker by Tencent.

the class TinkerDexLoader method loadTinkerJars.

/**
     * Load tinker JARs and add them to
     * the Application ClassLoader.
     *
     * @param application The application.
     */
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static boolean loadTinkerJars(Application application, boolean tinkerLoadVerifyFlag, String directory, Intent intentResult, boolean isSystemOTA) {
    if (dexList.isEmpty()) {
        Log.w(TAG, "there is no dex to load");
        return true;
    }
    PathClassLoader classLoader = (PathClassLoader) TinkerDexLoader.class.getClassLoader();
    if (classLoader != null) {
        Log.i(TAG, "classloader: " + classLoader.toString());
    } else {
        Log.e(TAG, "classloader is null");
        ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_CLASSLOADER_NULL);
        return false;
    }
    String dexPath = directory + "/" + DEX_PATH + "/";
    File optimizeDir = new File(directory + "/" + DEX_OPTIMIZE_PATH);
    //        Log.i(TAG, "loadTinkerJars: dex path: " + dexPath);
    //        Log.i(TAG, "loadTinkerJars: opt path: " + optimizeDir.getAbsolutePath());
    ArrayList<File> legalFiles = new ArrayList<>();
    final boolean isArtPlatForm = ShareTinkerInternals.isVmArt();
    for (ShareDexDiffPatchInfo info : dexList) {
        //for dalvik, ignore art support dex
        if (isJustArtSupportDex(info)) {
            continue;
        }
        String path = dexPath + info.realName;
        File file = new File(path);
        if (tinkerLoadVerifyFlag) {
            long start = System.currentTimeMillis();
            String checkMd5 = isArtPlatForm ? info.destMd5InArt : info.destMd5InDvm;
            if (!SharePatchFileUtil.verifyDexFileMd5(file, checkMd5)) {
                //it is good to delete the mismatch file
                ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_MD5_MISMATCH);
                intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_MISMATCH_DEX_PATH, file.getAbsolutePath());
                return false;
            }
            Log.i(TAG, "verify dex file:" + file.getPath() + " md5, use time: " + (System.currentTimeMillis() - start));
        }
        legalFiles.add(file);
    }
    if (isSystemOTA) {
        parallelOTAResult = true;
        parallelOTAThrowable = null;
        Log.w(TAG, "systemOTA, try parallel oat dexes!!!!!");
        TinkerParallelDexOptimizer.optimizeAll(legalFiles, optimizeDir, new TinkerParallelDexOptimizer.ResultCallback() {

            long start;

            @Override
            public void onStart(File dexFile, File optimizedDir) {
                start = System.currentTimeMillis();
                Log.i(TAG, "start to optimize dex:" + dexFile.getPath());
            }

            @Override
            public void onSuccess(File dexFile, File optimizedDir, File optimizedFile) {
                // Do nothing.
                Log.i(TAG, "success to optimize dex " + dexFile.getPath() + "use time " + (System.currentTimeMillis() - start));
            }

            @Override
            public void onFailed(File dexFile, File optimizedDir, Throwable thr) {
                parallelOTAResult = false;
                parallelOTAThrowable = thr;
                Log.i(TAG, "fail to optimize dex " + dexFile.getPath() + "use time " + (System.currentTimeMillis() - start));
            }
        });
        if (!parallelOTAResult) {
            Log.e(TAG, "parallel oat dexes failed");
            intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_EXCEPTION, parallelOTAThrowable);
            ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_PARALLEL_DEX_OPT_EXCEPTION);
            return false;
        }
    }
    try {
        SystemClassLoaderAdder.installDexes(application, classLoader, optimizeDir, legalFiles);
    } catch (Throwable e) {
        Log.e(TAG, "install dexes failed");
        //            e.printStackTrace();
        intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_EXCEPTION, e);
        ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_DEX_LOAD_EXCEPTION);
        return false;
    }
    return true;
}
Also used : ArrayList(java.util.ArrayList) PathClassLoader(dalvik.system.PathClassLoader) File(java.io.File) ShareDexDiffPatchInfo(com.tencent.tinker.loader.shareutil.ShareDexDiffPatchInfo) TargetApi(android.annotation.TargetApi)

Example 3 with ShareDexDiffPatchInfo

use of com.tencent.tinker.loader.shareutil.ShareDexDiffPatchInfo in project tinker by Tencent.

the class DexDiffPatchInternal method extractDexDiffInternals.

private static boolean extractDexDiffInternals(Context context, String dir, String meta, File patchFile, int type) {
    //parse
    ArrayList<ShareDexDiffPatchInfo> patchList = new ArrayList<>();
    ShareDexDiffPatchInfo.parseDexDiffPatchInfo(meta, patchList);
    if (patchList.isEmpty()) {
        TinkerLog.w(TAG, "extract patch list is empty! type:%s:", ShareTinkerInternals.getTypeString(type));
        return true;
    }
    File directory = new File(dir);
    if (!directory.exists()) {
        directory.mkdirs();
    }
    //I think it is better to extract the raw files from apk
    Tinker manager = Tinker.with(context);
    ZipFile apk = null;
    ZipFile patch = null;
    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;
        apk = new ZipFile(apkPath);
        patch = new ZipFile(patchFile);
        for (ShareDexDiffPatchInfo info : patchList) {
            long start = System.currentTimeMillis();
            final String infoPath = info.path;
            String patchRealPath;
            if (infoPath.equals("")) {
                patchRealPath = info.rawName;
            } else {
                patchRealPath = info.path + "/" + info.rawName;
            }
            String dexDiffMd5 = info.dexDiffMd5;
            String oldDexCrc = info.oldDexCrC;
            if (!ShareTinkerInternals.isVmArt() && info.destMd5InDvm.equals("0")) {
                TinkerLog.w(TAG, "patch dex %s is only for art, just continue", patchRealPath);
                continue;
            }
            String extractedFileMd5 = ShareTinkerInternals.isVmArt() ? info.destMd5InArt : info.destMd5InDvm;
            if (!SharePatchFileUtil.checkIfMd5Valid(extractedFileMd5)) {
                TinkerLog.w(TAG, "meta file md5 invalid, type:%s, name: %s, md5: %s", ShareTinkerInternals.getTypeString(type), info.rawName, extractedFileMd5);
                manager.getPatchReporter().onPatchPackageCheckFail(patchFile, BasePatchInternal.getMetaCorruptedCode(type));
                return false;
            }
            File extractedFile = new File(dir + info.realName);
            //check file whether already exist
            if (extractedFile.exists()) {
                if (SharePatchFileUtil.verifyDexFileMd5(extractedFile, extractedFileMd5)) {
                    //it is ok, just continue
                    TinkerLog.w(TAG, "dex file %s is already exist, and md5 match, just continue", extractedFile.getPath());
                    continue;
                } else {
                    TinkerLog.w(TAG, "have a mismatch corrupted dex " + extractedFile.getPath());
                    extractedFile.delete();
                }
            } else {
                extractedFile.getParentFile().mkdirs();
            }
            ZipEntry patchFileEntry = patch.getEntry(patchRealPath);
            ZipEntry rawApkFileEntry = apk.getEntry(patchRealPath);
            if (oldDexCrc.equals("0")) {
                if (patchFileEntry == null) {
                    TinkerLog.w(TAG, "patch entry is null. path:" + patchRealPath);
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    return false;
                }
                //it is a new file, but maybe we need to repack the dex file
                if (!extractDexFile(patch, patchFileEntry, extractedFile, info)) {
                    TinkerLog.w(TAG, "Failed to extract raw patch file " + extractedFile.getPath());
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    return false;
                }
            } else if (dexDiffMd5.equals("0")) {
                // skip process old dex for real dalvik vm
                if (!ShareTinkerInternals.isVmArt()) {
                    continue;
                }
                if (rawApkFileEntry == null) {
                    TinkerLog.w(TAG, "apk entry is null. path:" + patchRealPath);
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    return false;
                }
                //check source crc instead of md5 for faster
                String rawEntryCrc = String.valueOf(rawApkFileEntry.getCrc());
                if (!rawEntryCrc.equals(oldDexCrc)) {
                    TinkerLog.e(TAG, "apk entry %s crc is not equal, expect crc: %s, got crc: %s", patchRealPath, oldDexCrc, rawEntryCrc);
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    return false;
                }
                // Small patched dex generating strategy was disabled, we copy full original dex directly now.
                //patchDexFile(apk, patch, rawApkFileEntry, null, info, smallPatchInfoFile, extractedFile);
                extractDexFile(apk, rawApkFileEntry, extractedFile, info);
                if (!SharePatchFileUtil.verifyDexFileMd5(extractedFile, extractedFileMd5)) {
                    TinkerLog.w(TAG, "Failed to recover dex file when verify patched dex: " + extractedFile.getPath());
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    SharePatchFileUtil.safeDeleteFile(extractedFile);
                    return false;
                }
            } else {
                if (patchFileEntry == null) {
                    TinkerLog.w(TAG, "patch entry is null. path:" + patchRealPath);
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    return false;
                }
                if (!SharePatchFileUtil.checkIfMd5Valid(dexDiffMd5)) {
                    TinkerLog.w(TAG, "meta file md5 invalid, type:%s, name: %s, md5: %s", ShareTinkerInternals.getTypeString(type), info.rawName, dexDiffMd5);
                    manager.getPatchReporter().onPatchPackageCheckFail(patchFile, BasePatchInternal.getMetaCorruptedCode(type));
                    return false;
                }
                if (rawApkFileEntry == null) {
                    TinkerLog.w(TAG, "apk entry is null. path:" + patchRealPath);
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    return false;
                }
                //check source crc instead of md5 for faster
                String rawEntryCrc = String.valueOf(rawApkFileEntry.getCrc());
                if (!rawEntryCrc.equals(oldDexCrc)) {
                    TinkerLog.e(TAG, "apk entry %s crc is not equal, expect crc: %s, got crc: %s", patchRealPath, oldDexCrc, rawEntryCrc);
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    return false;
                }
                patchDexFile(apk, patch, rawApkFileEntry, patchFileEntry, info, extractedFile);
                if (!SharePatchFileUtil.verifyDexFileMd5(extractedFile, extractedFileMd5)) {
                    TinkerLog.w(TAG, "Failed to recover dex file when verify patched dex: " + extractedFile.getPath());
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.rawName, type);
                    SharePatchFileUtil.safeDeleteFile(extractedFile);
                    return false;
                }
                TinkerLog.w(TAG, "success recover dex file: %s, size: %d, use time: %d", extractedFile.getPath(), extractedFile.length(), (System.currentTimeMillis() - start));
            }
        }
    } catch (Throwable e) {
        throw new TinkerRuntimeException("patch " + ShareTinkerInternals.getTypeString(type) + " extract failed (" + e.getMessage() + ").", e);
    } finally {
        SharePatchFileUtil.closeZip(apk);
        SharePatchFileUtil.closeZip(patch);
    }
    return true;
}
Also used : TinkerRuntimeException(com.tencent.tinker.loader.TinkerRuntimeException) ZipFile(java.util.zip.ZipFile) ZipEntry(java.util.zip.ZipEntry) ArrayList(java.util.ArrayList) ApplicationInfo(android.content.pm.ApplicationInfo) ZipFile(java.util.zip.ZipFile) DexFile(dalvik.system.DexFile) File(java.io.File) Tinker(com.tencent.tinker.lib.tinker.Tinker) ShareDexDiffPatchInfo(com.tencent.tinker.loader.shareutil.ShareDexDiffPatchInfo)

Aggregations

ShareDexDiffPatchInfo (com.tencent.tinker.loader.shareutil.ShareDexDiffPatchInfo)3 File (java.io.File)3 ArrayList (java.util.ArrayList)2 TargetApi (android.annotation.TargetApi)1 ApplicationInfo (android.content.pm.ApplicationInfo)1 Tinker (com.tencent.tinker.lib.tinker.Tinker)1 TinkerRuntimeException (com.tencent.tinker.loader.TinkerRuntimeException)1 DexFile (dalvik.system.DexFile)1 PathClassLoader (dalvik.system.PathClassLoader)1 HashMap (java.util.HashMap)1 ZipEntry (java.util.zip.ZipEntry)1 ZipFile (java.util.zip.ZipFile)1