From 7fed5534eb921d3f64cbf78ffaaa4f473240ea0c Mon Sep 17 00:00:00 2001 From: Skylot Date: Fri, 7 Aug 2020 17:38:08 +0100 Subject: [PATCH] refactor: add method info caching to speed up initial loading --- .../java/jadx/core/dex/info/InfoStorage.java | 14 +++ .../java/jadx/core/dex/info/MethodInfo.java | 27 ++++-- .../core/dex/instructions/InsnDecoder.java | 4 +- .../java/jadx/core/dex/nodes/ClassNode.java | 2 +- .../java/jadx/core/dex/nodes/MethodNode.java | 4 +- .../dex/visitors/usage/UsageInfoVisitor.java | 2 +- .../jadx/plugins/input/dex/DexFileLoader.java | 16 ++- .../plugins/input/dex/DexInputPlugin.java | 4 + .../jadx/plugins/input/dex/DexReader.java | 9 +- .../plugins/input/dex/insns/DexInsnData.java | 6 +- .../input/dex/sections/DexClassData.java | 7 +- .../input/dex/sections/DexMethodData.java | 45 ++------- .../input/dex/sections/DexMethodRef.java | 97 +++++++++++++++++++ .../input/dex/sections/SectionReader.java | 38 +++++--- .../annotations/EncodedValueParser.java | 2 +- .../plugins/input/dex/smali/SmaliPrinter.java | 10 +- .../jadx/plugins/input/dex/utils/Utils.java | 3 + .../api/plugins/input/data/IMethodData.java | 7 +- .../api/plugins/input/data/IMethodRef.java | 21 ++++ .../api/plugins/input/insns/InsnData.java | 4 +- 20 files changed, 233 insertions(+), 89 deletions(-) create mode 100644 jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexMethodRef.java create mode 100644 jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/data/IMethodRef.java diff --git a/jadx-core/src/main/java/jadx/core/dex/info/InfoStorage.java b/jadx-core/src/main/java/jadx/core/dex/info/InfoStorage.java index 9daff3731..c6abd7584 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/InfoStorage.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/InfoStorage.java @@ -11,6 +11,8 @@ public class InfoStorage { private final Map fields = new HashMap<>(); // use only one MethodInfo instance private final Map uniqueMethods = new HashMap<>(); + // can contain same method with different ids (from different dex files) + private final Map methods = new HashMap<>(); public ClassInfo getCls(ArgType type) { return classes.get(type); @@ -23,6 +25,18 @@ public class InfoStorage { } } + public MethodInfo getByUniqId(int id) { + synchronized (methods) { + return methods.get(id); + } + } + + public void putByUniqId(int id, MethodInfo mth) { + synchronized (methods) { + methods.put(id, mth); + } + } + public MethodInfo putMethod(MethodInfo newMth) { synchronized (uniqueMethods) { MethodInfo prev = uniqueMethods.get(newMth); diff --git a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java index a6b24ba26..eae97571d 100644 --- a/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java +++ b/jadx-core/src/main/java/jadx/core/dex/info/MethodInfo.java @@ -5,7 +5,7 @@ import java.util.Objects; import org.jetbrains.annotations.Nullable; -import jadx.api.plugins.input.data.IMethodData; +import jadx.api.plugins.input.data.IMethodRef; import jadx.core.codegen.TypeGen; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.nodes.RootNode; @@ -31,18 +31,27 @@ public final class MethodInfo implements Comparable { this.shortId = makeShortId(name, argTypes, retType); } - public static MethodInfo fromData(RootNode root, IMethodData methodData) { - ArgType parentClsType = ArgType.parse(methodData.getParentClassType()); + public static MethodInfo fromRef(RootNode root, IMethodRef methodRef) { + InfoStorage infoStorage = root.getInfoStorage(); + int uniqId = methodRef.getUniqId(); + MethodInfo prevMth = infoStorage.getByUniqId(uniqId); + if (prevMth != null) { + return prevMth; + } + methodRef.load(); + ArgType parentClsType = ArgType.parse(methodRef.getParentClassType()); ClassInfo parentClass = ClassInfo.fromType(root, parentClsType); - ArgType returnType = ArgType.parse(methodData.getReturnType()); - List args = Utils.collectionMap(methodData.getArgTypes(), ArgType::parse); - MethodInfo newMth = new MethodInfo(parentClass, methodData.getName(), args, returnType); - return root.getInfoStorage().putMethod(newMth); + ArgType returnType = ArgType.parse(methodRef.getReturnType()); + List args = Utils.collectionMap(methodRef.getArgTypes(), ArgType::parse); + MethodInfo newMth = new MethodInfo(parentClass, methodRef.getName(), args, returnType); + MethodInfo uniqMth = infoStorage.putMethod(newMth); + infoStorage.putByUniqId(uniqId, uniqMth); + return uniqMth; } - public static MethodInfo fromDetails(RootNode rootNode, ClassInfo declClass, String name, List args, ArgType retType) { + public static MethodInfo fromDetails(RootNode root, ClassInfo declClass, String name, List args, ArgType retType) { MethodInfo newMth = new MethodInfo(declClass, name, args, retType); - return rootNode.getInfoStorage().putMethod(newMth); + return root.getInfoStorage().putMethod(newMth); } public String makeSignature(boolean includeRetType) { diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java index 969d5381e..3a0b798f3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java @@ -521,8 +521,8 @@ public class InsnDecoder { } private InsnNode invoke(InsnData insn, InvokeType type, boolean isRange) { - MethodInfo mth = MethodInfo.fromData(root, insn.getIndexAsMethod()); - return new InvokeNode(mth, insn, type, isRange); + MethodInfo mthInfo = MethodInfo.fromRef(root, insn.getIndexAsMethod()); + return new InvokeNode(mthInfo, insn, type, isRange); } private InsnNode arrayGet(InsnData insn, ArgType argType) { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index 5efa57c81..fe9ff68bf 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -81,8 +81,8 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN public ClassNode(RootNode root, IClassData cls) { this.root = root; this.clsInfo = ClassInfo.fromType(root, ArgType.object(cls.getType())); - initialLoad(cls); this.clsData = cls.copy(); + initialLoad(clsData); } private void initialLoad(IClassData cls) { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java index dba60cd80..65813824d 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java @@ -82,8 +82,8 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails, return methodNode; } - public MethodNode(ClassNode classNode, IMethodData mthData) { - this.mthInfo = MethodInfo.fromData(classNode.root(), mthData); + private MethodNode(ClassNode classNode, IMethodData mthData) { + this.mthInfo = MethodInfo.fromRef(classNode.root(), mthData.getMethodRef()); this.parentClass = classNode; this.accFlags = new AccessInfo(mthData.getAccessFlags(), AFType.METHOD); this.methodIsVirtual = !mthData.isDirect(); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java index d95bd4989..a64fb3bd4 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java @@ -104,7 +104,7 @@ public class UsageInfoVisitor extends AbstractVisitor { case METHOD_REF: insnData.decode(); - MethodNode methodNode = root.resolveMethod(MethodInfo.fromData(root, insnData.getIndexAsMethod())); + MethodNode methodNode = root.resolveMethod(MethodInfo.fromRef(root, insnData.getIndexAsMethod())); if (methodNode != null) { usageInfo.methodUse(mth, methodNode); } diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexFileLoader.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexFileLoader.java index 45215c239..9bcd8ac75 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexFileLoader.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexFileLoader.java @@ -24,6 +24,8 @@ import jadx.plugins.input.dex.sections.DexConsts; public class DexFileLoader { private static final Logger LOG = LoggerFactory.getLogger(DexFileLoader.class); + private static int dexUniqId = 1; + public static List collectDexFiles(List pathsList) { return pathsList.stream() .map(Path::toFile) @@ -52,7 +54,7 @@ public class DexFileLoader { } if (isStartWithBytes(magic, DexConsts.DEX_FILE_MAGIC)) { in.reset(); - DexReader dexReader = new DexReader(inputFileName, readAllBytes(in)); + DexReader dexReader = new DexReader(getNextUniqId(), inputFileName, readAllBytes(in)); return Collections.singletonList(dexReader); } if (file != null && isStartWithBytes(magic, DexConsts.ZIP_FILE_MAGIC)) { @@ -97,4 +99,16 @@ public class DexFileLoader { private static byte[] readAllBytes(InputStream in) throws IOException { return ByteStreams.toByteArray(in); } + + private static int getNextUniqId() { + dexUniqId++; + if (dexUniqId >= 0xFFFF) { + resetDexUniqId(); + } + return dexUniqId; + } + + public static void resetDexUniqId() { + dexUniqId = 1; + } } diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexInputPlugin.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexInputPlugin.java index ab5e9a533..5a6e855c8 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexInputPlugin.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexInputPlugin.java @@ -11,6 +11,10 @@ import jadx.api.plugins.input.data.impl.EmptyLoadResult; public class DexInputPlugin implements JadxInputPlugin { + public DexInputPlugin() { + DexFileLoader.resetDexUniqId(); + } + @Override public JadxPluginInfo getPluginInfo() { return new JadxPluginInfo("dex-input", "DexInput", "Load .dex and .apk files"); diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexReader.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexReader.java index 89bb86db0..5df0d1c1b 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexReader.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/DexReader.java @@ -10,12 +10,13 @@ import jadx.plugins.input.dex.sections.SectionReader; import jadx.plugins.input.dex.sections.annotations.AnnotationsParser; public class DexReader { - + private final int uniqId; private final String inputFileName; private final ByteBuffer buf; private final DexHeader header; - public DexReader(String inputFileName, byte[] content) { + public DexReader(int uniqId, String inputFileName, byte[] content) { + this.uniqId = uniqId; this.inputFileName = inputFileName; this.buf = ByteBuffer.wrap(content); this.header = new DexHeader(new SectionReader(this, 0)); @@ -48,6 +49,10 @@ public class DexReader { return inputFileName; } + public int getUniqId() { + return uniqId; + } + @Override public String toString() { return inputFileName; diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/insns/DexInsnData.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/insns/DexInsnData.java index 36fcc71bf..3e13633c6 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/insns/DexInsnData.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/insns/DexInsnData.java @@ -3,7 +3,7 @@ package jadx.plugins.input.dex.insns; import org.jetbrains.annotations.Nullable; import jadx.api.plugins.input.data.IFieldData; -import jadx.api.plugins.input.data.IMethodData; +import jadx.api.plugins.input.data.IMethodRef; import jadx.api.plugins.input.insns.InsnData; import jadx.api.plugins.input.insns.InsnIndexType; import jadx.api.plugins.input.insns.Opcode; @@ -106,8 +106,8 @@ public class DexInsnData implements InsnData { } @Override - public IMethodData getIndexAsMethod() { - return externalReader.getMethodData(index); + public IMethodRef getIndexAsMethod() { + return externalReader.getMethodRef(index); } @Nullable diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexClassData.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexClassData.java index cbca1fb80..8360457b1 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexClassData.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexClassData.java @@ -127,10 +127,10 @@ public class DexClassData implements IClassData { private void visitMethods(Consumer mthConsumer, SectionReader data, int directMthCount, int virtualMthCount) { DexMethodData methodData = new DexMethodData(annotationsParser); + methodData.setMethodRef(new DexMethodRef()); Map annotationOffsetMap = annotationsParser.readMethodsAnnotationOffsetMap(); Map paramsAnnOffsetMap = annotationsParser.readMethodParamsAnnRefOffsetMap(); - methodData.setParentClassType(getType()); methodData.setDirect(true); readMethods(mthConsumer, data, methodData, directMthCount, annotationOffsetMap, paramsAnnOffsetMap); methodData.setDirect(false); @@ -145,7 +145,10 @@ public class DexClassData implements IClassData { mthIdx += data.readUleb128(); int accFlags = data.readUleb128(); int codeOff = data.readUleb128(); - in.fillMethodData(methodData, mthIdx); + + DexMethodRef methodRef = methodData.getMethodRef(); + methodRef.reset(); + in.initMethodRef(mthIdx, methodRef); methodData.setAccessFlags(accFlags); if (codeOff == 0) { methodData.setCodeReader(null); diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexMethodData.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexMethodData.java index cba773eda..1c775abdf 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexMethodData.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexMethodData.java @@ -9,16 +9,13 @@ import jadx.api.plugins.input.data.IMethodData; import jadx.api.plugins.input.data.annotations.IAnnotation; import jadx.plugins.input.dex.sections.annotations.AnnotationsParser; import jadx.plugins.input.dex.smali.SmaliPrinter; -import jadx.plugins.input.dex.utils.Utils; public class DexMethodData implements IMethodData { @Nullable private final AnnotationsParser annotationsParser; - private String parentClassType; - private String returnType; - private List argTypes; - private String name; + private DexMethodRef methodRef; + private int accessFlags; private boolean isDirect; private int annotationsOffset; @@ -32,21 +29,12 @@ public class DexMethodData implements IMethodData { } @Override - public String getParentClassType() { - return parentClassType; + public DexMethodRef getMethodRef() { + return methodRef; } - public void setParentClassType(String parentClassType) { - this.parentClassType = parentClassType; - } - - @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; + public void setMethodRef(DexMethodRef methodRef) { + this.methodRef = methodRef; } @Override @@ -58,24 +46,6 @@ public class DexMethodData implements IMethodData { this.accessFlags = accessFlags; } - @Override - public String getReturnType() { - return returnType; - } - - public void setReturnType(String returnType) { - this.returnType = returnType; - } - - @Override - public List getArgTypes() { - return argTypes; - } - - public void setArgTypes(List argTypes) { - this.argTypes = argTypes; - } - @Override public boolean isDirect() { return isDirect; @@ -127,7 +97,6 @@ public class DexMethodData implements IMethodData { @Override public String toString() { - return getParentClassType() + "->" + getName() - + '(' + Utils.listToStr(getArgTypes()) + ")" + getReturnType(); + return getMethodRef().toString(); } } diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexMethodRef.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexMethodRef.java new file mode 100644 index 000000000..7377db23e --- /dev/null +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/DexMethodRef.java @@ -0,0 +1,97 @@ +package jadx.plugins.input.dex.sections; + +import java.util.List; + +import jadx.api.plugins.input.data.IMethodRef; +import jadx.plugins.input.dex.DexReader; +import jadx.plugins.input.dex.utils.Utils; + +public class DexMethodRef implements IMethodRef { + + private int uniqId; + private String name; + private String parentClassType; + private String returnType; + private List argTypes; + + // lazy loading info + private int dexIdx; + private SectionReader sectionReader; + + public void initUniqId(DexReader dexReader, int idx) { + this.uniqId = (dexReader.getUniqId() & 0xFFFF) << 16 | (idx & 0xFFFF); + } + + @Override + public void load() { + if (sectionReader != null) { + sectionReader.loadMethodRef(this, dexIdx); + sectionReader = null; + } + } + + public void setDexIdx(int dexIdx) { + this.dexIdx = dexIdx; + } + + public void setSectionReader(SectionReader sectionReader) { + this.sectionReader = sectionReader; + } + + @Override + public int getUniqId() { + return uniqId; + } + + public void reset() { + name = null; + parentClassType = null; + returnType = null; + argTypes = null; + } + + @Override + public String getParentClassType() { + return parentClassType; + } + + public void setParentClassType(String parentClassType) { + this.parentClassType = parentClassType; + } + + @Override + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + @Override + public List getArgTypes() { + return argTypes; + } + + public void setArgTypes(List argTypes) { + this.argTypes = argTypes; + } + + @Override + public String toString() { + if (name == null) { + // not loaded + return Integer.toHexString(uniqId); + } + return getParentClassType() + "->" + getName() + '(' + Utils.listToStr(getArgTypes()) + ")" + getReturnType(); + } +} diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/SectionReader.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/SectionReader.java index ebd9b4ab7..093efbcd4 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/SectionReader.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/SectionReader.java @@ -10,7 +10,6 @@ import java.util.List; import org.jetbrains.annotations.Nullable; import jadx.api.plugins.input.data.IFieldData; -import jadx.api.plugins.input.data.IMethodData; import jadx.plugins.input.dex.DexReader; import jadx.plugins.input.dex.utils.Leb128; import jadx.plugins.input.dex.utils.MUtf8; @@ -175,23 +174,29 @@ public class SectionReader { return classTypeIdx; } - public IMethodData getMethodData(int idx) { - DexMethodData methodData = new DexMethodData(null); - int clsTypeIdx = fillMethodData(methodData, idx); - methodData.setParentClassType(getType(clsTypeIdx)); - return methodData; + public DexMethodRef getMethodRef(int idx) { + DexMethodRef methodRef = new DexMethodRef(); + initMethodRef(idx, methodRef); + return methodRef; } - public int fillMethodData(DexMethodData methodData, int idx) { - int methodIdsOff = dexReader.getHeader().getMethodIdsOff(); + public void initMethodRef(int idx, DexMethodRef methodRef) { + methodRef.initUniqId(dexReader, idx); + methodRef.setDexIdx(idx); + methodRef.setSectionReader(this); + } + + public void loadMethodRef(DexMethodRef methodRef, int idx) { + DexHeader header = dexReader.getHeader(); + int methodIdsOff = header.getMethodIdsOff(); absPos(methodIdsOff + idx * 8); int classTypeIdx = readUShort(); int protoIdx = readUShort(); int nameIdx = readInt(); - int protoIdsOff = dexReader.getHeader().getProtoIdsOff(); + int protoIdsOff = header.getProtoIdsOff(); absPos(protoIdsOff + protoIdx * 12); - int shortyIdx = readInt(); + skip(4); // shortyIdx int returnTypeIdx = readInt(); int paramsOff = readInt(); @@ -201,18 +206,19 @@ public class SectionReader { } else { argTypes = absPos(paramsOff).readTypeList(); } - methodData.setName(getString(nameIdx)); - methodData.setReturnType(getType(returnTypeIdx)); - methodData.setArgTypes(argTypes); - return classTypeIdx; + methodRef.setParentClassType(getType(classTypeIdx)); + methodRef.setName(getString(nameIdx)); + methodRef.setReturnType(getType(returnTypeIdx)); + methodRef.setArgTypes(argTypes); } public List getMethodParamTypes(int idx) { - int methodIdsOff = dexReader.getHeader().getMethodIdsOff(); + DexHeader header = dexReader.getHeader(); + int methodIdsOff = header.getMethodIdsOff(); absPos(methodIdsOff + idx * 8 + 2); int protoIdx = readUShort(); - int protoIdsOff = dexReader.getHeader().getProtoIdsOff(); + int protoIdsOff = header.getProtoIdsOff(); absPos(protoIdsOff + protoIdx * 12 + 8); int paramsOff = readInt(); diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/annotations/EncodedValueParser.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/annotations/EncodedValueParser.java index adaaad25c..014f63179 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/annotations/EncodedValueParser.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/sections/annotations/EncodedValueParser.java @@ -63,7 +63,7 @@ public class EncodedValueParser { return new EncodedValue(EncodedType.ENCODED_TYPE, ext.getType(parseUnsignedInt(in, size))); case ENCODED_METHOD: - return new EncodedValue(EncodedType.ENCODED_METHOD, ext.getMethodData(parseUnsignedInt(in, size))); + return new EncodedValue(EncodedType.ENCODED_METHOD, ext.getMethodRef(parseUnsignedInt(in, size))); case ENCODED_FIELD: case ENCODED_ENUM: diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/smali/SmaliPrinter.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/smali/SmaliPrinter.java index 3f10cfe35..b70aeb1c3 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/smali/SmaliPrinter.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/smali/SmaliPrinter.java @@ -3,6 +3,7 @@ package jadx.plugins.input.dex.smali; import jadx.api.plugins.input.data.AccessFlags; import jadx.api.plugins.input.data.ICodeReader; import jadx.plugins.input.dex.sections.DexMethodData; +import jadx.plugins.input.dex.sections.DexMethodRef; import static jadx.api.plugins.input.data.AccessFlagsScope.METHOD; @@ -13,9 +14,12 @@ public class SmaliPrinter { SmaliCodeWriter codeWriter = new SmaliCodeWriter(); codeWriter.startLine(".method "); codeWriter.add(AccessFlags.format(mth.getAccessFlags(), METHOD)); - codeWriter.add(mth.getName()); - codeWriter.add('(').addArgs(mth.getArgTypes()).add(')'); - codeWriter.add(mth.getReturnType()); + + DexMethodRef methodRef = mth.getMethodRef(); + methodRef.load(); + codeWriter.add(methodRef.getName()); + codeWriter.add('(').addArgs(methodRef.getArgTypes()).add(')'); + codeWriter.add(methodRef.getReturnType()); codeWriter.incIndent(); ICodeReader codeReader = mth.getCodeReader(); diff --git a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/utils/Utils.java b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/utils/Utils.java index a0881a2c5..fc04b24d2 100644 --- a/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/utils/Utils.java +++ b/jadx-plugins/jadx-dex-input/src/main/java/jadx/plugins/input/dex/utils/Utils.java @@ -6,6 +6,9 @@ import java.util.List; public class Utils { public static String listToStr(List collection) { + if (collection == null) { + return "null"; + } StringBuilder sb = new StringBuilder(); Iterator it = collection.iterator(); if (it.hasNext()) { diff --git a/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/data/IMethodData.java b/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/data/IMethodData.java index d942f6147..874d2c95c 100644 --- a/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/data/IMethodData.java +++ b/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/data/IMethodData.java @@ -7,16 +7,11 @@ import org.jetbrains.annotations.Nullable; import jadx.api.plugins.input.data.annotations.IAnnotation; public interface IMethodData { - String getParentClassType(); - String getName(); + IMethodRef getMethodRef(); int getAccessFlags(); - String getReturnType(); - - List getArgTypes(); - boolean isDirect(); @Nullable diff --git a/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/data/IMethodRef.java b/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/data/IMethodRef.java new file mode 100644 index 000000000..d4aa3e9b5 --- /dev/null +++ b/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/data/IMethodRef.java @@ -0,0 +1,21 @@ +package jadx.api.plugins.input.data; + +import java.util.List; + +public interface IMethodRef { + + int getUniqId(); + + /** + * Lazy loading for method info, until load() is called only getUniqId() can be used + */ + void load(); + + String getParentClassType(); + + String getName(); + + String getReturnType(); + + List getArgTypes(); +} diff --git a/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/insns/InsnData.java b/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/insns/InsnData.java index dad3ae8f6..4d50fa488 100644 --- a/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/insns/InsnData.java +++ b/jadx-plugins/jadx-plugins-api/src/main/java/jadx/api/plugins/input/insns/InsnData.java @@ -3,7 +3,7 @@ package jadx.api.plugins.input.insns; import org.jetbrains.annotations.Nullable; import jadx.api.plugins.input.data.IFieldData; -import jadx.api.plugins.input.data.IMethodData; +import jadx.api.plugins.input.data.IMethodRef; import jadx.api.plugins.input.insns.custom.ICustomPayload; public interface InsnData { @@ -34,7 +34,7 @@ public interface InsnData { IFieldData getIndexAsField(); - IMethodData getIndexAsMethod(); + IMethodRef getIndexAsMethod(); @Nullable ICustomPayload getPayload();