Skip to content

Commit 1082f22

Browse files
committed
Fix empty /sdcard in proot: bind /storage tree and check permission properly
- Bind the whole /storage directory (not just /storage/emulated/0) so Android's FUSE symlinks and sub-mounts resolve correctly inside proot - Check Environment.isExternalStorageManager() on Android 11+ instead of just canRead(), which returns true even without actual file access - Create /sdcard symlink inside rootfs pointing to /storage/emulated/0 - Bind both /storage:/storage and /storage/emulated/0:/sdcard for maximum compatibility (matches Termux proot-distro behavior) Co-Authored-By: Mithun Gowda B <mithungowda.b7411@gmail.com>
1 parent 9e110dc commit 1082f22

File tree

1 file changed

+30
-6
lines changed

1 file changed

+30
-6
lines changed

flutter_app/android/app/src/main/kotlin/com/nxg/openclawproot/ProcessManager.kt

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.nxg.openclawproot
22

3+
import android.os.Build
34
import android.os.Environment
45
import java.io.BufferedReader
56
import java.io.File
@@ -96,12 +97,35 @@ class ProcessManager(
9697
"--bind=$configDir/resolv.conf:/etc/resolv.conf",
9798
"--bind=$homeDir:/root/home",
9899
).let { flags ->
99-
// Bind-mount shared storage into proot if accessible (Termux-style)
100-
val sdcard = Environment.getExternalStorageDirectory()
101-
if (sdcard.exists() && sdcard.canRead()) {
102-
val sdcardDir = File("$rootfsDir/sdcard")
103-
sdcardDir.mkdirs()
104-
flags + "--bind=${sdcard.absolutePath}:/sdcard"
100+
// Bind-mount shared storage into proot (Termux proot-distro style).
101+
// Bind the whole /storage tree so symlinks and sub-mounts resolve.
102+
// Then create /sdcard symlink inside rootfs pointing to the right path.
103+
val hasAccess = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
104+
Environment.isExternalStorageManager()
105+
} else {
106+
val sdcard = Environment.getExternalStorageDirectory()
107+
sdcard.exists() && sdcard.canRead()
108+
}
109+
110+
if (hasAccess) {
111+
val storageDir = File("$rootfsDir/storage")
112+
storageDir.mkdirs()
113+
// Create /sdcard symlink → /storage/emulated/0 inside rootfs
114+
val sdcardLink = File("$rootfsDir/sdcard")
115+
if (!sdcardLink.exists()) {
116+
try {
117+
Runtime.getRuntime().exec(
118+
arrayOf("ln", "-sf", "/storage/emulated/0", "$rootfsDir/sdcard")
119+
).waitFor()
120+
} catch (_: Exception) {
121+
// Fallback: create as directory if symlink fails
122+
sdcardLink.mkdirs()
123+
}
124+
}
125+
flags + listOf(
126+
"--bind=/storage:/storage",
127+
"--bind=/storage/emulated/0:/sdcard"
128+
)
105129
} else {
106130
flags
107131
}

0 commit comments

Comments
 (0)