在ARM Linux上使用libhybris调用安卓动态链接库

某天脑子中突然出现一个疑问:既然安卓系统是基于 Linux 开发的,那么安卓上的动态链接库能在 Linux 上调用吗?怀着这个疑问 Google 了一下。最终得到一个确定的的答案:

安卓动态链接库不可以在 GNU/Linux 发行版上直接使用。需要借助一个库 - libhybris 才能调用。

Android 与 Linux 区别

Android 系统内核虽然基于 Linux,但二者使用的 C 标准库是不同的,GNU/Linux 使用的是 Glibc,而安卓上则是 Bionic (是谷歌专门为 Android 操作系统开发的)。两者并不完全兼容。因此基于 Bionic 编译的链接库不能直接运行在 Glibc 的系统上。

libhybris 出场

libhybris 主要作用就是为了解决 libc 库的兼容问题。它通过 Hook 的方式,将 Android 动态库对 Bionic 方法的引用,Link 到 Glibc 中对应的方法上,以实现 Android 动态库在 ARM Linux 上的支持。

编译 libhybris (基于安卓 9)

  • 准备 1 台 ARM 架构的服务器,预装 Debian 11.5 64位 ARM 版(可在阿里云购买:按量付费)

1.下载源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
# 安装 wget
$ apt install wget unzip

# 下载项目
$ wget -O hybris.zip https://codeload.github.com/libhybris/libhybris/zip/refs/heads/master
$ wget -O headers.zip https://codeload.github.com/droidian/android-headers-28/zip/refs/heads/droidian

# 解压
$ unzip hybris.zip
$ unzip headers.zip

# 复制头文件
$ mv ./android-headers-28-droidian /usr/include/android-headers

2.安装编译环境

1
2
3
4
# 安装依赖
$ apt install make automake autoconf libtool pkg-config gawk

$ mkdir -p /var/task/libandroid

接下来将安卓 9 对应的链接库上传到 /var/task/libandroid 目录下。

  • libc.so
  • libm.so
  • libstdc++.so
  • libdl.so
  • ld-android.so

3.执行编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cd libhybris-master/hybris

# --enable-wayland 参数可以根据需求决定是否添加
# 若添加则需安装 libwayland-dev libegl1-mesa-dev wayland-protocols libwayland-bin libwayland-egl-backend-dev
$ ./autogen.sh --with-android-headers=/usr/include/android-headers --with-default-hybris-ld-library-path=/var/task/libandroid --prefix=/var/task/libhybris --enable-arch=arm64

$ make
$ make install

# 添加环境变量
$ export PATH=/var/task/libhybris/bin:$PATH
$ export LD_LIBRARY_PATH=/var/task/libhybris/lib:$LD_LIBRARY_PATH
$ export LIBRARY_PATH=/var/task/libhybris/lib:$LIBRARY_PATH
# 复制头文件
$ cp -r /var/task/libhybris/include /usr/

编译成功后会在 /var/task/ 目录下生成 libhybris 目录,运行 test_dlopen 如果 libc.so 不为 nil 则表示安装成功

使用 nodejs 调用安卓库

1.编译 node-ffi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装 nodejs
$ cd ~
$ wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
$ nvm install v18.19.0
$ nvm use v18.19.0

# 下载 ffi
$ wget -O ffi.zip https://github.com/node-ffi-napi/node-ffi-napi/archive/refs/tags/v4.0.3.zip
$ unzip ffi.zip

# 安装依赖
$ apt install binutils python3

$ cd node-ffi-napi-4.0.3
1
2
3
4
5
6
7
8
9
10
11
# 修改源文件 src/ffi.h 第 17 行,添加一行:
#include <hybris/common/dlfcn.h>

# 修改源文件 src/ffi.cc 第 43-46 行
o["dlopen"] = WrapPointer(env, hybris_dlopen);
o["dlclose"] = WrapPointer(env, hybris_dlclose);
o["dlsym"] = WrapPointer(env, hybris_dlsym);
o["dlerror"] = WrapPointer(env, hybris_dlerror);

# 修改源文件 binding.gyp 第 13 行,添加一行:
"libraries": ["-lhybris-common", "-landroid-properties"],
1
2
# 执行 npm install 会自动安装项目依赖并编译项目
$ npm install

编译成功后会在项目目录下生成 build/Realease/ffi_bindings.node 文件

2.调用安卓库

1
2
# 返回 node-ffi-napi-4.0.3 上一级目录
$ cd ../
1
2
3
4
5
6
7
8
// libm.js
var ffi = require('./node-ffi-napi-4.0.3');

var libm = ffi.Library('libm', {
'ceil': ['double', ['double']]
});

console.log(libm.ceil(1.5));
1
2
$ node libm.js
# 输出 2 表示调用成功

参考资料
Android应用的so,可以在Linux下使用吗?
Bionic 简介
Android bionic和GNU glibc
使用libhybris库linux调用android库
使用libhybris技术让linux调用android库
libhybris 编译和配置
Linux(ARM glibc)使用libhybris调用Android(ARM bionic)


在ARM Linux上使用libhybris调用安卓动态链接库
https://blog.itfox.net/posts/在arm-linux上使用libhybris调用安卓动态链接库.html
作者
blog.itfox.net
发布于
2023年6月12日
许可协议