From 29208479390eff6824b74300f269c89471336318 Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:52:02 +0000 Subject: [PATCH 1/8] fix(runtime): keep the user's home when a runtime update fails mid-swap --- .../runtime/LinuxRuntimeInstaller.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntimeInstaller.java b/app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntimeInstaller.java index 66f8f918a..730ac4eff 100644 --- a/app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntimeInstaller.java +++ b/app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntimeInstaller.java @@ -210,6 +210,8 @@ public final class LinuxRuntimeInstaller { // runtime that isInstalled() would happily launch. File root = LinuxRuntime.rootDir(context); File staging = new File(root.getParentFile(), LinuxRuntime.DIR + ".new"); + File old = new File(root.getParentFile(), LinuxRuntime.DIR + ".old"); + recoverInterruptedSwap(root, staging, old); FileUtils.delete(staging); if (!staging.mkdirs()) return false; if (listener != null) listener.onProgress("Extracting", -1); @@ -219,7 +221,6 @@ public final class LinuxRuntimeInstaller { } FileUtils.writeString(new File(staging, VERSION_FILE), release.version); - File old = new File(root.getParentFile(), LinuxRuntime.DIR + ".old"); FileUtils.delete(old); if (root.isDirectory() && !root.renameTo(old)) { FileUtils.delete(staging); @@ -244,6 +245,10 @@ public final class LinuxRuntimeInstaller { } if (!staging.renameTo(root)) { + // The user's home is inside staging by now: take it back before the old rootfs + // returns, or the next install's cleanup of staging deletes it. + File keptTo = new File(staging, USER_DATA); + if (keptTo.isDirectory() && old.isDirectory()) keptTo.renameTo(new File(old, USER_DATA)); if (old.isDirectory()) old.renameTo(root); return false; } @@ -257,6 +262,28 @@ public final class LinuxRuntimeInstaller { } } + /** + * Puts back what an update killed mid-swap left behind, before staging is cleared: the user's + * home may be sitting in staging and the previous rootfs in linuxfs.old. + */ + private static void recoverInterruptedSwap(File root, File staging, File old) { + File target = root.isDirectory() ? root : old; + File stagedHome = new File(staging, USER_DATA); + File home = new File(target, USER_DATA); + if (target.isDirectory() && stagedHome.isDirectory() && (!home.exists() || isEmptyDir(home))) { + FileUtils.delete(home); + if (stagedHome.renameTo(home)) Log.w(TAG, "recovered " + USER_DATA + " from an interrupted update"); + } + if (!root.isDirectory() && old.isDirectory() && old.renameTo(root)) { + Log.w(TAG, "restored the previous runtime after an interrupted update"); + } + } + + private static boolean isEmptyDir(File dir) { + String[] names = dir.list(); + return dir.isDirectory() && names != null && names.length == 0; + } + /** Removes the runtime; returns false without touching it while an install is running. */ public static boolean uninstall(Context context) { synchronized (JOB_LOCK) { From c029134ba2a1c1a5c1a592e1047ba74f560945e4 Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:52:02 +0000 Subject: [PATCH 2/8] chore(release): bump to 0.2.1 and check the version at release time --- .github/workflows/pr-release-publish.yml | 6 ++++-- .github/workflows/release.yml | 4 ++++ app/build.gradle | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr-release-publish.yml b/.github/workflows/pr-release-publish.yml index 72ef506be..810417565 100644 --- a/.github/workflows/pr-release-publish.yml +++ b/.github/workflows/pr-release-publish.yml @@ -79,8 +79,10 @@ jobs: } stable=$(package_line "$RUNNER_TEMP/stable/DroidDeck-$stable_tag.apk") candidate=$(package_line "${apks[0]}") - [[ "$stable" =~ ^com\.droiddeck\.launcher\ [0-9]+$ && "$candidate" == "$stable" ]] || { - echo "::error::PR package/versionCode '$candidate' differs from stable '$stable'"; exit 1; + # Same package, and a versionCode no lower than stable's, so the APK installs over it. + [[ "$stable" =~ ^com\.droiddeck\.launcher\ [0-9]+$ && "$candidate" =~ ^com\.droiddeck\.launcher\ [0-9]+$ && + ${candidate##* } -ge ${stable##* } ]] || { + echo "::error::PR package/versionCode '$candidate' cannot install over stable '$stable'"; exit 1; } current=$(gh api "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER") diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2620b96df..870c6b5f2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,6 +35,10 @@ jobs: run: | set -euo pipefail [[ $VERSION =~ ^[0-9A-Za-z._-]+$ ]] || { echo "::error::version '$VERSION': letters, digits, . _ - only"; exit 1; } + name=$(sed -n 's/^ *versionName "\(.*\)"$/\1/p' app/build.gradle) + [[ $VERSION == "$name" || $VERSION == "$name"-* ]] || { + echo "::error::version '$VERSION' does not match versionName '$name' in app/build.gradle: bump versionName and versionCode first"; exit 1; + } runs=$(gh run list -R "$GITHUB_REPOSITORY" --workflow build.yml --branch main --commit "$GITHUB_SHA" \ --status success --json databaseId,event,headSha -L 20) id=$(jq -r --arg sha "$GITHUB_SHA" \ diff --git a/app/build.gradle b/app/build.gradle index 666501a65..09585d08f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,8 +63,8 @@ android { // file out of its own data directory, and this app's entire job is to exec a rootfs: // proot, gamescope, the Steam client and everything it launches all live under files/. targetSdkVersion 28 - versionCode 8 - versionName "0.1.7" + versionCode 9 + versionName "0.2.1" buildConfigField "String", "BUILD_LABEL", "\"${escapedBuildLabel}\"" ndk { From 6e25e0b007e4a68107aafd0ba501bcf240d764f1 Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:52:02 +0000 Subject: [PATCH 3/8] fix(session): don't launch a cancelled session or end a newer one --- .../launcher/session/SessionService.kt | 57 ++++++++++++++----- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt b/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt index 419b4258f..fc529f147 100644 --- a/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt +++ b/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt @@ -57,6 +57,7 @@ import java.util.Locale */ class SessionService : Service() { private val components = java.util.concurrent.CopyOnWriteArrayList() + private val stopLock = Any() private var wakeLock: PowerManager.WakeLock? = null private var wifiLock: WifiManager.WifiLock? = null private var sessionPid = -1 @@ -84,7 +85,7 @@ class SessionService : Service() { } } /** Counts sessions this service has started; a process exit from an earlier one is ignored. */ - private var sessionGen = 0 + @Volatile private var sessionGen = 0 override fun onCreate() { super.onCreate() @@ -392,6 +393,13 @@ class SessionService : Service() { networkLink.attach(this) networkLink.publish() components.add(networkLink) + // Stopped from the loading screen while this was still setting up: the teardown has run + // and found nothing, so nothing may start behind it. + if (gen != sessionGen || !SessionState.running) { + Log.i(TAG, "session stopped while it was starting; not launching it") + if (gen == sessionGen) components.clear() + return + } components.forEach { it.start() } val line = command.joinToString(" ") { @@ -402,7 +410,7 @@ class SessionService : Service() { // by the teardown a second after the new one has started, and its exit used to arrive // here as "session ended: 137" and end the NEW session. An exit belongs to the session // that started it. - sessionPid = HostProcess.start(line, hostEnv.asArray(), root, { status -> + val pid = HostProcess.start(line, hostEnv.asArray(), root, { status -> if (gen != sessionGen) { Log.i(TAG, "an earlier session's process ended ($status); the current one carries on") return@start @@ -410,12 +418,25 @@ class SessionService : Service() { Log.i(TAG, "session ended: $status") stopSession(status ?: -1) }, null) - Log.i(TAG, "session pid $sessionPid, log ${sessionLog.path}") - if (gen == sessionGen && SessionState.running && sessionPid > 1) { - SessionEvents.guestStarted(sessionPid) - } else if (gen == sessionGen && SessionState.running) { - SessionEvents.record("guest.start_failed", mapOf("pid" to sessionPid)) - SessionEvents.fail("GUEST_START_FAILED", "The guest process could not be started", sessionPid) + Log.i(TAG, "session pid $pid, log ${sessionLog.path}") + if (gen != sessionGen || !SessionState.running) { + // Stopped in the moment the guest was launched: the teardown already ran without it. + Log.i(TAG, "session stopped while its guest was starting; taking it down") + if (gen == sessionGen) { + launchWatcher?.stopWatching() + launchWatcher = null + components.reversed().forEach { runCatching { it.stop() } } + components.clear() + } + if (pid > 1) Thread({ teardown(pid) }, "session-teardown").start() + return + } + sessionPid = pid + if (pid > 1) { + SessionEvents.guestStarted(pid) + } else { + SessionEvents.record("guest.start_failed", mapOf("pid" to pid)) + SessionEvents.fail("GUEST_START_FAILED", "The guest process could not be started", pid) stopSession(-1) return } @@ -877,8 +898,14 @@ class SessionService : Service() { } } - private fun finishSessionStop(status: Int) { + private fun finishSessionStop(status: Int, stoppedGen: Int) { mainHandler.post { + // Play was pressed again while this teardown ran: the locks, the activity and the + // service now belong to the new session. + if (stoppedGen != sessionGen || SessionState.running) { + Log.i(TAG, "session $stoppedGen finished stopping after a new one started") + return@post + } SessionState.suspended = false SessionState.guestPid = -1 releaseLocks() @@ -897,8 +924,12 @@ class SessionService : Service() { } private fun stopSession(status: Int) { - if (!SessionState.running) return - SessionState.running = false + // Called from the main thread, the session-start thread and the guest's exit watcher. + synchronized(stopLock) { + if (!SessionState.running) return + SessionState.running = false + } + val stoppedGen = sessionGen SessionState.stopRequested = false SessionEvents.record("guest.exited", mapOf("status" to status)) SessionEvents.transition(SessionPhase.STOPPING, "session.stopping", mapOf("status" to status)) @@ -942,10 +973,10 @@ class SessionService : Service() { auxiliary.forEach { (pid, started) -> teardown(pid, started) } if (prootPid > 1) teardown(prootPid) killGuestLeftovers() - finishSessionStop(status) + finishSessionStop(status, stoppedGen) }, "session-teardown").start() } else { - finishSessionStop(status) + finishSessionStop(status, stoppedGen) } } if (prootPid > 1) acquireLocks() From 1ea8eb6cb308dc708e0fe8bd8346646db0fcb68c Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:52:02 +0000 Subject: [PATCH 4/8] fix(session): cancel a session start that is still setting up --- .../java/com/droiddeck/launcher/session/SessionService.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt b/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt index fc529f147..df2529982 100644 --- a/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt +++ b/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt @@ -1158,6 +1158,12 @@ class SessionService : Service() { } fun stop(context: Context) { + // Not running yet (still downloading or setting up): the start path checks this flag + // and cancels, and a service started here would have no session to stop. + if (!SessionState.running) { + SessionState.stopRequested = true + return + } context.startService(Intent(context, SessionService::class.java).setAction(ACTION_STOP)) } From eeeba13b6c8c33a60b79177d01d110304f5af16d Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:52:03 +0000 Subject: [PATCH 5/8] fix(session): keep a retried session's first-frame and hud listeners --- .../com/droiddeck/launcher/SessionActivity.kt | 17 +++++++++-------- .../com/droiddeck/launcher/session/PerfHud.kt | 2 +- .../launcher/wayland/WaylandCompositor.java | 11 +++++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/droiddeck/launcher/SessionActivity.kt b/app/src/main/java/com/droiddeck/launcher/SessionActivity.kt index d10c89eb0..ae6c63ec4 100644 --- a/app/src/main/java/com/droiddeck/launcher/SessionActivity.kt +++ b/app/src/main/java/com/droiddeck/launcher/SessionActivity.kt @@ -264,13 +264,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback { handleHomeGuideIntent(intent) updateOnScreenControls() - WaylandCompositor.setFirstFrameListener { - SessionEvents.firstFrame() - runOnUiThread { - loading.visible = false - hud.start() - } - } + WaylandCompositor.setFirstFrameListener(firstFrameListener) SessionEvents.markReadyIfPossible() SessionState.endListener = endListener // A single Back opens the session menu; two quick presses/swipes send the Steam QAM chord. @@ -1537,6 +1531,13 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback { /** Ours, so a finishing activity never unhooks the one that replaced it. */ private val endListener: (Int) -> Unit = { status -> onSessionEnded(status) } + private val firstFrameListener = Runnable { + SessionEvents.firstFrame() + runOnUiThread { + loading.visible = false + hud.start() + } + } override fun onDestroy() { // Deliberately does NOT end the session: this activity can be destroyed while the user is @@ -1549,7 +1550,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback { if (::hud.isInitialized) hud.stop() padBridge?.stop() if (SessionState.endListener === endListener) SessionState.endListener = null - WaylandCompositor.setFirstFrameListener(null) + WaylandCompositor.clearFirstFrameListener(firstFrameListener) super.onDestroy() } diff --git a/app/src/main/java/com/droiddeck/launcher/session/PerfHud.kt b/app/src/main/java/com/droiddeck/launcher/session/PerfHud.kt index ae3326c1e..b0d49257b 100644 --- a/app/src/main/java/com/droiddeck/launcher/session/PerfHud.kt +++ b/app/src/main/java/com/droiddeck/launcher/session/PerfHud.kt @@ -81,7 +81,7 @@ class PerfHud(context: Context) { fun stop() { running = false - WaylandCompositor.setGameListener(null) + WaylandCompositor.clearGameListener(listener) text = "" } diff --git a/app/src/main/java/com/droiddeck/launcher/wayland/WaylandCompositor.java b/app/src/main/java/com/droiddeck/launcher/wayland/WaylandCompositor.java index ffd1a28e5..0af6057a5 100644 --- a/app/src/main/java/com/droiddeck/launcher/wayland/WaylandCompositor.java +++ b/app/src/main/java/com/droiddeck/launcher/wayland/WaylandCompositor.java @@ -26,6 +26,12 @@ public final class WaylandCompositor { * listener must marshal to the UI thread itself. */ public static void setFirstFrameListener(Runnable r) { firstFrameListener = r; } + /** Clears the first-frame listener only if it is still {@code r}, so an activity going away + * never drops the one its replacement registered. */ + public static synchronized void clearFirstFrameListener(Runnable r) { + if (firstFrameListener == r) firstFrameListener = null; + } + /** Invoked from native (banner_on_first_frame) on the first present. */ @SuppressWarnings("unused") static void onFirstFramePresented() { @@ -52,6 +58,11 @@ public final class WaylandCompositor { public static void setGameListener(GameListener l) { gameListener = l; } + /** Clears the game listener only if it is still {@code l}. */ + public static synchronized void clearGameListener(GameListener l) { + if (gameListener == l) gameListener = null; + } + /** Invoked from native (banner_on_game_surface). */ @SuppressWarnings("unused") static void onGameSurface(String window, String gpuName) { From dcf1dc33b1ed350c422b90f9fbc6e7a821020056 Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:52:03 +0000 Subject: [PATCH 6/8] fix(home): open drawer apps in their own task --- app/src/main/java/com/droiddeck/launcher/HomeApp.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/droiddeck/launcher/HomeApp.kt b/app/src/main/java/com/droiddeck/launcher/HomeApp.kt index f71ca928a..7def29754 100644 --- a/app/src/main/java/com/droiddeck/launcher/HomeApp.kt +++ b/app/src/main/java/com/droiddeck/launcher/HomeApp.kt @@ -97,13 +97,14 @@ object HomeApp { val intent = Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setComponent(ComponentName(app.packageName, app.className)) + // Keep the target app's task separate from DroidDeck. Without this, Android puts the app on + // top of the caller's task: swiping it out of Recents then removes DroidDeck's task and + // ends the session, and on another display the entire task moves there. + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) if (displayId == null) { context.startActivity(intent) return } - // Keep the target app's task separate from DroidDeck. Without this, Android can put the - // app on top of the caller's task and move the entire task to the chosen display. - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) val options = ActivityOptions.makeBasic().setLaunchDisplayId(displayId) context.startActivity(intent, options.toBundle()) } From 738c40cbb9b08e32da3566815f26c2ab95898d34 Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:52:03 +0000 Subject: [PATCH 7/8] fix(session): stop the session script's own loops when steam exits --- tools/linuxfs/overlay/usr/local/bin/bannerlator-session | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/linuxfs/overlay/usr/local/bin/bannerlator-session b/tools/linuxfs/overlay/usr/local/bin/bannerlator-session index 4e8402291..cae72823a 100755 --- a/tools/linuxfs/overlay/usr/local/bin/bannerlator-session +++ b/tools/linuxfs/overlay/usr/local/bin/bannerlator-session @@ -591,6 +591,10 @@ BUSCONF wait "$decky_supervisor" 2>/dev/null || true echo "== Decky: session supervisor stopped" fi + # This script's own loops and daemons (the fill-screen watcher never ends) would pass to + # gamescope's reaper when it exits and hold the compositor up on a black screen. + _bl_jobs=$(jobs -p) + [ -n "$_bl_jobs" ] && kill $_bl_jobs 2>/dev/null reap_orphans fi exit "$rc" From 20b63bba9bcfb15ee008c1e6ebcf639c0cd18bf4 Mon Sep 17 00:00:00 2001 From: xXJsonDeruloXx Date: Mon, 28 Sep 2026 10:32:12 -0400 Subject: [PATCH 8/8] chore(release): set version 0.2.0 and remove code comments --- .github/workflows/pr-release-publish.yml | 1 - app/build.gradle | 2 +- app/src/main/java/com/droiddeck/launcher/HomeApp.kt | 3 --- .../droiddeck/launcher/runtime/LinuxRuntimeInstaller.java | 6 ------ .../java/com/droiddeck/launcher/session/SessionService.kt | 8 -------- .../com/droiddeck/launcher/wayland/WaylandCompositor.java | 3 --- tools/linuxfs/overlay/usr/local/bin/bannerlator-session | 2 -- 7 files changed, 1 insertion(+), 24 deletions(-) diff --git a/.github/workflows/pr-release-publish.yml b/.github/workflows/pr-release-publish.yml index 810417565..1759674c1 100644 --- a/.github/workflows/pr-release-publish.yml +++ b/.github/workflows/pr-release-publish.yml @@ -79,7 +79,6 @@ jobs: } stable=$(package_line "$RUNNER_TEMP/stable/DroidDeck-$stable_tag.apk") candidate=$(package_line "${apks[0]}") - # Same package, and a versionCode no lower than stable's, so the APK installs over it. [[ "$stable" =~ ^com\.droiddeck\.launcher\ [0-9]+$ && "$candidate" =~ ^com\.droiddeck\.launcher\ [0-9]+$ && ${candidate##* } -ge ${stable##* } ]] || { echo "::error::PR package/versionCode '$candidate' cannot install over stable '$stable'"; exit 1; diff --git a/app/build.gradle b/app/build.gradle index 09585d08f..4195f0be8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -64,7 +64,7 @@ android { // proot, gamescope, the Steam client and everything it launches all live under files/. targetSdkVersion 28 versionCode 9 - versionName "0.2.1" + versionName "0.2.0" buildConfigField "String", "BUILD_LABEL", "\"${escapedBuildLabel}\"" ndk { diff --git a/app/src/main/java/com/droiddeck/launcher/HomeApp.kt b/app/src/main/java/com/droiddeck/launcher/HomeApp.kt index 7def29754..cc1b2afc0 100644 --- a/app/src/main/java/com/droiddeck/launcher/HomeApp.kt +++ b/app/src/main/java/com/droiddeck/launcher/HomeApp.kt @@ -97,9 +97,6 @@ object HomeApp { val intent = Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) .setComponent(ComponentName(app.packageName, app.className)) - // Keep the target app's task separate from DroidDeck. Without this, Android puts the app on - // top of the caller's task: swiping it out of Recents then removes DroidDeck's task and - // ends the session, and on another display the entire task moves there. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) if (displayId == null) { context.startActivity(intent) diff --git a/app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntimeInstaller.java b/app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntimeInstaller.java index 730ac4eff..4643e9b40 100644 --- a/app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntimeInstaller.java +++ b/app/src/main/java/com/droiddeck/launcher/runtime/LinuxRuntimeInstaller.java @@ -245,8 +245,6 @@ public final class LinuxRuntimeInstaller { } if (!staging.renameTo(root)) { - // The user's home is inside staging by now: take it back before the old rootfs - // returns, or the next install's cleanup of staging deletes it. File keptTo = new File(staging, USER_DATA); if (keptTo.isDirectory() && old.isDirectory()) keptTo.renameTo(new File(old, USER_DATA)); if (old.isDirectory()) old.renameTo(root); @@ -262,10 +260,6 @@ public final class LinuxRuntimeInstaller { } } - /** - * Puts back what an update killed mid-swap left behind, before staging is cleared: the user's - * home may be sitting in staging and the previous rootfs in linuxfs.old. - */ private static void recoverInterruptedSwap(File root, File staging, File old) { File target = root.isDirectory() ? root : old; File stagedHome = new File(staging, USER_DATA); diff --git a/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt b/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt index df2529982..87d690743 100644 --- a/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt +++ b/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt @@ -393,8 +393,6 @@ class SessionService : Service() { networkLink.attach(this) networkLink.publish() components.add(networkLink) - // Stopped from the loading screen while this was still setting up: the teardown has run - // and found nothing, so nothing may start behind it. if (gen != sessionGen || !SessionState.running) { Log.i(TAG, "session stopped while it was starting; not launching it") if (gen == sessionGen) components.clear() @@ -420,7 +418,6 @@ class SessionService : Service() { }, null) Log.i(TAG, "session pid $pid, log ${sessionLog.path}") if (gen != sessionGen || !SessionState.running) { - // Stopped in the moment the guest was launched: the teardown already ran without it. Log.i(TAG, "session stopped while its guest was starting; taking it down") if (gen == sessionGen) { launchWatcher?.stopWatching() @@ -900,8 +897,6 @@ class SessionService : Service() { private fun finishSessionStop(status: Int, stoppedGen: Int) { mainHandler.post { - // Play was pressed again while this teardown ran: the locks, the activity and the - // service now belong to the new session. if (stoppedGen != sessionGen || SessionState.running) { Log.i(TAG, "session $stoppedGen finished stopping after a new one started") return@post @@ -924,7 +919,6 @@ class SessionService : Service() { } private fun stopSession(status: Int) { - // Called from the main thread, the session-start thread and the guest's exit watcher. synchronized(stopLock) { if (!SessionState.running) return SessionState.running = false @@ -1158,8 +1152,6 @@ class SessionService : Service() { } fun stop(context: Context) { - // Not running yet (still downloading or setting up): the start path checks this flag - // and cancels, and a service started here would have no session to stop. if (!SessionState.running) { SessionState.stopRequested = true return diff --git a/app/src/main/java/com/droiddeck/launcher/wayland/WaylandCompositor.java b/app/src/main/java/com/droiddeck/launcher/wayland/WaylandCompositor.java index 0af6057a5..7b7717869 100644 --- a/app/src/main/java/com/droiddeck/launcher/wayland/WaylandCompositor.java +++ b/app/src/main/java/com/droiddeck/launcher/wayland/WaylandCompositor.java @@ -26,8 +26,6 @@ public final class WaylandCompositor { * listener must marshal to the UI thread itself. */ public static void setFirstFrameListener(Runnable r) { firstFrameListener = r; } - /** Clears the first-frame listener only if it is still {@code r}, so an activity going away - * never drops the one its replacement registered. */ public static synchronized void clearFirstFrameListener(Runnable r) { if (firstFrameListener == r) firstFrameListener = null; } @@ -58,7 +56,6 @@ public final class WaylandCompositor { public static void setGameListener(GameListener l) { gameListener = l; } - /** Clears the game listener only if it is still {@code l}. */ public static synchronized void clearGameListener(GameListener l) { if (gameListener == l) gameListener = null; } diff --git a/tools/linuxfs/overlay/usr/local/bin/bannerlator-session b/tools/linuxfs/overlay/usr/local/bin/bannerlator-session index cae72823a..c0adc95e7 100755 --- a/tools/linuxfs/overlay/usr/local/bin/bannerlator-session +++ b/tools/linuxfs/overlay/usr/local/bin/bannerlator-session @@ -591,8 +591,6 @@ BUSCONF wait "$decky_supervisor" 2>/dev/null || true echo "== Decky: session supervisor stopped" fi - # This script's own loops and daemons (the fill-screen watcher never ends) would pass to - # gamescope's reaper when it exits and hold the compositor up on a black screen. _bl_jobs=$(jobs -p) [ -n "$_bl_jobs" ] && kill $_bl_jobs 2>/dev/null reap_orphans