Skip to content

Terminal Runtime

AceGuru-mjh edited this page Oct 1, 2026 · 4 revisions

终端运行时

🖥️ 终端 & Linux · 🏠 首页 › Terminal-Runtime

Home Version Kotlin Modules Tools License

Terminal-Runtime typing

📑 本页目录

platform:terminal 在手机上供给并运行一个真实的 Ubuntu 24.04 用户态 Linux: 官方 rootfs + PRoot 用户态沙箱 + 原生 C++ PTY + 自研 VT100 模拟器 + Ubuntu 生命周期编排 + apt 包管理。

1. 分层实现

层 实现 要点
rootfs 供给 RootfsDownloader/Extractor/Configurator、BundledRootfsSource、RootfsProvisionerImpl、UbuntuBootstrapManager 官方 Ubuntu 24.04.4 归档(sha256 锁定)、断点续装、sources.list 配置、基础包档案;v1.2.0 起支持内置 rootfs 随 APK 分发(见 Ubuntu rootfs 供给)
执行后端 LinuxPRootBackend + ProotExecutor + SystemBindProfile + NativeLibraryPRootBinaryProvider PRoot 用户态 ptrace 沙箱(无需 root)、预编译 so 随包分发(指纹校验防篡改)、Fake 后端供测试
PTY C++ forkpty(pty_engine.cpp / pty_session.cpp / jni_bridge.cpp + headers) 原生伪终端、argv 编组、进程组信号、会话隔离;CMake 产出 apex_terminal,C++17
终端模拟 :terminal-emulator 模块 自研 VT100/ANSI:转义序列解析、滚动区、24 位色、UTF-8 解码(见 VT100/ANSI 模拟器)
背压 IO PtyOutputPump + BackpressureConfig 有界输出泵、EOF 语义、丢帧保护
观察引擎 ObservationEngine2 + SemanticStateReducer + InputWaitingDetector 把 ANSI 噪音降维成语义状态(等待输入 / 运行中 / 完成 / 错误),识别提示符
包管理 UbuntuAptPackageManager + PackageOperationLock 设备上 apt install,并发锁防交错
环境自适应 AdaptiveProvisionLoop + DiagnosticRules + ResolverCache 执行观察 → 诊断规则 → 自动修复
会话持久化 SessionMetadataStore + RuntimeRecoveryService、SessionManager 重启恢复会话元数据

2. 一次 apt install 的数据流

sequenceDiagram
    participant UI as TerminalScreen
    participant SM as SessionManager
    participant B as LinuxPRootBackend
    participant P as ProotExecutor
    participant PTY as C++ forkpty (JNI)
    participant G as guest bash/apt
    participant VTE as terminal-emulator
    participant OBS as ObservationEngine2

    UI->>SM: create(backend=proot, workspace)
    SM->>B: ensureRootfs() → BundledRootfsSource / RootfsDownloader
    B->>P: proot -r <rootfs> -b /sdcard … /bin/bash
    P->>PTY: forkpty execv argv[]
    PTY-->>G: 真·伪终端会话
    UI->>SM: write("apt install -y figlet\n")
    G-->>PTY: 输出字节流(含 ANSI)
    PTY-->>SM: PtyOutputPump(有界、丢帧保护)
    SM->>VTE: feed(bytes) → 屏幕模型(Glyphs / 光标 / 滚动区)
    SM->>OBS: 降维 → SemanticState(RUNNING / WAITING_INPUT / DONE / ERROR)
    OBS-->>UI: 语义状态(输入法桥据此切换、UI 据此显示"等待输入")
Loading

3. 为什么必须 targetSdk = 28

Warning

这是硬红线,不是忘记升级。

从 Android 10(API 29)开始,系统禁止应用从可写私有目录执行二进制 —— SELinux 把应用数据文件 标记为 app_data_file,而 untrusted_app 域对这个标签没有 execute 权限。 Ubuntu rootfs 恰恰依赖:

  • execve() guest ELF(rootfs 里的 /bin/bash、/usr/bin/apt);
  • ptrace()(PRoot 的实现机制)。

