Search in sources :

Example 1 with ClassDef

use of com.tencent.tinker.android.dex.ClassDef 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 2 with ClassDef

use of com.tencent.tinker.android.dex.ClassDef in project tinker by Tencent.

the class ExcludedClassModifiedChecker method checkIfExcludedClassWasModifiedInNewDex.

public void checkIfExcludedClassWasModifiedInNewDex(File oldFile, File newFile) throws IOException, TinkerPatchException {
    if (oldFile == null && newFile == null) {
        throw new TinkerPatchException("both oldFile and newFile are null.");
    }
    oldDex = (oldFile != null ? new Dex(oldFile) : null);
    newDex = (newFile != null ? new Dex(newFile) : null);
    int stmCode = STMCODE_START;
    while (stmCode != STMCODE_END) {
        switch(stmCode) {
            /**
                 * Check rule:
                 * Loader classes must only appear in primary dex and each of them in primary old dex should keep
                 * completely consistent in new primary dex.
                 *
                 * An error is announced when any of these conditions below is fit:
                 * 1. Primary old dex is missing.
                 * 2. Primary new dex is missing.
                 * 3. There are not any loader classes in primary old dex.
                 * 4. There are some new loader classes added in new primary dex.
                 * 5. Loader classes in old primary dex are modified, deleted in new primary dex.
                 * 6. Loader classes are found in secondary old dexes.
                 * 7. Loader classes are found in secondary new dexes.
                 */
            case STMCODE_START:
                {
                    boolean isPrimaryDex = isPrimaryDex((oldFile == null ? newFile : oldFile));
                    if (isPrimaryDex) {
                        if (oldFile == null) {
                            stmCode = STMCODE_ERROR_PRIMARY_OLD_DEX_IS_MISSING;
                        } else if (newFile == null) {
                            stmCode = STMCODE_ERROR_PRIMARY_NEW_DEX_IS_MISSING;
                        } else {
                            dexCmptor.startCheck(oldDex, newDex);
                            deletedClassInfos = dexCmptor.getDeletedClassInfos();
                            addedClassInfos = dexCmptor.getAddedClassInfos();
                            changedClassInfosMap = dexCmptor.getChangedClassDescToInfosMap();
                            // All loader classes are in new dex, while none of them in old one.
                            if (deletedClassInfos.isEmpty() && changedClassInfosMap.isEmpty() && !addedClassInfos.isEmpty()) {
                                stmCode = STMCODE_ERROR_LOADER_CLASS_NOT_IN_PRIMARY_OLD_DEX;
                            } else {
                                if (deletedClassInfos.isEmpty() && addedClassInfos.isEmpty()) {
                                    // class descriptor is completely matches, see if any contents changes.
                                    if (changedClassInfosMap.isEmpty()) {
                                        stmCode = STMCODE_END;
                                    } else {
                                        stmCode = STMCODE_ERROR_LOADER_CLASS_CHANGED;
                                    }
                                } else {
                                    stmCode = STMCODE_ERROR_LOADER_CLASS_IN_PRIMARY_DEX_MISMATCH;
                                }
                            }
                        }
                    } else {
                        Set<Pattern> patternsOfClassDescToCheck = new HashSet<>();
                        for (String patternStr : config.mDexLoaderPattern) {
                            patternsOfClassDescToCheck.add(Pattern.compile(PatternUtils.dotClassNamePatternToDescriptorRegEx(patternStr)));
                        }
                        if (oldDex != null) {
                            oldClassesDescToCheck.clear();
                            for (ClassDef classDef : oldDex.classDefs()) {
                                String desc = oldDex.typeNames().get(classDef.typeIndex);
                                if (Utils.isStringMatchesPatterns(desc, patternsOfClassDescToCheck)) {
                                    oldClassesDescToCheck.add(desc);
                                }
                            }
                            if (!oldClassesDescToCheck.isEmpty()) {
                                stmCode = STMCODE_ERROR_LOADER_CLASS_FOUND_IN_SECONDARY_OLD_DEX;
                                break;
                            }
                        }
                        if (newDex != null) {
                            newClassesDescToCheck.clear();
                            for (ClassDef classDef : newDex.classDefs()) {
                                String desc = newDex.typeNames().get(classDef.typeIndex);
                                if (Utils.isStringMatchesPatterns(desc, patternsOfClassDescToCheck)) {
                                    newClassesDescToCheck.add(desc);
                                }
                            }
                            if (!newClassesDescToCheck.isEmpty()) {
                                stmCode = STMCODE_ERROR_LOADER_CLASS_FOUND_IN_SECONDARY_NEW_DEX;
                                break;
                            }
                        }
                        stmCode = STMCODE_END;
                    }
                    break;
                }
            case STMCODE_ERROR_PRIMARY_OLD_DEX_IS_MISSING:
                {
                    throw new TinkerPatchException("old primary dex is missing.");
                }
            case STMCODE_ERROR_PRIMARY_NEW_DEX_IS_MISSING:
                {
                    throw new TinkerPatchException("new primary dex is missing.");
                }
            case STMCODE_ERROR_LOADER_CLASS_NOT_IN_PRIMARY_OLD_DEX:
                {
                    throw new TinkerPatchException("all loader classes don't appear in old primary dex.");
                }
            case STMCODE_ERROR_LOADER_CLASS_IN_PRIMARY_DEX_MISMATCH:
                {
                    throw new TinkerPatchException("loader classes in old primary dex are mismatched to those in new primary dex, \n" + "if deleted classes is not empty, check if your dex division strategy is fine. \n" + "added classes: " + Utils.collectionToString(addedClassInfos) + "\n" + "deleted classes: " + Utils.collectionToString(deletedClassInfos));
                }
            case STMCODE_ERROR_LOADER_CLASS_FOUND_IN_SECONDARY_OLD_DEX:
                {
                    throw new TinkerPatchException("loader classes are found in old secondary dex. Found classes: " + Utils.collectionToString(oldClassesDescToCheck));
                }
            case STMCODE_ERROR_LOADER_CLASS_FOUND_IN_SECONDARY_NEW_DEX:
                {
                    throw new TinkerPatchException("loader classes are found in new secondary dex. Found classes: " + Utils.collectionToString(newClassesDescToCheck));
                }
            case STMCODE_ERROR_LOADER_CLASS_CHANGED:
                {
                    String msg = "some loader class has been changed in new dex." + " Such these changes will not take effect!!" + " related classes: " + Utils.collectionToString(changedClassInfosMap.keySet());
                    throw new TinkerPatchException(msg);
                }
            default:
                {
                    Logger.e("internal-error: unexpected stmCode.");
                    stmCode = STMCODE_END;
                    break;
                }
        }
    }
}
Also used : ClassDef(com.tencent.tinker.android.dex.ClassDef) Set(java.util.Set) HashSet(java.util.HashSet) Dex(com.tencent.tinker.android.dex.Dex)

