fix(smali-input): use synced list for threaded processing, improve inner classes handling

This commit is contained in:
Skylot
2025-10-14 21:48:33 +01:00
parent bf2d5b5e2e
commit 654cf5e4fb
5 changed files with 17 additions and 44 deletions
@@ -435,7 +435,7 @@ public final class JadxDecompiler implements Closeable {
return list;
}
public List<JavaClass> getClasses() {
public synchronized List<JavaClass> getClasses() {
if (root == null) {
return Collections.emptyList();
}
@@ -443,10 +443,7 @@ public final class JadxDecompiler implements Closeable {
List<ClassNode> classNodeList = root.getClasses();
List<JavaClass> clsList = new ArrayList<>(classNodeList.size());
for (ClassNode classNode : classNodeList) {
if (classNode.contains(AFlag.DONT_GENERATE)) {
continue;
}
if (!classNode.getClassInfo().isInner()) {
if (!classNode.contains(AFlag.DONT_GENERATE) && !classNode.isInner()) {
clsList.add(convertClassNode(classNode));
}
}
@@ -612,17 +612,9 @@ public class ClassNode extends NotificationAttrNode
return parentClass;
}
public void updateParentClass() {
if (clsInfo.isInner()) {
ClassNode parent = root.resolveClass(clsInfo.getParentClass());
if (parent != null) {
parentClass = parent;
return;
}
// undo inner mark in class info
clsInfo.notInner(root);
}
parentClass = this;
public void notInner() {
this.clsInfo.notInner(root);
this.parentClass = this;
}
/**
@@ -159,7 +159,7 @@ public class RootNode {
LOG.info("Loaded classes: {}, methods: {}, instructions: {}", classes.size(), mthCount, insnsCount);
// sort classes by name, expect top classes before inner
classes.sort(Comparator.comparing(ClassNode::getFullName));
classes.sort(Comparator.comparing(ClassNode::getRawName));
if (args.isMoveInnerClasses()) {
// detect and move inner classes
@@ -309,10 +309,8 @@ public class RootNode {
ClassInfo clsInfo = cls.getClassInfo();
ClassNode parent = resolveParentClass(clsInfo);
if (parent == null) {
clsMap.remove(clsInfo);
clsInfo.notInner(this);
clsMap.put(clsInfo, cls);
updated.add(cls);
cls.notInner();
} else {
parent.addInnerClass(cls);
}
@@ -323,7 +321,6 @@ public class RootNode {
innerCls.getClassInfo().updateNames(this);
}
}
classes.forEach(ClassNode::updateParentClass);
for (PackageNode pkg : packages) {
pkg.getClasses().removeIf(cls -> cls.getClassInfo().isInner());
}
@@ -221,8 +221,7 @@ public abstract class IntegrationTest extends TestUtils {
} else {
LOG.info("Convert back to top level: {}", cls);
cls.getTopParentClass().decompile(); // keep correct process order
cls.getClassInfo().notInner(root);
cls.updateParentClass();
cls.notInner();
}
decompileAndCheck(cls);
return cls;
@@ -1,11 +1,11 @@
package jadx.plugins.input.smali;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -51,16 +51,18 @@ public class SmaliConvert {
long start = System.currentTimeMillis();
if (threads == 1 || inputFiles.size() == 1) {
for (Path inputFile : inputFiles) {
assemble(inputFile, smaliOptions);
assemble(dexData, inputFile, smaliOptions);
}
} else {
try {
ExecutorService executor = Executors.newFixedThreadPool(threads);
List<IDexData> syncList = Collections.synchronizedList(dexData);
for (Path inputFile : inputFiles) {
executor.execute(() -> assemble(inputFile, smaliOptions));
executor.execute(() -> assemble(syncList, inputFile, smaliOptions));
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.DAYS);
executor.awaitTermination(1, TimeUnit.HOURS);
dexData.sort(Comparator.comparing(IDexData::getFileName));
} catch (InterruptedException e) {
LOG.error("Smali compile interrupted", e);
}
@@ -70,30 +72,16 @@ public class SmaliConvert {
}
}
private void assemble(Path inputFile, SmaliOptions smaliOptions) {
private void assemble(List<IDexData> results, Path inputFile, SmaliOptions smaliOptions) {
Path path = inputFile.toAbsolutePath();
try {
byte[] dexContent = SmaliUtils.assemble(path.toFile(), smaliOptions);
dexData.add(new SimpleDexData(path.toString(), dexContent));
results.add(new SimpleDexData(path.toString(), dexContent));
} catch (Exception e) {
LOG.error("Failed to assemble smali file: {}", path, e);
}
}
private static void collectSystemErrors(OutputStream out, Runnable exec) {
PrintStream systemErr = System.err;
try (PrintStream err = new PrintStream(out)) {
System.setErr(err);
try {
exec.run();
} catch (Exception e) {
e.printStackTrace(err);
}
} finally {
System.setErr(systemErr);
}
}
private List<Path> filterSmaliFiles(List<Path> input) {
PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**.smali");
return input.stream()