fix(gui): split decompile and index tasks for correct time counting (#1361)
This commit is contained in:
@@ -310,7 +310,13 @@ public final class JadxDecompiler implements Closeable {
|
||||
}
|
||||
processQueue.add(cls);
|
||||
}
|
||||
for (List<JavaClass> decompileBatch : decompileScheduler.buildBatches(processQueue)) {
|
||||
List<List<JavaClass>> batches;
|
||||
try {
|
||||
batches = decompileScheduler.buildBatches(processQueue);
|
||||
} catch (Exception e) {
|
||||
throw new JadxRuntimeException("Decompilation batches build failed", e);
|
||||
}
|
||||
for (List<JavaClass> decompileBatch : batches) {
|
||||
tasks.add(() -> {
|
||||
for (JavaClass cls : decompileBatch) {
|
||||
try {
|
||||
|
||||
@@ -69,6 +69,10 @@ public final class JavaClass implements JavaNode {
|
||||
cls.unloadCode();
|
||||
}
|
||||
|
||||
public boolean isNoCode() {
|
||||
return cls.contains(AFlag.DONT_GENERATE);
|
||||
}
|
||||
|
||||
public synchronized String getSmali() {
|
||||
return cls.getDisassembledCode();
|
||||
}
|
||||
|
||||
@@ -358,6 +358,17 @@ public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeN
|
||||
return codeInfo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ICodeInfo getCodeFromCache() {
|
||||
ICodeCache codeCache = root().getCodeCache();
|
||||
String clsRawName = getRawName();
|
||||
ICodeInfo codeInfo = codeCache.get(clsRawName);
|
||||
if (codeInfo == ICodeInfo.EMPTY) {
|
||||
return null;
|
||||
}
|
||||
return codeInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
for (MethodNode mth : getMethods()) {
|
||||
|
||||
@@ -15,8 +15,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.panel.ProgressPanel;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
|
||||
/**
|
||||
@@ -46,6 +48,14 @@ public class BackgroundExecutor {
|
||||
return taskWorker;
|
||||
}
|
||||
|
||||
public TaskStatus executeAndWait(IBackgroundTask task) {
|
||||
try {
|
||||
return execute(task).get();
|
||||
} catch (Exception e) {
|
||||
throw new JadxRuntimeException("Task execution error", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelAll() {
|
||||
try {
|
||||
taskQueueExecutor.shutdownNow();
|
||||
@@ -74,11 +84,12 @@ public class BackgroundExecutor {
|
||||
return (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
|
||||
}
|
||||
|
||||
private final class TaskWorker extends SwingWorker<TaskStatus, Void> {
|
||||
private final class TaskWorker extends SwingWorker<TaskStatus, Void> implements ITaskInfo {
|
||||
private final IBackgroundTask task;
|
||||
private TaskStatus status = TaskStatus.WAIT;
|
||||
private long jobsCount;
|
||||
private long jobsComplete;
|
||||
private long time;
|
||||
|
||||
public TaskWorker(IBackgroundTask task) {
|
||||
this.task = task;
|
||||
@@ -111,13 +122,15 @@ public class BackgroundExecutor {
|
||||
executor.execute(job);
|
||||
}
|
||||
executor.shutdown();
|
||||
status = waitTermination(executor);
|
||||
long startTime = System.currentTimeMillis();
|
||||
status = waitTermination(executor, buildCancelCheck(startTime));
|
||||
time = System.currentTimeMillis() - startTime;
|
||||
jobsComplete = executor.getCompletedTaskCount();
|
||||
task.onDone(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("BusyWait")
|
||||
private TaskStatus waitTermination(ThreadPoolExecutor executor) throws InterruptedException {
|
||||
Supplier<TaskStatus> cancelCheck = buildCancelCheck();
|
||||
private TaskStatus waitTermination(ThreadPoolExecutor executor, Supplier<TaskStatus> cancelCheck) throws InterruptedException {
|
||||
try {
|
||||
int k = 0;
|
||||
while (true) {
|
||||
@@ -145,7 +158,7 @@ public class BackgroundExecutor {
|
||||
}
|
||||
|
||||
private void performCancel(ThreadPoolExecutor executor) throws InterruptedException {
|
||||
progressPane.changeLabel(this, task.getTitle() + " (Canceling)… ");
|
||||
progressPane.changeLabel(this, task.getTitle() + " (" + NLS.str("progress.canceling") + ")… ");
|
||||
progressPane.changeIndeterminate(this, true);
|
||||
// force termination
|
||||
executor.shutdownNow();
|
||||
@@ -153,8 +166,8 @@ public class BackgroundExecutor {
|
||||
LOG.debug("Task cancel complete: {}", complete);
|
||||
}
|
||||
|
||||
private Supplier<TaskStatus> buildCancelCheck() {
|
||||
long waitUntilTime = task.timeLimit() == 0 ? 0 : System.currentTimeMillis() + task.timeLimit();
|
||||
private Supplier<TaskStatus> buildCancelCheck(long startTime) {
|
||||
long waitUntilTime = task.timeLimit() == 0 ? 0 : startTime + task.timeLimit();
|
||||
boolean checkMemoryUsage = task.checkMemoryUsage();
|
||||
return () -> {
|
||||
if (waitUntilTime != 0 && waitUntilTime < System.currentTimeMillis()) {
|
||||
@@ -180,7 +193,32 @@ public class BackgroundExecutor {
|
||||
@Override
|
||||
protected void done() {
|
||||
progressPane.setVisible(false);
|
||||
task.onFinish(status, jobsCount - jobsComplete);
|
||||
task.onFinish(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getJobsCount() {
|
||||
return jobsCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getJobsComplete() {
|
||||
return jobsComplete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getJobsSkipped() {
|
||||
return jobsCount - jobsComplete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,9 +244,9 @@ public class BackgroundExecutor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(TaskStatus status, long l) {
|
||||
public void onFinish(ITaskInfo taskInfo) {
|
||||
if (onFinish != null) {
|
||||
onFinish.accept(status);
|
||||
onFinish.accept(taskInfo.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package jadx.gui.jobs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -29,7 +27,8 @@ public class DecompileTask implements IBackgroundTask {
|
||||
private final JadxWrapper wrapper;
|
||||
private final AtomicInteger complete = new AtomicInteger(0);
|
||||
private int expectedCompleteCount;
|
||||
private long startTime;
|
||||
|
||||
private ProcessResult result;
|
||||
|
||||
public DecompileTask(MainWindow mainWindow, JadxWrapper wrapper) {
|
||||
this.mainWindow = mainWindow;
|
||||
@@ -44,18 +43,21 @@ public class DecompileTask implements IBackgroundTask {
|
||||
@Override
|
||||
public List<Runnable> scheduleJobs() {
|
||||
IndexService indexService = mainWindow.getCacheObject().getIndexService();
|
||||
List<JavaClass> classesForIndex = wrapper.getIncludedClasses()
|
||||
.stream()
|
||||
.filter(indexService::isIndexNeeded)
|
||||
.collect(Collectors.toList());
|
||||
expectedCompleteCount = classesForIndex.size();
|
||||
List<JavaClass> classes = wrapper.getIncludedClasses();
|
||||
expectedCompleteCount = classes.size();
|
||||
|
||||
indexService.setComplete(false);
|
||||
complete.set(0);
|
||||
|
||||
List<Runnable> jobs = new ArrayList<>(expectedCompleteCount + 1);
|
||||
jobs.add(indexService::indexResources);
|
||||
for (List<JavaClass> batch : wrapper.buildDecompileBatches(classesForIndex)) {
|
||||
List<List<JavaClass>> batches;
|
||||
try {
|
||||
batches = wrapper.buildDecompileBatches(classes);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Decompile batches build error", e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Runnable> jobs = new ArrayList<>(batches.size());
|
||||
for (List<JavaClass> batch : batches) {
|
||||
jobs.add(() -> {
|
||||
for (JavaClass cls : batch) {
|
||||
try {
|
||||
@@ -68,58 +70,23 @@ public class DecompileTask implements IBackgroundTask {
|
||||
}
|
||||
});
|
||||
}
|
||||
jobs.add(() -> {
|
||||
for (JavaClass cls : classesForIndex) {
|
||||
try {
|
||||
// TODO: a lot of synchronizations to index object, not effective for parallel usage
|
||||
indexService.indexCls(cls);
|
||||
} catch (Throwable e) {
|
||||
LOG.error("Failed to index class: {}", cls, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
startTime = System.currentTimeMillis();
|
||||
return jobs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(TaskStatus status, long skippedJobs) {
|
||||
long taskTime = System.currentTimeMillis() - startTime;
|
||||
public void onDone(ITaskInfo taskInfo) {
|
||||
long taskTime = taskInfo.getTime();
|
||||
long avgPerCls = taskTime / Math.max(expectedCompleteCount, 1);
|
||||
int timeLimit = timeLimit();
|
||||
int skippedCls = expectedCompleteCount - complete.get();
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Decompile task complete in " + taskTime + " ms (avg " + avgPerCls + " ms per class)"
|
||||
+ ", classes: " + expectedCompleteCount
|
||||
+ ", time limit:{ total: " + timeLimit() + "ms, per cls: " + CLS_LIMIT + "ms }"
|
||||
+ ", status: " + status);
|
||||
}
|
||||
|
||||
IndexService indexService = mainWindow.getCacheObject().getIndexService();
|
||||
indexService.setComplete(true);
|
||||
if (skippedJobs == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int skippedCls = expectedCompleteCount - complete.get();
|
||||
LOG.warn("Decompile and indexing of some classes skipped: {}, status: {}", skippedCls, status);
|
||||
switch (status) {
|
||||
case CANCEL_BY_USER: {
|
||||
String reason = NLS.str("message.userCancelTask");
|
||||
String message = NLS.str("message.indexIncomplete", reason, skippedCls);
|
||||
JOptionPane.showMessageDialog(mainWindow, message);
|
||||
break;
|
||||
}
|
||||
case CANCEL_BY_TIMEOUT: {
|
||||
String reason = NLS.str("message.taskTimeout", timeLimit());
|
||||
String message = NLS.str("message.indexIncomplete", reason, skippedCls);
|
||||
JOptionPane.showMessageDialog(mainWindow, message);
|
||||
break;
|
||||
}
|
||||
case CANCEL_BY_MEMORY: {
|
||||
mainWindow.showHeapUsageBar();
|
||||
JOptionPane.showMessageDialog(mainWindow, NLS.str("message.indexingClassesSkipped", skippedCls));
|
||||
break;
|
||||
}
|
||||
+ ", skipped: " + skippedCls
|
||||
+ ", time limit:{ total: " + timeLimit + "ms, per cls: " + CLS_LIMIT + "ms }"
|
||||
+ ", status: " + taskInfo.getStatus());
|
||||
}
|
||||
this.result = new ProcessResult(skippedCls, taskInfo.getStatus(), timeLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,4 +103,8 @@ public class DecompileTask implements IBackgroundTask {
|
||||
public boolean checkMemoryUsage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public ProcessResult getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,16 +50,16 @@ public class ExportTask implements IBackgroundTask {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(TaskStatus status, long skipped) {
|
||||
public void onFinish(ITaskInfo taskInfo) {
|
||||
// restore initial code cache
|
||||
wrapper.getArgs().setCodeCache(uiCodeCache);
|
||||
if (skipped == 0) {
|
||||
if (taskInfo.getJobsSkipped() == 0) {
|
||||
return;
|
||||
}
|
||||
String reason = getIncompleteReason(status);
|
||||
String reason = getIncompleteReason(taskInfo.getStatus());
|
||||
if (reason != null) {
|
||||
JOptionPane.showMessageDialog(mainWindow,
|
||||
NLS.str("message.saveIncomplete", reason, skipped),
|
||||
NLS.str("message.saveIncomplete", reason, taskInfo.getJobsSkipped()),
|
||||
NLS.str("message.errorTitle"), JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,17 @@ public interface IBackgroundTask {
|
||||
|
||||
List<Runnable> scheduleJobs();
|
||||
|
||||
void onFinish(TaskStatus status, long skipped);
|
||||
/**
|
||||
* Called on executor thread after the all jobs finished.
|
||||
*/
|
||||
default void onDone(ITaskInfo taskInfo) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed on the Event Dispatch Thread after the all jobs finished.
|
||||
*/
|
||||
default void onFinish(ITaskInfo taskInfo) {
|
||||
}
|
||||
|
||||
default boolean canBeCanceled() {
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package jadx.gui.jobs;
|
||||
|
||||
public interface ITaskInfo {
|
||||
TaskStatus getStatus();
|
||||
|
||||
long getJobsCount();
|
||||
|
||||
long getJobsComplete();
|
||||
|
||||
long getJobsSkipped();
|
||||
|
||||
long getTime();
|
||||
}
|
||||
@@ -5,9 +5,11 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.ICodeWriter;
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.gui.utils.CacheObject;
|
||||
@@ -30,22 +32,36 @@ public class IndexService {
|
||||
/**
|
||||
* Warning! Not ready for parallel execution. Use only in a single thread.
|
||||
*/
|
||||
public void indexCls(JavaClass cls) {
|
||||
public boolean indexCls(JavaClass cls) {
|
||||
try {
|
||||
TextSearchIndex index = cache.getTextIndex();
|
||||
if (index == null) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
List<StringRef> lines = splitLines(cls);
|
||||
// get code from cache to avoid decompilation here
|
||||
String code = getCodeFromCache(cls);
|
||||
if (code == null) {
|
||||
return cls.isNoCode();
|
||||
}
|
||||
List<StringRef> lines = splitLines(code);
|
||||
CodeLinesInfo linesInfo = new CodeLinesInfo(cls);
|
||||
index.indexCode(cls, linesInfo, lines);
|
||||
index.indexNames(cls);
|
||||
indexSet.add(cls);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Index error in class: {}", cls.getFullName(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add to API
|
||||
@Nullable
|
||||
private String getCodeFromCache(JavaClass cls) {
|
||||
ICodeInfo codeInfo = cls.getClassNode().getCodeFromCache();
|
||||
return codeInfo != null ? codeInfo.getCodeStr() : null;
|
||||
}
|
||||
|
||||
public void indexResources() {
|
||||
TextSearchIndex index = cache.getTextIndex();
|
||||
index.indexResource();
|
||||
@@ -75,8 +91,8 @@ public class IndexService {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static List<StringRef> splitLines(JavaClass cls) {
|
||||
List<StringRef> lines = StringRef.split(cls.getCode(), ICodeWriter.NL);
|
||||
protected static List<StringRef> splitLines(String code) {
|
||||
List<StringRef> lines = StringRef.split(code, ICodeWriter.NL);
|
||||
int size = lines.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
lines.set(i, lines.get(i).trim());
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package jadx.gui.jobs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.gui.JadxWrapper;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class IndexTask implements IBackgroundTask {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(IndexTask.class);
|
||||
|
||||
private final MainWindow mainWindow;
|
||||
private final JadxWrapper wrapper;
|
||||
private final AtomicInteger complete = new AtomicInteger(0);
|
||||
private int expectedCompleteCount;
|
||||
|
||||
private ProcessResult result;
|
||||
|
||||
public IndexTask(MainWindow mainWindow, JadxWrapper wrapper) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.wrapper = wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return NLS.str("progress.index");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Runnable> scheduleJobs() {
|
||||
IndexService indexService = mainWindow.getCacheObject().getIndexService();
|
||||
List<JavaClass> classesForIndex = wrapper.getIncludedClasses()
|
||||
.stream()
|
||||
.filter(indexService::isIndexNeeded)
|
||||
.collect(Collectors.toList());
|
||||
expectedCompleteCount = classesForIndex.size();
|
||||
|
||||
indexService.setComplete(false);
|
||||
complete.set(0);
|
||||
|
||||
List<Runnable> jobs = new ArrayList<>(2);
|
||||
jobs.add(indexService::indexResources);
|
||||
jobs.add(() -> {
|
||||
for (JavaClass cls : classesForIndex) {
|
||||
try {
|
||||
// TODO: a lot of synchronizations to index object, not efficient for parallel usage
|
||||
if (indexService.indexCls(cls)) {
|
||||
complete.incrementAndGet();
|
||||
} else {
|
||||
LOG.debug("Index skipped for {}", cls);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LOG.error("Failed to index class: {}", cls, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return jobs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDone(ITaskInfo taskInfo) {
|
||||
int skippedCls = expectedCompleteCount - complete.get();
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info("Index task complete in " + taskInfo.getTime() + " ms"
|
||||
+ ", classes: " + expectedCompleteCount
|
||||
+ ", skipped: " + skippedCls
|
||||
+ ", status: " + taskInfo.getStatus());
|
||||
}
|
||||
IndexService indexService = mainWindow.getCacheObject().getIndexService();
|
||||
indexService.setComplete(true);
|
||||
this.result = new ProcessResult(skippedCls, taskInfo.getStatus(), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeCanceled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkMemoryUsage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public ProcessResult getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package jadx.gui.jobs;
|
||||
|
||||
public class ProcessResult {
|
||||
private final int skipped;
|
||||
private final TaskStatus status;
|
||||
private final int timeLimit;
|
||||
|
||||
public ProcessResult(int skipped, TaskStatus status, int timeLimit) {
|
||||
this.skipped = skipped;
|
||||
this.status = status;
|
||||
this.timeLimit = timeLimit;
|
||||
}
|
||||
|
||||
public int getSkipped() {
|
||||
return skipped;
|
||||
}
|
||||
|
||||
public TaskStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public int getTimeLimit() {
|
||||
return timeLimit;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -38,7 +39,6 @@ import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
@@ -94,6 +94,8 @@ import jadx.gui.jobs.BackgroundExecutor;
|
||||
import jadx.gui.jobs.DecompileTask;
|
||||
import jadx.gui.jobs.ExportTask;
|
||||
import jadx.gui.jobs.IndexService;
|
||||
import jadx.gui.jobs.IndexTask;
|
||||
import jadx.gui.jobs.ProcessResult;
|
||||
import jadx.gui.jobs.TaskStatus;
|
||||
import jadx.gui.plugins.quark.QuarkDialog;
|
||||
import jadx.gui.settings.JadxProject;
|
||||
@@ -555,14 +557,62 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
try {
|
||||
DecompileTask decompileTask = new DecompileTask(this, wrapper);
|
||||
Future<TaskStatus> task = backgroundExecutor.execute(decompileTask);
|
||||
task.get();
|
||||
backgroundExecutor.executeAndWait(decompileTask);
|
||||
|
||||
IndexTask indexTask = new IndexTask(this, wrapper);
|
||||
backgroundExecutor.executeAndWait(indexTask);
|
||||
|
||||
processDecompilationResults(decompileTask.getResult(), indexTask.getResult());
|
||||
} catch (Exception e) {
|
||||
LOG.error("Decompile task execution failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDecompilationResults(ProcessResult decompile, ProcessResult index) {
|
||||
int skippedCls = Math.max(decompile.getSkipped(), index.getSkipped());
|
||||
if (skippedCls == 0) {
|
||||
return;
|
||||
}
|
||||
TaskStatus status = mergeStatus(EnumSet.of(decompile.getStatus(), index.getStatus()));
|
||||
LOG.warn("Decompile and indexing of some classes skipped: {}, status: {}", skippedCls, status);
|
||||
switch (status) {
|
||||
case CANCEL_BY_USER: {
|
||||
String reason = NLS.str("message.userCancelTask");
|
||||
String message = NLS.str("message.indexIncomplete", reason, skippedCls);
|
||||
JOptionPane.showMessageDialog(this, message);
|
||||
break;
|
||||
}
|
||||
case CANCEL_BY_TIMEOUT: {
|
||||
String reason = NLS.str("message.taskTimeout", decompile.getTimeLimit());
|
||||
String message = NLS.str("message.indexIncomplete", reason, skippedCls);
|
||||
JOptionPane.showMessageDialog(this, message);
|
||||
break;
|
||||
}
|
||||
case CANCEL_BY_MEMORY: {
|
||||
showHeapUsageBar();
|
||||
JOptionPane.showMessageDialog(this, NLS.str("message.indexingClassesSkipped", skippedCls));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TaskStatus mergeStatus(Set<TaskStatus> statuses) {
|
||||
if (statuses.size() == 1) {
|
||||
return statuses.iterator().next();
|
||||
}
|
||||
if (statuses.contains(TaskStatus.CANCEL_BY_MEMORY)) {
|
||||
return TaskStatus.CANCEL_BY_MEMORY;
|
||||
}
|
||||
if (statuses.contains(TaskStatus.CANCEL_BY_TIMEOUT)) {
|
||||
return TaskStatus.CANCEL_BY_TIMEOUT;
|
||||
}
|
||||
if (statuses.contains(TaskStatus.CANCEL_BY_USER)) {
|
||||
return TaskStatus.CANCEL_BY_USER;
|
||||
}
|
||||
return TaskStatus.COMPLETE;
|
||||
}
|
||||
|
||||
public void cancelBackgroundJobs() {
|
||||
ExecutorService worker = Executors.newSingleThreadExecutor();
|
||||
worker.execute(backgroundExecutor::cancelAll);
|
||||
|
||||
@@ -38,6 +38,7 @@ tree.loading=Laden…
|
||||
progress.load=Laden
|
||||
progress.decompile=Dekompilieren
|
||||
progress.index=Indizieren
|
||||
#progress.canceling=Canceling
|
||||
|
||||
error_dialog.title=Fehler
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ tree.loading=Loading...
|
||||
|
||||
progress.load=Loading
|
||||
progress.decompile=Decompiling
|
||||
#progress.index=Indexing
|
||||
progress.index=Indexing
|
||||
progress.canceling=Canceling
|
||||
|
||||
error_dialog.title=Error
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ tree.loading=Cargando...
|
||||
progress.load=Cargando
|
||||
progress.decompile=Decompiling
|
||||
#progress.index=Indexing
|
||||
#progress.canceling=Canceling
|
||||
|
||||
#error_dialog.title=
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ tree.loading=로딩중...
|
||||
progress.load=로딩중
|
||||
progress.decompile=디컴파일 중
|
||||
progress.index=인덱싱 중
|
||||
#progress.canceling=Canceling
|
||||
|
||||
error_dialog.title=오류
|
||||
|
||||
@@ -193,7 +194,7 @@ popup.copy=붙여넣기
|
||||
popup.paste=복사
|
||||
popup.delete=삭제
|
||||
popup.select_all=모두 선택
|
||||
popup.frida=frida 스니펫으로 복사
|
||||
popup.frida=frida 스니펫으로 복사
|
||||
popup.find_usage=사용 찾기
|
||||
popup.go_to_declaration=선언문으로 이동
|
||||
popup.exclude=제외
|
||||
|
||||
@@ -37,7 +37,8 @@ tree.loading=加载中...
|
||||
|
||||
progress.load=正在加载
|
||||
progress.decompile=反编译中
|
||||
#progress.index=索引中
|
||||
progress.index=索引中
|
||||
#progress.canceling=Canceling
|
||||
|
||||
error_dialog.title=错误
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ tree.loading=載入中...
|
||||
progress.load=載入中
|
||||
progress.decompile=正在反編譯
|
||||
#progress.index=Indexing
|
||||
#progress.canceling=Canceling
|
||||
|
||||
error_dialog.title=錯誤
|
||||
|
||||
|
||||
Reference in New Issue
Block a user