Search in sources :

Example 1 with ShareBsDiffPatchInfo

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

the class BsDiffPatchInternal method extractBsDiffInternals.

private static boolean extractBsDiffInternals(Context context, String dir, String meta, File patchFile, int type) {
    //parse
    ArrayList<ShareBsDiffPatchInfo> patchList = new ArrayList<>();
    ShareBsDiffPatchInfo.parseDiffPatchInfo(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);
    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;
    }
    ZipFile apk = null;
    ZipFile patch = null;
    try {
        String apkPath = applicationInfo.sourceDir;
        apk = new ZipFile(apkPath);
        patch = new ZipFile(patchFile);
        for (ShareBsDiffPatchInfo info : patchList) {
            long start = System.currentTimeMillis();
            final String infoPath = info.path;
            String patchRealPath;
            if (infoPath.equals("")) {
                patchRealPath = info.name;
            } else {
                patchRealPath = info.path + "/" + info.name;
            }
            final String fileMd5 = info.md5;
            if (!SharePatchFileUtil.checkIfMd5Valid(fileMd5)) {
                TinkerLog.w(TAG, "meta file md5 mismatch, type:%s, name: %s, md5: %s", ShareTinkerInternals.getTypeString(type), info.name, info.md5);
                manager.getPatchReporter().onPatchPackageCheckFail(patchFile, BasePatchInternal.getMetaCorruptedCode(type));
                return false;
            }
            String middle;
            middle = info.path + "/" + info.name;
            File extractedFile = new File(dir + middle);
            //check file whether already exist
            if (extractedFile.exists()) {
                if (fileMd5.equals(SharePatchFileUtil.getMD5(extractedFile))) {
                    //it is ok, just continue
                    TinkerLog.w(TAG, "bsdiff 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();
            }
            String patchFileMd5 = info.patchMd5;
            //it is a new file, just copy
            ZipEntry patchFileEntry = patch.getEntry(patchRealPath);
            if (patchFileEntry == null) {
                TinkerLog.w(TAG, "patch entry is null. path:" + patchRealPath);
                manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
                return false;
            }
            if (patchFileMd5.equals("0")) {
                if (!extract(patch, patchFileEntry, extractedFile, fileMd5, false)) {
                    TinkerLog.w(TAG, "Failed to extract file " + extractedFile.getPath());
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
                    return false;
                }
            } else {
                //we do not check the intermediate files' md5 to save time, use check whether it is 32 length
                if (!SharePatchFileUtil.checkIfMd5Valid(patchFileMd5)) {
                    TinkerLog.w(TAG, "meta file md5 mismatch, type:%s, name: %s, md5: %s", ShareTinkerInternals.getTypeString(type), info.name, patchFileMd5);
                    manager.getPatchReporter().onPatchPackageCheckFail(patchFile, BasePatchInternal.getMetaCorruptedCode(type));
                    return false;
                }
                ZipEntry rawApkFileEntry = apk.getEntry(patchRealPath);
                if (rawApkFileEntry == null) {
                    TinkerLog.w(TAG, "apk entry is null. path:" + patchRealPath);
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
                    return false;
                }
                String rawApkCrc = info.rawCrc;
                //check source crc instead of md5 for faster
                String rawEntryCrc = String.valueOf(rawApkFileEntry.getCrc());
                if (!rawEntryCrc.equals(rawApkCrc)) {
                    TinkerLog.e(TAG, "apk entry %s crc is not equal, expect crc: %s, got crc: %s", patchRealPath, rawApkCrc, rawEntryCrc);
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
                    return false;
                }
                InputStream oldStream = null;
                InputStream newStream = null;
                try {
                    oldStream = apk.getInputStream(rawApkFileEntry);
                    newStream = patch.getInputStream(patchFileEntry);
                    BSPatch.patchFast(oldStream, newStream, extractedFile);
                } finally {
                    SharePatchFileUtil.closeQuietly(oldStream);
                    SharePatchFileUtil.closeQuietly(newStream);
                }
                //go go go bsdiff get the
                if (!SharePatchFileUtil.verifyFileMd5(extractedFile, fileMd5)) {
                    TinkerLog.w(TAG, "Failed to recover diff file " + extractedFile.getPath());
                    manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
                    SharePatchFileUtil.safeDeleteFile(extractedFile);
                    return false;
                }
                TinkerLog.w(TAG, "success recover bsdiff file: %s, use time: %d", extractedFile.getPath(), (System.currentTimeMillis() - start));
            }
        }
    } catch (Throwable e) {
        //            e.printStackTrace();
        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) InputStream(java.io.InputStream) ZipEntry(java.util.zip.ZipEntry) ArrayList(java.util.ArrayList) ApplicationInfo(android.content.pm.ApplicationInfo) Tinker(com.tencent.tinker.lib.tinker.Tinker) ZipFile(java.util.zip.ZipFile) ShareBsDiffPatchInfo(com.tencent.tinker.loader.shareutil.ShareBsDiffPatchInfo) File(java.io.File) ZipFile(java.util.zip.ZipFile)

Example 2 with ShareBsDiffPatchInfo

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

the class TinkerSoLoader method checkComplete.

/**
     * all the library 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(SO_MEAT_FILE);
    //not found lib
    if (meta == null) {
        return true;
    }
    ArrayList<ShareBsDiffPatchInfo> libraryList = new ArrayList<>();
    ShareBsDiffPatchInfo.parseDiffPatchInfo(meta, libraryList);
    if (libraryList.isEmpty()) {
        return true;
    }
    //tinker//patch-641e634c/lib
    String libraryPath = directory + "/" + SO_PATH + "/";
    HashMap<String, String> libs = new HashMap<>();
    for (ShareBsDiffPatchInfo info : libraryList) {
        if (!ShareBsDiffPatchInfo.checkDiffPatchInfo(info)) {
            intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_PACKAGE_PATCH_CHECK, ShareConstants.ERROR_PACKAGE_CHECK_LIB_META_CORRUPTED);
            ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_PACKAGE_CHECK_FAIL);
            return false;
        }
        String middle = info.path + "/" + info.name;
        //unlike dex, keep the original structure
        libs.put(middle, info.md5);
    }
    File libraryDir = new File(libraryPath);
    if (!libraryDir.exists() || !libraryDir.isDirectory()) {
        ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_LIB_DIRECTORY_NOT_EXIST);
        return false;
    }
    //fast check whether there is any dex files missing
    for (String relative : libs.keySet()) {
        File libFile = new File(libraryPath + relative);
        if (!SharePatchFileUtil.isLegalFile(libFile)) {
            ShareIntentUtil.setIntentReturnCode(intentResult, ShareConstants.ERROR_LOAD_PATCH_VERSION_LIB_FILE_NOT_EXIST);
            intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_MISSING_LIB_PATH, libFile.getAbsolutePath());
            return false;
        }
    }
    //if is ok, add to result intent
    intentResult.putExtra(ShareIntentUtil.INTENT_PATCH_LIBS_PATH, libs);
    return true;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ShareBsDiffPatchInfo(com.tencent.tinker.loader.shareutil.ShareBsDiffPatchInfo) File(java.io.File)

Aggregations

ShareBsDiffPatchInfo (com.tencent.tinker.loader.shareutil.ShareBsDiffPatchInfo)2 File (java.io.File)2 ArrayList (java.util.ArrayList)2 ApplicationInfo (android.content.pm.ApplicationInfo)1 Tinker (com.tencent.tinker.lib.tinker.Tinker)1 TinkerRuntimeException (com.tencent.tinker.loader.TinkerRuntimeException)1 InputStream (java.io.InputStream)1 HashMap (java.util.HashMap)1 ZipEntry (java.util.zip.ZipEntry)1 ZipFile (java.util.zip.ZipFile)1