一个问题
当你首次安装 Termux,打开 App 看到一个 $ 提示符时,有没有想过一个根本问题:Android 根本没有 /bin、/usr、/lib 这些标准 Linux 目录,那 ls、bash、apt 这些命令从哪里来?
这就是 Bootstrap(自举启动)要解决的问题。
Android 文件系统的"缺损"
标准 Linux 文件系统有一棵大家熟悉的目录树:
/
├── bin/ # 基础命令
├── lib/ # C 运行库 (libc.so)
├── usr/
│ ├── bin/ # 用户级命令
│ └── lib/ # 用户级库
├── etc/ # 系统配置
└── proc/ # 进程虚拟文件系统
Android 虽然基于 Linux 内核,但它的文件系统布局完全不同:
- 没有
/bin、/lib、/usr这些目录 - C 运行库不是
glibc,是 Google 定制的bionic - App 被严格沙箱化,每个 App 只能访问自己的数据目录
- 不能直接执行来自文件系统的二进制程序(root 用户除外)
Termux 要做的,就是在这样一个"缺损"的环境中,凭空构建出一套完整的 Linux 用户空间。
Bootstrap 的四个阶段
阶段一:加载自己的 C 运行库
Linux 上每一个二进制程序都依赖 C 运行库(libc)。Android 的 bionic libc 为移动端做了大量裁剪,Termux 的软件包(来自 Debian/Ubuntu 的 ARM 编译版本)需要的是标准的 glibc 或 musl libc。
Termux 的做法是在自己的数据目录里自带一整套 Linux 用户空间的文件:
/data/data/com.termux/files/usr/
├── bin/ # bash, ls, apt, python...
├── lib/ # libc.so, libm.so, libdl.so...
├── etc/ # apt 源配置, bashrc...
├── tmp/ # 临时文件
└── var/ # dpkg 数据库
当启动 Termux 时,它的 native loader 会修改 LD_LIBRARY_PATH 环境变量,让动态链接器先搜索自己的 /data/data/com.termux/files/usr/lib/,而不是系统默认路径。这样,Termux 中的程序全部使用自带的 C 运行库,跟 Android 系统的 bionic libc 互不干扰。
阶段二:构建虚拟文件系统
即使有了自己的 /lib,Linux 程序还需要虚拟文件系统来正常工作:
/proc:进程信息(ps命令需要)/dev:设备节点(pty 终端需要)/dev/pts:伪终端(命令行交互需要)
Android 对 App 沙箱的访问控制非常严格。常规 App 根本没权限挂载 /proc 和 /dev。
Termux 利用了 proot(PTRACE Root) 这种"用户态 chroot"技术:
proot 原理:
1. 使用 ptrace() 系统调用拦截目标进程的所有系统调用
2. 当目标程序试图访问 /bin/ls 时,proot 把路径翻译成
/data/data/com.termux/files/usr/bin/ls
3. 当目标程序试图访问 /proc 时,proot 用自定义实现
来模拟 /proc 文件系统
4. 整个过程不需要 root 权限,纯用户态完成
简单理解:proot 像一个"翻译官",把所有文件路径从标准 Linux 格式翻译成 Android App 数据目录下的实际路径。
阶段三:初始化 Shell 环境
文件系统就绪后,Termux 启动 bash Shell,然后执行一系列初始化脚本:
1. bash 启动
2. source /data/data/com.termux/files/usr/etc/bash.bashrc
↓
3. 设置 PATH=/data/data/com.termux/files/usr/bin:...
4. 设置 TERM=xterm-256color
5. 设置 HOME=/data/data/com.termux/files/home
6. source ~/.bashrc(如果有的话)
至此,一个熟悉的 Linux Shell 环境就出现了。
阶段四:包管理器(apt/dpkg)
Termux 最后一个关键环节是 apt 包管理器。它会读取:
/etc/apt/sources.list
里面配的 Termux 社区仓库,包含数千个经过 ARM 编译适配的 Linux 软件包。通过 pkg install 可以安装 python、nodejs、openssh、git 等,和 Debian/Ubuntu 的体验几乎一致。
dpkg 数据库(/data/data/com.termux/files/usr/var/lib/dpkg/)记录了所有已安装包的信息,确保依赖关系和版本一致性。
为什么 Bootstrap 不能简单复制到另一台手机?
了解了 Bootstrap 的过程,就明白为什么无法把 Termux 环境"打包成 APK"发给别人:
- 架构绑定:Termux 的软件包是为 ARM64 编译的,复制到 x86 手机直接段错误
- Android 版本依赖:proot 的 ptrace 行为依赖内核版本,Android 版本不同可能导致 proot 行为异常
- 内核特性:Android 内核可能禁用了某些
CONFIG_特性,导致某些虚拟文件系统功能不可用 - selinux 策略:不同厂商的 selinux 策略不同,可能影响 Termux 的文件访问权限
简单说:Termux 不是"装一个 App 就好了",它是"在自己的数据目录里搭建了一个和手机硬件/内核紧密绑定的微型操作系统"。
局限性
Bootstrap 带来了终端环境,但也有一些限制:
| 能做的 | 不能做的 |
|---|---|
| 运行各种脚本和服务器 | 直接操作系统文件(没有 root) |
| 安装 Linux 软件包 | 访问其他 App 数据(沙箱隔离) |
| SSH 连接、Web 服务 | 修改 Android 系统设置 |
| 使用标准开发工具链 | 使用需要 root 权限的底层工具 |
总结
Termux 的 Bootstrap 本质是在 Android 沙箱里模拟了一套 Linux 用户空间,核心依赖三个技术:
- 自带 C 运行库:绕过 Android bionic libc 的限制
- proot/ptrace:用户态文件路径翻译 + 虚拟文件系统模拟
- apt/dpkg:标准 Linux 包管理体验
这就是为什么打开一个 Android App 就能看到熟悉的 $ 提示符——它背后是一套精密的自举机制,在没有 root 权限的情况下,凭空构建了一个微型 Linux 操作系统。