标签 :
DeepSeek Harness安卓移植PRootseccomp 容器沙箱边界端侧执行环境本篇定位:回答四个问题------DSH 在安卓上跑起来到底卡在哪?社区卷出的五条移植路线各是怎么绕的?Linux 塞进 APK 之后,这套"沙箱"到底关不关得住?这波听起来有点野的操作,创新到底在哪一层?
适用读者:想拿手机跑 coding agent 的人;关心 agent 执行环境如何下沉到手机端的构建者;对"免 root 跑 Linux"底层机制好奇的工程师。
本篇素材:各项目仓库 README、DSH 官方 Discussions 与社区对比文章,2026-11-13 逐项核实;star 数为当日仓库页数值。要提前说明的一点:那篇五路线对比文的作者声明自己没有安卓真机、全文未实测,文中引用它的地方都标了"对比文说法";性能数字一律以各项目自己 README 给出的数据为准,本篇没有做独立实测。
先把你放进场景里:你在通勤路上,手边只有一台安卓手机,想让学生(agent)帮你修一个 bug------clone 代码、装依赖、跑测试、改文件。这套动作在电脑上是日常,因为电脑上有 shell、有文件系统、有一整套 Linux 工具链。而 DeepSeek Harness(下面简称 DSH)这个 2026-08-13 开源、一个月冲到 21.9 万 star 的当红 harness(开源潮全景、Cordis 深读讲过它的来路),恰恰就是这么一个离不开真实 Unix 环境的程序 :它是 Node.js 写的,默认跑法是 npx @deepseek-ai/dsh web 起一个 Web UI,底下要 shell、要 ripgrep(一个代码搜索工具)、要原生模块、要包管理器。
最近火的"DSH 安卓版",干的就是这件事:让你装一个 APK、填一个 API Key,手机里就长出一整套 Linux + Node + DSH------不用 root,不用装 Termux(手机上敲 Linux 命令用的终端模拟器),不用碰命令行。这活儿官方没干(DeepSeek 至今没有出安卓版),全是社区第三方做的,而且已经卷出了五条技术路线。下面一样一样讲。
一、先说清楚:火的是"民间搬运工",不是官方
把名字先对上,免得后面混淆。目前叫得上号的安卓 DSH 项目至少有五个,全是第三方,作者也都明确声明与 DeepSeek 无隶属关系:
| 项目 | 形态 | 热度(2026-11-13) |
|---|---|---|
| dsh-Go | Flutter 客户端,内置 Ubuntu + Node.js(约 1GB) | 发布首周约 2,300★(2026-10-30 报道数字),最像"最近火的那个" |
| Soodok/DSH Mobile | Kotlin 应用,原生 Node + 自研 Linux 容器 | 525★,1,172 commits,迭代最凶 |
| dphmoblie/deepseek-harness-android | Capacitor 壳 + PRoot Ubuntu | 120★,888 commits |
| woaiys3/deepseek-harness-android-app | Java 应用,走系统特权通道 | 166★(对比文成文时数据) |
| Vengisk/deepseek-harness-termux | Termux 补丁脚本集 | 51★(同上) |
它们的共同卖点只有一句话:开箱即用 。装 APK → 填 API Key → 开始用,三步引导把过去"装 Termux → 换源 → 装包 → 配环境"一小时起步的折腾压缩没了。至于模型------都不在手机里跑,全部走你配的云端 API。手机在这里的角色是执行环境,不是大脑。
这一点值得先记住,因为它也是后面所有技术选择的出发点:推理在云,执行在端。 手机只要能提供"一个像样的 Unix 环境",DSH 就能干活。
二、卡点:一个为桌面 Linux 写的程序,到了手机上哪都不对
为什么这事有难度?因为 DSH 从头到脚都是按桌面 Linux 的假设写的,而安卓恰好每一条都不满足。
先解释一个关键词 libc :所有 Linux 程序都站在 C 标准库上跑,程序调用的 open、malloc、fork 这些基础动作全由它实现。桌面 Linux 世界用的实现叫 glibc ;安卓当年为了体积和许可,自己造了一个精简版叫 Bionic。两边接口大体相似、细节处处不同------就像插座制式:电器(程序)是按欧标插头造的,墙上(系统)只有国标插座,硬插要么插不进,要么冒火星。DSH 依赖的一批原生模块(node-pty 这类含编译产物的组件)都是按 glibc 编译的,对比文的原话是:在 Bionic 上"要么编译失败要么行为异常"。
下面这张表还压着三个名词,先给个速查:bubblewrap ------Linux 桌面常用的沙箱工具,DSH 桌面端靠它把 agent 的 shell 关进笼子;user namespace (常缩写 userns)------内核的一种隔离机制,让普通进程也能圈出一块自己的地盘、在里面搭隔离环境;sepolicy------安卓按 SELinux(内核的强制访问控制)给每个进程划的权限清单,手机上谁能干什么它说了算。
| DSH 的假设 | 安卓的现实 |
|---|---|
| glibc 标准库 | Bionic,原生模块编译失败或行为异常 |
| 沙箱可用(bubblewrap,依赖 user namespace) | sepolicy 把非特权 userns 挡死 ,沙箱直接报 SandboxUnavailableError |
| 任意路径读写、可执行 | 只有 App 自己的私有目录可写、可执行 |
| apt / npm 包生态 | 什么都没有,得自己带 |
把这张表看完,结论其实很清晰:手机的内核本身跑得了 Linux 程序(arm64 二进制、系统调用都在),堵住的全在"用户态"那一层------标准库不对、权限不够、目录结构不存在。 所以五条路线干的其实是同一件事:免 root 地在 App 沙箱里,再造一个 Linux 用户态。区别只在于"造到什么程度、用什么手段造"。
三、五条路线全景:从"借系统权限"到"自带操作系统"
按"对安卓系统的侵入程度"从深到浅排,五条路线一张表看清(对比文说法,作者无真机未实测;star 为其成文时数据):
| 路线 | 代表项目 | 一句话原理 | 体积 | 特点 |
|---|---|---|---|---|
| ① 系统特权通道 | woaiys3(166★,Java) | Root → Shizuku → 无障碍服务,三级降级拿权限 | 仓库 6.4MB | 唯一真正让 AI 操作手机本身的路线 |
| ② Termux 补丁层 | Vengisk(51★,Shell) | diff -u 自动补丁集,修补 Bionic 兼容问题 |
仅 100KB | 最轻最可控,但沙箱被 sepolicy 挡死 |
| ③ 内嵌 Node 直跑 | thness/dsh-mobile(18★,Kotlin) | APK 打包 Node 运行时 + Web UI | 41MB | 最省事,首启约 30 秒 |
| ④ PRoot 完整 Ubuntu | dphmoblie(现 120★) | PRoot 用户态跑 Ubuntu 24.04 | 数 GB | 最完整,通用 Linux 环境不止跑 DSH |
| ⑤ 盒装 Ubuntu 客户端 | dsh-Go(首周约 2,300★) | Flutter 应用内置 Ubuntu + Node | 约 1GB | 产品化最好,还能 SSH 遥控桌面端 |
逐条用人话说一遍:
① 借权限。 这条路线的问题意识不是"怎么跑 Linux",而是"怎么让 AI 碰到手机本身"。它搭了三条特权通道按深度降级:有 Root 用 Root;没 Root 用 Shizuku(一个通过 ADB 拿到系统 shell 权限的中转 App,能装应用、点屏幕、改设置);连 Shizuku 都不装,v1.7.0 起还能用无障碍服务读屏、点击、输入。三条通道都没有时退化成文件读写。代价也直白:无 root 时 Shizuku 每次重启要重新 ADB 激活,无障碍权限经常被国产 ROM 悄悄回收,而且权限面这么大,出事影响面也大。
② 打补丁。 不做 App,只维护一套对官方 DSH 的 diff 补丁,专修 Bionic 下的兼容问题------node-pty 重编译、把 link(2) 系统调用换成 rename(2) 绕开 sepolicy 的限制,这类活儿。100KB 解决战斗,最克制。但它也把天花板暴露得最清楚:想上 bubblewrap 沙箱?sepolicy 直接挡死,安全降级成"沙箱不可用"。这条路线证明了一件事:修修补补能让 DSH 活,但活不出完整形态。
③ 硬塞。 把 Node.js 运行时和官方 Web UI 直接打进 APK,装完即用。简单粗暴,适合"我只想在平板上看看 agent 干活"的诉求。手机在这里只是个运行宿主。
④ 和 ⑤ 才是本篇的主角 ------它们回答的问题上了一个台阶:不满足于"让 DSH 勉强活着",而是把一个真正的 Linux 环境整体搬进手机,DSH 拿到的就是一个原生 habitat,glibc、apt、工具链全都在。区别在实现手段:dphmoblie 用的是老牌方案 PRoot,dsh-Go 的报道没披露内部机制(只说内置 Ubuntu + Node,约 1GB)。而真正把这个思路做出花来的,是下一节和下下节的两个深挖对象。
另外提前打个预防针:对比文还点出五条路线的三个共同前提------都基于 MIT 协议、当时都基于 DSH 0.1.0-rc.6、推理都走云端 API。手机始终是执行环境,不是推理设备。
四、PRoot 路线:雇个"翻译官",把整个 Ubuntu 背在身上
PRoot 是 Linux 老玩家熟悉的名字:它用 ptrace (调试器用的进程跟踪机制)拦截目标程序的每一次 系统调用,在用户态把路径改写、把身份伪装成 root,再转交给真内核。打个比方:你请了一位全程陪同的翻译官,程序说的每一句话(每个 syscall)都要经过他翻译一遍才能到达内核。好处是无条件通用------内核不用改一个字、不需要任何权限,就能跑起一个完整发行版;代价也明摆着,每个系统调用都要停一下、翻译一下,性能损耗是原理性的。
dphmoblie 这个项目就是把 PRoot 方案做到产品级的代表。它的三层结构:
| 层 | 技术 | 干什么 |
|---|---|---|
| 管理界面 | Capacitor + React | 运行时安装、服务控制、模型配置、终端 |
| 原生运行时层 | Kotlin | rootfs 校验解压、PRoot 运行器(libdsh_proot.so)、PTY 会话监管、Shizuku 连接 |
| Ubuntu 运行时 | PRoot 内 Ubuntu 24.04 ARM64 + Node 24.19 + DSH 0.2.1-rc.1 | 白名单入口启动 dsh web |
两处工程细节值得单独表扬,因为它们超出了"能跑就行"的水位线:
- 供应链安全做到了偏执级:rootfs 镜像与清单 digest-pinned(摘要固定),按精确长度 + SHA-256 校验;下载仅 HTTPS、解析出私有地址直接拒绝;断点续传;解压防路径穿越;就绪后原子切换,不会出现解压一半的坏环境。连 PRoot 二进制本身都注明取自 Operit2 工具链(GPL-2.0 的 PRoot + AGPL-3.0 的 Operit2),版本和哈希记录在 THIRD_PARTY_NOTICES 里。
- 网络边界收得很紧:DSH 只监听回环地址 127.0.0.1,每次启动生成一个 256 位临时令牌做鉴权------不持久化、不进 URL、不给 WebView。
丑话也要说:PRoot 的性能开销它 README 没给基准数字(只说对编译类能力提供 18 项自检),存储要数 GB,且仅支持 arm64。它赢在"完整"两个字------PRoot 里就是一个如假包换的 Ubuntu,你不止能跑 DSH,apt 装什么都能跑。
五、seccomp 路线:不请翻译官,只设一个"安检口"
技术上是这波移植里最有意思的一个,来自 Soodok 的 DSH Mobile。它的设计哲学一句话就能说清:翻译官太贵了,绝大多数系统调用根本不需要翻译,为什么每个都要拦?
先看它的双路线设计,这个设计本身就很说明问题:
- 默认路线(原生 bionic) :把整个 Node.js 编译成安卓原生二进制直接打进 APK,用
execve启动------连 rootfs 都不要,没有任何伪文件系统。能在"安卓原生"层面解决的事,就不动用容器; - 容器路线(dsh_alpine):只有需要 glibc 或 apt 生态时才启用,这时才把 Linux 用户态请出来。
也就是说:它不是"把 Ubuntu 塞进手机",而是"能不塞就不塞,必须塞时用最便宜的方式塞"。 这个"最便宜的方式"就是它的自研容器,四个部件(每个都先解释术语):
- seccomp BPF + SIGSYS 信号 。seccomp 是 Linux 内核自带的系统调用过滤器(安卓 App 沙箱自己也靠它),BPF 是配置过滤规则的语言。它的用法是:只把带路径的少数系统调用 (
openat这类)设为"触发信号",一旦程序调到,内核发一个 SIGSYS 信号,用户态的 handler 把路径翻译好,再重新发起调用。回到比喻:不是全程翻译官,而是机场安检口------只对需要开箱检查的行李(带路径的 syscall)开箱,其余行李直通行李舱。 - 自写 ELF loader。ELF 是 Linux 可执行文件的格式,loader 负责把它装进内存。它自己写了一个迷你 loader,把 guest 程序装到固定内存地址(0x2000000000)、按非 PIE(不支持地址随机化)的方式加载------这样就不依赖宿主的加载器,也不需要 user namespace。
- self-reexec。容器进程启动时把自己重新执行一遍,从"宿主视角"切换到"客人视角",完成 guest 用户态的接管------之后跑的就是一棵普通的 Linux 进程树,不再是"被特殊照顾的进程"。
- 路径翻译 + 伪文件透传 。
/proc、/sys、/dev直接透传宿主的,不用 chroot 换根(chroot:把程序眼里的根目录整个换掉,正经做需要 root)。
四件套合起来:不用 ptrace、不用 user namespace、不用 chroot、不用 root,全程待在 App 沙箱里。效果对比(Soodok README 数据):
| 指标 | seccomp 容器 | 真 chroot(需要 root) | PRoot |
|---|---|---|---|
| 单命令开销 | 2.4 ms | 1.6 ms | 19--33 ms(慢 8--14 倍) |
| 文件 IO | --- | 基准 | 慢约 30 倍 |
| 系统调用 | --- | 基准 | 慢 2.7 倍 |
#mermaid-svg-VKqITJ01geDTN2fD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VKqITJ01geDTN2fD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VKqITJ01geDTN2fD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VKqITJ01geDTN2fD .error-icon{fill:#552222;}#mermaid-svg-VKqITJ01geDTN2fD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VKqITJ01geDTN2fD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VKqITJ01geDTN2fD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VKqITJ01geDTN2fD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VKqITJ01geDTN2fD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VKqITJ01geDTN2fD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VKqITJ01geDTN2fD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VKqITJ01geDTN2fD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VKqITJ01geDTN2fD .marker.cross{stroke:#333333;}#mermaid-svg-VKqITJ01geDTN2fD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VKqITJ01geDTN2fD p{margin:0;}#mermaid-svg-VKqITJ01geDTN2fD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VKqITJ01geDTN2fD .cluster-label text{fill:#333;}#mermaid-svg-VKqITJ01geDTN2fD .cluster-label span{color:#333;}#mermaid-svg-VKqITJ01geDTN2fD .cluster-label span p{background-color:transparent;}#mermaid-svg-VKqITJ01geDTN2fD .label text,#mermaid-svg-VKqITJ01geDTN2fD span{fill:#333;color:#333;}#mermaid-svg-VKqITJ01geDTN2fD .node rect,#mermaid-svg-VKqITJ01geDTN2fD .node circle,#mermaid-svg-VKqITJ01geDTN2fD .node ellipse,#mermaid-svg-VKqITJ01geDTN2fD .node polygon,#mermaid-svg-VKqITJ01geDTN2fD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VKqITJ01geDTN2fD .rough-node .label text,#mermaid-svg-VKqITJ01geDTN2fD .node .label text,#mermaid-svg-VKqITJ01geDTN2fD .image-shape .label,#mermaid-svg-VKqITJ01geDTN2fD .icon-shape .label{text-anchor:middle;}#mermaid-svg-VKqITJ01geDTN2fD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VKqITJ01geDTN2fD .rough-node .label,#mermaid-svg-VKqITJ01geDTN2fD .node .label,#mermaid-svg-VKqITJ01geDTN2fD .image-shape .label,#mermaid-svg-VKqITJ01geDTN2fD .icon-shape .label{text-align:center;}#mermaid-svg-VKqITJ01geDTN2fD .node.clickable{cursor:pointer;}#mermaid-svg-VKqITJ01geDTN2fD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VKqITJ01geDTN2fD .arrowheadPath{fill:#333333;}#mermaid-svg-VKqITJ01geDTN2fD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VKqITJ01geDTN2fD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VKqITJ01geDTN2fD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VKqITJ01geDTN2fD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VKqITJ01geDTN2fD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VKqITJ01geDTN2fD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VKqITJ01geDTN2fD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VKqITJ01geDTN2fD .cluster text{fill:#333;}#mermaid-svg-VKqITJ01geDTN2fD .cluster span{color:#333;}#mermaid-svg-VKqITJ01geDTN2fD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VKqITJ01geDTN2fD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VKqITJ01geDTN2fD rect.text{fill:none;stroke-width:0;}#mermaid-svg-VKqITJ01geDTN2fD .icon-shape,#mermaid-svg-VKqITJ01geDTN2fD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VKqITJ01geDTN2fD .icon-shape p,#mermaid-svg-VKqITJ01geDTN2fD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VKqITJ01geDTN2fD .icon-shape .label rect,#mermaid-svg-VKqITJ01geDTN2fD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VKqITJ01geDTN2fD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VKqITJ01geDTN2fD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VKqITJ01geDTN2fD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} seccomp:只设安检口
带路径的少数 syscall
其余 syscall 直达
App 内的 Linux 程序
seccomp 过滤 → SIGSYS
翻译路径 → 重发
安卓内核
PRoot:全程翻译官
每一个 syscall 都拦
App 内的 Linux 程序
ptrace 拦截
用户态翻译路径与身份
安卓内核
两边的差距就是设计哲学的差距:PRoot 对所有系统调用无差别拦截翻译,seccomp 方案只拦"必须改的",其余原生直通。思路与 gVisor 那类"用户态接管系统调用"的沙箱同宗------拦截面越小、直通越多就越快;只是它的目标是兼容而不是隔离(Soodok 自己在 README 里明说:这不是安全沙箱,不隔离不可信代码)。
工程上的几个数字也值得看,因为它们说明"容器层几乎不是瓶颈":
- 冷启动:一加 15T / Android 16 上 2.3 秒,主流中端机 5--6 秒------对比文里"多数 Termux 方案要数分钟"的起步时间,这是数量级的改善;
- 耗时构成 :容器端到端中位 1.33 秒里,容器层本身只占 0.8%,96% 的时间花在 Node 插件加载上 ------瓶颈早就不在"Linux 环境",而在 JS 生态本身。配套用
NODE_COMPILE_CACHE(Node 的字节码编译缓存)再砍掉约 1.1 秒启动; - 双 rootfs 很务实:Alpine 3.22(musl 系)压缩后仅 3.98MB、内置离线可用,日常够用;要 glibc 或 apt 生态时,Ubuntu 24.04 按需下载 29.9MB;
- 内存:容器 loader 自身常驻仅 1.8MB,README 称与真 chroot 几乎等同。
还有一个"钻系统空子"的细节:它把 targetSdk 钉在 28------安卓 10 之后,App 被禁止执行自己可写目录里的二进制(W^X 限制:同一文件不可既可写又可执行),而 targetSdk 28 的老应用豁免这条。整个"App 里跑原生 Linux 程序"的把戏,都建立在这样一个豁免之上。(代价是永远升不了 targetSdk,这是另一个故事了。)
顺带一提迭代速度:9 月 16 日 Soodok 在 DSH 官方仓库 Discussions 发帖时,自称全家桶 70MB;到 11 月本篇核实时,完整包已经 161MB(不想要内置运行时还有 34MB 的 noruntime 版,首启联网下载 130.8MB),扩展中心攒到 57 项、含 20 套工具链(clang、JustJDK、rust、go、python......)。两个月长了一倍多,这个方向的社区投入力度可见一斑。
六、塞进去之后关得住吗:把"沙箱"拆成三层看
到这儿,"怎么把 Linux 塞进手机"讲完了,但先别急着高兴。想想 agent 平时都在干什么:装插件,npm install 拉包(包里可能带 postinstall 脚本------安装完自动执行的那种),从扩展中心装二十套工具链,写段代码然后自己跑------agent 的日常,就是不停地执行来路不明的代码 。所以下一个问题是:这套环境,坏代码进来了关得住吗?
一路上"沙箱"这个词我们已经撞见三次:卡点表里的"sepolicy 禁 userns"、Termux 路线报的 SandboxUnavailableError、Soodok 自己承认的"非安全沙箱,不隔离不可信代码"。三次都是一笔带过,现在把它拆开------"沙箱"其实是个三层的东西,一层一层看:
| 层 | 是什么 | 防什么 | 手机上的现状 |
|---|---|---|---|
| ① 安卓 App 沙箱 | 每个 App 一个独立 UID(身份号,一 App 一身份)+ SELinux + 系统级 seccomp 过滤,内核强制 | 这个 App 伤害手机上的其他东西(其他 App 的数据、系统分区) | 在,是真的 |
| ② bubblewrap 那层 | DSH 桌面端把 agent 的 shell 关进独立的 user/mount namespace,限制它能看到什么文件、能碰到哪些进程 | agent 跑的代码伤害你本人:偷密钥、毁工作区、留后门 | 没有 ------bubblewrap 靠非特权 user namespace 起隔离环境,sepolicy 把这条路封死,一开沙箱就报 SandboxUnavailableError |
| ③ 项目的"沙箱档" | Soodok 权限三档里的默认档,含义只是"不给 Shizuku、不给 Root" | 碰不碰得到手机系统 | 只有这一层,但它是权限档位,不是隔离层 |
打个比方:①号是真围墙,而且围得很好------但它围的是整栋楼 ;你缺的是楼内的防火门 。围墙防得住外面的人进不来,防不住 302 室着火烧穿整个楼层。所以"非真沙箱"的准确含义是:它防得住"App 之间互相伤害",防不住"App 内部的不可信代码伤害你本人"------而后者才是 agent 场景的主要威胁。
**那"真沙箱"拿什么衡量?**不用背定义,问三个问题就够了。
第一问:代码坏到极致,会发生什么? 真沙箱的保证是写给"百分之百恶意、水平无限高"的代码的,不是写给"正常程序偶尔失手"的。bubblewrap 是真沙箱,因为它圈住的就是恶意代码;"开关默认全关""危险命令先 dry-run"不是,因为它们只是把作恶的门槛抬高了几级,代码真要坏,拦不住。前者叫边界 ,后者只能叫加固------"沙箱"这个词被用烂,根子就是把加固吹成了边界。
第二问:笼子是谁焊的? 关代码的锁,钥匙不能在囚犯手里。真沙箱必须由比里面代码权限更高的东西 来强制:PRoot 那种"旁边有个进程帮你翻译系统调用",翻译的和被翻译的同身份、同权限,等于让犯人自己看门------出局;内核来焊(namespace、seccomp、SELinux)------合格;再往上是虚拟机那一层(Firecracker、云沙箱)------更硬。微软有个很实在的判法:官方认定的安全边界被突破,才算安全漏洞、必须发补丁;边界内部的问题一般不算。"跨过它算不算安全事故"------这比任何形容词都硬。
第三问:降权、藏东西、限口粮,做了几样? 真沙箱三件套,缺一样漏一类攻击。降权 ------让里面的代码换个更低的身份,系统调用面也收窄(seccomp),"以现有身份乱来"的路就断了;藏东西 ------用 mount namespace 把密钥目录、家目录从它眼前抹掉,想偷 Key?先得看得见;限口粮------CPU、内存、进程数、网络出口全设上限(cgroups + 出口控制),想挤死宿主、偷偷外传,都没门。下面那张恶意脚本表里偷 Key、翻文件、外传数据全拦不住,就是因为"藏东西"和"限口粮"整个缺席。
三问全过也别急着发奖牌,真沙箱还分牢度。行话叫 TCB(可信计算基) ,说人话就是:你不得不信任的那部分代码有多少------要信任的越少,沙箱越"真"。按"越狱要付出什么"排个阶梯,从低到高:
| 逃逸需要什么 | 等级 | 例子 |
|---|---|---|
| 不需要任何 bug(逻辑上就不设防) | 不是沙箱,是加固或伪装 | PRoot、"沙箱档" |
| 拿到一个用户态 bug | 语言级(运行时内存隔离是真的,但整个运行时都得信任) | V8 isolate、WASM |
| 拿到一个内核 bug | 内核强制级 | bubblewrap、Chromium 渲染进程、安卓 App 沙箱 |
| 拿到 hypervisor bug | 虚拟化级 | Firecracker、云沙箱(gVisor 的"内核"跑在用户态,介于这两级之间) |
| 硬件漏洞 | 硬件级 | TEE、独立设备 |
拿这三问去照开头那三层,答案就齐了:
- ①安卓 App 沙箱:第二问过关,锁是内核焊的(SELinux + 独立 UID)。但它只管"App 别伤害别人",App 自己家里的事不在它的职责范围里;
- ②bubblewrap:第二问也过关,不过 DSH 官方自己都不说它是安全边界------配置到底多严,官方没讲,这里不替它猜;
- ③"沙箱档":第二问第一关就倒,那是个权限档位,不是笼子。
这事还有个有意思的连环扣:安卓封死 user namespace,理由之一恰恰是"真沙箱机制本身会加大内核被攻击的面"------userns 出了名地容易出内核漏洞,连桌面 Linux 发行版这几年都在收紧它。所以不是"安卓懒",是系统层在算自己的安全账:少开一扇真沙箱的门,换内核少一块软肋。代价嘛,就是手机 DSH 在第一问上交了白卷。
为什么第四节、第五节的两个容器方案也补不上? 因为它们解决的都是"能不能跑",不是"关不关得住":PRoot 是伪装 不是隔离------它伪造 root 身份和文件系统视图,但里面每个进程还是以 App 自己的 UID 在跑,权限没降一分(Unix 世界的老共识:chroot 本来就不是安全边界,何况 PRoot 只是 chroot 的模拟器);seccomp 容器那层是翻译不是安检------拦下带路径的系统调用是为了改写路径(兼容),不是按安全策略收缩系统调用面。
拿一个最日常的威胁场景走一遍边界在哪------你让 agent 装个包,包里带恶意 postinstall 脚本。表格先说清楚"挡"字的两层意思:谁来挡 ------手机上实际存在的防线,也就是①号安卓 App 沙箱加上各项目的权限门控(②号不存在,指望不上);替谁挡 ------每行不一样,前五行保护的是你 (你的 Key、你的代码、你的手机),最后一行保护的是别人(其他 App 和系统):
| 恶意脚本能干什么 | 防线挡得住吗 | 说明 |
|---|---|---|
| 偷你的模型 API Key | 挡不住 | Key 就在 $DSH_HOME 的配置里,跟它同 UID、同文件系统 |
| 读、改、删工作区代码 | 挡不住 | 跟它在同一个 App 私有目录里,没人替你把代码藏起来 |
| 改其他插件、留持久化后门 | 挡不住 | 插件目录同样裸露,没有进程/挂载隔离 |
| 联网把数据传出去 | 挡不住 | 用的就是 App 自己的网络权限 |
| 开了无障碍/Shizuku 档后操作手机本身 | 挡不住,且档位越高能碰的越多 | 权限档位与隔离缺失在这里叠加 |
| 碰系统分区、偷其他 App 的数据 | 挡得住 | 这层是真的------①号安卓 App 沙箱在挡,但护住的是别人,不是你 |
一句话读这张表:伤害你的,一件都拦不住;伤害别人的,一件也干不成。
还有半句丑话要说完整:这不是"手机做得差、桌面做得好"的差距。 DSH 官方对自家沙箱的表述本来就很谨慎------动态包与 bash 同权,沙箱不构成安全边界(官方原话,Cordis 篇第七节引过)。把梯度摆出来:桌面有 bubblewrap 这层"尽力而为"的隔离、官方也不承诺它是安全边界;手机上连这层尽力而为都没有。
各项目的替代招数,如实列在下面------管的是"入口"和"概率",不是"圈住灾害":
- Soodok :21 个设备能力开关默认全关;Root 档下危险命令默认 dry-run;
rm进隔离区、可恢复; - dphmoblie:网络边界收得紧(第四节说过的只听 127.0.0.1 + 256 位临时令牌),另加支付、密码页面拒绝无障碍操作。
这些是减速带,不是防火门------恶意代码一旦拿到执行权,减速带就都已经绕过去了。一句话收束:当前"沙箱"的功能边界 = 安卓 App 沙箱的外壳 + 项目自己的权限门控;缺的那块是内核强制的进程/文件系统/权限隔离(user namespace 一族),只有安卓系统层能给答案。
七、这波创新到底在哪一层:三笔账 + 三句丑话
把五条路线放在一起看,"有点创新"这个直觉可以拆成三层,一层比一层深:
第一层,技术账:被约束逼出来的巧思。 安卓的约束清单很长------不给 root、sepolicy 禁 user namespace、Bionic 不兼容 glibc、W^X 限制执行。seccomp 容器在这张约束清单下做出了接近真 chroot 的性能(2.4ms vs 1.6ms),这不是"把开源软件移植到新平台"的常规操作,而是在系统调用层面重新发明了一个最小拦截面的兼容层。约束越紧,解法越见功力------这是这篇最值得记住的工程样本。
第二层,产品账:手机从"聊天入口"变成"执行环境"。 Termux + proot-distro 十年前就能在手机上跑完整 Linux,但那是极客玩具,门槛在命令行。这波做的事是把同一件事装进"APK → 填 Key → 三步引导"的盒子里,让普通用户也能拥有口袋里的 agent 工作站。配合Super-agent 架构篇里讲的 BYOM(个人设备接入)趋势------agent 的"手"越来越常放在个人设备上------手机端执行环境就从锦上添花变成了刚需。
第三层,生态账:一个新需求品类正在成型。 DSH 证明了 harness 对真实 Unix 环境的依赖是硬性的(shell、文件系统、工具链、包管理缺一不可),于是"App 自带完整 Linux 用户态"正在从奇技淫巧变成标配需求。这件事只有安卓能做------它允许 App 执行自己目录里的二进制;iOS 从政策层面就走不通。安卓的开放性在这里成了 agent 下沉端侧的试验田,这个信号比任何单个项目都重要。
丑话也照例三句(第一句的完整拆解在上一节):
- 没有真沙箱。 上一节拆的三层边界里,真正缺的是内核强制的隔离层------sepolicy 封死了 user namespace,社区层没有替代路径,这道题只能等安卓系统层给答案;
- 模型不在手机里。 所有安卓版的推理都走云端 API,别被"手机跑 AI agent"的说法带偏------手机跑的是 agent 的手脚,不是大脑;
- 安卓的顽疾一个没解决。 厂商后台查杀(README 点名 OplusHansManager 这类冻结策略)、无障碍权限被 ROM 回收、长任务被强停------agent 在手机上干活,得先学会在手机上活下来。
课程小结
- DSH 官方没有安卓版;火的是社区第三方移植,共同形态是"APK 内置 Linux + Node + DSH,推理走云 API"------推理在云,执行在端;
- 核心卡点在用户态不在内核:glibc 原生模块对上 Bionic、sepolicy 禁 user namespace、无可执行目录------五条路线本质上都是"免 root 再造一个 Linux 用户态";
- 两种代表性"App 内 Linux":PRoot (ptrace 全程拦截翻译,通用但每个 syscall 都有税)和 seccomp 容器(只拦带路径的少数 syscall,其余直通内核,单命令 2.4ms、比 PRoot 快 8--14 倍,容器层只占启动耗时的 0.8%);
- 沙箱要分三层看:安卓 App 沙箱是真的,但防的是"App 互相伤害";bubblewrap 那层(防 agent 跑的代码伤害你本人)被 sepolicy 封死;项目自称的"沙箱档"只是权限档位------agent 的本职就是执行不可信代码,缺的恰好是中间那层。衡量"真沙箱"就问三句话:代码坏到极致会怎样、笼子是谁焊的、降权藏东西限口粮做了几样,外加一张"越狱要付什么代价"的 TCB 阶梯;
- 创新分三层(技术/产品/生态),天花板也没藏着:无真沙箱、非端侧推理、厂商后台查杀------其中沙箱和杀后台是安卓系统层的题,社区层解不了。
思考题
- seccomp 方案把拦截面收窄到"带路径的系统调用",但如果某个插件要在容器里做
chroot或挂载文件系统,这个设计会发生什么?你会怎么补? - PRoot 性能税是原理性的(每个 syscall 都要拦),seccomp 方案是选择性的(只拦少数)。把这个对比推广到 gVisor、Wine 这类"用户态兼容层",你能总结出一个通用的设计权衡吗?
- "推理在云、执行在端"意味着你的代码仓库会经过云端模型、再回到手机本地执行。对照 dphmoblie 的供应链校验和 127.0.0.1 + 令牌设计,还有哪个环节是它没防住的?
延伸阅读
官方一手(2026-11-13 核实)
- deepseek-ai/deepseek-harness------DSH 官方仓库(约 28 万 star,MIT,developer preview)
- Soodok/Deepseek-Harness-Local-Android------seccomp 容器方案(本篇第五节主要素材,性能数字均出自其 README)
- dphmoblie/deepseek-harness-android------PRoot 方案(本篇第四节主要素材)
- DSH Mobile 发布讨论(DSH 官方 Discussions #6865,2026-09-16)
第三方(已标注)
- DeepSeek Harness 装进安卓手机的四条路线(mushroom.cv)------路线盘点框架来源;作者声明无安卓真机、未实测
- dsh-Go 报道(Hermes AI,2026-10-30)------dsh-Go 事实来源
- DSHA 完整指南:免 ROOT 免 Termux(CSDN)
关联课程 :开源 Harness 潮流全景盘点(DSH 开源时间线出处)| Cordis 深度解读(DSH 底座)| Super-agent 架构深度解读(BYOM 个人设备接入,本篇是它的"口袋版"注脚)
本文为内部学习整理:结构与评注为原创提炼;各项目数据(star、性能数字、机制描述)为 2026-11-13 各仓库 README / 官方 Discussions 数据,未做独立实测;gVisor 类比为笔者评注,非官方表述;流程图为内嵌 mermaid,仅作学习交流用途。