一个问题

当你首次安装 Termux,打开 App 看到一个 $ 提示符时,有没有想过一个根本问题:Android 根本没有 /bin/usr/lib 这些标准 Linux 目录,那 lsbashapt 这些命令从哪里来?

这就是 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 编译版本)需要的是标准的 glibcmusl 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 可以安装 pythonnodejsopensshgit 等,和 Debian/Ubuntu 的体验几乎一致。

dpkg 数据库(/data/data/com.termux/files/usr/var/lib/dpkg/)记录了所有已安装包的信息,确保依赖关系和版本一致性。

为什么 Bootstrap 不能简单复制到另一台手机?

了解了 Bootstrap 的过程,就明白为什么无法把 Termux 环境"打包成 APK"发给别人:

  1. 架构绑定:Termux 的软件包是为 ARM64 编译的,复制到 x86 手机直接段错误
  2. Android 版本依赖:proot 的 ptrace 行为依赖内核版本,Android 版本不同可能导致 proot 行为异常
  3. 内核特性:Android 内核可能禁用了某些 CONFIG_ 特性,导致某些虚拟文件系统功能不可用
  4. 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 操作系统。