在 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,一经查实,立即删除!

相关文章

Java 8 Lambda表达式:基本语法及在集合中的应用

目录 Lambda表达式的基本语法 lambda表达式在集合中的应用 Lambda表达式的基本语法 (参数列表) -> { 函数体 } 其中: 参数列表:包含Lambda表达式的参数。如果参数只有一个,则括号可以省略。如果参数没有,则必须保留空括号。-…

HarmonyOS卡片生命周期管理

卡片生命周期管理 创建ArkTS卡片,需实现FormExtensionAbility生命周期接口。 在EntryFormAbility.ts中,导入相关模块。 import formInfo from ohos.app.form.formInfo; import formBindingData from ohos.app.form.formBindingData; import FormExtensi…

【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配置收费价格 阿里…

SpringBoot中 Mybatis 的xml映射文件配置

目录 1.依赖 2.示例代码 2.1不带resultMap标签示例 2.1带resultMap标签示例 3.resultMap标签不加的情况说明 1.依赖 在pom.xml文件中引入依赖 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter-t…

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

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

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

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

【每日前端面经】2023-02-27

题目来源: 牛客 CSS盒模型 CSS中的盒子包括margin|border|padding|content四个部分&#xff0c;对于标准盒子模型&#xff08;content-box&#xff09;的widthcontent&#xff0c;但是对于IE盒子模型&#xff08;border-box&#xff09;的widthcontentborder2padding2 CSS选…

C# 中的装箱(boxing)和拆箱(unboxing)

在 C# 中&#xff0c;装箱&#xff08;boxing&#xff09;和拆箱&#xff08;unboxing&#xff09;是用来在值类型&#xff08;如 int、double 等&#xff09;和引用类型&#xff08;如 object&#xff09;之间进行转换的过程。 装箱&#xff08;Boxing&#xff09;&#xff1…

ROS 图像预处理

为了使机械臂从复杂的场景中准确地识别出目标物体&#xff0c;首先要对机械臂相机采集的图像信息进行系列的预处理操作&#xff0c;图像预处理的目的就是为了方便提取采集图像的特征点信息。 1、图像灰度化 图像灰度化处理是一种将彩色图像转换为灰度图像的过程&#xff0c;目…

shell中正则表达式讲解

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

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

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

大语言模型LLM微调技术深度解析:Fine-tuning、Adapter-Tuning与Prompt Tuning的作用机制、流程及实践应用(LLM系列08)

文章目录 大语言模型LLM微调技术深度解析&#xff1a;Fine-tuning、Adapter-Tuning与Prompt Tuning的作用机制、流程及实践应用&#xff08;LLM系列08&#xff09;Fine-tuningAdapter-TuningPrompt Tuning策略对比与应用场景 大语言模型LLM微调技术深度解析&#xff1a;Fine-tu…

【vue】computed 、 watch、method 的区别

三个关键字【惰性】【缓存】【异步】 计算属性 computed 计算属性返回的值不属于 data&#xff0c;但是基于data声明的值会根据它们所依赖的数据的变化而自动重新计算惰性计算 初始化不会执行&#xff0c;只有在第一次访问时才会被计算render 函数执行时&#xff0c;会触发计算…

Gemma

Gemma 1.使用2.RAG3.LoRA3.1LoRA分类任务3.2LoRA中文建模任务 1.使用 首先是去HF下载模型&#xff0c;但一直下载不了&#xff0c;所以去了HF镜像网站&#xff0c;下载gemma需要HF的Token&#xff0c;按照步骤就可以下载。代码主要是Kaggle论坛里面的分享内容。 huggingface-…

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

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

RTCA DO-178C 机载系统和设备认证中的软件注意事项-附录 B

ANNEX B 附录 B 缩略语和术语表 ACRONYMS AND GLOSSARY OF TERMS 缩写 Acronym 释义 Meaning 译文 Translate ARP Aerospace Recommended Practice 航空航天推荐做法 ATM Air Traffic Management 空中交通管理 CAST Certification Authorities Software Team 认证机…

小程序里.vue界面中传值的两种方式

1.跳转携带参数后通过生命周期取值 1.1跳转 function juMp(){let arr JSON.stringify(specs.specs_data)wx.navigateTo({url:/pages/specs/specs?sku arr})}1.2取值 import {onLoad} from dcloudio/uni-apponLoad((event)>{let Arr JSON.parse(event.sku)})2.通过监听器…

String类-equals和==的区别-遍历-SubString()-StringBuilder-StringJoiner-打乱字符串

概述 String 类代表字符串&#xff0c;Java 程序中的所有字符串文字&#xff08;例如“abc”&#xff09;都被实现为此类的实例。也就是说&#xff0c;Java 程序中所有的双引号字符串&#xff0c;都是 String 类的对象。String 类在 java.lang 包下&#xff0c;所以使用的时候…

jquery实现select2插件鼠标点击任意地方时默认选中该输入框内的值

jquery实现select2插件鼠标点击任意地方时默认选中该输入框内的值 最近发现一个问题&#xff0c;插件select2中的select2可输入可选择的下拉框&#xff0c;在你输入值后鼠标点击别的地方&#xff0c;输入框内的值会被清空&#xff0c;特此记录一下这里的优化&#xff0c;这里修…