RK3399E Android 11 将自己的库放到系统库方法

1.系统库的准备

1.1 检查库

检查需要放入系统的系统库libxxx.so是否非TLS 64, 在命令行中输入:

bash 复制代码
/home/xxx/Android/Sdk/ndk/27.3.13750724/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-readelf -l libxxx.so  | grep -A5 TLS

命令行输出:

bash 复制代码
  TLS            0x12f0440 0x00000000012f1440 0x00000000012f1440 0x000000 0x000028 R   0x40
  DYNAMIC        0x13777b8 0x00000000013787b8 0x00000000013787b8 0x0001c0 0x0001c0 RW  0x8
  GNU_RELRO      0x12f1430 0x00000000012f2430 0x00000000012f2430 0x0a7280 0x0a7bd0 R   0x1
  GNU_EH_FRAME   0x64b810 0x000000000064b810 0x000000000064b810 0x04526c 0x04526c R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x0
  NOTE           0x0002a8 0x00000000000002a8 0x00000000000002a8 0x0000bc 0x0000bc R   0x4

可以看到第一行最后一列为: 0x40, 如果不为0x40, 则需要重新编译so。

另外一种方法是在将libxxx.so 库放到/system/lib64 目录下,然后运行如下命令:

bash 复制代码
adb shell ldd /system/lib64/libxxx.so  # 检查依赖

如果输出如下:

bash 复制代码
	linux-vdso.so.1 => [vdso] (0x7bc9149000)
error: "linker64": executable's TLS segment is underaligned: alignment is 8, needs to be at least 64 for ARM64 Bionic
Aborted

说明该库没有64位对齐, 需要重新编译so库

如果输出为:

cpp 复制代码
	linux-vdso.so.1 => [vdso] (0x78fca6c000)
	liblog.so => /system/lib64/liblog.so (0x78fb726000)
	libdl.so => /apex/com.android.runtime/lib64/bionic/libdl.so (0x78fa2a0000)
	libm.so => /apex/com.android.runtime/lib64/bionic/libm.so (0x78fb748000)
	libc.so => /apex/com.android.runtime/lib64/bionic/libc.so (0x78fa195000)
	libc++.so => /system/lib64/libc++.so (0x78fb786000)

则该库正常。

1.2 重新编译库

在libxxx.so 的任意C++文件中添加如下代码:注意只需要添加一次:

cpp 复制代码
#if defined(__ANDROID__) && defined(__aarch64__)
// 放在任意一个参与编译的 .cpp 文件中即可
extern "C" {
    __attribute__((visibility("default"))) 
    __attribute__((aligned(64)))
    thread_local int _android_tls_alignment_fix = 0;
}
#endif

为了确保它能成功修复对齐问题,请注意以下几点:

  1. 必须被链接进目标库

这个代码片段必须放在会被编译并链接进 librosa.so 的源文件中。你把它放在 rosa/RosaLinux.cc 是完美的,因为你的 CMakeLists.txt 中明确把这个文件编译进了 rosa 库。

  1. 每个动态库(.so)只需要一个

链接器(linker)在生成 librosa.so 时,会扫描所有参与链接的 .o 文件(对象文件)。它会找到所有 thread_local 变量,并取其中最大的对齐值作为整个 PT_TLS 段的对齐属性。只要有一个地方定义了 alignas(64) 的 TLS 变量,整个库的 TLS 就会变成 64 字节对齐。不要在同一个库的多个源文件中放置同名的变量,否则会触发"重定义(multiple definition)"错误。

  1. 不要放在 .h 头文件中

千万不要放在 .h 文件中(除非使用了 static 或 inline 修饰),原因有二:

如果头文件被多个 .cpp 包含,会导致重定义错误。如果头文件没被任何 .cpp 包含,代码就不会被编译,也就没法生效。

cpp 复制代码
adb root
adb remount
# 确认是 lib64 还是 lib
adb push librosa.so /system/lib64/
adb shell chmod 644 /system/lib64/libxxx.so
# 恢复 SELinux 标签
adb shell restorecon /system/lib64/libxx.so
adb reboot
  1. 为什么这个代码能"隔空"生效?

你可能会奇怪:我只是在 RosaLinux.cc 里加了一个没被用到的变量,为什么能解决 spdlog 或其他代码里的错误?

物理结构决定:在一个 ELF 文件(.so)中,所有的线程本地变量(来自不同的 .cpp)最终都会被挤在同一个物理段(Segment)里,这个段叫 PT_TLS。

整体属性:PT_TLS 段作为一个整体,在文件头中只有一个"对齐(Alignment)"属性。链接器必须满足该段内要求最严格(对齐值最大)的那个变量。

木桶效应反转:这就像木桶效应的反面------只要有一块木板足够长,整个木桶的额定长度就会被标记为那个长度。

重新编译后,记得用 llvm-readelf -l librosa.so | grep TLS 确认最后那一列是否变成了 0x40。如果是,你的 adb shell ldd 报错就彻底解决了。

2. 将SO库设置为系统库

2.1 部署SO库

在命令行中依次输入如下命令:

cpp 复制代码
adb root
adb remount
# 确认是 lib64 还是 lib
adb push libxxx.so /system/lib64/
adb shell chmod 644 /system/lib64/libxxx.so
# 恢复 SELinux 标签
adb shell restorecon /system/lib64/libxxx.so
adb reboot

重启后,如果系统正常起来,说明设置成功。

2.2 如何正确测试库是否能加载?

如果你想验证这个库是否能被系统正确识别(且不再报 TLS 对齐错误),你应该使用 Android 链接器 来"追踪"加载过程,而不是直接运行它。

请在终端执行:

bash 复制代码
# 验证库的依赖和对齐是否通过

adb shell LD_TRACE_LOADED_OBJECTS=1 /system/bin/linker64 /system/lib64/libxxx.so

终端输出为:

bash 复制代码
Segmentation fault 

3.公开系统库

通过 public.libraries.txt 公开(推荐系统开发者使用)

如果你希望这个库像 liblog.solibc.so 一样,让所有 App 都能通过 System.loadLibrary 访问,确实需要在 public.libraries.txt 中添加它。

3.1 remount 系统

bash 复制代码
adb root

adb remount

3.2 修改文件:

在 /system/etc/public.libraries.txt 的末尾添加一行

bash 复制代码
libxxx.so

注意(非常重要):

格式:只写库的文件名,不要写路径。

换行符:必须使用 Unix 格式的换行符(LF)。

末尾:确保最后一行后有一个换行符,且没有多余的空格或乱码。

3.3 SELinux 检查:

确保 /system/lib64/libxxx.so 的标签是正确的,否则 App 在加载时会报 Permission Denied:

bash 复制代码
adb shell restorecon /system/lib64/libxxx.so

adb shell restorecon /system/etc/public.libraries.txt

3.4 重启系统:

bash 复制代码
adb reboot

修改该文件后必须重启,Android 的库管理服务才会重新加载配置。

相关推荐
Kapaseker13 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952714 小时前
Andorid Google 登录接入文档
android
黄林晴15 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android
_小马快跑_1 天前
Kotlin | 从SparseArray、ArrayMap的set操作符看类型检查的不同
android