Search in sources :

Example 6 with org.jf.dexlib2

use of org.jf.dexlib2 in project tinker by Tencent.

the class DexDiffDecoder method generateChangedClassesDexFile.

@SuppressWarnings("NewApi")
private void generateChangedClassesDexFile() throws IOException {
    final String dexMode = config.mDexRaw ? "raw" : "jar";
    List<File> oldDexList = new ArrayList<>();
    List<File> newDexList = new ArrayList<>();
    for (AbstractMap.SimpleEntry<File, File> oldAndNewDexFilePair : oldAndNewDexFilePairList) {
        File oldDexFile = oldAndNewDexFilePair.getKey();
        File newDexFile = oldAndNewDexFilePair.getValue();
        if (oldDexFile != null) {
            oldDexList.add(oldDexFile);
        }
        if (newDexFile != null) {
            newDexList.add(newDexFile);
        }
    }
    DexGroup oldDexGroup = DexGroup.wrap(oldDexList);
    DexGroup newDexGroup = DexGroup.wrap(newDexList);
    ChangedClassesDexClassInfoCollector collector = new ChangedClassesDexClassInfoCollector();
    collector.setExcludedClassPatterns(config.mDexLoaderPattern);
    collector.setLogger(dexPatcherLoggerBridge);
    collector.setIncludeRefererToRefererAffectedClasses(true);
    Set<DexClassInfo> classInfosInChangedClassesDex = collector.doCollect(oldDexGroup, newDexGroup);
    Set<Dex> owners = new HashSet<>();
    Map<Dex, Set<String>> ownerToDescOfChangedClassesMap = new HashMap<>();
    for (DexClassInfo classInfo : classInfosInChangedClassesDex) {
        owners.add(classInfo.owner);
        Set<String> descOfChangedClasses = ownerToDescOfChangedClassesMap.get(classInfo.owner);
        if (descOfChangedClasses == null) {
            descOfChangedClasses = new HashSet<>();
            ownerToDescOfChangedClassesMap.put(classInfo.owner, descOfChangedClasses);
        }
        descOfChangedClasses.add(classInfo.classDesc);
    }
    StringBuilder metaBuilder = new StringBuilder();
    int changedDexId = 1;
    for (Dex dex : owners) {
        Set<String> descOfChangedClassesInCurrDex = ownerToDescOfChangedClassesMap.get(dex);
        DexFile dexFile = new DexBackedDexFile(org.jf.dexlib2.Opcodes.forApi(20), dex.getBytes());
        boolean isCurrentDexHasChangedClass = false;
        for (org.jf.dexlib2.iface.ClassDef classDef : dexFile.getClasses()) {
            if (descOfChangedClassesInCurrDex.contains(classDef.getType())) {
                isCurrentDexHasChangedClass = true;
                break;
            }
        }
        if (!isCurrentDexHasChangedClass) {
            continue;
        }
        DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(23));
        for (org.jf.dexlib2.iface.ClassDef classDef : dexFile.getClasses()) {
            if (!descOfChangedClassesInCurrDex.contains(classDef.getType())) {
                continue;
            }
            Logger.d("Class %s will be added into changed classes dex ...", classDef.getType());
            List<BuilderField> builderFields = new ArrayList<>();
            for (Field field : classDef.getFields()) {
                final BuilderField builderField = dexBuilder.internField(field.getDefiningClass(), field.getName(), field.getType(), field.getAccessFlags(), field.getInitialValue(), field.getAnnotations());
                builderFields.add(builderField);
            }
            List<BuilderMethod> builderMethods = new ArrayList<>();
            for (Method method : classDef.getMethods()) {
                MethodImplementation methodImpl = method.getImplementation();
                if (methodImpl != null) {
                    methodImpl = new BuilderMutableMethodImplementation(dexBuilder, methodImpl);
                }
                BuilderMethod builderMethod = dexBuilder.internMethod(method.getDefiningClass(), method.getName(), method.getParameters(), method.getReturnType(), method.getAccessFlags(), method.getAnnotations(), methodImpl);
                builderMethods.add(builderMethod);
            }
            dexBuilder.internClassDef(classDef.getType(), classDef.getAccessFlags(), classDef.getSuperclass(), classDef.getInterfaces(), classDef.getSourceFile(), classDef.getAnnotations(), builderFields, builderMethods);
        }
        // Write constructed changed classes dex to file and record it in meta file.
        String changedDexName = null;
        if (changedDexId == 1) {
            changedDexName = "classes.dex";
        } else {
            changedDexName = "classes" + changedDexId + ".dex";
        }
        final File dest = new File(config.mTempResultDir + "/" + changedDexName);
        final FileDataStore fileDataStore = new FileDataStore(dest);
        dexBuilder.writeTo(fileDataStore);
        final String md5 = MD5.getMD5(dest);
        appendMetaLine(metaBuilder, changedDexName, "", md5, md5, 0, 0, 0, dexMode);
        ++changedDexId;
    }
    final String meta = metaBuilder.toString();
    Logger.d("\nDexDecoder:write changed classes dex meta file data:\n%s", meta);
    metaWriter.writeLineToInfoFile(meta);
}
Also used : DexGroup(com.tencent.tinker.build.util.DexClassesComparator.DexGroup) MethodImplementation(org.jf.dexlib2.iface.MethodImplementation) BuilderMutableMethodImplementation(org.jf.dexlib2.builder.BuilderMutableMethodImplementation) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) AbstractMap(java.util.AbstractMap) BuilderField(org.jf.dexlib2.writer.builder.BuilderField) Field(org.jf.dexlib2.iface.Field) BuilderField(org.jf.dexlib2.writer.builder.BuilderField) FileDataStore(org.jf.dexlib2.writer.io.FileDataStore) HashSet(java.util.HashSet) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) ChangedClassesDexClassInfoCollector(com.tencent.tinker.build.dexpatcher.util.ChangedClassesDexClassInfoCollector) BuilderMutableMethodImplementation(org.jf.dexlib2.builder.BuilderMutableMethodImplementation) Method(org.jf.dexlib2.iface.Method) BuilderMethod(org.jf.dexlib2.writer.builder.BuilderMethod) DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) DexBuilder(org.jf.dexlib2.writer.builder.DexBuilder) Dex(com.tencent.tinker.android.dex.Dex) BuilderMethod(org.jf.dexlib2.writer.builder.BuilderMethod) JarFile(java.util.jar.JarFile) DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) File(java.io.File) DexClassInfo(com.tencent.tinker.build.util.DexClassesComparator.DexClassInfo)