Example 3 with ClassDef

use of com.tencent.tinker.android.dex.ClassDef in project tinker by Tencent.

the class DexClassesComparator method isTypeChangeAffectedToRef.

private boolean isTypeChangeAffectedToRef(Dex oldDex, Dex newDex, int oldTypeId, int newTypeId) {
    if (oldTypeId != ClassDef.NO_INDEX && newTypeId != ClassDef.NO_INDEX) {
        String oldClassDesc = oldDex.typeNames().get(oldTypeId);
        String newClassDesc = newDex.typeNames().get(newTypeId);
        if (!oldClassDesc.equals(newClassDesc)) {
            return true;
        }
        final DexClassInfo oldClassInfo = oldClassDescriptorToClassInfoMap.get(oldClassDesc);
        final DexClassInfo newClassInfo = newClassDescriptorToClassInfoMap.get(newClassDesc);
        ClassDef oldClassDef = (oldClassInfo != null ? oldClassInfo.classDef : null);
        ClassDef newClassDef = (newClassInfo != null ? newClassInfo.classDef : null);
        if (oldClassDef != null && newClassDef != null) {
            return isClassChangeAffectedToRef(oldClassInfo.owner, newClassInfo.owner, oldClassDef, newClassDef);
        } else if (oldClassDef == null && newClassDef == null) {
            return false;
        } else {
            // in patched dexes as we expected, here we ignore this kind of changes.
            return !Utils.isStringMatchesPatterns(oldClassDesc, patternsOfIgnoredRemovedClassDesc);
        }
    } else {
        if (!(oldTypeId == ClassDef.NO_INDEX && newTypeId == ClassDef.NO_INDEX)) {
            return true;
        }
    }
    return false;
}
Also used : ClassDef(com.tencent.tinker.android.dex.ClassDef)

Example 4 with ClassDef

use of com.tencent.tinker.android.dex.ClassDef 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)

Example 5 with ClassDef

use of com.tencent.tinker.android.dex.ClassDef in project tinker by Tencent.

the class DexClassesComparator method startCheck.

