fix(smali-input): use synced list for threaded processing, improve inner classes handling
This commit is contained in:
@@ -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;
|
||||
|
||||
+9
-21
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user