把下面整段粘贴给 DSH 即可。 重要:本提示词**不含任何设备硬编码**(不写型号、CPU、内存、系统版本)。所有硬件与系统事实由你自己探测—— 如果你发现本机条件更好(有 root、内核支持 Landlock、存在可写可执行的非 FUSE 分区等),请主动利用,并告诉我因此多出了哪些能力。 ──────────────────────────────────────────────────────────── # 任务 把这台 Android 手机改造成一台 7×24 在线的 Linux 小服务器,并在最后交付一份可验证的验收报告。 你现在运行在手机内部(容器里的 Web 控制台)。所有"只能人工做"的步骤(装应用、点系统弹窗、厂商私有设置)人已经做完,其余全部由你完成。 请注意你自己的"视角":你的 bash 工具跑在容器里,它看到的内核版本、负载、可用权限都可能被翻译层加工过。 凡是与内核、性能、负载、权限有关的判断,都要再经 SSH(宿主)或 adb(整机)**交叉验证**一次,别单凭容器内的读数下结论。 # 第 0 步:先探测环境,不要假设 在动手之前,先把下面这些事实查清楚,写成一段 5~10 行的"环境事实",之后每一步都以它为依据: 原生侧(需要先建立 SSH 通道,见交付项 1;或先用 adb): uname -r; uptime; nproc; free -m; df -h /data getprop ro.build.version.release; getprop ro.build.version.sdk; getprop ro.product.cpu.abi 容器侧: cat /etc/os-release; node -v; ldd --version | head -1 adb 侧(注意:`adb devices` 里可能额外冒出一个 `emulator-XXXX` 的假条目——那是 adb 把 TCP 调试端口误当成了模拟器端口。 忽略它,并**始终用 `-s <地址:端口>` 指定目标**,否则会报 "more than one device/emulator"): adb devices adb -s 127.0.0.1:5555 shell id adb -s 127.0.0.1:5555 shell getprop ro.build.version.release adb -s 127.0.0.1:5555 shell device_config get activity_manager max_phantom_processes 如果 adb 不可用(`unauthorized` / 连不上):先确认设备端是否弹了授权对话框(需要人点"允许"); 若是较新 Android 的"无线调试",还需要先用配对码配对:`adb pair 127.0.0.1:<配对端口>`(配对码要问用户)。 需要你判定的关键问题(结论会影响方案,别略过): - 你这个 shell 是不是跑在某种"翻译层"里?对比 `id` 与 `/proc/self/status` 里的 `Uid`,看 `TracerPid`,看 `/proc/self/exe` 指向谁 - 内核版本是多少?是否 ≥ 5.13(决定有没有 Landlock 真正的文件沙箱可用) - `/sdcard` 是不是 FUSE 文件系统(能否执行文件、能否建软链、chmod 是否生效) - 是否存在可写且可执行的分区(决定服务该放哪) - Termux 侧的 `sh` 到底是 bash 还是 dash;`~/.termux/boot/` 是否存在 - ROM 是否有激进的后台管理(华为/小米/OPPO/vivo 等);`max_phantom_processes` 是否还是默认值 # 环境类别特征(这套方案的常见陷阱,逐条实测确认,不要当事实直接采信) 若你的 bash 跑在 proot 类翻译层里: - 身份是"假 root":`id` 显示 uid=0,但 `/proc/self/status` 里 Uid 是宿主 app uid;`CapEff` 通常为 0 - 因此:不能绑 <1024 端口、`mount`/`setgid` 可能"返回成功但无效"、`unshare` 可能返回 0 却没有真正隔离 - `/proc/loadavg`、`/proc/stat`、`/proc/uptime` 有可能是**静态快照文件**(读数永远不变)→ 真实负载用 `uptime`(走 sysinfo 系统调用) - `uname -r` 可能是伪造的 → 真实内核版本走 SSH 到宿主侧查 - `/sdcard` 通常是 FUSE:**不能执行文件**、不能建软链、chmod 无效 - 沙箱探测可能是**假阳性**:某些隔离工具在翻译层下会"报告成功但毫无约束"。如果你为了"让沙箱可用"而安装了它,务必用"往只读挂载里写文件"这种实验验证真实效果;验证不了就保持 fail-closed,不要制造"已隔离"的错觉 若宿主是 Termux(Android 上的 Linux 用户态): - `$PREFIX/bin/sh` 可能是 **dash** 而不是 bash:脚本只写 POSIX 语法,shebang 一律用绝对路径 - `pgrep -x` / `pkill -x` 这类**按进程名匹配可能不可靠**:判断服务是否在跑请用**端口探测**(python3 socket),挑进程请用 `/proc/*/exe` 精确匹配 - 装包用 `pkg install`;宿主侧的私有目录在容器内通常可见(bind mount),你可以直接读写它(这一点后面有大用) - 端口探测脚本需要宿主侧有 **python3**:没有就先 `pkg install python3`(你也可以用别的可靠探测方式,但别依赖按进程名匹配) - 如果 `pkg install` 失败或极慢,先检查软件源镜像是否失效(换一个可用镜像再试),不要盲目重试几十次 - 访问共享存储通常需要用户级授权:如果被拒绝,请用户执行宿主的存储授权命令(会弹系统对话框,需要人点"允许") - **非交互式 SSH 命令不会读 `~/.bashrc`**:所以"打开终端就自动补齐服务"的兜底钩子只在人真正打开终端时生效,不能把它当常驻保障 - `$PREFIX/etc/profile` 会 source `~/.bashrc`(交互式登录时)→ 这是做"打开终端自动拉起服务"的钩子位置 - 宿主 SSH 的**用户名往往不重要**(认证会把任意用户名映射到同一个 app uid),别在"我该用哪个用户名"上卡住; 首次连接记得放宽 host key 校验(例如 `-o StrictHostKeyChecking=accept-new`) - 登录横幅:`login` 通常**优先执行用户级的 `~/.termux/motd.sh`**,其次才是 `$PREFIX/etc/motd*`。要定制横幅请动用户级文件,不要改系统文件 若系统是较新的 Android: - 存在"子进程过多的应用会被杀"的限制(幽灵进程监控)。检查 `device_config get activity_manager max_phantom_processes`; 如果它还是默认值(常见 32),而你需要跑很多子进程,就把它调大: `adb shell device_config put activity_manager max_phantom_processes 2147483647` - 注意 `service.adb.tcp.port` 这类属性**重启后未必保留**(但 adb 授权是持久的,重启后再连一次即可) # 你要交付的东西(按顺序做,每步都要验证并给出真实证据) 1. **建立原生通道(SSH)**:宿主侧应当已经有 SSH 服务在监听(如果还没有,告诉用户先执行:`pkg install -y openssh && ssh-keygen -A && sshd`)。 然后你自己完成剩下的事: - 在容器里生成密钥对;把公钥写入宿主家目录的 `~/.ssh/authorized_keys`(目录 700、文件 600)——**你不需要用户帮你复制公钥** - `ssh -p 8022 ...@127.0.0.1` 连上去,并用 `TracerPid=0`、真实 `uname -r`、真实 `uptime` 证明这条通道是真原生(不是翻译层的子进程) - 记住一个结论:**从这一刻起,宿主侧的一切操作都走 SSH**(装包、起服务、写开机脚本),因为宿主的家目录就是开机脚本所在的地方 2. **原生侧装服务**: - 网盘:优先用宿主包管理器里的 OpenList(它是 AList 的继任者,包元数据里通常 `Provides/Replaces: alist`)。数据目录放 app 私有区,**不要放 /sdcard**(SQLite 在 FUSE 上不可靠) - 下载器:aria2。配置要点:只监听 127.0.0.1、设 `rpc-secret`、`dir` 指向你的下载目录、FUSE 目标分区上 `file-allocation=none`、 `save-session` + `input-file` 做断点续传;**绝对不要开 `force-save`** —— 它会把已完成任务留在会话文件里, 而网盘程序下载完成后会把文件从临时目录移走,于是重启后下载器按会话文件重新加载、发现临时目录空了、就把同一批文件**又下一遍**(这个坑我们踩过,1.7GB 白下) - 启动方式统一用 `setsid nohup ... &` 脱离会话,避免随终端关闭而死 - 装完下载器后做一次**端到端小测试**:用一个几十 KB 的 URL 触发下载,确认文件真的落盘、RPC 里能看到任务, 然后**清理测试文件与任务记录**(别在你用户的下载目录里留测试残留) 3. **网盘配置**(可以用管理界面,也可以直接改它的配置/数据库;改前先备份): - 挂载本地存储指向共享存储目录,**验证状态是 "work"**(不是只看到配置项存在) - 把它的临时目录改到共享存储下的一个独立目录(与最终存储同一文件系统 → 完成后是 rename 而不是跨设备复制) - 如果它用临时目录+移动的方式处理下载,注意回收站/临时目录要放在**同一文件系统**内,否则移动会失败 - 接上下载器:在它的设置里填上 aria2 的 RPC 地址与密钥,并**验证真的连上了**(不是只填了字段) 4. **管理员密码的卫生**(很重要): - 初始化或重设管理员密码时,**不要把明文写进对话**;生成随机值后写入权限 600 的文件,并告诉用户如何读取 - 注意很多这类程序的重设命令会把**明文密码写进日志**:事后要清理那份日志,并在汇报里提醒用户 - **不要修改用户已有的密码**(除非用户明确要求) 5. **开机自启 + 保活**(这是"7×24"的关键): - 写宿主侧开机脚本(例如 `~/.termux/boot/01-services.sh`,**chmod 700**),要求: · 守卫用**端口探测**(每个服务一个端口),幂等:已在跑就跳过,绝不产生重复实例 · 结构用 `if/else`,守卫在前台、只把启动命令 `setsid nohup ... &` 放后台(不要写成 `A || B &`,那会把守卫一起丢进后台) · 全部绝对路径(开机时环境极简,PATH 可能不全) · 每个服务写各自的日志,并写一份主日志(例如 `~/boot.log`),记录**触发者**(父进程的命令行)与**当前 uptime** —— 这样"开机触发"和"打开终端触发"一眼可分,"广播被拦"和"脚本报错"也能分清 - **加一层兜底**:在宿主 `~/.bashrc` 里挂一个"确保服务在跑"的钩子(打开终端就补齐),并把当前控制台地址打印出来 - `termux-wake-lock`(若存在)也叫上,减少系统休眠导致的冻结 - 自启验证必须**真的重启一次**:`adb reboot` 会把你一起杀掉,所以**让用户来重启**;重启前把状态写盘,并告诉用户重启后怎么核对 - 前置条件(属于人工步骤,缺了要提醒用户补):宿主侧的开机自启插件必须**与宿主应用同源同签名**、并且**被打开过一次**; 某些厂商 ROM 还要在"应用启动管理/自启动管理"里放行它 - **如果重启后开机日志是空的**:优先怀疑"开机广播没送到"(插件没装、没打开过、签名不一致、被厂商后台管理拦截), 其次才怀疑脚本本身;不要一上来就改脚本 6. **小工具 + 登录提示**: - 端口探测脚本(python3 socket)、控制台地址工具(显示/保存/打开)、服务状态脚本、临时目录查看/清理脚本 - 控制台自身也要留档:它的启动输出里通常有一个**一次性地址**(每次启动都不同、打开一次后换取长期 cookie), 所以启动脚本要把输出 `| tee -a` 到日志,并提供命令让用户随时找回地址 - 登录横幅(MOTD):先显示系统默认横幅,再显示常用命令与**本次控制台地址**(用用户级文件,别改系统文件) 7. **验收报告**(markdown 写到工作区,并在对话里给要点): - 每个服务:端口是否监听、进程是否只有一个、各自日志尾部(附命令与真实输出) - 开机脚本的日志内容(证明触发者与 uptime) - 下载器:RPC 可用、无残留任务、会话文件为空 - 网盘:存储挂载状态、临时目录位置 - 资源占用:用 adb 抓 `dumpsys meminfo`(PSS)/ `dumpsys cpuinfo` / `batterystats --charged`, 重点列出本次部署的进程,并指出翻译层本身的 CPU 开销(这是这类方案的真实成本) - 电池体检(如果这台设备是常年插电使用):`adb shell dumpsys battery` 记录 `level / temperature / health`; 若温度长期偏高或健康度明显下降,提醒用户考虑"充电上限设 80%"或用定时插座限制充电时间, 必要时更换为直供电电池小板(长期满电 + 高温会导致锂电池鼓包,这是硬件安全项) - **重启后复核**:等用户重启完成后,核对开机日志是否有"距开机 1 分钟内"的记录、端口是否都在、adb 是否需要重连 - **明确列出仍需人工完成的剩余项**(如果有) # 工作方式(重要) - **先只读取证,再动手**。任何写操作前先确认当前状态,并说明:要改什么、为什么、怎么回滚 - 一次只改一件事,改完**立刻验证**(端口/进程/日志/HTTP 状态码/哈希) - 所有自动化脚本必须**幂等 + 可回滚 + 有日志** - 每一步都给**证据**(命令 + 真实输出片段),不要用"应该可以了"这类表述 - 修改配置文件前先备份;重启服务前先确认没有别的实例在占用端口 - 清理进程时用 `/proc/*/exe` 精确挑选 pid;**别用 `kill -9 -$PGID` 这类批量杀法**(模式匹配到自己就一起死) - 也不要用 `pgrep -f <模式>` 做守卫:你的模式串可能出现在别的进程(甚至自己)的命令行里造成误判 # 安全红线(不可越) - 不修改用户已有的密码;不把密钥/token 明文打印到对话里(写文件 + 告知读取方式) - 不为"让沙箱可用"而安装会产生**假隔离**的东西(先验证真实性,验证不了就保持拒绝执行的状态) - 不开启宿主侧"允许外部应用执行命令"之类的开关;如确有必要,先解释安全代价并取得明确同意 - 不放可执行文件到 FUSE 分区(那边通常 noexec);不把 adb 私钥复制出私有目录 - 不执行 `adb reboot`(会连你自己一起杀掉) - 删除数据前先给证据(大小/哈希比对)并征得同意 # 必须停下来找人的情况 - 需要重启设备、需要点系统弹窗、需要改厂商私有设置(后台管理/省电策略) - adb 连不上(可能需要人重新打开"无线调试"或再执行一次 `adb tcpip`) - 需要你无法获取的凭据,或某个操作要求确认(例如卸载/停用系统应用) 汇报格式:**要人做什么 → 为什么你做不了 → 做完如何确认**。 # 可选扩展(先问用户要不要) - 终端 API 能力(通知/剪贴板/传感器)、WebDAV 对外共享、BT 下载器、定时任务、 把控制台也纳入自启并延长登录有效期、定期资源报告与趋势对比