From b6734a81afa2ae5981b288cca6145a808fe5dfa0 Mon Sep 17 00:00:00 2001 From: EpicDima <37583380+EpicDima@users.noreply.github.com> Date: Tue, 3 Sep 2024 19:02:28 +0300 Subject: [PATCH] Add "Min API" setting (#69) Changing min API can be useful when working with R8, when it changes the code for older APIs. Example: ```kotlin import java. lang. Thread import android.os.Looper fun test3() { Looper.getMainLooper().isCurrentThread() } ``` DEX with min API 21 (R8 enabled): ```dex class KotlinExplorerKt$$ExternalSyntheticApiModelOutline0 void KotlinExplorerKt$$ExternalSyntheticApiModelOutline0.m(android.os.Looper) -- 2 instructions 0000: invoke-virtual {v0}, Landroid/os/Looper;.isCurrentThread:()Z // method@0003 0003: return-void class KotlinExplorerKt void KotlinExplorerKt.test3() -- 4 instructions 0000: invoke-static {}, Landroid/os/Looper;.getMainLooper:()Landroid/os/Looper; // method@0002 0003: move-result-object v0 0004: invoke-static {v0}, LKotlinExplorerKt$$ExternalSyntheticApiModelOutline0;.m:(Landroid/os/Looper;)V // method@0000 0007: return-void ``` DEX with min API 26 (R8 enabled): ```dex class KotlinExplorerKt void KotlinExplorerKt.test3() -- 4 instructions 0000: invoke-static {}, Landroid/os/Looper;.getMainLooper:()Landroid/os/Looper; // method@0001 0003: move-result-object v0 0004: invoke-virtual {v0}, Landroid/os/Looper;.isCurrentThread:()Z // method@0002 0007: return-void ``` --- .../kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt | 3 ++- .../kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt | 1 + src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Settings.kt | 5 +++++ src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/State.kt | 5 +++-- .../dev/romainguy/kotlin/explorer/build/DexCompiler.kt | 4 ++-- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt index b1ce29a3..0d928cc6 100644 --- a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt @@ -96,6 +96,7 @@ suspend fun buildAndDisassemble( toolPaths: ToolPaths, source: String, r8rules: String, + minApi: Int, instructionSets: Map, onByteCode: (CodeContent) -> Unit, onDex: (CodeContent) -> Unit, @@ -150,7 +151,7 @@ suspend fun buildAndDisassemble( launch(ui) { updater.advance("") } } - val dexCompiler = DexCompiler(toolPaths, directory, r8rules) + val dexCompiler = DexCompiler(toolPaths, directory, r8rules, minApi) val dex = dexCompiler.buildDex(optimize, keepEverything) diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt index 1cabdb95..eff7b10e 100644 --- a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/KotlinExplorer.kt @@ -433,6 +433,7 @@ private fun FrameWindowScope.MainMenu( explorerState.toolPaths, sourceTextArea.text, explorerState.r8Rules, + explorerState.minApi, instructionSets, onByteCodeUpdate, onDexUpdate, diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Settings.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Settings.kt index bc442d88..4cdf7c01 100644 --- a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Settings.kt +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Settings.kt @@ -39,6 +39,7 @@ fun Settings( val androidHome = rememberTextFieldState(state.androidHome) val kotlinHome = rememberTextFieldState(state.kotlinHome) val r8rules = rememberTextFieldState(state.r8Rules) + val minApi = rememberTextFieldState(state.minApi.toString()) val indent = rememberTextFieldState(state.indent.toString()) val lineNumberWidth = rememberTextFieldState(state.lineNumberWidth.toString()) val decompileHiddenIsa = remember { mutableStateOf(state.decompileHiddenIsa) } @@ -47,6 +48,7 @@ fun Settings( androidHome.text.toString(), kotlinHome.text.toString(), r8rules.text.toString(), + minApi.text.toString(), indent.text.toString(), lineNumberWidth.text.toString(), decompileHiddenIsa.value @@ -61,6 +63,7 @@ fun Settings( IntSetting("Decompiled code indent: ", indent, minValue = 2) IntSetting("Line number column width: ", lineNumberWidth, minValue = 1) MultiLineStringSetting("R8 rules: ", r8rules) + IntSetting("Min API: ", minApi, minValue = 1) BooleanSetting("Decompile hidden instruction sets", decompileHiddenIsa) Spacer(modifier = Modifier.height(8.dp)) Buttons(saveEnabled = toolPaths.isValid, onSaveClick, onDismissRequest) @@ -87,6 +90,7 @@ private fun ExplorerState.saveState( androidHome: String, kotlinHome: String, r8Rules: String, + minApi: String, indent: String, lineNumberWidth: String, decompileHiddenIsa: Boolean, @@ -94,6 +98,7 @@ private fun ExplorerState.saveState( this.androidHome = androidHome this.kotlinHome = kotlinHome this.r8Rules = r8Rules + this.minApi = minApi.toIntOrNull() ?: 21 this.indent = indent.toIntOrNull() ?: 4 this.lineNumberWidth = lineNumberWidth.toIntOrNull() ?: 4 this.decompileHiddenIsa = decompileHiddenIsa diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/State.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/State.kt index ace78086..a0656c8e 100644 --- a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/State.kt +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/State.kt @@ -30,6 +30,7 @@ private const val KotlinHome = "KOTLIN_HOME" private const val Optimize = "OPTIMIZE" private const val KeepEverything = "KEEP_EVERYTHING" private const val R8Rules = "R8_RULES" +private const val MinApi = "MIN_API" private const val AutoBuildOnStartup = "AUTO_BUILD_ON_STARTUP" private const val Presentation = "PRESENTATION" private const val ShowLineNumbers = "SHOW_LINE_NUMBERS" @@ -58,6 +59,7 @@ class ExplorerState { var optimize by BooleanState(Optimize, true) var keepEverything by BooleanState(KeepEverything, true) var r8Rules by StringState(R8Rules, "") + var minApi by IntState(MinApi, 21) var autoBuildOnStartup by BooleanState(AutoBuildOnStartup, false) var presentationMode by BooleanState(Presentation, false) var showLineNumbers by BooleanState(ShowLineNumbers, false) @@ -80,8 +82,7 @@ class ExplorerState { toolPaths = createToolPaths() } - private fun createToolPaths() = - ToolPaths(directory, Path.of(androidHome.toString()), Path.of(kotlinHome.toString())) + private fun createToolPaths() = ToolPaths(directory, Path.of(androidHome), Path.of(kotlinHome)) private inner class BooleanState(key: String, initialValue: Boolean) : SettingsState(key, initialValue, { toBoolean() }) diff --git a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/build/DexCompiler.kt b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/build/DexCompiler.kt index e46ee984..c603a9b0 100644 --- a/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/build/DexCompiler.kt +++ b/src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/build/DexCompiler.kt @@ -23,7 +23,7 @@ import java.nio.file.Files import java.nio.file.Path import kotlin.io.path.* -class DexCompiler(private val toolPaths: ToolPaths, private val outputDirectory: Path, private val r8rules: String) { +class DexCompiler(private val toolPaths: ToolPaths, private val outputDirectory: Path, private val r8rules: String, private val minApi: Int) { suspend fun buildDex(optimize: Boolean, keepEverything: Boolean): ProcessResult { return process(*buildDexCommand(optimize, keepEverything), directory = outputDirectory) } @@ -45,7 +45,7 @@ class DexCompiler(private val toolPaths: ToolPaths, private val outputDirectory: add(toolPaths.d8.toString()) add(if (optimize) "com.android.tools.r8.R8" else "com.android.tools.r8.D8") add("--min-api") - add("21") + add(minApi.toString()) if (optimize) { add("--pg-conf") add("rules.txt")