Example 7 with org.jf.dexlib2

use of org.jf.dexlib2 in project tinker by Tencent.

the class DexDiffDecoder method collectClassesInDex.

private void collectClassesInDex(File dexFile) throws IOException {
    Logger.d("Collect class descriptors in " + dexFile.getName());
    final DexFile dex = DexFileFactory.loadDexFile(dexFile, Opcodes.forApi(29));
    for (org.jf.dexlib2.iface.ClassDef classDef : dex.getClasses()) {
        descOfClassesInApk.add(classDef.getType());
        if (AccessFlags.SYNTHETIC.isSet(classDef.getAccessFlags())) {
            descOfSyntheticClassesInApk.add(classDef.getType());
        }
    }
}
Also used : DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile)

Example 8 with org.jf.dexlib2

use of org.jf.dexlib2 in project tinker by Tencent.

the class DexDiffDecoder method checkIfLoaderClassesReferToNonLoaderClasses.

private void checkIfLoaderClassesReferToNonLoaderClasses() throws IOException, TinkerPatchException {
    boolean hasInvalidCases = false;
    for (File dexFile : oldDexFiles) {
        Logger.d("Check if loader classes in " + dexFile.getName() + " refer to any classes that is not in loader class patterns.");
        final DexFile dex = DexFileFactory.loadDexFile(dexFile, Opcodes.forApi(29));
        for (org.jf.dexlib2.iface.ClassDef classDef : dex.getClasses()) {
            final String currClassDesc = classDef.getType();
            if (!Utils.isStringMatchesPatterns(currClassDesc, loaderClassPatterns)) {
                continue;
            }
            for (Field field : classDef.getFields()) {
                final String currFieldTypeDesc = field.getType();
                if (!isReferenceFromLoaderClassValid(currFieldTypeDesc)) {
                    Logger.e("FATAL: field '%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", field.getName(), currClassDesc, currFieldTypeDesc);
                    hasInvalidCases = true;
                }
            }
            for (Method method : classDef.getMethods()) {
                boolean isCurrentMethodInvalid = false;
                final String currMethodRetTypeDesc = method.getReturnType();
                if (!isReferenceFromLoaderClassValid(currMethodRetTypeDesc)) {
                    Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, currMethodRetTypeDesc);
                    isCurrentMethodInvalid = true;
                } else {
                    for (CharSequence paramTypeDesc : method.getParameterTypes()) {
                        if (!isReferenceFromLoaderClassValid(paramTypeDesc.toString())) {
                            Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, paramTypeDesc);
                            isCurrentMethodInvalid = true;
                            break;
                        }
                    }
                }
                check_method_impl: {
                    final MethodImplementation methodImpl = method.getImplementation();
                    if (methodImpl == null) {
                        break check_method_impl;
                    }
                    final Iterable<? extends Instruction> insns = methodImpl.getInstructions();
                    if (!insns.iterator().hasNext()) {
                        break check_method_impl;
                    }
                    for (Instruction insn : insns) {
                        if (insn instanceof ReferenceInstruction) {
                            final ReferenceInstruction refInsn = (ReferenceInstruction) insn;
                            switch(refInsn.getReferenceType()) {
                                case ReferenceType.TYPE:
                                    {
                                        final TypeReference typeRefInsn = (TypeReference) refInsn.getReference();
                                        final String refereeTypeDesc = typeRefInsn.getType();
                                        if (isReferenceFromLoaderClassValid(refereeTypeDesc)) {
                                            break;
                                        }
                                        Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to class '%s' which " + "is not loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeTypeDesc);
                                        isCurrentMethodInvalid = true;
                                        break;
                                    }
                                case ReferenceType.FIELD:
                                    {
                                        final FieldReference fieldRefInsn = (FieldReference) refInsn.getReference();
                                        final String refereeFieldName = fieldRefInsn.getName();
                                        final String refereeFieldDefTypeDesc = fieldRefInsn.getDefiningClass();
                                        if (isReferenceFromLoaderClassValid(refereeFieldDefTypeDesc)) {
                                            break;
                                        }
                                        Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to field '%s' in class '%s' which " + "is not in loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeFieldName, refereeFieldDefTypeDesc);
                                        isCurrentMethodInvalid = true;
                                        break;
                                    }
                                case ReferenceType.METHOD:
                                    {
                                        final MethodReference methodRefInsn = (MethodReference) refInsn.getReference();
                                        final String refereeMethodName = methodRefInsn.getName();
                                        final Collection<? extends CharSequence> refereeMethodParamTypes = methodRefInsn.getParameterTypes();
                                        final String refereeMethodRetType = methodRefInsn.getReturnType();
                                        final String refereeMethodDefClassDesc = methodRefInsn.getDefiningClass();
                                        if (isReferenceFromLoaderClassValid(refereeMethodDefClassDesc)) {
                                            break;
                                        }
                                        Logger.e("FATAL: method '%s:%s' in loader class '%s' refers to method '%s:%s' in class '%s' which " + "is not in loader class, this may cause crash when patch is loaded.", method.getName(), MethodUtil.getShorty(method.getParameterTypes(), currMethodRetTypeDesc), currClassDesc, refereeMethodName, MethodUtil.getShorty(refereeMethodParamTypes, refereeMethodRetType), refereeMethodDefClassDesc);
                                        isCurrentMethodInvalid = true;
                                        break;
                                    }
                                default:
                                    {
                                        break;
                                    }
                            }
                        }
                    }
                }
                if (isCurrentMethodInvalid) {
                    hasInvalidCases = true;
                }
            }
        }
    }
    if (hasInvalidCases) {
        throw new TinkerPatchException("There are fatal reasons that cause Tinker interrupt" + " patch generating procedure, see logs above.");
    }
}
Also used : MethodImplementation(org.jf.dexlib2.iface.MethodImplementation) BuilderMutableMethodImplementation(org.jf.dexlib2.builder.BuilderMutableMethodImplementation) FieldReference(org.jf.dexlib2.iface.reference.FieldReference) ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) Method(org.jf.dexlib2.iface.Method) BuilderMethod(org.jf.dexlib2.writer.builder.BuilderMethod) Instruction(org.jf.dexlib2.iface.instruction.Instruction) ReferenceInstruction(org.jf.dexlib2.iface.instruction.ReferenceInstruction) DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) TinkerPatchException(com.tencent.tinker.build.util.TinkerPatchException) Field(org.jf.dexlib2.iface.Field) BuilderField(org.jf.dexlib2.writer.builder.BuilderField) Collection(java.util.Collection) MethodReference(org.jf.dexlib2.iface.reference.MethodReference) TypeReference(org.jf.dexlib2.iface.reference.TypeReference) JarFile(java.util.jar.JarFile) DexFile(org.jf.dexlib2.iface.DexFile) DexBackedDexFile(org.jf.dexlib2.dexbacked.DexBackedDexFile) File(java.io.File)

