Android system — Android链接器命名空间(Android 11后)

server/2024/11/17 10:58:35/

Android system — Android链接器命名空间

  • 0. 前言
  • 1. 链接器命名空间
    • 1.1 工作原理
    • 1.2 配置文件格式
      • 1.2.1 “目录-区段”映射属性
      • 1.2.2 关系属性
      • 1.2.3 命名空间属性
    • 1.3 链接器命名空间创建
    • 1.4 链接器命名空间隔离
      • 1.4.1 VNDK 配置
      • 1.4.2 VNDK Lite 配置

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,vndknamespace.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}/hwnamespace.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/${LIB}
namespace.sphal.links = default,vndk
namespace.sphal.link.default.shared_libs = libc.so:libm.so
namespace.sphal.link.vndk.shared_libs = libbase.so:libcutils.sonamespace.vndk.isolated = true
namespace.vndk.search.paths = /system/${LIB}/vndk-sp-29
namespace.vndk.permitted.paths = /system/${LIB}/vndk-sp-29
namespace.vndk.links = default
namespace.vndk.link.default.shared_libs = libc.so:libm.so[vendor]
namespace.default.isolated = false
namespace.default.search.paths = /vendor/${LIB}:/system/${LIB}

配置文件包含以下内容:

  • 位于开头的多个“目录-区段”映射属性,用于让动态链接器选择有效的区段。
  • 多个链接器命名空间配置区段:
    • 每个区段都包含多个命名空间(图形顶点)以及各命名空间之间的多个回退链接(图形弧)。
    • 每个命名空间都具有自己的隔离、搜索路径、允许的路径以及可见性设置。
      下表详细介绍了各属性的含义。

下表详细介绍了各属性的含义。

1.2.1 “目录-区段”映射属性

属性说明示例
dir.name指向 [name] 区段所应用到的目录的路径。

每个属性都会将目录下的可执行文件映射到链接器命名空间配置区段。可能会有 2 个(或 2 个以上)属性具有相同的 name,但却指向不同的目录。
dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin

这表示在 [system] 区段中指定的配置适用于从 /system/bin/system/xbin 加载的可执行文件。

在 [vendor] 区段中指定的配置适用于从 /vendor/bin 加载的可执行文件。

1.2.2 关系属性

属性说明示例
additional.
namespaces
相应区段的其他命名空间(除 default 命名空间外)的英文逗号分隔列表。additional.namespaces = sphal,vndk

这表示在 [system] 配置中有 3 个命名空间(defaultsphalvndk)。
namespace.
name.links
回退命名空间的英文逗号分隔列表。

如果在当前命名空间中找不到共享库,动态链接器会尝试从回退命名空间加载共享库。在列表开头指定的命名空间优先级较高。

注意:回退命名空间没有传递特性。例如,命名空间 A 链接到命名空间 B,命名空间 B 链接到命名空间 C。如果动态链接器在命名空间 A 中找不到相应的库,它仅会搜索命名空间 B,而不会搜索命名空间 C.
namespace.sphal.links = default,vndk

如果某个共享库或可执行文件请求另一个共享库,而后者无法加载到 sphal 命名空间,动态链接器就会尝试从 default 命名空间加载此共享库。

然后,如果此共享库也无法从 default 命名空间加载,动态链接器就会尝试从 vndk 命名空间加载此共享库。

最后,如果所有尝试都失败,动态链接器就会返回一个错误。
namespace.
name.link.
other.
shared_libs
用英文冒号分隔的共享库列表(如果在 name 命名空间中找不到这些共享库,可以在 other 命名空间中搜索)。

此属性无法与 namespace.name.link.other.allow_all_shared_libs 一起使用。

注意:此属性与 public.libraries.txt 文件在底层实现上是相同的。这两种机制都通过使用库名称过滤器指定链接的方式来控制导入的共享库。

