在 Android 运行 GNU/Linux 二进制程序 (proot)

在 GNU/Linux 系统上运行 Android 应用比较容易 (比如 waydroid), 但是反过来就很麻烦了.

Android 虽然也使用 Linux 内核 (kernel), 但是系统环境和一般的 GNU/Linux 系统 (比如 ArchLinux, Debian, Ubuntu, Fedora, NixOS 等) 具有不可忽略的显著差异, 所以为 GNU/Linux 编译的二进制可执行文件, 不能拿过来直接运行.

想要在 Android 系统运行这些应用, 有几种不同的方法. 性能最高的方法当然是重新编译, 编译后的二进制文件就可以直接在 Android 运行了, Termux 就是这么做的. 但是, 虽然最后一步很简单, 前面的为 Android 编译, 就是很麻烦甚至很困难的了.

如果能把为 GNU/Linux 编译的二进制文件直接拿来, 不加修改的运行, 在很多情况下会简单容易很多. proot 就是一种这样的技术. proot 通过使用 Linux 内核的 ptrace 功能, 对程序的内核调用 (syscall) 进行翻译, 从而实现一个很薄的兼容层, 性能只有很小的损失 (并不是虚拟机方法).

本文以应用程序 deno 举栗, 介绍在 Android 运行的方法. 本文不仅介绍最终结果 (具体的实现方案), 还重点说明探索的过程, 也就是这个结果是如何获得的.


相关链接:

  • https://proot-me.github.io/
  • https://github.com/proot-me/proot
  • https://termux.dev/
  • https://github.com/termux/termux-app
  • https://wiki.termux.com/wiki/PRoot
  • https://github.com/termux/proot
  • https://github.com/termux/proot-distro
  • https://deno.com/

目录

  • 1 获取所需文件
  • 2 组装运行环境
  • 3 测试
  • 4 总结与展望
  • 附录 1 proot-distro 简介

1 获取所需文件

本文的目标是构建一个相对独立的, 最小的运行环境. 这个运行环境所需的各种文件, 需要从多个地方分别获取.

  • (1) proot (termux)

    首先在手机上安装 Termux: https://termux.dev/

    然后在 Termux 中安装 proot:

    > pkg install proot
    

    在这里插入图片描述

  • (2) GNU/Linux 系统文件包 (proot-distro)

    这个需要从 proot-distro 的发布页面下载: https://github.com/termux/proot-distro/releases

    下载这个文件: debian-bookworm-aarch64-pd-v4.7.0.tar.xz

  • (3) deno (aarch64 linux)

    这个需要从 deno 的发布页面下载: https://github.com/denoland/deno/releases

    下载这个文件 (v1.41.0): deno-aarch64-unknown-linux-gnu.zip

2 组装运行环境

万事俱备, 可以开始拼凑运行环境了 !

  • (1) proot 运行所需文件.

    先来看看 proot 软件包都有哪些文件 (在 termux 中操作):

    > dpkg -L proot
    

    在这里插入图片描述

    其中 usr/bin/proot 是 proot 的可执行文件, usr/libexec/proot/loader 这个也是 proot 的重要组成部分.

    再来看看 proot 的依赖库:

    > ldd /data/data/com.termux/files/usr/bin/proot
    

    在这里插入图片描述

    libtalloc.so.2 这个是 proot 运行所需要的库文件, 需要注意. libc.so, ld-android.so, libdl.so 这些库是 Android 系统自身提供的, 不用管.

  • (2) deno 运行所需文件.

    把压缩包 deno-aarch64-unknown-linux-gnu.zip 解压之后, 把里面的 deno 文件拿出来, 放到 termux 中, 然后:

    > ldd deno
    

    在这里插入图片描述

    这里可以看到一些依赖库文件: libgcc_s.so.1, libpthread.so.0, libm.so.6, libc.so.6 等.

    deno 使用 rust 编程语言开发, 虽然 rust 号称是静态链接, 在最后生成的单个二进制可执行文件中打包所有依赖, 但实际上还是有少量系统库是动态链接的 (比如 glibc).

    把压缩包 debian-bookworm-aarch64-pd-v4.7.0.tar.xz 解压之后, 从里面获取此处所需的库文件.

  • (3) 开始组装:

    > find setup
    setup
    setup/proot
    setup/loader
    setup/libtalloc.so.2
    setup/run.sh
    setup/setup.sh
    setup/debian12_aarch64
    setup/debian12_aarch64/usr
    setup/debian12_aarch64/usr/bin
    setup/debian12_aarch64/usr/bin/env
    setup/debian12_aarch64/usr/bin/deno
    setup/debian12_aarch64/usr/lib
    setup/debian12_aarch64/usr/lib/aarch64-linux-gnu
    setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
    setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libc.so.6
    setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libm.so.6
    setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libpthread.so.0
    setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libgcc_s.so.1
    setup/debian12_aarch64/usr/lib/aarch64-linux-gnu/libdl.so.2
    

    这是最终组装好的运行环境的文件清单, 所有文件放在 setup 目录中. 其中 proot, loader, libtalloc.so.2 是从 termux 中获取的. usr/bin/deno 是从压缩包 deno-aarch64-unknown-linux-gnu.zip 中获取的. debian12_aarch64 目录中的文件是从压缩包 debian-bookworm-aarch64-pd-v4.7.0.tar.xz 中获取的.


