玩转Termux | 10.内部实现
玩转Termux | 10.内部实现
Termux是一个在Android设备上运行Linux环境的实用工具,它能够在不获取root权限的情况下,为用户提供一个完整的Linux终端环境。本文将深入探讨Termux的内部实现原理,包括其系统架构、关键技术和具体实现过程。
系统架构
整个系统包含两部分内容:
客户端软件:
一个前端模拟器,用于实现一个终端命令行界面
一个根文件系统,这里包含一个最小系统,类似于Linux发行版的live CD,里面包含了最基础的系统命令,通过这些命令,可以下载更大的系统。
服务器软件:
一套包管理系统,类似Ubuntu的apt
三方软件包
我们重点放在客户端软件上。
实现
我们通过几个典型问题来了解Termux的一些内部实现逻辑。
为什么不需要root权限?
要实现一套Linux系统体验,需要三样东西:Linux内核、根文件系统、以及chroot命令,其中Linux内核是Android系统自带的,可以直接用。根文件系统是Termux App提供的,chroot是一个系统命令,一般存在根文件系统中。但执行chroot需要root权限才行。Termux是如何做到不需要root权限的呢?
答案就是:修改了所有软件的PREFIX
到/data/data/com.termux/files/usr
,这样就不需要用到传统Linux的典型目录结构(/etc, /bin /sbin
等),看上去是个笨方法,但非常有效。因此直接从其他开源仓库中下载的软件包时不能直接在Termux上使用的,需要按照Termux的规则重新编译和修改相关路径才可以。
如何制作一个根文件系统?
通过这个子项目:termux-packages(https://github.com/termux/termux-packages),这里有全部三方软件包的编译脚本和patch,它不但可以编译生成一个最小根文件系统,还能生成所有三方软件包,共计1000+个。
这个项目中也有编译好的最小根文件系统压缩包:bootstrap-xxx.zip,在这个地址可以找到https://github.com/termux/termux-packages/releases。
一个典型的最小根文件系统目录结构是这样的:
.
├── SYMLINKS.txt # 符号连接配置项,首次启动APP的时候用到
├── bin # 系统命令
├── etc # 系统配置
├── include # 系统库头文件
├── lib # 系统库文件
├── libexec
├── share
├── tmp
└── var
如何将一个根文件系统装进APK的?
.global blob
.global blob_size
.section .rodata
blob:
#if defined __i686__
.incbin "bootstrap-i686.zip"
#elif defined __x86_64__
.incbin "bootstrap-x86_64.zip"
#elif defined __aarch64__
.incbin "bootstrap-aarch64.zip"
#elif defined __arm__
.incbin "bootstrap-arm.zip"
#else
# error Unsupported arch
#endif
1:
blob_size:
.int 1b - blob
上面的代码非常简单,有用的就是两个变量:
blob
:存储者压缩包的起始地址blob-size
:存储压缩包大小
有了这两个变量,就可以解压缩了。这里的.incbin
指令负责将压缩包打包到so中
APP首次启动流程是什么?
- 启动activity:
TermuxActivity::onCreate()
- 解压缩bootstrap压缩包到
/data/data/com.termux/files/
下: TermuxInstaller::setupBootstrapIfNeeded()
- 启动命令行
$PREFIX/bin/login
: TermuxTerminalSessionActivityClient::addNewSession()
TermuxService::createTermuxSession()
TermuxSession.execute()
- 启动
$PREFIX/bin/bash
:$PREFIX/bin/login
脚本负责调用bash,接收终端用户输入。