UI: drop Magisk prompt — ResourceMonitor stops probing su

ResourceMonitor.init ran `su -c id` at every ChatActivity launch to see
if root was available, then used root to read /sys/class/kgsl/... and
/sys/bus/platform/devices/soc:qcom,msm-cdsp-rm/... for GPU/NPU usage %.
That probe was the only thing still triggering the Magisk auth dialog
on each app start after the no-root LLM migration.

Remove the root probe and the execRoot helper. GPU/NPU reads now return
-1 (UI already renders "—" for negative values). The non-root
/sys/class/kgsl/kgsl-3d0/gpubusy path is kept as a best-effort — it's
world-readable on some devices, silently fails otherwise. CPU and RAM
readouts are unaffected (never needed root).

Dead-code `su -c ...` calls remain in Qwen3TtsEngine (hexStartRunner,
hexStartCpRunner, hexStopRunner, etc.) and WhisperNpuSttEngine, but all
are gated behind fallback paths that don't execute under the current
PTE-only config (talkerPteModule != null && cpPteModule != null short-
circuits before any su call). Left in place to avoid churning the TTS
Hexagon fallback; can be purged in a later cleanup pass if needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kazeia Team 2026-04-14 18:35:18 +02:00
parent 10fd10fd90
commit 0632db1ee0
1 changed files with 12 additions and 47 deletions

View File

@ -18,17 +18,12 @@ class ResourceMonitor(private val context: Context) {
private var prevIdle = 0L
private var prevGpuBusy = 0L
private var prevGpuTotal = 0L
private var hasRoot = false
init {
// Test root access once
hasRoot = try {
val p = Runtime.getRuntime().exec(arrayOf("su", "-c", "id"))
val result = p.inputStream.bufferedReader().readText()
p.waitFor()
result.contains("uid=0")
} catch (_: Exception) { false }
}
// No-root deployment (2026-04-14): the previous `su -c id` probe used to
// enable GPU/NPU sysfs reads via root, but it also triggered a Magisk
// prompt on every ChatActivity launch. The whole pipeline now runs in
// the app process so root is never needed — GPU/NPU usage is reported
// as -1 (UI shows "—") and the dashboard shows CPU + RAM only.
fun snapshot(): ResourceSnapshot {
return ResourceSnapshot(
@ -67,7 +62,9 @@ class ResourceMonitor(private val context: Context) {
}
private fun readGpu(): Float {
// Try direct read first (works on some devices)
// Non-root path: some devices expose /sys/class/kgsl/kgsl-3d0/gpubusy
// as world-readable. If it's locked down (most SELinux configs do),
// just return -1 — no root fallback, no Magisk prompt.
try {
val content = File("/sys/class/kgsl/kgsl-3d0/gpubusy").readText().trim()
val parts = content.split("\\s+".toRegex())
@ -81,38 +78,14 @@ class ResourceMonitor(private val context: Context) {
if (dt > 0) return (db * 100f / dt).coerceIn(0f, 100f)
}
} catch (_: Exception) {}
// Try with root
if (hasRoot) {
try {
val content = execRoot("cat /sys/class/kgsl/kgsl-3d0/gpu_busy_percentage").trim()
val pct = content.replace("%", "").trim().toFloatOrNull()
if (pct != null) return pct.coerceIn(0f, 100f)
} catch (_: Exception) {}
}
return -1f
}
private fun readNpu(): Float {
// NPU doesn't have a standard busy metric
// Use CDSP (compute DSP) load as proxy if available
if (hasRoot) {
try {
// Check if CDSP is active by reading vote count
val vote = execRoot("cat /sys/bus/platform/devices/soc:qcom,msm-cdsp-rm/cdsp_rm/cpu_vote 2>/dev/null").trim()
if (vote.isNotEmpty()) {
val v = vote.toIntOrNull() ?: 0
return if (v > 0) 100f else 0f
}
} catch (_: Exception) {}
try {
// Alternative: check fastrpc activity
val stat = execRoot("cat /proc/fastrpc 2>/dev/null || echo none").trim()
if (stat != "none" && stat.isNotEmpty()) return 50f
} catch (_: Exception) {}
}
// NPU usage reporting required root sysfs reads (cdsp_rm/cpu_vote,
// /proc/fastrpc) that always triggered a Magisk prompt. Removed with
// the no-root migration — no equivalent public API exists, so the
// UI just shows "—" for NPU load.
return -1f
}
@ -134,12 +107,4 @@ class ResourceMonitor(private val context: Context) {
} catch (_: Exception) { return 0 }
}
private fun execRoot(cmd: String): String {
return try {
val p = Runtime.getRuntime().exec(arrayOf("su", "-c", cmd))
val result = p.inputStream.bufferedReader().readText()
p.waitFor()
result
} catch (_: Exception) { "" }
}
}