diff --git a/jadx-core/src/main/java/jadx/core/utils/Utils.java b/jadx-core/src/main/java/jadx/core/utils/Utils.java index bb07f9604..2f7afac36 100644 --- a/jadx-core/src/main/java/jadx/core/utils/Utils.java +++ b/jadx-core/src/main/java/jadx/core/utils/Utils.java @@ -16,9 +16,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Function; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import jadx.api.ICodeWriter; @@ -504,6 +507,27 @@ public class Utils { } } + public static ThreadFactory simpleThreadFactory(String name) { + return new SimpleThreadFactory(name); + } + + private static final class SimpleThreadFactory implements ThreadFactory { + private static final AtomicInteger POOL = new AtomicInteger(0); + private final AtomicInteger number = new AtomicInteger(0); + private final String name; + + public SimpleThreadFactory(String name) { + this.name = name; + } + + @Override + public Thread newThread(@NotNull Runnable r) { + return new Thread(r, "jadx-" + name + + '-' + POOL.incrementAndGet() + + '-' + number.incrementAndGet()); + } + } + /** * @deprecated env vars shouldn't be used in core modules. * Prefer to parse in `app` (use JadxCommonEnv from 'app-commons') and set in jadx args. diff --git a/jadx-core/src/main/java/jadx/core/utils/tasks/TaskExecutor.java b/jadx-core/src/main/java/jadx/core/utils/tasks/TaskExecutor.java index 8b850d91c..6d323f9dd 100644 --- a/jadx-core/src/main/java/jadx/core/utils/tasks/TaskExecutor.java +++ b/jadx-core/src/main/java/jadx/core/utils/tasks/TaskExecutor.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import jadx.api.JadxArgs; import jadx.api.utils.tasks.ITaskExecutor; +import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxRuntimeException; public class TaskExecutor implements ITaskExecutor { @@ -99,7 +100,7 @@ public class TaskExecutor implements ITaskExecutor { running.set(true); progress.set(0); terminating.set(false); - executor = Executors.newFixedThreadPool(1); + executor = Executors.newFixedThreadPool(1, Utils.simpleThreadFactory("task-s")); executor.execute(this::runStages); executor.shutdown(); } @@ -142,7 +143,8 @@ public class TaskExecutor implements ITaskExecutor { wrapTask(task); } } else { - ExecutorService parallelExecutor = Executors.newFixedThreadPool(threads); + ExecutorService parallelExecutor = Executors.newFixedThreadPool( + threads, Utils.simpleThreadFactory("task-p")); for (Runnable task : stage.getTasks()) { parallelExecutor.execute(() -> wrapTask(task)); } diff --git a/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java b/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java index 2f0714646..d9630d416 100644 --- a/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java +++ b/jadx-gui/src/main/java/jadx/gui/jobs/BackgroundExecutor.java @@ -22,6 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.api.utils.tasks.ITaskExecutor; +import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.settings.JadxSettings; import jadx.gui.ui.MainWindow; @@ -104,7 +105,7 @@ public class BackgroundExecutor { } private synchronized void reset() { - taskQueueExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1); + taskQueueExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1, Utils.simpleThreadFactory("bg")); taskRunning.clear(); idSupplier.set(0); } @@ -162,6 +163,7 @@ public class BackgroundExecutor { } finally { taskComplete(id); progressPane.changeVisibility(this, false); + removePropertyChangeListener(progressPane); } } return status; diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 7353001e0..ff43f08bc 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -537,14 +537,19 @@ public class MainWindow extends JFrame { } public void reopen() { - synchronized (ReloadProject.EVENT) { - saveAll(); - closeAll(); - loadFiles(() -> { - menuBar.reloadShortcuts(); - events().send(ReloadSettingsWindow.INSTANCE); - }); - } + LOG.debug("starting reopen"); + UiUtils.bgRun(() -> { + getBackgroundExecutor().waitForComplete(); + synchronized (ReloadProject.EVENT) { + saveAll(); + closeAll(); + loadFiles(() -> { + menuBar.reloadShortcuts(); + events().send(ReloadSettingsWindow.INSTANCE); + LOG.debug("reopen complete"); + }); + } + }); } private void openProject(Path path, Runnable onFinish) { @@ -622,7 +627,7 @@ public class MainWindow extends JFrame { shortcutsController.reset(); UiUtils.resetClipboardOwner(); System.gc(); - update(); + UiUtils.uiRun(this::update); } private void checkLoadedStatus() { diff --git a/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java b/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java index 47dd6c1a8..edd2fed9f 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java @@ -20,6 +20,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import javax.swing.AbstractAction; import javax.swing.Action; @@ -79,6 +81,8 @@ public class UiUtils { } }; + private static final ExecutorService BACKGROUND_THREAD = Executors.newSingleThreadExecutor(Utils.simpleThreadFactory("utils-bg")); + private UiUtils() { } @@ -420,6 +424,14 @@ public class UiUtils { } } + /** + * Run task in background thread. + * Uses single thread, so all tasks are ordered. + */ + public static void bgRun(Runnable runnable) { + BACKGROUND_THREAD.submit(runnable); + } + public static void uiThreadGuard() { if (!SwingUtilities.isEventDispatchThread()) { LOG.warn("Expect UI thread, got: {}", Thread.currentThread(), new JadxRuntimeException());