Android namespace权限问题
在做OpenXR Runtime的过程中,打算把Runtime apk直接预置到/system/app
分区下,主要是因为Runtime Apk本身算的上是一个“系统应用”,直接预置是一个比较方便的做法。
Runtime的机制
OpenXR Runtime的机制,实际是一个dlopen
的过程,根据之前的经验和认知,整个OpenXR App实际是一个链式调用的过程。
因此,Application实际是通过集成的libopenxr_loader.so
去发现系统中的libopenxr_runtime.so
,然后通过dlopen
的方式把Runtime加载到Application进程中。
由于我们把OpenXR Runtime集成到了
/system/app
分区,所以肯定会把其中的libopenr_runtime.so
预置到/system/app/OpenXRRuntime/lib/arm64/libopenxr_monado.so
Broker在做发现runtime so动作的时候,就会告知Application去加载
/system/app/OpenXRRuntime/lib/arm64/libopenxr_monado.so
这个时候就会触发类似下文的错误,提示无法
dlopen
E/linker: library “/system/app/OpenXRRuntime/lib/arm64/libopenxr_monado.so” (/system/app/OpenXRRuntime/lib/arm64/libopenxr_monado.so”) needed or dlopened by “xxxxxxx is not accessible for the namespace: [name=”classloader-namespace”, ld_library_paths=””, default_library_paths=””, permitted_paths=”xxxxxxx”]
问题的原因
正如错误日志所表述的,发生问题的原因其实是因为Application中的libopenxr_loader.so
是没有权限去加载/system/app/OpenXRRuntime/lib/arm64/libopenxr_monado.so
。
这个部分的内容早在Android 7.0的版本上就已经引入了:原生库的命名空间
AOSP的官方文档也说的很清楚,namespace的出现是防止/避免应用意外使用平台的库,可是我们这边就是应用需要使用平台的库,针对这种情况,AOSP的文档也非常友好的给出了几个建议。
解决的方法
我们先看一下AOSP文档中的几个建议,最后再来说明实际的解决方案。
方案一:添加库到声明的txt文件里
这个是AOSP文档中给出的第一条建议,也是非常正规的一套做法,即在特定的声明txt文件中明示可以被应用加载库。其中txt的文件会有两处:
/vendor/etc/public.libraries.txt
(对于芯片供应商的库)/system/etc/public.libraries-COMPANYNAME.txt
(对于设备制造商的库)
格式上也做比较好的隔离,可以区分是芯片供应商添加的,还是具体设备制造商添加的,此外,针对命名还有这一套强规范限定:
不得不说,Android在应对碎片化的过程中还是做了很多努力的,隔离的部分已经是做的很好了,但是我在实际操作过程里添加后还是NG,这里就出现了第二个坑,它的限定是针对/system/lib/以及/system/lib64而言的,我们的目录是:/system/app/OpenXRRuntime/lib/arm64/libopenxr_monado.so
,所以这套方案就不行了。
方案二:把runtime so放到/system/lib目录下
这个方案是从方案一的失败案例上衍生出来,自然而然可以想到的,但是在实际操作中发现不是优选方案:
libopenxr_monado.so
是依赖Monado整体编译的,根据《OpenXR223-OutOfProcess实现框架》一文的介绍,这部分主要是帮助实现Client-Server的IPC通讯连接,把client端的OpenXR Command发送到Server端。- 所以
libopenxr_monado.so
是存在变动可能的
- 所以
- 通过public公开的so需要具备32/64bit两套,而现在的Runtime本身是以64bit运行的,所以,还需要去额外凑一个32bit的库放到
/system/lib
目录下,不然就是开机NG无限重启。
当然,在实际操作过程中,即使我们把libopenxr_monado.so
放到了/system/lib
和/system/lib64
两个目录下去,虽然不再出现libopenxr_monado.so
的denied,但会报出libc++_shared.so
库not found error
,究其原因是因为libopenxr_monado.so
在编译的时候会link libc++_shared.so
,而如果我们把这个库放进去的话,显然影响面就太大了,因为每个NDK版本的libc++_shared.so
可能都不太一样,那么应用可能就会出现各种莫名的crash
了。
方案三:究其所以然
这个也是最终的方案,实际上是有一点patch的味道,具体的修改方案可以参考:《第三方app加载系统/system/lib下的库–is not accessible for the namespace》,就是去源码中找一下是哪里阻止了load so,然后针对性的修改一下。CSDN中博客的部分是针对Android 7的平台,实际在Android 12的版本上:
可以在红框的部分加上libopenxr_monado.so
,然后在使用名单的地方做一下兼容处理:
这样的话,实际就是在linker
做library
检查的时候让它认为libopenxr_monado.so
也是一个特例库,从而Application可以用到它。
参考资料
- 《android Linker:namespace隔离机制》:https://www.jianshu.com/p/1672b52548ce
- 《第三方app加载系统/system/lib下的库–is not accessible for the namespace》:https://blog.csdn.net/u012459903/article/details/100731487
- 《原生库的命名空间》:https://source.android.com/devices/tech/config/namespaces_libraries?hl=zh-cn
- 《链接器命名空间》:https://source.android.com/devices/architecture/vndk/linker-namespace?hl=zh-cn