Aggregations

File (java.io.File)3 DexBackedDexFile (org.jf.dexlib2.dexbacked.DexBackedDexFile)3 DexFile (org.jf.dexlib2.iface.DexFile)3 ArrayList (java.util.ArrayList)2 JarFile (java.util.jar.JarFile)2 BuilderMutableMethodImplementation (org.jf.dexlib2.builder.BuilderMutableMethodImplementation)2 ClassDef (org.jf.dexlib2.iface.ClassDef)2 Field (org.jf.dexlib2.iface.Field)2 Method (org.jf.dexlib2.iface.Method)2 MethodImplementation (org.jf.dexlib2.iface.MethodImplementation)2 FieldReference (org.jf.dexlib2.iface.reference.FieldReference)2 MethodReference (org.jf.dexlib2.iface.reference.MethodReference)2 TypeReference (org.jf.dexlib2.iface.reference.TypeReference)2 BuilderField (org.jf.dexlib2.writer.builder.BuilderField)2 BuilderMethod (org.jf.dexlib2.writer.builder.BuilderMethod)2 FileDataStore (org.jf.dexlib2.writer.io.FileDataStore)2 MethodDefinition (com.taobao.android.baksmali.adaptors.MethodDefinition)1 Dex (com.tencent.tinker.android.dex.Dex)1 ChangedClassesDexClassInfoCollector (com.tencent.tinker.build.dexpatcher.util.ChangedClassesDexClassInfoCollector)1 DexClassInfo (com.tencent.tinker.build.util.DexClassesComparator.DexClassInfo)1