From 05bdf9daae1b1c6605c929399bc23a7d28c21d31 Mon Sep 17 00:00:00 2001 From: Jan S Date: Mon, 29 Nov 2021 13:08:54 +0100 Subject: [PATCH] perf(res): XML decoding speed enhancement (PR #1293) * chore: XML decoding speed improved for large APKs (finding class references) * skip attach class node to xml for SimpleCodeWriter (used in jadx-cli) Co-authored-by: Skylot --- .../java/jadx/core/dex/nodes/RootNode.java | 27 +++++++++++++++++++ .../jadx/core/xmlgen/BinaryXMLParser.java | 14 ++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java index e462e992..89009641 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java @@ -334,6 +334,15 @@ public class RootNode { return resolveClass(clsInfo); } + /** + * Searches for ClassNode by its full name (original or alias name) + * + * Warning: This method has a runtime of O(n) (n = number of classes). + * If you need to call it more than once consider {@link #buildFullAliasClassCache()} instead + * + * @param fullName + * @return + */ @Nullable public ClassNode searchClassByFullAlias(String fullName) { for (ClassNode cls : classes) { @@ -346,6 +355,24 @@ public class RootNode { return null; } + /** + * + * @return + */ + public Map buildFullAliasClassCache() { + Map classNameCache = new HashMap<>(classes.size()); + for (ClassNode cls : classes) { + ClassInfo classInfo = cls.getClassInfo(); + String fullName = classInfo.getFullName(); + String alias = classInfo.getAliasFullName(); + classNameCache.put(fullName, cls); + if (alias != null && !fullName.equals(alias)) { + classNameCache.put(alias, cls); + } + } + return classNameCache; + } + public List searchClassByShortName(String shortName) { List list = new ArrayList<>(); for (ClassNode cls : classes) { diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java index 67611922..59046c66 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java @@ -56,6 +56,8 @@ public class BinaryXMLParser extends CommonBinaryParser { private final RootNode rootNode; private String appPackageName; + private Map classNameCache; + public BinaryXMLParser(RootNode rootNode) { this.rootNode = rootNode; try { @@ -78,7 +80,9 @@ public class BinaryXMLParser extends CommonBinaryParser { firstElement = true; decode(); nsMap = null; - return writer.finish(); + ICodeInfo codeInfo = writer.finish(); + this.classNameCache = null; // reset class name cache + return codeInfo; } private boolean isBinaryXml() throws IOException { @@ -467,6 +471,9 @@ public class BinaryXMLParser extends CommonBinaryParser { } private void attachClassNode(ICodeWriter writer, String attrName, String clsName) { + if (!writer.isMetadataSupported()) { + return; + } if (clsName == null || !attrName.equals("name")) { return; } @@ -476,7 +483,10 @@ public class BinaryXMLParser extends CommonBinaryParser { } else { clsFullName = clsName; } - ClassNode classNode = rootNode.searchClassByFullAlias(clsFullName); + if (classNameCache == null) { + classNameCache = rootNode.buildFullAliasClassCache(); + } + ClassNode classNode = classNameCache.get(clsFullName); if (classNode != null) { writer.attachAnnotation(classNode); } -- GitLab