其中 setup.sh 文件:

#!/system/bin/sh
echo setup.sh $1
#cd $1chmod +x run.sh
chmod +x proot
chmod +x loaderchmod +x debian12_aarch64/usr/bin/env
chmod +x debian12_aarch64/usr/bin/denomkdir -p tmp
mkdir -p debian12_aarch64/tmpln -s usr/lib debian12_aarch64/lib
ln -s aarch64-linux-gnu/ld-linux-aarch64.so.1 debian12_aarch64/usr/lib/ld-linux-aarch64.so.1echo setup ok.

这个脚本用来做一些初始化的事情.

其中 run.sh 文件:

#!/system/bin/sh
export LD_LIBRARY_PATH=$(pwd)export PROOT_TMP_DIR=$(pwd)/tmp
export PROOT_LOADER=$(pwd)/loader./proot \--bind=debian12_aarch64/tmp:/dev/shm \--bind=/sys \--bind=/proc/self/fd/2:/dev/stderr \--bind=/proc/self/fd/1:/dev/stdout \--bind=/proc/self/fd/0:/dev/stdin \--bind=/proc/self/fd:/dev/fd \--bind=/proc \--bind=/dev/urandom:/dev/random \--bind=/dev \-L \--kernel-release=6.2.1-PRoot-Distro \--sysvipc \--link2symlink \--kill-on-exit \--cwd=/ \--change-id=0:0 \--rootfs=debian12_aarch64 \/usr/bin/deno "$@"

这个脚本调用 proot 来运行 deno.

3 测试

测试设备: 手机 Android 11 (MIUI 12.5)

使用 USB 数据线连接 PC 和手机:

> adb devices
List of devices attached
643fa0f6	device

然后:

> adb push setup /data/local/tmp
setup/: 13 files pushed, 0 skipped. 62.6 MB/s (94798346 bytes in 1.444s)
> adb shell
raphael:/ $ cd /data/local/tmp/setup
raphael:/data/local/tmp/setup $ ls -l
total 288
drwxrwxr-x 3 shell shell   4096 2024-02-27 21:15 debian12_aarch64
-rw-rw-rw- 1 shell shell  30504 2024-02-26 19:39 libtalloc.so.2
-rw-rw-rw- 1 shell shell   5736 2024-02-27 01:59 loader
-rwxrwxrwx 1 shell shell 213976 2024-02-26 19:39 proot
-rwxrwxrwx 1 shell shell    590 2024-02-27 03:38 run.sh
-rw-rw-rw- 1 shell shell    356 2024-02-27 03:34 setup.sh
raphael:/data/local/tmp/setup $ chmod +x setup.sh
raphael:/data/local/tmp/setup $ ./setup.sh
setup.sh
setup ok.
raphael:/data/local/tmp/setup $ ls -l
total 296
drwxrwxr-x 4 shell shell   4096 2024-02-27 21:16 debian12_aarch64
-rw-rw-rw- 1 shell shell  30504 2024-02-26 19:39 libtalloc.so.2
-rwxrwxrwx 1 shell shell   5736 2024-02-27 01:59 loader
-rwxrwxrwx 1 shell shell 213976 2024-02-26 19:39 proot
-rwxrwxrwx 1 shell shell    590 2024-02-27 03:38 run.sh
-rwxrwxrwx 1 shell shell    356 2024-02-27 03:34 setup.sh
drwxrwxrwx 2 shell shell   4096 2024-02-27 21:16 tmp
raphael:/data/local/tmp/setup $ ./run.sh --version
deno 1.41.0 (release, aarch64-unknown-linux-gnu)
v8 12.1.285.27
typescript 5.3.3
raphael:/data/local/tmp/setup $ ./run.sh repl -A
Deno 1.41.0
exit using ctrl+d, ctrl+c, or close()
> 0.1 + 0.2
0.30000000000000004
> 

