diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java index ca4281bcc..55e37974e 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java @@ -15,6 +15,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.beust.jcommander.DynamicParameter; import com.beust.jcommander.IStringConverter; @@ -43,6 +45,7 @@ import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.files.FileUtils; public class JadxCLIArgs implements IJadxConfig { + private static final Logger LOG = LoggerFactory.getLogger(JadxCLIArgs.class); @JadxConfigExclude @Parameter(description = " (.apk, .dex, .jar, .class, .smali, .zip, .aar, .arsc, .aab, .xapk, .apkm, .jadx.kts)") @@ -376,11 +379,15 @@ public class JadxCLIArgs implements IJadxConfig { } if (!argsObj.config.equalsIgnoreCase("none")) { // load config file and merge with command line args - configAdapter.useConfigRef(argsObj.config); - T configObj = configAdapter.load(); - if (configObj != null) { - jcw.overrideProvided(configObj); - argsObj = configObj; + try { + configAdapter.useConfigRef(argsObj.config); + T configObj = configAdapter.load(); + if (configObj != null) { + jcw.overrideProvided(configObj); + argsObj = configObj; + } + } catch (Exception e) { + LOG.error("Config load failed, continue with default values", e); } } } diff --git a/jadx-cli/src/main/java/jadx/cli/config/JadxConfigAdapter.java b/jadx-cli/src/main/java/jadx/cli/config/JadxConfigAdapter.java index cdb74af64..5c4edd3db 100644 --- a/jadx-cli/src/main/java/jadx/cli/config/JadxConfigAdapter.java +++ b/jadx-cli/src/main/java/jadx/cli/config/JadxConfigAdapter.java @@ -1,6 +1,5 @@ package jadx.cli.config; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.function.Consumer; @@ -12,17 +11,12 @@ import com.google.gson.FieldAttributes; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; import jadx.commons.app.JadxCommonFiles; import jadx.core.utils.GsonUtils; import jadx.core.utils.exceptions.JadxArgsValidateException; import jadx.core.utils.exceptions.JadxRuntimeException; -import static java.nio.file.StandardOpenOption.CREATE; -import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; -import static java.nio.file.StandardOpenOption.WRITE; - public class JadxConfigAdapter { private static final ExclusionStrategy GSON_EXCLUSION_STRATEGY = new ExclusionStrategy() { @Override @@ -81,9 +75,10 @@ public class JadxConfigAdapter { } public void save(T configObject) { - try (JsonWriter writer = gson.newJsonWriter( - Files.newBufferedWriter(configPath, StandardCharsets.UTF_8, WRITE, CREATE, TRUNCATE_EXISTING))) { - gson.toJson(configObject, configCls, writer); + try { + String jsonStr = gson.toJson(configObject, configCls); + // don't use stream writer here because serialization errors will corrupt config + Files.writeString(configPath, jsonStr); } catch (Exception e) { throw new JadxRuntimeException("Failed to save config file: " + configPath, e); } diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java index 9a4df2830..c70b84cf5 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -51,6 +51,7 @@ public class JadxSettings { private static final int RECENT_PROJECTS_COUNT = 30; private final JadxConfigAdapter configAdapter; + private final Object dataWriteSync = new Object(); private final ShortcutsWrapper shortcutsWrapper = new ShortcutsWrapper(); private final FontSettings fontSettings = new FontSettings(); @@ -112,7 +113,9 @@ public class JadxSettings { } public void sync() { - configAdapter.save(settingsData); + synchronized (dataWriteSync) { + configAdapter.save(settingsData); + } } public String exportSettingsString() { @@ -218,8 +221,10 @@ public class JadxSettings { } public void saveWindowPos(Window window) { - WindowLocation pos = new WindowLocation(window.getClass().getSimpleName(), window.getBounds()); - settingsData.getWindowPos().put(pos.getWindowId(), pos); + synchronized (dataWriteSync) { + WindowLocation pos = new WindowLocation(window.getClass().getSimpleName(), window.getBounds()); + settingsData.getWindowPos().put(pos.getWindowId(), pos); + } } public boolean loadWindowPos(Window window) { 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 ac4e6bba2..df3dde984 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -1613,7 +1613,9 @@ public class MainWindow extends JFrame { if (debuggerPanel != null) { saveSplittersInfo(); } - settings.sync(); + // block UI thread to avoid settings data changes during sync + UiUtils.uiRunAndWait(settings::sync); + closeAll(); UiUtils.uiRunAndWait(() -> { heapUsageBar.reset();