不同之处在于,ld.config.txt 由动态链接器进行加载,并且所有命名空间都是在程序启动时创建的。相反,libnativeloader 会在 Zygote 进程针对某个应用进行创建分支和专门化操作时创建链接器命名空间。应用原生库的命名空间有一个链接,该链接仅允许使用在 public.libraries.txt 中指定的库名称。
namespace.sphal.link.default.shared_libs = libc.so:libm.so

这表示回退链接仅接受 libc.solibm.so 作为请求的库名称。如果请求的库名称既不是 libc.so 也不是 libm.so,动态链接器会忽略从 sphaldefault 命名空间的回退链接。
namespace.
name.link.
other.allow_
all_shared_libs
一个布尔值,用于指示当无法在 name 命名空间中找到共享库时,能否在 other 命名空间中搜索到所有这些共享库。

此属性无法与 namespace.name.link.other.shared_libs 一起使用。
namespace.vndk.link.sphal.allow_all_shared_libs = true

这表示所有库名称都可以遍历从 vndksphal 命名空间的回退链接。

  举个简单的例子,命名空间可以链接到其他命名空间并设置此链接的共享库范围。例如一个命名空间B链接到命名空间A,此链接设置允许所有的库都可以在无法加载到命名空间B的时候去链接的命名空间A中搜索加载(allow_all_shared_libs = true)。一个命名空间C也链接到命名空间A,而此链接设置只允许部分库(liba.so,libb.so,libc.so)在无法加载到命名空间A的时候去链接的命名空间B中搜索加载(设置shared_libs列表),需要注意allow_all_shared_libs = true与shared_libs无法同时设置。(特别注意共享库范围是对某个链接有效的,不同的链接其设置的共享库范围可能不同)
在这里插入图片描述

1.2.3 命名空间属性

属性说明示例
namespace.
name.
isolated
一个布尔值,用于指示动态链接器是否应该检查共享库在什么位置。

如果 isolatedtrue,系统只能加载某个 search.paths 目录(不包含子目录)中的共享库或某个 permitted.paths 目录(包含子目录)下的共享库。

如果 isolatedfalse(默认值),动态链接器不会检查共享库的路径。
namespace.sphal.isolated = true

这表示只有 search.paths 中或 permitted.paths 下的共享库才能加载到 sphal 命名空间。
namespace.
name.
search.
paths
以英文冒号分隔的目录列表,用于搜索共享库。

如果函数调用 dlopen()DT_NEEDED 条目时未指定完整路径,在 search.paths 中指定的目录将附加到请求的库名称前面。在列表开头指定的目录优先级较高。

如果 isolatedtrue,系统可加载某个 search.paths 目录(不包含子目录)中的共享库(无论 permitted.paths 为何属性)。

例如,如果 search.paths/system/${LIB}permitted.paths 为空,可以加载 /system/${LIB}/libc.so,但无法加载 /system/${LIB}/vndk/libutils.so

注意:${LIB} 是内置占位符。对于 32 位进程,此占位符将替换为 lib;对于 64 位进程,此占位符将替换为 lib64
namespace.default.search.paths = /system/${LIB}

这表示动态链接器会在 /system/${LIB} 中搜索共享库。
namespace.
name.asan.
search.
paths
以英文冒号分隔的目录列表,用于在启用 AddressSanitizer (ASan) 后搜索共享库。

在启用 ASan 后,系统会忽略 namespace.name.search.paths
namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}

这表示在启用 ASan 后,动态链接器会先搜索 /data/asan/system/${LIB},然后再搜索 /system/${LIB}
namespace.
name.
permitted.
paths
以英文冒号分隔的目录列表(包含子目录),当 isolatedtrue 时,动态链接器可在其中加载共享库(以及 search.paths)。

permitted.paths 的子目录下的共享库也可以加载。例如,如果 permitted.paths/system/${LIB}/system/${LIB}/libc.so/system/${LIB}/vndk/libutils.so 均可加载。

如果 isolatedfalse,系统会忽略 permitted.paths 并发出相应警告。