public void startCheck(DexGroup oldDexGroup, DexGroup newDexGroup) {
    // Init assist structures.
    addedClassInfoList.clear();
    deletedClassInfoList.clear();
    changedClassDescToClassInfosMap.clear();
    oldDescriptorOfClassesToCheck.clear();
    newDescriptorOfClassesToCheck.clear();
    oldClassDescriptorToClassInfoMap.clear();
    newClassDescriptorToClassInfoMap.clear();
    refAffectedClassDescs.clear();
    // and collect typeIndex of classes to check in oldDexes.
    for (Dex oldDex : oldDexGroup.dexes) {
        int classDefIndex = 0;
        for (ClassDef oldClassDef : oldDex.classDefs()) {
            String desc = oldDex.typeNames().get(oldClassDef.typeIndex);
            if (Utils.isStringMatchesPatterns(desc, patternsOfClassDescToCheck)) {
                if (!oldDescriptorOfClassesToCheck.add(desc)) {
                    throw new IllegalStateException(String.format("duplicate class descriptor [%s] in different old dexes.", desc));
                }
            }
            DexClassInfo classInfo = new DexClassInfo(desc, classDefIndex, oldClassDef, oldDex);
            ++classDefIndex;
            oldClassDescriptorToClassInfoMap.put(desc, classInfo);
        }
    }
    // and collect typeIndex of classes to check in newDexes.
    for (Dex newDex : newDexGroup.dexes) {
        int classDefIndex = 0;
        for (ClassDef newClassDef : newDex.classDefs()) {
            String desc = newDex.typeNames().get(newClassDef.typeIndex);
            if (Utils.isStringMatchesPatterns(desc, patternsOfClassDescToCheck)) {
                if (!newDescriptorOfClassesToCheck.add(desc)) {
                    throw new IllegalStateException(String.format("duplicate class descriptor [%s] in different new dexes.", desc));
                }
            }
            DexClassInfo classInfo = new DexClassInfo(desc, classDefIndex, newClassDef, newDex);
            ++classDefIndex;
            newClassDescriptorToClassInfoMap.put(desc, classInfo);
        }
    }
    Set<String> deletedClassDescs = new HashSet<>(oldDescriptorOfClassesToCheck);
    deletedClassDescs.removeAll(newDescriptorOfClassesToCheck);
    for (String desc : deletedClassDescs) {
        // from result.
        if (Utils.isStringMatchesPatterns(desc, patternsOfIgnoredRemovedClassDesc)) {
            logger.i(TAG, "Ignored deleted class: %s", desc);
            continue;
        } else {
            logger.i(TAG, "Deleted class: %s", desc);
        }
        deletedClassInfoList.add(oldClassDescriptorToClassInfoMap.get(desc));
    }
    Set<String> addedClassDescs = new HashSet<>(newDescriptorOfClassesToCheck);
    addedClassDescs.removeAll(oldDescriptorOfClassesToCheck);
    for (String desc : addedClassDescs) {
        logger.i(TAG, "Added class: %s", desc);
        addedClassInfoList.add(newClassDescriptorToClassInfoMap.get(desc));
    }
    Set<String> mayBeChangedClassDescs = new HashSet<>(oldDescriptorOfClassesToCheck);
    mayBeChangedClassDescs.retainAll(newDescriptorOfClassesToCheck);
    for (String desc : mayBeChangedClassDescs) {
        DexClassInfo oldClassInfo = oldClassDescriptorToClassInfoMap.get(desc);
        DexClassInfo newClassInfo = newClassDescriptorToClassInfoMap.get(desc);
        switch(compareMode) {
            case COMPARE_MODE_NORMAL:
                {
                    if (!isSameClass(oldClassInfo.owner, newClassInfo.owner, oldClassInfo.classDef, newClassInfo.classDef)) {
                        logger.i(TAG, "Changed class: %s", desc);
                        changedClassDescToClassInfosMap.put(desc, new DexClassInfo[] { oldClassInfo, newClassInfo });
                    }
                    break;
                }
            case COMPARE_MODE_CAUSE_REF_CHANGE_ONLY:
                {
                    if (isClassChangeAffectedToRef(oldClassInfo.owner, newClassInfo.owner, oldClassInfo.classDef, newClassInfo.classDef)) {
                        logger.i(TAG, "Ref-changed class: %s", desc);
                        changedClassDescToClassInfosMap.put(desc, new DexClassInfo[] { oldClassInfo, newClassInfo });
                    }
                    break;
                }
        }
    }
}
Also used : ClassDef(com.tencent.tinker.android.dex.ClassDef) Dex(com.tencent.tinker.android.dex.Dex) HashSet(java.util.HashSet)

Aggregations

ClassDef (com.tencent.tinker.android.dex.ClassDef)5 Dex (com.tencent.tinker.android.dex.Dex)3 HashSet (java.util.HashSet)3 ClassDataSectionDiffAlgorithm (com.tencent.tinker.build.dexpatcher.algorithms.diff.ClassDataSectionDiffAlgorithm)1 ClassDefSectionDiffAlgorithm (com.tencent.tinker.build.dexpatcher.algorithms.diff.ClassDefSectionDiffAlgorithm)1 TinkerPatchException (com.tencent.tinker.build.util.TinkerPatchException)1 ArrayList (java.util.ArrayList)1 Set (java.util.Set)1 Pattern (java.util.regex.Pattern)1