成功运行了 GNU/Linux (aarch64) 版本的 deno.

在这里插入图片描述

4 总结与展望

在 proot, termux, proot-distro 的帮助下, 我们终于成功在 Android 运行了最新版 deno. 这个小的运行环境是相对独立的, 可以单独拿出来放在一个地方就能运行.

虽然 proot 的工作原理很简单, 这个方案看起来也很简单, 窝之前以为不用费多大功夫就能轻松搞定. 实际上却是这也不行, 那也不行, 这里有问题, 那里也有问题, 这里是坑, 那里也是坑 … . 折腾了好久, 遭遇了许多困难和挫折, 因为太笨气哭了好几次, 擦干眼睛旁边的小小水滴之后, 才有了这个最终方案. 好在最后雨过天晴了, 努力没有白费.

最好的方法还是重新编译, 然后直接在 Android 运行. 但是为 Android 编译很麻烦甚至很困难的情况下, 本文的方法就是一个好的替代方案.

附录 1 proot-distro 简介

  • https://wiki.termux.com/wiki/PRoot
  • https://github.com/termux/proot-distro

proot-distro 是 termux 团队开发的一个工具, 用来方便的在 Termux 中安装和运行 GNU/Linux 发行版 (比如 debian).

  • (1) 在 termux 中安装 proot-distro:

    > pkg install proot-distro
    
  • (2) 查看有哪些发行版可用:

    > proot-distro list
    
  • (3) 安装一个发行版 (比如 debian):

    > proot-distro install debian
    
  • (4) 启动一个发行版 (比如 debian):

    > proot-distro login debian
    

然后就获得了一个在 Android 运行的 GNU/Linux 系统环境.

如果拿到一个 GNU/Linux 的二进制程序, 首先在这个环境中测试一下, 能不能正常运行. 这是快速验证的方法.

如果可以运行, 那再用本文的方法. 如果不能运行, 那就不用考虑本文了, 早点洗洗睡吧.

本文之中构建的运行环境, 其实就是 proot-distro 的运行环境简化而来.


本文使用 CC-BY-SA 4.0 许可发布.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/706388.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【React源码 - 调度任务循环EventLoop】

我们知道在React中有4个核心包、2个关键循环。而React正是在这4个核心包中运行,从输入到输出渲染到web端,主要流程可简单分为一下4步:如下图,本文主要是介绍两大循环中的任务调度循环。 4个核心包: react:…

4核8G服务器多少钱?腾讯云和阿里云哪家便宜?

4核8G云服务器多少钱一年?阿里云ECS服务器u1价格955.58元一年,腾讯云轻量4核8G12M带宽价格是646元15个月,阿腾云atengyun.com整理4核8G云服务器价格表,包括一年费用和1个月收费明细: 云服务器4核8G配置收费价格 阿里…

网站的安全防护需要注意哪些问题?有什么方法可以加固网站的防护

网站的安全防护,是一项复杂性、多方面的系统工程。现如今网络安全风险的增加,使得上至国家部门机关,小到个人博客,都有可能遭受网络安全问题。说到网络安全问题,比如:竞争最为激烈的游戏行业,从…

MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)

文章目录 一、InnoDB引擎逻辑储存结构二、架构——内存结构三、架构——磁盘结构四、架构——后台线程五、事务原理持久性:redo log。重做日志原子性:undo log。回滚日志 六、MVCC基本概念七、MVCC实现原理八、undo log日志 回滚日志,版本链九…

shell中正则表达式讲解

1. 概念 在进行程序设计的过程中,用户会不可避免地遇到处理某些文本的情况。有的 时候,用户还需要查找符合某些比较复杂规则的字符串。对于这些情况,如果 单纯依靠程序设计语言本身,则往往会使得用户通过复杂的代码来实现。但 是&…

在linux上不依赖于Nignx等服务器部署ASP.NET Core 7.0 WebAPI

笔者近期需要部署一款基于B/S架构的后端程序在linux的Debian发行版上,本文章以本次部署遇到的问题为线索,总结如何在Debian上部署ASP.NET Core7.0WebAPI应用程序。 在linux上不依赖于Nignx等服务器部署ASP.NET Core 7.0 WebAPI 1.先决条件2.应用发布3.部…

3D可视化项目,选择unity3D还是three.js,是时候挑明了。

2023-08-10 23:07贝格前端工场 Hi,我是贝格前端工场,在开发3D可视化项目中,是选择U3D还是three,js时,很多老铁非常的迷茫,本文给老铁们讲清楚该如何选择,欢迎点赞评论分享转发。 一、Unity3D和three.js简…