注意:在动态链接器搜索共享库时,permitted.paths 不会附加到请求的库名称前面。其主要目的是让程序员能够通过指定共享库的完整路径将共享库加载到隔离的命名空间。
namespace.default.permitted.paths = /system/${LIB}/hw

这表示 /system/${LIB}/hw 下的共享库可以加载到隔离的 default 命名空间。

例如,如果没有 permitted.pathslibaudiohal.so 就无法将 /system/${LIB}/hw/audio.a2dp.default.so 加载到 default 命名空间。
namespace.
name.asan.
permitted.
paths
以英文冒号分隔的目录列表,在启用 ASan 后,动态链接器可在其中加载共享库。

在启用 ASan 后,系统会忽略 namespace.name.permitted.paths
namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw

这表示在启用 ASan 后,/data/asan/system/${LIB}/hw/system/${LIB}/hw 下的共享库可以加载到隔离的 default 命名空间。
namespace.
name.
visible
一个布尔值,用于指示程序(不包括 libc)能否包含带有 android_get_exported_namespace() 的链接器命名空间句柄,以及能否通过将此句柄传递到 android_dlopen_ext() 来打开链接器命名空间中的共享库。

如果 visibletrueandroid_get_exported_namespace() 在命名空间存在时始终返回此句柄。

如果 visiblefalse(默认值),无论命名空间是否存在,android_get_exported_namespace() 始终返回 NULL。仅当符合以下条件时,共享库才能加载到此命名空间:(1) 具有指向此命名空间的回退链接的其他链接器命名空间请求这些共享库,或者 (2) 此命名空间中的其他共享库或可执行文件请求这些共享库。
namespace.sphal.visible = true

这表示 android_get_exported_namespace(“sphal”) 可以返回有效的链接器命名空间句柄。

1.3 链接器命名空间创建

在 Android 11 中,系统会在运行时在 /linkerconfig 下创建链接器配置,而不是在 ${android-src}/system/core/rootdir/etc 中使用纯文本文件来创建链接器配置。配置是在启动时根据运行时环境生成的,其中包括以下内容:

  • 设备是否支持 VNDK
  • vendor 分区的目标 VNDK 版本
  • product 分区的 VNDK 版本
  • 已安装的 APEX 模块

链接器配置是通过解析链接器命名空间之间的依赖关系来创建的。例如,如果 APEX 模块上有包括依赖项更新在内的任何更新,就会生成链接器配置,以反映这些变化。

1.4 链接器命名空间隔离

有 3 类配置文件。系统会根据 BoardConfig.mkPRODUCT_TREBLE_LINKER_NAMESPACESBOARD_VNDK_VERSION 的值在启动时生成相应的配置。

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_VERSION选择的配置VTS 要求
truecurrentVNDK搭载 Android 9 或更高版本的设备的必要配置
true空白VNDK Lite搭载 Android 8.x 的设备的必要配置
false空白Legacy适用于不支持 Treble 的设备

VNDK Lite 配置会隔离 SP-HAL 和 VNDK-SP 共享库。在 Android 8.0 中,当 PRODUCT_TREBLE_LINKER_NAMESPACEStrue 时,该配置必须是动态链接器的配置文件。

VNDK 配置还会隔离 SP-HAL 和 VNDK-SP 共享库。此外,此配置还会提供全面的动态链接器隔离。它可确保 system 分区中的模块不依赖于 vendor 分区中的共享库,反之亦然。

在 Android 8.1 或更高版本中,VNDK 配置是默认配置。

1.4.1 VNDK 配置

