在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 方法的引用,LinkGlibc 中对应的方法上,以实现 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日
许可协议