Search in sources :

Example 1 with TinkerPatchException

use of com.tencent.tinker.build.util.TinkerPatchException in project tinker by Tencent.

the class CliMain method loadConfigFromXml.

private void loadConfigFromXml(File configFile, File outputFile, File oldApkFile, File newApkFile) {
    if (configFile == null) {
        configFile = new File(mRunningLocation + File.separator + TypedValue.FILE_CONFIG);
        if (!configFile.exists()) {
            System.err.printf("the config file %s does not exit\n", configFile.getAbsolutePath());
            printUsage(System.err);
            System.exit(ERRNO_USAGE);
        }
    }
    try {
        config = new Configuration(configFile, outputFile, oldApkFile, newApkFile);
    } catch (IOException | ParserConfigurationException | SAXException e) {
        e.printStackTrace();
        goToError();
    } catch (TinkerPatchException e) {
        e.printStackTrace();
        goToError();
    }
}
Also used : Configuration(com.tencent.tinker.build.patch.Configuration) IOException(java.io.IOException) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException) File(java.io.File) SAXException(org.xml.sax.SAXException) TinkerPatchException(com.tencent.tinker.build.util.TinkerPatchException)

Example 2 with TinkerPatchException

use of com.tencent.tinker.build.util.TinkerPatchException in project tinker by Tencent.

the class DexDiffDecoder method collectAddedOrDeletedClasses.

/**
     * Before starting real diff works, we collect added class descriptor
     * and deleted class descriptor for further analysing in {@code checkCrossDexMovingClasses}.
     */
private void collectAddedOrDeletedClasses(File oldFile, File newFile) throws IOException {
    Dex oldDex = new Dex(oldFile);
    Dex newDex = new Dex(newFile);
    Set<String> oldClassDescs = new HashSet<>();
    for (ClassDef oldClassDef : oldDex.classDefs()) {
        oldClassDescs.add(oldDex.typeNames().get(oldClassDef.typeIndex));
    }
    Set<String> newClassDescs = new HashSet<>();
    for (ClassDef newClassDef : newDex.classDefs()) {
        newClassDescs.add(newDex.typeNames().get(newClassDef.typeIndex));
    }
    Set<String> addedClassDescs = new HashSet<>(newClassDescs);
    addedClassDescs.removeAll(oldClassDescs);
    Set<String> deletedClassDescs = new HashSet<>(oldClassDescs);
    deletedClassDescs.removeAll(newClassDescs);
    for (String addedClassDesc : addedClassDescs) {
        if (addedClassDescToDexNameMap.containsKey(addedClassDesc)) {
            throw new TinkerPatchException(String.format("Class Duplicate. Class [%s] is added in both new dex: [%s] and [%s]. Please check your newly apk.", addedClassDesc, addedClassDescToDexNameMap.get(addedClassDesc), newFile.toString()));
        } else {
            addedClassDescToDexNameMap.put(addedClassDesc, newFile.toString());
        }
    }
    for (String deletedClassDesc : deletedClassDescs) {
        if (deletedClassDescToDexNameMap.containsKey(deletedClassDesc)) {
            throw new TinkerPatchException(String.format("Class Duplicate. Class [%s] is deleted in both old dex: [%s] and [%s]. Please check your base apk.", deletedClassDesc, addedClassDescToDexNameMap.get(deletedClassDesc), oldFile.toString()));
        } else {
            deletedClassDescToDexNameMap.put(deletedClassDesc, newFile.toString());
        }
    }
}
Also used : ClassDef(com.tencent.tinker.android.dex.ClassDef) Dex(com.tencent.tinker.android.dex.Dex) HashSet(java.util.HashSet) TinkerPatchException(com.tencent.tinker.build.util.TinkerPatchException)

Example 3 with TinkerPatchException

use of com.tencent.tinker.build.util.TinkerPatchException in project tinker by Tencent.

the class DexDiffDecoder method getRawOrWrappedDexMD5.

private String getRawOrWrappedDexMD5(File dexOrJarFile) {
    final String name = dexOrJarFile.getName();
    if (name.endsWith(".dex")) {
        return MD5.getMD5(dexOrJarFile);
    } else {
        JarFile dexJar = null;
        try {
            dexJar = new JarFile(dexOrJarFile);
            ZipEntry classesDex = dexJar.getEntry(DexFormat.DEX_IN_JAR_NAME);
            // no code
            if (classesDex == null) {
                throw new TinkerPatchException(String.format("Jar file %s do not contain 'classes.dex', it is not a correct dex jar file!", dexOrJarFile.getAbsolutePath()));
            }
            return MD5.getMD5(dexJar.getInputStream(classesDex), 1024 * 100);
        } catch (IOException e) {
            throw new TinkerPatchException(String.format("File %s is not end with '.dex', but it is not a correct dex jar file !", dexOrJarFile.getAbsolutePath()), e);
        } finally {
            if (dexJar != null) {
                try {
                    dexJar.close();
                } catch (Exception e) {
                // Ignored.
                }
            }
        }
    }
}
Also used : ZipEntry(java.util.zip.ZipEntry) IOException(java.io.IOException) JarFile(java.util.jar.JarFile) TinkerPatchException(com.tencent.tinker.build.util.TinkerPatchException) IOException(java.io.IOException) TinkerPatchException(com.tencent.tinker.build.util.TinkerPatchException)