VNDK 配置会隔离 system 分区和 vendor 分区之间的共享库依赖项。下文概述了该配置文件与上一子部分中提到的配置相比有哪些不同:

  • 框架进程

    • 创建了 default、vndk、sphal 和 rs 命名空间。
    • 系统会隔离所有命名空间。
    • 将系统共享库加载到 default 命名空间中。
    • 将 SP-HAL 加载到 sphal 命名空间中。
    • 将 VNDK-SP 共享库加载到 vndk 命名空间中。
  • 供应商进程

    • 创建了 default、vndk 和 system 命名空间。
    • 隔离 default 命名空间。
    • 将供应商共享库加载到 default 命名空间中。
    • 将 VNDK 和 VNDK-SP 共享库加载到 vndk 命名空间中。
    • 将 LL-NDK 及其依赖项加载到 system 命名空间中。

链接器命名空间之间的关系如下所示:
在这里插入图片描述

1.4.2 VNDK Lite 配置

从 Android 8.0 开始,动态链接器将配置为隔离 SP-HAL 和 VNDK-SP 共享库,以使其符号不会与其他框架共享库发生冲突。链接器命名空间之间的关系如下所示。
在这里插入图片描述


http://www.ppmy.cn/server/22971.html

相关文章

华为P系列“砍了”,三角美学系列全新登场

2021 年 10 月,Intel 正式带来了颠覆以往的第 12 代酷睿「混合架构」 CPU。 不知道是良心发现还是为了弥补 11 代酷睿过于拉胯表现,Intel 终于把狠活儿都用在了这代。 全新 Intel 7 工艺、全新架构、单核与多核性能大幅提升,让大家十分默契…

2024制造企业数字化趋势

2024年制造企业数字化趋势主要表现在以下几个方面: 一、人工智能的广泛应用人工智能正逐渐成为制造企业数字化转型的关键催化剂。企业开始尝试并扩大生成式人工智能和机器学习的使用范围,以提高生产力、提升客户体验并改善决策。例如,利用人工…

玩机进阶教程------高通刷机 纯adb脚本操作刷写分区 备份分区的一些简单操作步骤解析

目前来说大多数刷机平台都是使用官方提供的工具。但一般这类工具刷写校验较多。例如小米刷机平台miflash和高通qpst平台。都对于电脑系统刷写环境有一定的要求。而且平台刷写校验md5等等。虽然可以通过修改脚本去除类似校验。但还是有必要了解一些纯adb脚本来刷写9008固件的方法…

Vue2学习笔记(尚硅谷天禹老师)

目录 一、入门案例 二、模板语法 三、数据绑定 四、el和data的两种写法 五、MVVM模型 六、Object.defineproperty方法 七、Vue中响应式原理 八、数据代理 九、methods配置项 十、Vue中的事件处理 十一、Vue中的键盘事件 十二、计算属性 十三、监视属性watch 十四、绑定Class样式…

在Ubuntu 22.04上部署WendaSNS

一、前提条件 由于WendaSNS不支持PHP8,因此这里再安装php 7.4版本 1. 增加ondrej/php PPA,提供了多个PHP 版本(会因为网络原因,下载较慢) sudo add-apt-repository ppa:ondrej/php 2.更新包列表 sudo apt update 3.安装 PHP 7.4 及相关…

MySQL中连接查询的几种方式

在 MySQL 中,连接查询是使用两个或多个表中的列之间的关联来检索数据的一种方法。MySQL 支持多种类型的连接查询,包括内连接、外连接和交叉连接。下面我将详细介绍每种连接查询的类型,并举例说明: 1. 内连接(INNER JO…

三. TensorRT基础入门-TensorRT内部的优化模块

目录 前言0. 简述1.TensorRT的优化策略2. Layer Fusion3. Kernel Auto-Tuning4. Quantization总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》,链接。记录下个人学习笔记,仅供自己参考 本次课程我们来学习课程第三章—TensorRT 基础入…

大会预告|第五届隆道数智大会重磅嘉宾阵容

5月16日,第五届隆道数智大会——2024数字化采购与供应链发展论坛将在北京举办。本届大会将围绕采购与供应链数字化创新发展趋势,聚焦AI、大数据在企业数字化转型中的应用落地,以深刻的产业洞察、案例型技术和实践探讨,全面展示数智…