dex2jar源码解析----解析dex文件

时间:2021-07-17 17:17:24

接上面,我们继续分析doTranslate的下一部分

private void doTranslate(final Path dist) throws IOException {

DexFileNode fileNode = new DexFileNode();//创建一个DexFileNode的访问者
try {
reader.accept(fileNode, readerConfig | DexFileReader.IGNORE_READ_EXCEPTION);
} catch (Exception ex) {
exceptionHandler.handleFileException(ex);
}
ClassVisitorFactory cvf = new ClassVisitorFactory() {
@Override
public ClassVisitor create(final String name) {
return new ClassVisitor(Opcodes.ASM4, new ClassWriter(ClassWriter.COMPUTE_MAXS)) {
@Override
public void visitEnd() {
super.visitEnd();
ClassWriter cw = (ClassWriter) super.cv;

byte[] data;
try {
// FIXME handle 'java.lang.RuntimeException: Method code too large!'
data = cw.toByteArray();
} catch (Exception ex) {
System.err.println(String.format("ASM fail to generate .class file: %s", name));
exceptionHandler.handleFileException(ex);
return;
}
try {
Path dist1 = dist.resolve(name + ".class");
Path parent = dist1.getParent();
if (parent != null && !Files.exists(parent)) {
Files.createDirectories(parent);
}
Files.write(dist1, data);
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
};
}
};

new ExDex2Asm(exceptionHandler) {
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
if ((readerConfig & DexFileReader.SKIP_CODE) != 0 && methodNode.method.getName().equals("<clinit>")) {
// also skip clinit
return;
}
super.convertCode(methodNode, mv);
}

@Override
public void optimize(IrMethod irMethod) {
T_cleanLabel.transform(irMethod);
if (0 != (v3Config & V3.TOPOLOGICAL_SORT)) {
// T_topologicalSort.transform(irMethod);
}
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
T_zero.transform(irMethod);
if (T_npe.transformReportChanged(irMethod)) {
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
}
T_new.transform(irMethod);
T_fillArray.transform(irMethod);
T_agg.transform(irMethod);
T_multiArray.transform(irMethod);
T_voidInvoke.transform(irMethod);
if (0 != (v3Config & V3.PRINT_IR)) {
int i = 0;
for (Stmt p : irMethod.stmts) {
if (p.st == Stmt.ST.LABEL) {
LabelStmt labelStmt = (LabelStmt) p;
labelStmt.displayName = "L" + i++;
}
}
System.out.println(irMethod);
}
T_type.transform(irMethod);
T_unssa.transform(irMethod);
T_ir2jRegAssign.transform(irMethod);
T_trimEx.transform(irMethod);
}

@Override
public void ir2j(IrMethod irMethod, MethodVisitor mv) {
new IR2JConverter(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config)).convert(irMethod, mv);
}
}.convertDex(fileNode, cvf);

}
这里定义了一个ClassVisitorFactory cvf,主要是实现了ClassVisitorFactory的create方法,创建一个ClassVisitor,ClassVisitor的构造函数里面又new了一个ClassWriter,并实现了visitEnd方法

然后定义了一个ExDex2Asm,他继承于Dex2Asm,主要重写了convertCode和optimize、ir2j方法

调用convertDex方法

    public void convertDex(DexFileNode fileNode, ClassVisitorFactory cvf) {        if (fileNode.clzs != null) {            Map<String, Clz> classes = collectClzInfo(fileNode);            for (DexClassNode classNode : fileNode.clzs) {                convertClass(classNode, cvf, classes);            }        }    }

主要是对dex里面的class调用convertClass

