Fix rooted-device setup failure: chroot bind mounts silently skipped + TMPDIR/HOME env leak breaking apt postinst - #37
Open
lota09 wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On rooted devices using the chroot-based Linux runtime, running the setup wizard reliably failed at the desktop environment install step with:
with a
dpkg/apt-geterror surfaced from theca-certificatespostinst script. This reproduced consistently, including after a full device factory reset and fresh install, which ruled out any stale/corrupted local state.This PR fixes two independent, confirmed root causes in
ChrootRuntime.kt, both verified viaadb logcatbefore and after the fix on a physical rooted device.Root cause #1 —
mountIfNeeded()'s "already mounted" pre-check always returns a false positiveensureMounts()callsmountIfNeeded()for each of the 7 required mount points (/dev,/dev/pts,/dev/shm,/proc,/sys,/run,/tmp). The original implementation pre-checked whether a path was already mounted by runningsu -c mountand string-matching the output:On the affected device, this check always evaluated true, even on a freshly extracted rootfs where none of the paths were actually mounted yet. As a result, every single
mountIfNeeded()call short-circuited and no mount was ever attempted.This was confirmed via
logcat: between the initialsu exec: mount(table fetch) call and the finalexecChroot("mkdir -p /tmp/.X11-unix ...")call, there were zerosu exec: mkdir -p ... && mount ...log lines — proving all 7 mount attempts were being skipped, not attempted-and-failed.Downstream, this meant
/dev,/proc,/sys, and a writable/tmpwere never available inside the chroot, which is what ultimately brokemktemp/update-ca-certificateslater in the install (see root cause #2 for the specific failure once mounts were restored).Fix
Removed the fragile string-matching pre-check entirely.
mountIfNeeded()now always attempts the mount and trusts the real process exit code (via the two-argRootShell.exec(command, onOutput): Intoverload, instead of the one-argexec(command): Stringoverload that discarded the exit status):Mount is idempotent-safe in practice here: re-mounting an already-mounted bind/tmpfs target is harmless, and any real failure is now surfaced via the exit code and logged instead of being silently swallowed.
Root cause #2 — Android app's
TMPDIR/HOMEenv vars leak into the chroot, breakingca-certificatespostinstOnce root cause #1 was fixed and all 7 mounts started succeeding, the install progressed further but still failed on
ca-certificateswithapt-get installexiting 100. Digging into the on-screen error log revealed:This path (
/data/user/0/com.orailnoor.droiddesk/cache/...) is the Android app process's own private cache directory, not anything inside the chroot. The Android app'sTMPDIR(andHOME) environment variables were leaking through into thesu/chrootinvocation, so whenupdate-ca-certificates's postinst script calledmktemp, it respected the inherited$TMPDIRand tried (and failed) to create a file at a path that doesn't exist from inside the chroot's mount namespace.Notably,
startSession()'srunScriptin this same file already resets these variables (export TMPDIR=/tmp; export HOME=/root; export PREFIX=/usr) for interactive sessions — this reset had simply never been applied to the package-installation code path (executeCommand()/execChroot()), which is whatinstallDesktopEnvironment()uses.Fix
Applied the same environment-reset pattern to both
executeCommand()andexecChroot():This ensures every command executed inside the chroot — not just interactive shell sessions — gets a clean, chroot-appropriate environment, regardless of what the host Android app process's own environment looks like.
Testing
Both fixes were verified end-to-end on a physical rooted device (factory reset beforehand to rule out any leftover state from prior chroot experimentation):
logcatshowed zero mount attempts (root cause Plasma is unable to start as it could not correctly use OpenGL #1); after partially patching just the mount fix, install progressed but failed onca-certificateswith themktemp/TMPDIRerror visible both inlogcatand in the app's on-screen setup log (root cause Major Overhaul: Session Management, Termux:Widget Support, and Firefox ESR #2).logcatconfirms all 7 mount points succeed (Mounted ...logs with real exit codes), followed by successfulapt-get installcompletion forca-certificates, Mesa GPU drivers, XFCE desktop packages, and Desktop Essentials tools, ending inDesktop environment installation complete.Notes for reviewers
.github/workflows), so verification here was manual/device-based as described above.ChrootRuntime.kt(the rooted chroot runtime). The non-root Termux/proot runtime (RootfsManager.kt) has its own separate install path and was not touched.app_state.dart's_runChrootSetup()/installDesktopEnvironment()always throw the same hardcodedStateError('Desktop Essentials package installation failed')regardless of which native install stage actually failed, which made initial diagnosis harder from the UI alone. Happy to open a follow-up PR to surface the real native error message in the UI if that's of interest — let me know.