一旦 targetSdk ≥ 29,哪怕设备已 Root、哪怕 Binary 已被解压到 /data/data/.../lib, 都会触发 permission denied / Operation not permitted,整个终端链路失效。 相关的 lint(ExpiredTargetSdkVersion)在 app/build.gradle.kts 中被显式关闭并写了理由注释。

配套:

  • useLegacyPackaging = true:让 .so(含伪装成 .so 的 rootfs 归档)被解压到原生库目录,而不是保持压缩状态;
  • keepDebugSymbols += "**/libubuntu-rootfs.so":跳过 llvm-strip,否则归档会被"瘦身"损坏。

4. PRoot 沙箱的能力边界

能做 不能做 / 要注意
完整用户态 Linux:apt、bash 脚本、python、gcc/clang(小项目) 无内核模块、无 systemd(用 proot-services 之类替代或直接跑前台进程)
绑定 /sdcard 等宿主目录(SystemBindProfile) 无 Root 时不能 mount 物理分区、不能改系统属性
多会话隔离(SessionManager + 独立 PTY) 性能:ptrace 会带来显著开销,编译大项目很慢
网络访问(走宿主网络栈) ping/raw socket 等需要特权的操作受宿主限制

5. 语义状态机(给 Agent 用的抽象)

把"终端显示器上出现了什么"翻译给 LLM 是没意义的(全是 ANSI 噪音),所以有:

组件 输出
ObservationEngine2 观察窗口内的原始输出 + 时间戳 + 窗口大小
SemanticStateReducer RUNNING / WAITING_INPUT / DONE / ERROR + 关键行摘要
InputWaitingDetector 识别 shell 提示符、Password:、[Y/n] 等(决定是否需要继续喂输入)

这让 Agent 可以"用.Terminal 像人一样操作":观察 → 判断状态 → 写输入 → 再观察,而不是 sleep 等死。

6. 暴露给 LLM 的 terminal.* 工具(18 个)

terminal.create      terminal.run        terminal.write      terminal.observe
terminal.snapshot    terminal.wait       terminal.resize     terminal.signal
terminal.close       terminal.workspaces terminal.backends   terminal.linux_bootstrap
terminal.linux_status terminal.linux_packages terminal.linux_network terminal.ubuntu_install
terminal.ubuntu.ensure(T82)  terminal.ubuntu.status(T82)

其中 ubuntu.ensure / ubuntu.status 是一键生命周期编排入口(见 UbuntuLifecycleCoordinator)。 另有 tools/v2/*(22 个实现)与 tools/legacy/*(7 个旧实现)在模块内部演进。

Note

终端工具遵循 SDK 边界约束::terminal-emulator 不允许依赖 :platform:terminal, 详见 VT100/ANSI 模拟器。

7. 典型命令(给 Agent 的示例)

terminal.create(workspace="default", backend="proot")
terminal.ubuntu.ensure()                       # 保证 Ubuntu 就绪(内置版免下载)
terminal.run("apt-get update && apt-get install -y figlet")
terminal.write("figlet HELLO\n")
terminal.observe()                             # 语义状态 + 关键输出
terminal.wait(until="DONE", timeoutMs=30000)
terminal.close()

8. 排错

现象 原因与处理
execve: permission denied 几乎一定是 targetSdk ≥ 29 或 rootfs 未解压(见 §3);确认装的是带内置 rootfs 的版本
卡在 "rootfs 供给中" 下载大文件 + 解压较慢;内置 APK 版本应完全离线。检查 RootfsHealthCheck 日志
apt 报无法解析域名 rootfs 内 DNS:检查 RootfsConfigurator 写入的 resolv.conf;宿主能否联网
输出乱码 / 方框字 Termux 风格字体未安装(需支持 box-drawing 的等宽字体);确认渲染层 UTF-8 解码
会话断开后无法恢复 SessionMetadataStore 恢复的是元数据而非进程;进程级恢复不支持(Linux 语义)
编译特别慢 PRoot ptrace 开销 + 手机 CPU 决定,属预期;大工程建议 在移动端用 shell 工具替代

9. 相关页面

footer

🏠 返回首页 · 📚 文档索引 · ❓ FAQ · 🔧 故障排查 · 🗺️ 路线图 · 🐛 提 Issue

Android Guru Agent · v1.4.4 · Kotlin 2.0.21 · Compose · PRoot · Room

Clone this wiki locally