public void convertClass(DexClassNode classNode, ClassVisitorFactory cvf, Map<String, Clz> classes) {        ClassVisitor cv = cvf.create(toInternalName(classNode.className));        if (cv == null) {            return;        }        // the default value of static-final field are omitted by dex, fix it        DexFix.fixStaticFinalFieldValue(classNode);//默认static-final 字段的值被dex忽略,这里修正        String signature = null;        if (classNode.anns != null) {//是否有注解            for (DexAnnotationNode ann : classNode.anns) {                if (ann.visibility == Visibility.SYSTEM) {                    switch (ann.type) {                    case DexConstants.ANNOTATION_SIGNATURE_TYPE: {                        Object[] strs = (Object[]) findAnnotationAttribute(ann, "value");                        if (strs != null) {                            StringBuilder sb = new StringBuilder();                            for (Object str : strs) {                                sb.append(str);                            }                            signature = sb.toString();                        }                    }                        break;                    }                }            }        }        String interfaceInterNames[] = null;        if (classNode.interfaceNames != null) {//接口处理            interfaceInterNames = new String[classNode.interfaceNames.length];            for (int i = 0; i < classNode.interfaceNames.length; i++) {                interfaceInterNames[i] = toInternalName(classNode.interfaceNames[i]);            }        }        Clz clzInfo = classes.get(classNode.className);        int access = classNode.access;        boolean isInnerClass = false;        if (clzInfo != null) {            isInnerClass = clzInfo.enclosingClass != null || clzInfo.enclosingMethod != null;        }        access = clearClassAccess(isInnerClass, access);//清除一些类的标志        cv.visit(Opcodes.V1_6, access, toInternalName(classNode.className), signature,//访问类 把类名 接口名添加到常量池                classNode.superClass == null ? null : toInternalName(classNode.superClass), interfaceInterNames);        List<InnerClassNode> innerClassNodes = new ArrayList<InnerClassNode>(5);        if (clzInfo != null) {            searchInnerClass(clzInfo, innerClassNodes, classNode.className);        }        if (isInnerClass) {//是不是内部类            // build Outer Clz            if (clzInfo.innerName == null) {// anonymous Innerclass                Method enclosingMethod = clzInfo.enclosingMethod;                if (enclosingMethod != null) {                    cv.visitOuterClass(toInternalName(enclosingMethod.getOwner()), enclosingMethod.getName(),                            enclosingMethod.getDesc());                } else {                    Clz enclosingClass = clzInfo.enclosingClass;                    cv.visitOuterClass(toInternalName(enclosingClass.name), null, null);                }            }            searchEnclosing(clzInfo, innerClassNodes);        }        Collections.sort(innerClassNodes, INNER_CLASS_NODE_COMPARATOR);        for (InnerClassNode icn : innerClassNodes) {            if (icn.innerName != null && !isJavaIdentifier(icn.innerName)) {                System.err.println("WARN: ignored invalid inner class name " + ", treat as anonymous inner class.");                icn.innerName = null;                icn.outerName = null;            }            icn.accept(cv);        }        accept(classNode.anns, cv);        if (classNode.fields != null) {            for (DexFieldNode fieldNode : classNode.fields) {                convertField(classNode, fieldNode, cv);            }        }        if (classNode.methods != null) {            for (DexMethodNode methodNode : classNode.methods) {                convertMethod(classNode, methodNode, cv);            }        }        cv.visitEnd();    }

这个函数比较长,主要做了如下工作:

1、调用 cvf.create创建一个ClassVisitor,ClassVisitorFactory是我们前面定义的

2、处理注解,接口,清除一些类标志

3、调用ClassVisitor 的visit

4、convertField访问字段

5、convertMethod访问方法



先看ClassVisitor的创建

public ClassVisitor create(final String name) {                return new ClassVisitor(Opcodes.ASM4, new ClassWriter(ClassWriter.COMPUTE_MAXS)) {                    @Override                    public void visitEnd() {                        super.visitEnd();                        ClassWriter cw = (ClassWriter) super.cv;                        byte[] data;                        try {                            // FIXME handle 'java.lang.RuntimeException: Method code too large!'                            data = cw.toByteArray();                        } catch (Exception ex) {                            System.err.println(String.format("ASM fail to generate .class file: %s", name));                            exceptionHandler.handleFileException(ex);                            return;                        }                        try {                            Path dist1 = dist.resolve(name + ".class");                            Path parent = dist1.getParent();                            if (parent != null && !Files.exists(parent)) {                                Files.createDirectories(parent);                            }                            Files.write(dist1, data);                        } catch (IOException e) {                            e.printStackTrace(System.err);                        }                    }                };            }

这里主要又创建了一个ClassWriter

    public ClassWriter(final int flags) {        super(Opcodes.ASM5);        index = 1;        pool = new ByteVector();        items = new Item[256];        threshold = (int) (0.75d * items.length);        key = new Item();        key2 = new Item();        key3 = new Item();        key4 = new Item();        this.computeMaxs = (flags & COMPUTE_MAXS) != 0;        this.computeFrames = (flags & COMPUTE_FRAMES) != 0;    }

这里的pool就是我们的常量池

    public ClassVisitor(final int api, final ClassVisitor cv) {        if (api != Opcodes.ASM4 && api != Opcodes.ASM5) {            throw new IllegalArgumentException();        }        this.api = api;        this.cv = cv;    }
ClassWriter继承于ClassVisitor,这里保存在新创建ClassVisitor的cv里面

回到convertClass,接着

分析3 调用ClassVisitor 的visit 

   public void visit(int version, int access, String name, String signature,            String superName, String[] interfaces) {        if (cv != null) {            cv.visit(version, access, name, signature, superName, interfaces);        }    }
这里的cv是我们前面创建的ClassWriter

 @Override    public final void visit(final int version, final int access,            final String name, final String signature, final String superName,            final String[] interfaces) {        this.version = version;        this.access = access;        this.name = newClass(name);        thisName = name;        if (ClassReader.SIGNATURES && signature != null) {            this.signature = newUTF8(signature);        }        this.superName = superName == null ? 0 : newClass(superName);        if (interfaces != null && interfaces.length > 0) {            interfaceCount = interfaces.length;            this.interfaces = new int[interfaceCount];            for (int i = 0; i < interfaceCount; ++i) {                this.interfaces[i] = newClass(interfaces[i]);            }        }    }

这里主要是访问并保存类相关的一些信息
我们看下newClass

    public int newClass(final String value) {        return newClassItem(value).index;    }
    Item newClassItem(final String value) {        key2.set(CLASS, value, null, null);        Item result = get(key2);        if (result == null) {            pool.put12(CLASS, newUTF8(value));            result = new Item(index++, key2);            put(result);        }        return result;    }
这里的value是我们的类名a/Test,这里CLASS对应是7,跟我们前面http://blog.csdn.net/new_abc/article/details/53501765中常量池中数据类型是一致的。

首先给key2临时变量设置值和类型

void set(final int type, final String strVal1, final String strVal2,            final String strVal3) {        this.type = type;        this.strVal1 = strVal1;        this.strVal2 = strVal2;        this.strVal3 = strVal3;        switch (type) {        case ClassWriter.CLASS:            this.intVal = 0;     // intVal of a class must be zero, see visitInnerClass        case ClassWriter.UTF8:        case ClassWriter.STR:        case ClassWriter.MTYPE:        case ClassWriter.TYPE_NORMAL:            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());            return;        case ClassWriter.NAME_TYPE: {            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()                    * strVal2.hashCode());            return;        }        // ClassWriter.FIELD:        // ClassWriter.METH:        // ClassWriter.IMETH:        // ClassWriter.HANDLE_BASE + 1..9        default:            hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()                    * strVal2.hashCode() * strVal3.hashCode());        }    }
这里会通过type和value计算hashCode的值

然后调用get查找是否已经存在

   private Item get(final Item key) {        Item i = items[key.hashCode % items.length];        while (i != null && (i.type != key.type || !key.isEqualTo(i))) {            i = i.next;        }        return i;    }
这里就是通过hashCode % item.lengt获取索引,后面我们会看到put时就是这么设置的

回到newClassItem

如果item不存在,则添加到常量池,添加到常量池之前,先调用newUTF8新建一个UTF8的字符串表示类名

   public int newUTF8(final String value) {        key.set(UTF8, value, null, null);        Item result = get(key);        if (result == null) {            pool.putByte(UTF8).putUTF8(value);            result = new Item(index++, key);            put(result);        }        return result.index;    }
先查找对应的字符串是否存在,不存在则先添加一个UTF8,然后把UTF8的字符串添加到常量池

    public ByteVector putByte(final int b) {        int length = this.length;        if (length + 1 > data.length) {            enlarge(1);        }        data[length++] = (byte) b;        this.length = length;        return this;    }
public ByteVector putUTF8(final String s) {        int charLength = s.length();        if (charLength > 65535) {            throw new IllegalArgumentException();        }        int len = length;        if (len + 2 + charLength > data.length) {            enlarge(2 + charLength);        }        byte[] data = this.data;        // optimistic algorithm: instead of computing the byte length and then        // serializing the string (which requires two loops), we assume the byte        // length is equal to char length (which is the most frequent case), and        // we start serializing the string right away. During the serialization,        // if we find that this assumption is wrong, we continue with the        // general method.        data[len++] = (byte) (charLength >>> 8);        data[len++] = (byte) charLength;        for (int i = 0; i < charLength; ++i) {            char c = s.charAt(i);            if (c >= '\001' && c <= '\177') {                data[len++] = (byte) c;            } else {                length = len;                return encodeUTF8(s, i, 65535);            }        }        length = len;        return this;    }

putUTF8先写2字节的长度,然后把字符串写到常量池

newUTF8然后调用put添加到item列表中

private void put(final Item i) {        if (index + typeCount > threshold) {            int ll = items.length;            int nl = ll * 2 + 1;            Item[] newItems = new Item[nl];            for (int l = ll - 1; l >= 0; --l) {                Item j = items[l];                while (j != null) {                    int index = j.hashCode % newItems.length;                    Item k = j.next;                    j.next = newItems[index];                    newItems[index] = j;                    j = k;                }            }            items = newItems;            threshold = (int) (nl * 0.75);        }        int index = i.hashCode % items.length;        i.next = items[index];        items[index] = i;    }


回到ClassWriter的visit如果有超类,也会建立超类的相关常量,接口也是一样的。

到这里visit就完了,主要是新建了类相关的一些信息保存到常量池


回到convertClass,接着调用convertField访问字段

//访问字段    public void convertField(DexClassNode classNode, DexFieldNode fieldNode, ClassVisitor cv) {        String signature = null;        if (fieldNode.anns != null) {            for (DexAnnotationNode ann : fieldNode.anns) {                if (ann.visibility == Visibility.SYSTEM) {                    switch (ann.type) {                    case DexConstants.ANNOTATION_SIGNATURE_TYPE: {                        Object[] strs = (Object[]) findAnnotationAttribute(ann, "value");                        if (strs != null) {                            StringBuilder sb = new StringBuilder();                            for (Object str : strs) {                                sb.append(str);                            }                            signature = sb.toString();                        }                    }                        break;                    }                }            }        }        Object value = fieldNode.cst;        if (value instanceof DexType) {            value = Type.getType(((DexType) value).desc);        }        final int FieldCleanFlag = ~DexConstants.ACC_DECLARED_SYNCHRONIZED;        FieldVisitor fv = cv.visitField(fieldNode.access & FieldCleanFlag, fieldNode.field.getName(),//最终里面创建了一个FieldWriter                fieldNode.field.getType(), signature, value);        if (fv == null) {            return;        }        accept(fieldNode.anns, fv);        fv.visitEnd();    }
先检查有没有注解,然后调用ClassVisitor的visitField访问字段

    public FieldVisitor visitField(int access, String name, String desc,            String signature, Object value) {        if (cv != null) {            return cv.visitField(access, name, desc, signature, value);        }        return null;    }
    public final FieldVisitor visitField(final int access, final String name,            final String desc, final String signature, final Object value) {        return new FieldWriter(this, access, name, desc, signature, value);    }

FieldWriter(final ClassWriter cw, final int access, final String name,            final String desc, final String signature, final Object value) {        super(Opcodes.ASM5);        if (cw.firstField == null) {            cw.firstField = this;        } else {            cw.lastField.fv = this;        }        cw.lastField = this;        this.cw = cw;        this.access = access;        this.name = cw.newUTF8(name);        this.desc = cw.newUTF8(desc);        if (ClassReader.SIGNATURES && signature != null) {            this.signature = cw.newUTF8(signature);        }        if (value != null) {            this.value = cw.newConstItem(value).index;        }    }
这里主要是新建一个FieldWriter,同样会把field相关的字段保存到常量池


然后再看下convertMethod

public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, ClassVisitor cv) {        MethodVisitor mv = collectBasicMethodInfo(methodNode, cv);//返回一个MethodWriter        if (mv == null) {            return;        }        if (0 != (classNode.access & DexConstants.ACC_ANNOTATION)) { // its inside an annotation            Object defaultValue = null;            if (classNode.anns != null) {                for (DexAnnotationNode ann : classNode.anns) {                    if (ann.visibility == Visibility.SYSTEM && ann.type.equals(DexConstants.ANNOTATION_DEFAULT_TYPE)) {                        DexAnnotationNode node = (DexAnnotationNode) findAnnotationAttribute(ann, "value");                        if (node != null) {                            defaultValue = findAnnotationAttribute(node, methodNode.method.getName());                        }                        break;                    }                }            }            if (defaultValue != null) {                AnnotationVisitor av = mv.visitAnnotationDefault();                if (av != null) {                    accept(av, null, defaultValue);                    av.visitEnd();                }            }        }        accept(methodNode.anns, mv);        if (methodNode.parameterAnns != null) {            for (int i = 0; i < methodNode.parameterAnns.length; i++) {                List<DexAnnotationNode> anns = methodNode.parameterAnns[i];                if (anns != null) {                    for (DexAnnotationNode ann : anns) {                        if (ann.visibility != Visibility.SYSTEM) {                            acceptParameter(ann, i, mv);                        }                    }                }            }        }        if ((NO_CODE_MASK & methodNode.access) == 0) { // has code            if (methodNode.codeNode != null) {                mv.visitCode();                convertCode(methodNode, mv);            }        }        mv.visitEnd();    }

collectBasicMethodInfo最终返回一个MethodWriter
 MethodWriter(final ClassWriter cw, final int access, final String name,            final String desc, final String signature,            final String[] exceptions, final boolean computeMaxs,            final boolean computeFrames) {        super(Opcodes.ASM5);        if (cw.firstMethod == null) {            cw.firstMethod = this;        } else {            cw.lastMethod.mv = this;        }        cw.lastMethod = this;        this.cw = cw;        this.access = access;        if ("<init>".equals(name)) {            this.access |= ACC_CONSTRUCTOR;        }        this.name = cw.newUTF8(name);        this.desc = cw.newUTF8(desc);        this.descriptor = desc;        if (ClassReader.SIGNATURES) {            this.signature = signature;        }        if (exceptions != null && exceptions.length > 0) {            exceptionCount = exceptions.length;            this.exceptions = new int[exceptionCount];            for (int i = 0; i < exceptionCount; ++i) {                this.exceptions[i] = cw.newClass(exceptions[i]);            }        }        this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING);        if (computeMaxs || computeFrames) {            // updates maxLocals            int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2;            if ((access & Opcodes.ACC_STATIC) != 0) {                --size;            }            maxLocals = size;            currentLocals = size;            // creates and visits the label for the first basic block            labels = new Label();            labels.status |= Label.PUSHED;            visitLabel(labels);        }    }
如果方法有参数,则调用acceptParameter访问参数


然后最重要的是调用convertCode转换code部分,convertCode最终调用的是我们前面定义的ExDex2Asm的convertCode

public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {        if (!AsmBridge.isMethodWriter(mv)) {            throw new RuntimeException("We use a MethodWriter tricky here!");        }        MethodNode mn = new MethodNode(Opcodes.ASM4, methodNode.access, methodNode.method.getName(),                methodNode.method.getDesc(), null, null);//新建一个MethodNode节点        try {            super.convertCode(methodNode, mn);        } catch (Exception ex) {            if (exceptionHandler == null) {                throw new DexException(ex, "fail convert code for %s", methodNode.method);            } else {                mn.instructions.clear();                mn.tryCatchBlocks.clear();                exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex);            }        }        // code convert ok, copy to MethodWriter and check for Size        mn.accept(mv);//把获取到的指令转换为二进制写到MethodVisitor的code字节数组中去        try {            AsmBridge.sizeOfMethodWriter(mv);        } catch (Exception ex) {            mn.instructions.clear();            mn.tryCatchBlocks.clear();            exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex);            AsmBridge.replaceMethodWriter(mv, mn);        }    }
这里新建一个MethodNode,由他负责对code的访问,传进来的MethodVisitor只后面负责接受二进制的结果

这里主要是调用父类的convertCode
由于后面部分还比较长,再下一篇介绍