From b26abdc851c63e9503b3c02f5f1ce062da7590ad Mon Sep 17 00:00:00 2001 From: Skylot <118523+skylot@users.noreply.github.com> Date: Sat, 28 Sep 2024 22:37:31 +0100 Subject: [PATCH] feat(plugins): get config and cache dirs for plugins --- jadx-cli/build.gradle.kts | 1 + jadx-cli/src/main/java/jadx/cli/JadxCLI.java | 2 + .../jadx/cli/plugins/JadxFilesGetter.java | 31 ++++++++++++++++ .../src/main/java/jadx/api/JadxArgs.java | 16 ++++++++ .../jadx/api/plugins/JadxPluginContext.java | 6 +++ .../jadx/api/plugins/data/IJadxFiles.java | 21 +++++++++++ .../java/jadx/core/plugins/AppContext.java | 31 ++++++++++++++++ .../jadx/core/plugins/JadxPluginManager.java | 11 ++++++ .../java/jadx/core/plugins/PluginContext.java | 24 +++++++++--- .../core/plugins/files/IJadxFilesGetter.java | 12 ++++++ .../core/plugins/files/JadxFilesData.java | 37 +++++++++++++++++++ .../core/plugins/files/TempFilesGetter.java | 29 +++++++++++++++ .../java/jadx/core/utils/files/FileUtils.java | 4 ++ .../src/main/java/jadx/gui/JadxWrapper.java | 16 +++++--- .../gui/utils/plugins/CollectPlugins.java | 9 +---- 15 files changed, 231 insertions(+), 19 deletions(-) create mode 100644 jadx-cli/src/main/java/jadx/cli/plugins/JadxFilesGetter.java create mode 100644 jadx-core/src/main/java/jadx/api/plugins/data/IJadxFiles.java create mode 100644 jadx-core/src/main/java/jadx/core/plugins/AppContext.java create mode 100644 jadx-core/src/main/java/jadx/core/plugins/files/IJadxFilesGetter.java create mode 100644 jadx-core/src/main/java/jadx/core/plugins/files/JadxFilesData.java create mode 100644 jadx-core/src/main/java/jadx/core/plugins/files/TempFilesGetter.java diff --git a/jadx-cli/build.gradle.kts b/jadx-cli/build.gradle.kts index 88e29974a..ec2dc7722 100644 --- a/jadx-cli/build.gradle.kts +++ b/jadx-cli/build.gradle.kts @@ -9,6 +9,7 @@ plugins { dependencies { implementation(project(":jadx-core")) implementation(project(":jadx-plugins-tools")) + implementation(project(":jadx-commons:jadx-app-commons")) runtimeOnly(project(":jadx-plugins:jadx-dex-input")) runtimeOnly(project(":jadx-plugins:jadx-java-input")) diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java index 0911f893a..98131417a 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLI.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLI.java @@ -9,6 +9,7 @@ import jadx.api.impl.AnnotatedCodeWriter; import jadx.api.impl.NoOpCodeCache; import jadx.api.impl.SimpleCodeWriter; import jadx.cli.LogHelper.LogLevelEnum; +import jadx.cli.plugins.JadxFilesGetter; import jadx.core.utils.exceptions.JadxArgsValidateException; import jadx.core.utils.files.FileUtils; import jadx.plugins.tools.JadxExternalPluginsLoader; @@ -46,6 +47,7 @@ public class JadxCLI { JadxArgs jadxArgs = cliArgs.toJadxArgs(); jadxArgs.setCodeCache(new NoOpCodeCache()); jadxArgs.setPluginLoader(new JadxExternalPluginsLoader()); + jadxArgs.setFilesGetter(JadxFilesGetter.INSTANCE); initCodeWriterProvider(jadxArgs); try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs)) { jadx.load(); diff --git a/jadx-cli/src/main/java/jadx/cli/plugins/JadxFilesGetter.java b/jadx-cli/src/main/java/jadx/cli/plugins/JadxFilesGetter.java new file mode 100644 index 000000000..6c8320bbd --- /dev/null +++ b/jadx-cli/src/main/java/jadx/cli/plugins/JadxFilesGetter.java @@ -0,0 +1,31 @@ +package jadx.cli.plugins; + +import java.nio.file.Path; + +import jadx.commons.app.JadxCommonFiles; +import jadx.core.plugins.files.IJadxFilesGetter; +import jadx.core.utils.files.FileUtils; + +public class JadxFilesGetter implements IJadxFilesGetter { + + public static final JadxFilesGetter INSTANCE = new JadxFilesGetter(); + + @Override + public Path getConfigDir() { + return JadxCommonFiles.getConfigDir(); + } + + @Override + public Path getCacheDir() { + return JadxCommonFiles.getCacheDir(); + } + + @Override + public Path getTempDir() { + return FileUtils.getTempRootDir(); + } + + private JadxFilesGetter() { + // singleton + } +} diff --git a/jadx-core/src/main/java/jadx/api/JadxArgs.java b/jadx-core/src/main/java/jadx/api/JadxArgs.java index 143f6d161..1d38123a5 100644 --- a/jadx-core/src/main/java/jadx/api/JadxArgs.java +++ b/jadx-core/src/main/java/jadx/api/JadxArgs.java @@ -36,6 +36,8 @@ import jadx.core.deobf.DeobfAliasProvider; import jadx.core.deobf.conditions.DeobfWhitelist; import jadx.core.deobf.conditions.JadxRenameConditions; import jadx.core.plugins.PluginContext; +import jadx.core.plugins.files.IJadxFilesGetter; +import jadx.core.plugins.files.TempFilesGetter; import jadx.core.utils.files.FileUtils; public class JadxArgs implements Closeable { @@ -166,6 +168,12 @@ public class JadxArgs implements Closeable { private UseKotlinMethodsForVarNames useKotlinMethodsForVarNames = UseKotlinMethodsForVarNames.APPLY; + /** + * Additional files structure info. + * Defaults to tmp dirs. + */ + private IJadxFilesGetter filesGetter = TempFilesGetter.INSTANCE; + /** * Don't save files (can be using for performance testing) */ @@ -710,6 +718,14 @@ public class JadxArgs implements Closeable { this.useKotlinMethodsForVarNames = useKotlinMethodsForVarNames; } + public IJadxFilesGetter getFilesGetter() { + return filesGetter; + } + + public void setFilesGetter(IJadxFilesGetter filesGetter) { + this.filesGetter = filesGetter; + } + public boolean isSkipFilesSave() { return skipFilesSave; } diff --git a/jadx-core/src/main/java/jadx/api/plugins/JadxPluginContext.java b/jadx-core/src/main/java/jadx/api/plugins/JadxPluginContext.java index e203df43c..d70cb7165 100644 --- a/jadx-core/src/main/java/jadx/api/plugins/JadxPluginContext.java +++ b/jadx-core/src/main/java/jadx/api/plugins/JadxPluginContext.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable; import jadx.api.JadxArgs; import jadx.api.JadxDecompiler; +import jadx.api.plugins.data.IJadxFiles; import jadx.api.plugins.data.IJadxPlugins; import jadx.api.plugins.events.IJadxEvents; import jadx.api.plugins.gui.JadxGuiContext; @@ -53,4 +54,9 @@ public interface JadxPluginContext { * Access to registered plugins and runtime data */ IJadxPlugins plugins(); + + /** + * Access to plugin specific files and directories + */ + IJadxFiles files(); } diff --git a/jadx-core/src/main/java/jadx/api/plugins/data/IJadxFiles.java b/jadx-core/src/main/java/jadx/api/plugins/data/IJadxFiles.java new file mode 100644 index 000000000..c3c14c4fb --- /dev/null +++ b/jadx-core/src/main/java/jadx/api/plugins/data/IJadxFiles.java @@ -0,0 +1,21 @@ +package jadx.api.plugins.data; + +import java.nio.file.Path; + +public interface IJadxFiles { + + /** + * Plugin cache directory. + */ + Path getPluginCacheDir(); + + /** + * Plugin config directory. + */ + Path getPluginConfigDir(); + + /** + * Plugin temp directory. + */ + Path getPluginTempDir(); +} diff --git a/jadx-core/src/main/java/jadx/core/plugins/AppContext.java b/jadx-core/src/main/java/jadx/core/plugins/AppContext.java new file mode 100644 index 000000000..7b25ee0de --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/plugins/AppContext.java @@ -0,0 +1,31 @@ +package jadx.core.plugins; + +import java.util.Objects; + +import org.jetbrains.annotations.Nullable; + +import jadx.api.plugins.gui.JadxGuiContext; +import jadx.core.plugins.files.IJadxFilesGetter; + +public class AppContext { + + private @Nullable JadxGuiContext guiContext; + + private IJadxFilesGetter filesGetter; + + public @Nullable JadxGuiContext getGuiContext() { + return guiContext; + } + + public void setGuiContext(@Nullable JadxGuiContext guiContext) { + this.guiContext = guiContext; + } + + public IJadxFilesGetter getFilesGetter() { + return Objects.requireNonNull(filesGetter); + } + + public void setFilesGetter(IJadxFilesGetter filesGetter) { + this.filesGetter = filesGetter; + } +} diff --git a/jadx-core/src/main/java/jadx/core/plugins/JadxPluginManager.java b/jadx-core/src/main/java/jadx/core/plugins/JadxPluginManager.java index fa2d3e2bf..b79d42bff 100644 --- a/jadx-core/src/main/java/jadx/core/plugins/JadxPluginManager.java +++ b/jadx-core/src/main/java/jadx/core/plugins/JadxPluginManager.java @@ -122,8 +122,12 @@ public class JadxPluginManager { } public void init(SortedSet pluginContexts) { + AppContext defAppContext = buildDefaultAppContext(); for (PluginContext context : pluginContexts) { try { + if (context.getAppContext() == null) { + context.setAppContext(defAppContext); + } context.init(); } catch (Exception e) { throw new JadxRuntimeException("Failed to init plugin: " + context.getPluginId(), e); @@ -137,6 +141,13 @@ public class JadxPluginManager { } } + private AppContext buildDefaultAppContext() { + AppContext appContext = new AppContext(); + appContext.setGuiContext(null); + appContext.setFilesGetter(decompiler.getArgs().getFilesGetter()); + return appContext; + } + private void verifyOptions(PluginContext pluginContext, JadxPluginOptions options) { String pluginId = pluginContext.getPluginId(); List descriptions = options.getOptionsDescriptions(); diff --git a/jadx-core/src/main/java/jadx/core/plugins/PluginContext.java b/jadx-core/src/main/java/jadx/core/plugins/PluginContext.java index 4fcf4a276..4739dd0d0 100644 --- a/jadx-core/src/main/java/jadx/core/plugins/PluginContext.java +++ b/jadx-core/src/main/java/jadx/core/plugins/PluginContext.java @@ -15,6 +15,7 @@ import jadx.api.JadxDecompiler; import jadx.api.plugins.JadxPlugin; import jadx.api.plugins.JadxPluginContext; import jadx.api.plugins.JadxPluginInfo; +import jadx.api.plugins.data.IJadxFiles; import jadx.api.plugins.data.IJadxPlugins; import jadx.api.plugins.data.JadxPluginRuntimeData; import jadx.api.plugins.events.IJadxEvents; @@ -27,6 +28,7 @@ import jadx.api.plugins.options.OptionDescription; import jadx.api.plugins.options.OptionFlag; import jadx.api.plugins.pass.JadxPass; import jadx.api.plugins.resources.IResourcesLoader; +import jadx.core.plugins.files.JadxFilesData; import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.files.FileUtils; @@ -36,7 +38,8 @@ public class PluginContext implements JadxPluginContext, JadxPluginRuntimeData, private final JadxPluginsData pluginsData; private final JadxPlugin plugin; private final JadxPluginInfo pluginInfo; - private @Nullable JadxGuiContext guiContext; + + private AppContext appContext; private final List codeInputs = new ArrayList<>(); private @Nullable JadxPluginOptions options; @@ -137,13 +140,17 @@ public class PluginContext implements JadxPluginContext, JadxPluginRuntimeData, return decompiler.getResourcesLoader(); } - @Override - public @Nullable JadxGuiContext getGuiContext() { - return guiContext; + public AppContext getAppContext() { + return appContext; } - public void setGuiContext(JadxGuiContext guiContext) { - this.guiContext = guiContext; + public void setAppContext(AppContext appContext) { + this.appContext = appContext; + } + + @Override + public @Nullable JadxGuiContext getGuiContext() { + return appContext.getGuiContext(); } @Override @@ -171,6 +178,11 @@ public class PluginContext implements JadxPluginContext, JadxPluginRuntimeData, return pluginsData; } + @Override + public IJadxFiles files() { + return new JadxFilesData(pluginInfo, appContext.getFilesGetter()); + } + @Override public ICodeLoader loadCodeFiles(List files, @Nullable Closeable closeable) { return new MergeCodeLoader( diff --git a/jadx-core/src/main/java/jadx/core/plugins/files/IJadxFilesGetter.java b/jadx-core/src/main/java/jadx/core/plugins/files/IJadxFilesGetter.java new file mode 100644 index 000000000..e6cc4e185 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/plugins/files/IJadxFilesGetter.java @@ -0,0 +1,12 @@ +package jadx.core.plugins.files; + +import java.nio.file.Path; + +public interface IJadxFilesGetter { + + Path getConfigDir(); + + Path getCacheDir(); + + Path getTempDir(); +} diff --git a/jadx-core/src/main/java/jadx/core/plugins/files/JadxFilesData.java b/jadx-core/src/main/java/jadx/core/plugins/files/JadxFilesData.java new file mode 100644 index 000000000..8f688c821 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/plugins/files/JadxFilesData.java @@ -0,0 +1,37 @@ +package jadx.core.plugins.files; + +import java.nio.file.Path; + +import jadx.api.plugins.JadxPluginInfo; +import jadx.api.plugins.data.IJadxFiles; + +public class JadxFilesData implements IJadxFiles { + private static final String PLUGINS_DATA_DIR = "plugins-data"; + + private final JadxPluginInfo pluginInfo; + private final IJadxFilesGetter filesGetter; + + public JadxFilesData(JadxPluginInfo pluginInfo, IJadxFilesGetter filesGetter) { + this.pluginInfo = pluginInfo; + this.filesGetter = filesGetter; + } + + @Override + public Path getPluginCacheDir() { + return toPluginPath(filesGetter.getCacheDir()); + } + + @Override + public Path getPluginConfigDir() { + return toPluginPath(filesGetter.getConfigDir()); + } + + @Override + public Path getPluginTempDir() { + return toPluginPath(filesGetter.getTempDir()); + } + + private Path toPluginPath(Path dir) { + return dir.resolve(PLUGINS_DATA_DIR).resolve(pluginInfo.getPluginId()); + } +} diff --git a/jadx-core/src/main/java/jadx/core/plugins/files/TempFilesGetter.java b/jadx-core/src/main/java/jadx/core/plugins/files/TempFilesGetter.java new file mode 100644 index 000000000..ce9c31802 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/plugins/files/TempFilesGetter.java @@ -0,0 +1,29 @@ +package jadx.core.plugins.files; + +import java.nio.file.Path; + +import jadx.core.utils.files.FileUtils; + +public class TempFilesGetter implements IJadxFilesGetter { + + public static final TempFilesGetter INSTANCE = new TempFilesGetter(); + + @Override + public Path getConfigDir() { + return FileUtils.getTempRootDir().resolve("config"); + } + + @Override + public Path getCacheDir() { + return FileUtils.getTempRootDir().resolve("cache"); + } + + @Override + public Path getTempDir() { + return FileUtils.getTempRootDir().resolve("temp"); + } + + private TempFilesGetter() { + // singleton + } +} diff --git a/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java b/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java index b6a894517..e5b71a281 100644 --- a/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java @@ -168,6 +168,10 @@ public class FileUtils { } } + public static Path getTempRootDir() { + return TEMP_ROOT_DIR; + } + public static void deleteTempRootDir() { deleteDirIfExists(TEMP_ROOT_DIR); } diff --git a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java index 11c08c726..1b13438c7 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java @@ -23,16 +23,17 @@ import jadx.api.impl.InMemoryCodeCache; import jadx.api.metadata.ICodeNodeRef; import jadx.api.usage.impl.EmptyUsageInfoCache; import jadx.api.usage.impl.InMemoryUsageInfoCache; +import jadx.cli.plugins.JadxFilesGetter; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ProcessState; import jadx.core.dex.nodes.RootNode; +import jadx.core.plugins.AppContext; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.cache.code.CodeStringCache; import jadx.gui.cache.code.disk.BufferCodeCache; import jadx.gui.cache.code.disk.DiskCodeCache; import jadx.gui.cache.usage.UsageInfoCache; import jadx.gui.plugins.context.CommonGuiPluginsContext; -import jadx.gui.plugins.context.GuiPluginContext; import jadx.gui.settings.JadxProject; import jadx.gui.settings.JadxSettings; import jadx.gui.ui.MainWindow; @@ -67,7 +68,7 @@ public class JadxWrapper { project.fillJadxArgs(jadxArgs); decompiler = new JadxDecompiler(jadxArgs); - initGuiPluginsContext(); + guiPluginsContext = initGuiPluginsContext(decompiler, mainWindow); initUsageCache(jadxArgs); decompiler.load(); initCodeCache(); @@ -139,12 +140,15 @@ public class JadxWrapper { } } - private void initGuiPluginsContext() { - guiPluginsContext = new CommonGuiPluginsContext(mainWindow); + public static CommonGuiPluginsContext initGuiPluginsContext(JadxDecompiler decompiler, MainWindow mainWindow) { + CommonGuiPluginsContext guiPluginsContext = new CommonGuiPluginsContext(mainWindow); decompiler.getPluginManager().registerAddPluginListener(pluginContext -> { - GuiPluginContext guiContext = guiPluginsContext.buildForPlugin(pluginContext); - pluginContext.setGuiContext(guiContext); + AppContext appContext = new AppContext(); + appContext.setGuiContext(guiPluginsContext.buildForPlugin(pluginContext)); + appContext.setFilesGetter(JadxFilesGetter.INSTANCE); + pluginContext.setAppContext(appContext); }); + return guiPluginsContext; } public CommonGuiPluginsContext getGuiPluginsContext() { diff --git a/jadx-gui/src/main/java/jadx/gui/utils/plugins/CollectPlugins.java b/jadx-gui/src/main/java/jadx/gui/utils/plugins/CollectPlugins.java index 5d856e3ab..8046d9c23 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/plugins/CollectPlugins.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/plugins/CollectPlugins.java @@ -9,8 +9,7 @@ import jadx.api.JadxArgs; import jadx.api.JadxDecompiler; import jadx.core.plugins.JadxPluginManager; import jadx.core.plugins.PluginContext; -import jadx.gui.plugins.context.CommonGuiPluginsContext; -import jadx.gui.plugins.context.GuiPluginContext; +import jadx.gui.JadxWrapper; import jadx.gui.ui.MainWindow; import jadx.plugins.tools.JadxExternalPluginsLoader; @@ -36,11 +35,7 @@ public class CollectPlugins { try (JadxDecompiler decompiler = new JadxDecompiler(new JadxArgs())) { JadxPluginManager pluginManager = decompiler.getPluginManager(); pluginManager.load(new JadxExternalPluginsLoader()); - CommonGuiPluginsContext guiPluginsContext = new CommonGuiPluginsContext(mainWindow); - decompiler.getPluginManager().registerAddPluginListener(pluginContext -> { - GuiPluginContext guiContext = guiPluginsContext.buildForPlugin(pluginContext); - pluginContext.setGuiContext(guiContext); - }); + JadxWrapper.initGuiPluginsContext(decompiler, mainWindow); SortedSet missingPlugins = new TreeSet<>(); for (PluginContext context : pluginManager.getAllPluginContexts()) { if (!allPlugins.contains(context)) {