package com.telerik.metadata.dx; import com.android.dex.Annotation; import com.android.dex.ClassData; import com.android.dex.ClassDef; import com.android.dex.Dex; import com.android.dex.MethodId; import com.android.dex.ProtoId; import com.android.dx.rop.code.AccessFlags; import com.telerik.metadata.desc.MetadataInfoAnnotationDescriptor; import com.telerik.metadata.desc.MethodDescriptor; import com.telerik.metadata.desc.TypeDescriptor; import java.util.List; public class MethodInfo implements MethodDescriptor { private final DexFile dexFile; private final ClassData.Method method; public MethodInfo(DexFile dexFile, ClassData.Method method) { this.dexFile = dexFile; this.method = method; } @Override public boolean isPublic() { return AccessFlags.isPublic(method.getAccessFlags()); } @Override public boolean isProtected() { return AccessFlags.isProtected(method.getAccessFlags()); } @Override public boolean isSynthetic() { boolean isSynthetic = (method.getAccessFlags() & AccessFlags.ACC_SYNTHETIC) == AccessFlags.ACC_SYNTHETIC; return isSynthetic; } @Override public boolean isStatic() { return AccessFlags.isStatic(method.getAccessFlags()); } @Override public String getName() { Dex dex = dexFile.getDex(); List<String> strings = dex.strings(); int idx = dex.nameIndexFromMethodIndex(method.getMethodIndex()); String methodName = strings.get(idx); return methodName; } @Override public String getSignature() { Dex dex = dexFile.getDex(); List<String> typeNames = dex.typeNames(); MethodId methodId = dex.methodIds().get(method.getMethodIndex()); ProtoId methodProtoId = dex.protoIds().get(methodId.getProtoIndex()); short[] parameterTypes = dex.readTypeList(methodProtoId.getParametersOffset()).getTypes(); String signature = "("; for (short paramId: parameterTypes) { signature += typeNames.get(paramId); } signature += ")" + getReturnType().getSignature(); return signature; } @Override public TypeDescriptor[] getArgumentTypes() { Dex dex = dexFile.getDex(); List<String> typeNames = dex.typeNames(); MethodId methodId = dex.methodIds().get(method.getMethodIndex()); ProtoId methodProtoId = dex.protoIds().get(methodId.getProtoIndex()); short[] parameterTypes = dex.readTypeList(methodProtoId.getParametersOffset()).getTypes(); TypeDescriptor[] argTypes = new TypeDescriptor[parameterTypes.length]; for (int i=0; i<argTypes.length; i++) { int paramId = parameterTypes[i]; String typeName = typeNames.get(paramId); argTypes[i] = new TypeInfo(typeName); } return argTypes; } @Override public TypeDescriptor getReturnType() { Dex dex = dexFile.getDex(); List<String> typeNames = dex.typeNames(); MethodId methodId = dex.methodIds().get(method.getMethodIndex()); ProtoId methodProtoId = dex.protoIds().get(methodId.getProtoIndex()); int retTypeIdx = methodProtoId.getReturnTypeIndex(); String retTypeName = typeNames.get(retTypeIdx); return new TypeInfo(retTypeName); } @Override public MetadataInfoAnnotationDescriptor getMetadataInfoAnnotation() { Dex dex = dexFile.getDex(); MethodId methodId = dex.methodIds().get(method.getMethodIndex()); int cdIdx = methodId.getDeclaringClassIndex(); ClassDef classDef = null; for (ClassDef currClassDef : dex.classDefs()) { if (cdIdx == currClassDef.getTypeIndex()) { classDef = currClassDef; break; } } int classDefIndex = dex.findClassDefIndexFromTypeIndex(classDef.getTypeIndex()); int directoryOffset = dex.annotationDirectoryOffsetFromClassDefIndex(classDefIndex); if (directoryOffset == 0) { return null; } Dex.Section directoryIn = dex.open(directoryOffset); int classSetOffset = directoryIn.readInt(); int fieldCount = directoryIn.readInt(); int methodsCount = directoryIn.readInt(); directoryIn.readInt(); for (int i = 0; i < fieldCount; i++) { directoryIn.readInt(); directoryIn.readInt(); } int methodIdx = method.getMethodIndex(); int annotationSetOffset = 0; for (int i = 0; i < methodsCount; i++) { int candidateMethodIndex = directoryIn.readInt(); int currAnnotationSetOffset = directoryIn.readInt(); if (candidateMethodIndex == methodIdx) { annotationSetOffset = currAnnotationSetOffset; } } if (annotationSetOffset == 0) { return null; } Dex.Section annSetSection = dex.open(annotationSetOffset); int size = annSetSection.readInt(); for (int i = 0; i < size; i++) { int annotationOffset = annSetSection.readInt(); Dex.Section annSection = dex.open(annotationOffset); Annotation annotation = annSection.readAnnotation(); String annotationName = dex.strings().get(dex.typeIds().get(annotation.getTypeIndex())); if (annotationName.equals("Lcom/telerik/metadata/MetadataInfo;")) { return new MetadataInfoAnnotationInfo(dexFile, annotation); } } return null; } }