From e3c168c5a6c249e7ecd6a2cbef0ee939d20727c6 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 19 Jul 2026 09:09:21 +0900 Subject: [PATCH] Android: Isolate game execution process The launcher and GameActivity previously ran in the same process. Native globals and library state therefore survived after returning to the launcher, leaking static data from one game to the next game. Run GameActivity in a private :game process and terminate it after SDL shutdown completes, so every game starts with fresh native state. Keep the launcher in the main process and refresh its game list from disk when it resumes. --- android/app/src/main/AndroidManifest.xml | 1 + .../kichikuou/xsystem35/GameActivity.kt | 60 +++++++++++++++---- .../io/github/kichikuou/xsystem35/Launcher.kt | 5 +- .../kichikuou/xsystem35/LauncherActivity.kt | 5 ++ 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6fb7073..f6a413e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -78,6 +78,7 @@ { return arrayOf("SDL2", "xsystem35") } @@ -75,7 +88,6 @@ class GameActivity : SDLActivity() { return } File(gameRoot, Launcher.TITLE_FILE).writeText(str) - Launcher.updateGameList() } private fun textInputDialog(msg: String, oldVal: String, maxLen: Int, result: Array) { @@ -154,11 +166,21 @@ class GameActivity : SDLActivity() { } private class MidiPlayer { + private enum class State { + STOPPED, + PLAYING, + PAUSED, + RELEASED, + } + private val player = MediaPlayer() - private var playing = false - private var playerPaused = false + private var state = State.STOPPED fun start(path: String, loop: Boolean) { + if (state == State.RELEASED) { + return + } + state = State.STOPPED try { player.apply { reset() @@ -167,7 +189,7 @@ private class MidiPlayer { prepare() start() } - playing = true + state = State.PLAYING } catch (e: IOException) { Log.e("midiStart", "Cannot play midi", e) player.reset() @@ -175,27 +197,41 @@ private class MidiPlayer { } fun stop() { - if (playing && player.isPlaying) { - player.stop() - playing = false + when (state) { + State.PLAYING, State.PAUSED -> { + player.stop() + state = State.STOPPED + } + State.STOPPED, State.RELEASED -> Unit } } fun currentPosition(): Int { - return if (playing) player.currentPosition else 0 + return when (state) { + State.PLAYING, State.PAUSED -> player.currentPosition + State.STOPPED, State.RELEASED -> 0 + } } fun onActivityStop() { - if (playing && player.isPlaying) { + if (state == State.PLAYING && player.isPlaying) { player.pause() - playerPaused = true + state = State.PAUSED } } fun onActivityResume() { - if (playerPaused) { + if (state == State.PAUSED) { player.start() - playerPaused = false + state = State.PLAYING } } + + fun release() { + if (state == State.RELEASED) { + return + } + state = State.RELEASED + player.release() + } } diff --git a/android/app/src/main/java/io/github/kichikuou/xsystem35/Launcher.kt b/android/app/src/main/java/io/github/kichikuou/xsystem35/Launcher.kt index e932061..f7887ef 100644 --- a/android/app/src/main/java/io/github/kichikuou/xsystem35/Launcher.kt +++ b/android/app/src/main/java/io/github/kichikuou/xsystem35/Launcher.kt @@ -60,9 +60,6 @@ class Launcher private constructor(rootDir: File) { return gLauncher!! } - fun updateGameList() { - gLauncher?.updateGameList() - } } private val store = GameStore(rootDir) @@ -160,7 +157,7 @@ class Launcher private constructor(rootDir: File) { observer?.onGameListChange() } - private fun updateGameList() { + fun refreshGameList() { store.updateGameList() observer?.onGameListChange() } diff --git a/android/app/src/main/java/io/github/kichikuou/xsystem35/LauncherActivity.kt b/android/app/src/main/java/io/github/kichikuou/xsystem35/LauncherActivity.kt index e55bdc9..71a61bc 100644 --- a/android/app/src/main/java/io/github/kichikuou/xsystem35/LauncherActivity.kt +++ b/android/app/src/main/java/io/github/kichikuou/xsystem35/LauncherActivity.kt @@ -68,6 +68,11 @@ class LauncherActivity : Activity(), LauncherObserver { super.onDestroy() } + override fun onResume() { + super.onResume() + launcher.refreshGameList() + } + private fun onListItemClick(position: Int) { startGame(launcher.games[position].path, null) }