Android system — Android链接器命名空间
0. 前言
android 7.0加入了对私有系统so库API调用的限制(因为私有系统库会在任意时刻更新,使用这些系统库的应用有可能会在更新后崩溃),android 8.0引入了project Treble实现框架与供应商解耦合(解决系统碎片化,升级慢),这都需要依赖链接器命名空间机制。这里主要关注的重点是链接器命名空间在android 7.0引入后对System.loadLibrary,dlopen和dlsym函数的限制。Android 11 又对配置方式进行了修改,不再使用静态 ld.config.*.txt
文件进行配置。
1. 链接器命名空间
1.1 工作原理
动态链接器负责加载 DT_NEEDED 条目中指定的共享库,或由 dlopen() 或 android_dlopen_ext() 的参数指定的共享库。在这两种情况下,动态链接器都会找出调用方所在的链接器命名空间,并尝试将相关依赖项加载到同一个链接器命名空间中。如果动态链接器无法将共享库加载到指定的链接器命名空间中,它会向关联的链接器命名空间索取导出的共享库。
当链接器收到一个库加载的命令时会遍历库搜索路径(Library Search Path)LSPath 去寻找文件并将其加载到内存中,并通过已加载库列表(Alread Load Library list)ALList去跟踪已加载的所有库,当需要加载的库已经在ALList中时将不会再进行重复加载。android 7.0之前就是使用这种方式,所有的库都被加载到同一个ALList列表中。android7.0之后引入了链接器命名空间,每个命名空间都有自己的LSPach和ALList。每个命名空间只能在自己的LSPath中加载库,在进行库搜索时也只能再自己的ALList中进行搜索。
1.2 配置文件格式
下面会简要介绍下配置文件的格式,具体详情可参阅官方文档和ROM中的/linkerconfig/ld.config.txt
文件。
配置文件格式取决于 INI 文件格式。典型的配置文件如下所示:
dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin
[system]
additional.namespaces = sphal,vndk
namespace.default.isolated = true
namespace.default.search.paths = /system/${LIB}
namespace.default.permitted.paths = /system/${LIB}/hw
namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw
namespace.sphal.isolated = true
namespace.sphal.visible = true
namespace.sphal.search.paths = /odm/${LIB}:/vendor/${LIB}
namespace.sphal.permitted.paths = /odm/${LIB}:/vendor/${LIB}
namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}:/odm/${LIB}
namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}:/odm/${LIB}
namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}:/vendor/