Search in sources :

Example 1 with ClassDefSectionDiffAlgorithm

use of com.tencent.tinker.build.dexpatcher.algorithms.diff.ClassDefSectionDiffAlgorithm in project tinker by Tencent.

the class DexPatchGenerator method executeAndSaveTo.

public void executeAndSaveTo(OutputStream out) throws IOException {
    // Firstly, collect information of items we want to remove additionally
    // in new dex and set them to corresponding diff algorithm implementations.
    Pattern[] classNamePatterns = new Pattern[this.additionalRemovingClassPatternSet.size()];
    int classNamePatternCount = 0;
    for (String regExStr : this.additionalRemovingClassPatternSet) {
        classNamePatterns[classNamePatternCount++] = Pattern.compile(regExStr);
    }
    List<Integer> typeIdOfClassDefsToRemove = new ArrayList<>(classNamePatternCount);
    List<Integer> offsetOfClassDatasToRemove = new ArrayList<>(classNamePatternCount);
    for (ClassDef classDef : this.newDex.classDefs()) {
        String typeName = this.newDex.typeNames().get(classDef.typeIndex);
        for (Pattern pattern : classNamePatterns) {
            if (pattern.matcher(typeName).matches()) {
                typeIdOfClassDefsToRemove.add(classDef.typeIndex);
                offsetOfClassDatasToRemove.add(classDef.classDataOffset);
                break;
            }
        }
    }
    ((ClassDefSectionDiffAlgorithm) this.classDefSectionDiffAlg).setTypeIdOfClassDefsToRemove(typeIdOfClassDefsToRemove);
    ((ClassDataSectionDiffAlgorithm) this.classDataSectionDiffAlg).setOffsetOfClassDatasToRemove(offsetOfClassDatasToRemove);
    // Then, run diff algorithms according to sections' dependencies.
    // Use size calculated by algorithms above or from dex file definition to
    // calculate sections' offset and patched dex size.
    // Calculate header and id sections size, so that we can work out
    // the base offset of typeLists Section.
    int patchedheaderSize = SizeOf.HEADER_ITEM;
    int patchedStringIdsSize = newDex.getTableOfContents().stringIds.size * SizeOf.STRING_ID_ITEM;
    int patchedTypeIdsSize = newDex.getTableOfContents().typeIds.size * SizeOf.TYPE_ID_ITEM;
    // Although simulatePatchOperation can calculate this value, since protoIds section
    // depends on typeLists section, we can't run protoIds Section's simulatePatchOperation
    // method so far. Instead we calculate protoIds section's size using information in newDex
    // directly.
    int patchedProtoIdsSize = newDex.getTableOfContents().protoIds.size * SizeOf.PROTO_ID_ITEM;
    int patchedFieldIdsSize = newDex.getTableOfContents().fieldIds.size * SizeOf.MEMBER_ID_ITEM;
    int patchedMethodIdsSize = newDex.getTableOfContents().methodIds.size * SizeOf.MEMBER_ID_ITEM;
    int patchedClassDefsSize = newDex.getTableOfContents().classDefs.size * SizeOf.CLASS_DEF_ITEM;
    int patchedIdSectionSize = patchedStringIdsSize + patchedTypeIdsSize + patchedProtoIdsSize + patchedFieldIdsSize + patchedMethodIdsSize + patchedClassDefsSize;
    this.patchedHeaderOffset = 0;
    // The diff works on each sections obey such procedure:
    //  1. Execute diff algorithms to calculate indices of items we need to add, del and replace.
    //  2. Execute patch algorithm simulation to calculate indices and offsets mappings that is
    //  necessary to next section's diff works.
    // Immediately do the patch simulation so that we can know:
    //  1. Indices and offsets mapping between old dex and patched dex.
    //  2. Indices and offsets mapping between new dex and patched dex.
    // These information will be used to do next diff works.
    this.patchedStringIdsOffset = patchedHeaderOffset + patchedheaderSize;
    if (this.oldDex.getTableOfContents().stringIds.isElementFourByteAligned) {
        this.patchedStringIdsOffset = SizeOf.roundToTimesOfFour(this.patchedStringIdsOffset);
    }
    this.stringDataSectionDiffAlg.execute();
    this.patchedStringDataItemsOffset = patchedheaderSize + patchedIdSectionSize;
    if (this.oldDex.getTableOfContents().stringDatas.isElementFourByteAligned) {
        this.patchedStringDataItemsOffset = SizeOf.roundToTimesOfFour(this.patchedStringDataItemsOffset);
    }
    this.stringDataSectionDiffAlg.simulatePatchOperation(this.patchedStringDataItemsOffset);
    this.typeIdSectionDiffAlg.execute();
    this.patchedTypeIdsOffset = this.patchedStringIdsOffset + patchedStringIdsSize;
    if (this.oldDex.getTableOfContents().typeIds.isElementFourByteAligned) {
        this.patchedTypeIdsOffset = SizeOf.roundToTimesOfFour(this.patchedTypeIdsOffset);
    }
    this.typeIdSectionDiffAlg.simulatePatchOperation(this.patchedTypeIdsOffset);
    this.typeListSectionDiffAlg.execute();
    this.patchedTypeListsOffset = patchedheaderSize + patchedIdSectionSize + this.stringDataSectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().typeLists.isElementFourByteAligned) {
        this.patchedTypeListsOffset = SizeOf.roundToTimesOfFour(this.patchedTypeListsOffset);
    }
    this.typeListSectionDiffAlg.simulatePatchOperation(this.patchedTypeListsOffset);
    this.protoIdSectionDiffAlg.execute();
    this.patchedProtoIdsOffset = this.patchedTypeIdsOffset + patchedTypeIdsSize;
    if (this.oldDex.getTableOfContents().protoIds.isElementFourByteAligned) {
        this.patchedProtoIdsOffset = SizeOf.roundToTimesOfFour(this.patchedProtoIdsOffset);
    }
    this.protoIdSectionDiffAlg.simulatePatchOperation(this.patchedProtoIdsOffset);
    this.fieldIdSectionDiffAlg.execute();
    this.patchedFieldIdsOffset = this.patchedProtoIdsOffset + patchedProtoIdsSize;
    if (this.oldDex.getTableOfContents().fieldIds.isElementFourByteAligned) {
        this.patchedFieldIdsOffset = SizeOf.roundToTimesOfFour(this.patchedFieldIdsOffset);
    }
    this.fieldIdSectionDiffAlg.simulatePatchOperation(this.patchedFieldIdsOffset);
    this.methodIdSectionDiffAlg.execute();
    this.patchedMethodIdsOffset = this.patchedFieldIdsOffset + patchedFieldIdsSize;
    if (this.oldDex.getTableOfContents().methodIds.isElementFourByteAligned) {
        this.patchedMethodIdsOffset = SizeOf.roundToTimesOfFour(this.patchedMethodIdsOffset);
    }
    this.methodIdSectionDiffAlg.simulatePatchOperation(this.patchedMethodIdsOffset);
    this.annotationSectionDiffAlg.execute();
    this.patchedAnnotationItemsOffset = this.patchedTypeListsOffset + this.typeListSectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().annotations.isElementFourByteAligned) {
        this.patchedAnnotationItemsOffset = SizeOf.roundToTimesOfFour(this.patchedAnnotationItemsOffset);
    }
    this.annotationSectionDiffAlg.simulatePatchOperation(this.patchedAnnotationItemsOffset);
    this.annotationSetSectionDiffAlg.execute();
    this.patchedAnnotationSetItemsOffset = this.patchedAnnotationItemsOffset + this.annotationSectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().annotationSets.isElementFourByteAligned) {
        this.patchedAnnotationSetItemsOffset = SizeOf.roundToTimesOfFour(this.patchedAnnotationSetItemsOffset);
    }
    this.annotationSetSectionDiffAlg.simulatePatchOperation(this.patchedAnnotationSetItemsOffset);
    this.annotationSetRefListSectionDiffAlg.execute();
    this.patchedAnnotationSetRefListItemsOffset = this.patchedAnnotationSetItemsOffset + this.annotationSetSectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().annotationSetRefLists.isElementFourByteAligned) {
        this.patchedAnnotationSetRefListItemsOffset = SizeOf.roundToTimesOfFour(this.patchedAnnotationSetRefListItemsOffset);
    }
    this.annotationSetRefListSectionDiffAlg.simulatePatchOperation(this.patchedAnnotationSetRefListItemsOffset);
    this.annotationsDirectorySectionDiffAlg.execute();
    this.patchedAnnotationsDirectoryItemsOffset = this.patchedAnnotationSetRefListItemsOffset + this.annotationSetRefListSectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().annotationsDirectories.isElementFourByteAligned) {
        this.patchedAnnotationsDirectoryItemsOffset = SizeOf.roundToTimesOfFour(this.patchedAnnotationsDirectoryItemsOffset);
    }
    this.annotationsDirectorySectionDiffAlg.simulatePatchOperation(this.patchedAnnotationsDirectoryItemsOffset);
    this.debugInfoSectionDiffAlg.execute();
    this.patchedDebugInfoItemsOffset = this.patchedAnnotationsDirectoryItemsOffset + this.annotationsDirectorySectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().debugInfos.isElementFourByteAligned) {
        this.patchedDebugInfoItemsOffset = SizeOf.roundToTimesOfFour(this.patchedDebugInfoItemsOffset);
    }
    this.debugInfoSectionDiffAlg.simulatePatchOperation(this.patchedDebugInfoItemsOffset);
    this.codeSectionDiffAlg.execute();
    this.patchedCodeItemsOffset = this.patchedDebugInfoItemsOffset + this.debugInfoSectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().codes.isElementFourByteAligned) {
        this.patchedCodeItemsOffset = SizeOf.roundToTimesOfFour(this.patchedCodeItemsOffset);
    }
    this.codeSectionDiffAlg.simulatePatchOperation(this.patchedCodeItemsOffset);
    this.classDataSectionDiffAlg.execute();
    this.patchedClassDataItemsOffset = this.patchedCodeItemsOffset + this.codeSectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().classDatas.isElementFourByteAligned) {
        this.patchedClassDataItemsOffset = SizeOf.roundToTimesOfFour(this.patchedClassDataItemsOffset);
    }
    this.classDataSectionDiffAlg.simulatePatchOperation(this.patchedClassDataItemsOffset);
    this.encodedArraySectionDiffAlg.execute();
    this.patchedEncodedArrayItemsOffset = this.patchedClassDataItemsOffset + this.classDataSectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().encodedArrays.isElementFourByteAligned) {
        this.patchedEncodedArrayItemsOffset = SizeOf.roundToTimesOfFour(this.patchedEncodedArrayItemsOffset);
    }
    this.encodedArraySectionDiffAlg.simulatePatchOperation(this.patchedEncodedArrayItemsOffset);
    this.classDefSectionDiffAlg.execute();
    this.patchedClassDefsOffset = this.patchedMethodIdsOffset + patchedMethodIdsSize;
    if (this.oldDex.getTableOfContents().classDefs.isElementFourByteAligned) {
        this.patchedClassDefsOffset = SizeOf.roundToTimesOfFour(this.patchedClassDefsOffset);
    }
    // Calculate any values we still know nothing about them.
    this.patchedMapListOffset = this.patchedEncodedArrayItemsOffset + this.encodedArraySectionDiffAlg.getPatchedSectionSize();
    if (this.oldDex.getTableOfContents().mapList.isElementFourByteAligned) {
        this.patchedMapListOffset = SizeOf.roundToTimesOfFour(this.patchedMapListOffset);
    }
    int patchedMapListSize = newDex.getTableOfContents().mapList.byteCount;
    this.patchedDexSize = this.patchedMapListOffset + patchedMapListSize;
    // Finally, write results to patch file.
    writeResultToStream(out);
}
Also used : Pattern(java.util.regex.Pattern) ClassDef(com.tencent.tinker.android.dex.ClassDef) ArrayList(java.util.ArrayList) ClassDataSectionDiffAlgorithm(com.tencent.tinker.build.dexpatcher.algorithms.diff.ClassDataSectionDiffAlgorithm) ClassDefSectionDiffAlgorithm(com.tencent.tinker.build.dexpatcher.algorithms.diff.ClassDefSectionDiffAlgorithm)

Aggregations

ClassDef (com.tencent.tinker.android.dex.ClassDef)1 ClassDataSectionDiffAlgorithm (com.tencent.tinker.build.dexpatcher.algorithms.diff.ClassDataSectionDiffAlgorithm)1 ClassDefSectionDiffAlgorithm (com.tencent.tinker.build.dexpatcher.algorithms.diff.ClassDefSectionDiffAlgorithm)1 ArrayList (java.util.ArrayList)1 Pattern (java.util.regex.Pattern)1