玩转termux | 10.内部实现

2024/03/18 | 字数1618 | 阅读4分钟


这是笔者的一个嗜好,喜欢研究软件的内部实现。今天我们就来扒一扒termux,看看它是如何做到在Android系统上搭建一套Linux系统的,关键还不需要root权限,只通过一个APP就做到了。

系统架构

架构图

整个系统包含两部分内容:

  1. 客户端软件:
    • 一个前端模拟器,用于实现一个终端命令行界面
    • 一个根文件系统,这里包含一个最小系统,类似于Linux发行版的live CD,里面包含了最基础的系统命令,通过这些命令,可以下载更大的系统。
  2. 服务器软件:
    • 一套包管理系统,类似ubuntu的apt
    • 三方软件包

我们重点放在客户端软件上。

实现

我们通过几个典型问题来了解termux的一些内部实现逻辑。

  1. 为什么不需要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的规则重新编译和修改相关路径才可以。

  1. 如何制作一个根文件系统?

通过这个子项目:termux-packages(https://github.com/termux/termux-packages),这里有全部三方软件包的编译脚本和patch,它不但可以编译生成一个最小根文件系统,还能生成所有三方软件包,共计1000+个。

这个项目中也有编译好的最小根文件系统压缩包:bootstrap-xxx.zip,在这个地址可以找到 https://github.com/termux/termux-packages/releases

一个典型的最小根文件系统目录结构是这样的:

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
.
├── SYMLINKS.txt ## 符号连接配置项,首次启动APP的时候用到
├── bin          ## 系统命令
├── etc          ## 系统配置
├── include      ## 系统库头文件
├── lib          ## 系统库文件
├── libexec
├── share
├── tmp
└── var
  1. 如何将一个根文件系统装进APK的?

这个项目termux-app (https://github.com/termux/termux-app)负责生成我们用到的termux.apk,在这个项目中,app/src/main/cpp目录负责将上面的bootstrap-xxx.zip打包为libtermux-bootstrap.so动态库给APK使用,实现的代码在一个termux-bootstrap-zip.S汇编代码中:

asm
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
     .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

上面的代码非常简单,有用的就是两个变量:

有了这两个变量,就可以解压缩了。

这里的.incbin指令负责将压缩包打包到so中

  1. 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,接收终端用户输入。

参考

上一篇:玩转termux | 9.外网访问

【文章不错,鼓励一下】