Example 4 with TinkerPatchException

use of com.tencent.tinker.build.util.TinkerPatchException in project tinker by Tencent.

the class DexDiffDecoder method checkDexChange.

private void checkDexChange(Dex originDex, Dex newDex) {
    DexClassesComparator classesCmptor = new DexClassesComparator("*");
    classesCmptor.setIgnoredRemovedClassDescPattern(config.mDexLoaderPattern);
    classesCmptor.startCheck(originDex, newDex);
    List<DexClassInfo> addedClassInfos = classesCmptor.getAddedClassInfos();
    boolean isNoClassesAdded = addedClassInfos.isEmpty();
    Map<String, DexClassInfo[]> changedClassDescToClassInfosMap;
    boolean isNoClassesChanged;
    if (isNoClassesAdded) {
        changedClassDescToClassInfosMap = classesCmptor.getChangedClassDescToInfosMap();
        isNoClassesChanged = changedClassDescToClassInfosMap.isEmpty();
    } else {
        throw new TinkerPatchException("some classes was unexpectedly added in patched new dex, check if there's any bugs in " + "patch algorithm. Related classes: " + Utils.collectionToString(addedClassInfos));
    }
    if (isNoClassesChanged) {
        List<DexClassInfo> deletedClassInfos = classesCmptor.getDeletedClassInfos();
        if (!deletedClassInfos.isEmpty()) {
            throw new TinkerPatchException("some classes that are not matched to loader class pattern " + "was unexpectedly deleted in patched new dex, check if there's any bugs in " + "patch algorithm. Related classes: " + Utils.collectionToString(deletedClassInfos));
        }
    } else {
        throw new TinkerPatchException("some classes was unexpectedly changed in patched new dex, check if there's any bugs in " + "patch algorithm. Related classes: " + Utils.collectionToString(changedClassDescToClassInfosMap.keySet()));
    }
}
Also used : DexClassesComparator(com.tencent.tinker.build.util.DexClassesComparator) DexClassInfo(com.tencent.tinker.build.util.DexClassesComparator.DexClassInfo) TinkerPatchException(com.tencent.tinker.build.util.TinkerPatchException)

Example 5 with TinkerPatchException

use of com.tencent.tinker.build.util.TinkerPatchException in project tinker by Tencent.

the class ResDiffDecoder method onAllPatchesEnd.

