From 1008da4e8d6398aef5eae87dd6e8f1650eb7938f Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Mon, 9 Nov 2026 06:53:23 -0500 Subject: [PATCH] fix(native): proot fast path turns off and greys out while running without proot --- .../com/droiddeck/launcher/runtime/ProotFastPath.kt | 9 +++++---- .../com/droiddeck/launcher/session/SessionFiles.kt | 2 +- .../com/droiddeck/launcher/session/SessionService.kt | 2 +- .../com/droiddeck/launcher/ui/PerformanceDialog.kt | 10 +++++++--- app/src/main/res/values/strings.xml | 1 + .../droiddeck/launcher/runtime/ProotFastPathTest.kt | 4 ++++ 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/droiddeck/launcher/runtime/ProotFastPath.kt b/app/src/main/java/com/droiddeck/launcher/runtime/ProotFastPath.kt index e9a9f4a72..11265bd8a 100644 --- a/app/src/main/java/com/droiddeck/launcher/runtime/ProotFastPath.kt +++ b/app/src/main/java/com/droiddeck/launcher/runtime/ProotFastPath.kt @@ -12,15 +12,16 @@ object ProotFastPath { const val LIBRARY = "/usr/local/lib/libblfastpath.so" const val MAX_BINDS = 256 - fun allows(preference: Boolean, noSeccomp: Boolean, source: String): Boolean = - preference && !noSeccomp && source == LinuxRuntime.PROOT_PACK + fun allows(preference: Boolean, noSeccomp: Boolean, source: String, nativeUserland: Boolean = false): Boolean = + preference && !noSeccomp && !nativeUserland && source == LinuxRuntime.PROOT_PACK fun enabled(context: Context): Boolean { val preference = SessionPrefs.prootFastPath(context) val noSeccomp = SessionPrefs.prootNoSeccomp(context) + val nativeUserland = SessionPrefs.nativeUserland(context) val source = LinuxRuntime.prootSource(context) - val on = allows(preference, noSeccomp, source) - if (preference && !noSeccomp && !on) + val on = allows(preference, noSeccomp, source, nativeUserland) + if (preference && !noSeccomp && !nativeUserland && !on) Log.i(TAG, "proot: fast path off - binary is $source, not the patched proot") return on } diff --git a/app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt b/app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt index ae85d8e3e..1e967fb8e 100644 --- a/app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt +++ b/app/src/main/java/com/droiddeck/launcher/session/SessionFiles.kt @@ -264,7 +264,7 @@ object SessionFiles { if (patched > 0) Log.i(TAG, "native userland: $patched system call sites in ld.so and libc answer Android's blocked calls") com.droiddeck.launcher.runtime.NativeGuest.syncLibraryDirs(root) } - if (ProotFastPath.enabled(context) && !nativeUserland) { + if (ProotFastPath.enabled(context)) { val library = com.droiddeck.launcher.agent.AgentEnv.fastPathLibrary(context) preload.append(library + "\n") if (startsSession && library != ProotFastPath.LIBRARY) Log.i(TAG, "fast path preload: $library (debugging override)") 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 93d981458..93a49d991 100644 --- a/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt +++ b/app/src/main/java/com/droiddeck/launcher/session/SessionService.kt @@ -666,7 +666,7 @@ class SessionService : Service() { val binds = sessionBinds(controllersOn, fakeInputDir, sessionDir, guest, sessionRoot, runtimeDir) val nativeUserland = com.droiddeck.launcher.runtime.NativeGuest.enabled(this) - val fastPathKey = if (ProotFastPath.enabled(this) && !nativeUserland) { + val fastPathKey = if (ProotFastPath.enabled(this)) { val prootBinds = LinuxRuntime.binds( this, sessionRoot, runtimeDir, Environment.getExternalStorageDirectory(), binds, ) diff --git a/app/src/main/java/com/droiddeck/launcher/ui/PerformanceDialog.kt b/app/src/main/java/com/droiddeck/launcher/ui/PerformanceDialog.kt index 7fd324baf..f8f44907a 100644 --- a/app/src/main/java/com/droiddeck/launcher/ui/PerformanceDialog.kt +++ b/app/src/main/java/com/droiddeck/launcher/ui/PerformanceDialog.kt @@ -189,9 +189,13 @@ fun PerformancePage( ) ToggleRow( host, "fastpath", stringResource(R.string.perf_fastpath), - if (prootNoSeccomp) stringResource(R.string.perf_fastpath_needs_seccomp) - else stringResource(R.string.perf_fastpath_hint), - prootFastPath && !prootNoSeccomp, enabled = !prootNoSeccomp, onChange = onProotFastPath, + when { + nativeUserland -> stringResource(R.string.perf_fastpath_needs_proot) + prootNoSeccomp -> stringResource(R.string.perf_fastpath_needs_seccomp) + else -> stringResource(R.string.perf_fastpath_hint) + }, + prootFastPath && !prootNoSeccomp && !nativeUserland, enabled = !prootNoSeccomp && !nativeUserland, + onChange = onProotFastPath, ) ToggleRow( host, "nativeuserland", stringResource(R.string.perf_native_userland), diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6ce40e73b..6ef75377f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -651,6 +651,7 @@ Run without proot (experimental) Starts the Linux side directly on Android. Applies to the next session. Turn off if something fails to start. proot fast path + Not used without proot. Needs proot\'s seccomp filter. Faster file lookups and less stutter. Turn off if a program can\'t find its files. Draw the cursor inside gamescope diff --git a/app/src/test/java/com/droiddeck/launcher/runtime/ProotFastPathTest.kt b/app/src/test/java/com/droiddeck/launcher/runtime/ProotFastPathTest.kt index 12fb45bf9..f41361894 100644 --- a/app/src/test/java/com/droiddeck/launcher/runtime/ProotFastPathTest.kt +++ b/app/src/test/java/com/droiddeck/launcher/runtime/ProotFastPathTest.kt @@ -33,4 +33,8 @@ class ProotFastPathTest { assertFalse(ProotFastPath.allows(preference = false, noSeccomp = false, source = LinuxRuntime.PROOT_PACK)) assertFalse(ProotFastPath.allows(preference = true, noSeccomp = true, source = LinuxRuntime.PROOT_PACK)) } + + @Test fun fastPathStaysOffWithoutProot() { + assertFalse(ProotFastPath.allows(preference = true, noSeccomp = false, source = LinuxRuntime.PROOT_PACK, nativeUserland = true)) + } }