[Mac软件]Adobe Substance 3D Stager 2.1.4 3D场景搭建工具

应用介绍 Adobe Substance 3D Stager,您设备齐全的虚拟工作室。在这个直观的舞台工具中构建和组装 3D 场景。设置资产、材质、灯光和相机。导出和共享媒体,从图像到 Web 和 AR 体验。 处理您的最终图像 Substance 3D Stager 可让您在上下文中做出创造性…

网络原理——HTTPS

HTTPS是 在HTTP的基础上,引入了一个加密层(SSL)。 1. 为什么需要HTTPS 在我们使用浏览器下载一些软件时,相信大家都遇到过这种情况:明明这个链接显示的是下载A软件,点击下载时就变成了B软件,这种情况是运…

计算机设计大赛 深度学习手势检测与识别算法 - opencv python

文章目录 0 前言1 实现效果2 技术原理2.1 手部检测2.1.1 基于肤色空间的手势检测方法2.1.2 基于运动的手势检测方法2.1.3 基于边缘的手势检测方法2.1.4 基于模板的手势检测方法2.1.5 基于机器学习的手势检测方法 3 手部识别3.1 SSD网络3.2 数据集3.3 最终改进的网络结构 4 最后…

深入理解Python中的JSON模块:基础大总结与实战代码解析【第102篇—JSON模块】

深入理解Python中的JSON模块:基础大总结与实战代码解析 在Python中,JSON(JavaScript Object Notation)模块是处理JSON数据的重要工具之一。JSON是一种轻量级的数据交换格式,广泛应用于Web开发、API通信等领域。本文将…

WinForms中的Timer探究:Form Timer与Thread Timer的差异

WinForms中的Timer探究:Form Timer与Thread Timer的差异 在Windows Forms(WinForms)应用程序开发中,定时器(Timer)是一个常用的组件,它允许我们执行定时任务,如界面更新、周期性数据…

osi模型,tcp/ip模型(名字由来+各层介绍+中间设备介绍)

目录 网络协议如何分层 引入 osi模型 tcp/ip模型 引入 命名由来 介绍 物理层 数据链路层 网络层 传输层 应用层 中间设备 网络协议如何分层 引入 我们已经知道了网络协议是层状结构,接下来就来了解了解下网络协议如何分层 常见的网络协议分层模型是OSI模型 和 …

windows 连接 Ubuntu 失败 -- samba服务

1. windows10连接ubuntu的时候,提示不允许一个用户使用一个以上用户名与服务器或共享资源的多重连接,中断与此服务器或共享资源的所有连接,然后再试一次 2. 换一台同事的电脑却又可以连上,我之前一直能用的,隔一段时间…

UE5 C++ 单播 多播代理 动态多播代理

一. 代理机制,代理也叫做委托,其作用就是提供一种消息机制。 发送方 ,接收方 分别叫做 触发点和执行点。就是软件中的观察者模式的原理。 创建一个C Actor作为练习 二.单播代理 创建一个C Actor MyDeligateActor作为练习 在MyDeligateAc…

【蓝桥杯】包子凑数(DP)

一.题目描述 二.输入描述 三.输出描述 四.问题分析 几个两两互质的数,最大公约数是1,最小公倍数是他们的乘积。 两个互质的数a和b最小不能表示的数就是(a-1)(b-1)-1,即,两个互质的数…

uniapp_微信小程序日历

一、需求要求这样 二、代码实现 <view class"calender" click"showriliall"><text class"lineText">探视日期&#xff1a;</text><text class"middleText">{{timerili}}</text><image src"/s…

Ubuntu服务器fail2ban的使用

作用&#xff1a;限制ssh远程登录&#xff0c;防止被人爆破服务器&#xff0c;封禁登录ip 使用lastb命令可查看到登录失败的用户及ip&#xff0c;无时无刻的不在爆破服务器 目录 一、安装fail2ban 二&#xff0c;配置fail2ban封禁ip的规则 1&#xff0c;进入目录并创建ssh…

【c++leetcode】1382. Balance a Binary Search Tree

问题入口 DSW (DAY, STOUT & WARREN) ALGORITHM 时间复杂度O(n) class Solution { public:int makeVine(TreeNode* grand, int cnt 0){auto n grand->right;while (n ! nullptr){if(n->left ! nullptr){auto old_n n;n n->left;old_n->left n->righ…

力扣hot100题解(python版18-21题)

18、矩阵置零 给定一个 *m* x *n* 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法**。** 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例…