@Override
public void onAllPatchesEnd() throws IOException, TinkerPatchException {
    //only there is only deleted set, we just ignore
    if (addedSet.isEmpty() && modifiedSet.isEmpty() && largeModifiedSet.isEmpty()) {
        return;
    }
    if (!config.mResRawPattern.contains(TypedValue.RES_ARSC)) {
        throw new TinkerPatchException("resource must contain resources.arsc pattern");
    }
    if (!config.mResRawPattern.contains(TypedValue.RES_MANIFEST)) {
        throw new TinkerPatchException("resource must contain AndroidManifest.xml pattern");
    }
    //check gradle build
    if (config.mUsingGradle) {
        final boolean ignoreWarning = config.mIgnoreWarning;
        final boolean resourceArscChanged = modifiedSet.contains(TypedValue.RES_ARSC) || largeModifiedSet.contains(TypedValue.RES_ARSC);
        if (resourceArscChanged && !config.mUseApplyResource) {
            if (ignoreWarning) {
                //ignoreWarning, just log
                Logger.e("Warning:ignoreWarning is true, but resources.arsc is changed, you should use applyResourceMapping mode to build the new apk, otherwise, it may be crash at some times");
            } else {
                Logger.e("Warning:ignoreWarning is false, but resources.arsc is changed, you should use applyResourceMapping mode to build the new apk, otherwise, it may be crash at some times");
                throw new TinkerPatchException(String.format("ignoreWarning is false, but resources.arsc is changed, you should use applyResourceMapping mode to build the new apk, otherwise, it may be crash at some times"));
            }
        }
    /*else if (config.mUseApplyResource) {
                int totalChangeSize = addedSet.size() + modifiedSet.size() + largeModifiedSet.size();
                if (totalChangeSize == 1 && resourceArscChanged) {
                    Logger.e("Warning: we are using applyResourceMapping mode to build the new apk, but there is only resources.arsc changed, you should ensure there is actually resource changed!");
                }
            }*/
    }
    //add delete set
    deletedSet.addAll(getDeletedResource(config.mTempUnzipOldDir, config.mTempUnzipNewDir));
    //we can't modify AndroidManifest file
    addedSet.remove(TypedValue.RES_MANIFEST);
    deletedSet.remove(TypedValue.RES_MANIFEST);
    modifiedSet.remove(TypedValue.RES_MANIFEST);
    largeModifiedSet.remove(TypedValue.RES_MANIFEST);
    //remove add, delete or modified if they are in ignore change pattern also
    removeIgnoreChangeFile(modifiedSet);
    removeIgnoreChangeFile(deletedSet);
    removeIgnoreChangeFile(addedSet);
    removeIgnoreChangeFile(largeModifiedSet);
    // last add test res in assets for user cannot ignore it;
    addAssetsFileForTestResource();
    File tempResZip = new File(config.mOutFolder + File.separator + TEMP_RES_ZIP);
    final File tempResFiles = config.mTempResultDir;
    //gen zip resources_out.zip
    FileOperation.zipInputDir(tempResFiles, tempResZip);
    File extractToZip = new File(config.mOutFolder + File.separator + TypedValue.RES_OUT);
    String resZipMd5 = Utils.genResOutputFile(extractToZip, tempResZip, config, addedSet, modifiedSet, deletedSet, largeModifiedSet, largeModifiedMap);
    Logger.e("Final normal zip resource: %s, size=%d, md5=%s", extractToZip.getName(), extractToZip.length(), resZipMd5);
    logWriter.writeLineToInfoFile(String.format("Final normal zip resource: %s, size=%d, md5=%s", extractToZip.getName(), extractToZip.length(), resZipMd5));
    //delete temp file
    FileOperation.deleteFile(tempResZip);
    //gen zip resources_out_7z.zip
    File extractTo7Zip = new File(config.mOutFolder + File.separator + TypedValue.RES_OUT_7ZIP);
    File tempRes7Zip = new File(config.mOutFolder + File.separator + TEMP_RES_7ZIP);
    //ensure 7zip is enable
    if (FileOperation.sevenZipInputDir(tempResFiles, tempRes7Zip, config)) {
        //7zip whether actual exist
        if (tempRes7Zip.exists()) {
            String res7zipMd5 = Utils.genResOutputFile(extractTo7Zip, tempRes7Zip, config, addedSet, modifiedSet, deletedSet, largeModifiedSet, largeModifiedMap);
            //delete temp file
            FileOperation.deleteFile(tempRes7Zip);
            Logger.e("Final 7zip resource: %s, size=%d, md5=%s", extractTo7Zip.getName(), extractTo7Zip.length(), res7zipMd5);
            logWriter.writeLineToInfoFile(String.format("Final 7zip resource: %s, size=%d, md5=%s", extractTo7Zip.getName(), extractTo7Zip.length(), res7zipMd5));
        }
    }
    //first, write resource meta first
    //use resources.arsc's base crc to identify base.apk
    String arscBaseCrc = FileOperation.getZipEntryCrc(config.mOldApkFile, TypedValue.RES_ARSC);
    String arscMd5 = FileOperation.getZipEntryMd5(extractToZip, TypedValue.RES_ARSC);
    if (arscBaseCrc == null || arscMd5 == null) {
        throw new TinkerPatchException("can't find resources.arsc's base crc or md5");
    }
    String resourceMeta = Utils.getResourceMeta(arscBaseCrc, arscMd5);
    writeMetaFile(resourceMeta);
    //pattern
    String patternMeta = TypedValue.PATTERN_TITLE;
    HashSet<String> patterns = new HashSet<>(config.mResRawPattern);
    //we will process them separate
    patterns.remove(TypedValue.RES_MANIFEST);
    writeMetaFile(patternMeta + patterns.size());
    //write pattern
    for (String item : patterns) {
        writeMetaFile(item);
    }
    //write meta file, write large modify first
    writeMetaFile(largeModifiedSet, TypedValue.LARGE_MOD);
    writeMetaFile(modifiedSet, TypedValue.MOD);
    writeMetaFile(addedSet, TypedValue.ADD);
    writeMetaFile(deletedSet, TypedValue.DEL);
}
Also used : File(java.io.File) TinkerPatchException(com.tencent.tinker.build.util.TinkerPatchException) HashSet(java.util.HashSet)

Aggregations

TinkerPatchException (com.tencent.tinker.build.util.TinkerPatchException)10 File (java.io.File)5 IOException (java.io.IOException)4 JarFile (java.util.jar.JarFile)3 Dex (com.tencent.tinker.android.dex.Dex)2 AndroidParser (com.tencent.tinker.build.apkparser.AndroidParser)2 HashSet (java.util.HashSet)2 ClassDef (com.tencent.tinker.android.dex.ClassDef)1 DexPatchGenerator (com.tencent.tinker.build.dexpatcher.DexPatchGenerator)1 Configuration (com.tencent.tinker.build.patch.Configuration)1 DexClassesComparator (com.tencent.tinker.build.util.DexClassesComparator)1 DexClassInfo (com.tencent.tinker.build.util.DexClassesComparator.DexClassInfo)1 DexPatchApplier (com.tencent.tinker.commons.dexpatcher.DexPatchApplier)1 ParseException (java.text.ParseException)1 AbstractMap (java.util.AbstractMap)1 ZipEntry (java.util.zip.ZipEntry)1 ParserConfigurationException (javax.xml.parsers.ParserConfigurationException)1 SAXException (org.xml.sax.SAXException)1