動態鏈接器解決了 Treble VNDK 設計中的兩個挑戰:
- SP-HAL 共享庫及其依賴項(包括 VNDK-SP 庫)被加載到框架進程中。應該有一些機制來防止符號衝突。
-
dlopen()
和android_dlopen_ext()
可以引入一些在構建時不可見的運行時依賴項,並且使用靜態分析很難檢測到。
這兩個挑戰可以通過鏈接器命名空間機制來解決。該機制由動態鏈接器提供。它可以隔離不同鏈接器命名空間中的共享庫,使庫名相同但符號不同的庫不會發生衝突。
另一方面,鏈接器命名空間機制提供了靈活性,使得一些共享庫可以由鏈接器命名空間導出並由另一個鏈接器命名空間使用。這些導出的共享庫可以成為對其他程序公共的應用程序編程接口,同時將它們的實現細節隱藏在它們的鏈接器命名空間中。
例如,/system/lib[ /system/lib[64]/libcutils.so
和/system/lib[64]/vndk-sp-${VER}/libcutils.so
是兩個共享庫。這兩個庫可以有不同的符號。它們被加載到不同的鏈接器命名空間中,因此框架模塊可以依賴於/system/lib[64]/libcutils.so
並且 SP-HAL 共享庫可以依賴於/system/lib[64]/vndk-sp-${VER}/libcutils.so
。
另一方面, /system/lib[64]/libc.so
是一個由鏈接器命名空間導出並導入到許多鏈接器命名空間的公共庫的示例。 /system/lib[64]/libc.so
的依賴項,例如libnetd_client.so
,被加載到/system/lib[64]/libc.so
所在的命名空間中。其他命名空間將無法訪問這些依賴項。這種機制在提供公共接口的同時封裝了實現細節。
它是如何工作的?
動態鏈接器負責加載在DT_NEEDED
條目中指定的共享庫或由dlopen()
或android_dlopen_ext()
的參數指定的共享庫。在這兩種情況下,動態鏈接器都會找到調用者所在的鏈接器命名空間,並嘗試將依賴項加載到同一個鏈接器命名空間中。如果動態鏈接器無法將共享庫加載到指定的鏈接器命名空間,它會向鏈接的鏈接器命名空間詢問導出的共享庫。
配置文件格式
配置文件格式基於 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/${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.so namespace.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}
配置文件包括:
- 開頭的幾個目錄-節映射屬性供動態鏈接器選擇有效節。
- 幾個鏈接器命名空間配置部分:
- 每個部分包含幾個命名空間(圖頂點)和命名空間之間的幾個後備鏈接(圖弧)。
- 每個命名空間都有自己的隔離、搜索路徑、允許的路徑和可見性設置。
下表詳細描述了每個屬性的含義。
目錄部分映射屬性
財產 | 描述 | 例子 |
---|---|---|
| 每個屬性將目錄下的可執行文件映射到鏈接器命名空間配置部分。可能有兩個(或多個)具有相同 | 這表明 |
關係屬性
財產 | 描述 | 例子 |
---|---|---|
additional. namespaces | 該部分的其他名稱空間(除了 | 這表明 |
namespace. name . links | 以逗號分隔的後備命名空間列表。 如果在當前命名空間中找不到共享庫,動態鏈接器會嘗試從備用命名空間加載共享庫。在列表開頭指定的命名空間具有更高的優先級。 | 如果共享庫或可執行文件請求無法加載到 然後,如果共享庫也無法從 最後,如果所有嘗試都失敗,動態鏈接器會返回錯誤。 |
namespace. name . link. other . shared_libs | 當在 此屬性不能與 | 這表明後備鏈接僅接受 |
namespace. name . link. other . allow_all_shared_libs | 一個布爾值,指示當在 此屬性不能與 | 這表明所有庫名稱都可以通過從 |
命名空間屬性
財產 | 描述 | 例子 |
---|---|---|
namespace. name . isolated | 一個布爾值,指示動態鏈接器是否應檢查共享庫所在的位置。 如果 如果 | 這表明只有 |
namespace. name . search.paths | 用於搜索共享庫的以冒號分隔的目錄列表。 如果對 當 例如,如果 | 這表明動態鏈接器在 |
namespace. name . asan.search.paths | 啟用AddressSanitizer (ASan)時用於搜索共享庫的以冒號分隔的目錄列表。 | 這表明當啟用ASan時,動態鏈接器首先搜索 |
namespace. name . permitted.paths | 以冒號分隔的目錄列表(包括子目錄),當 也可以加載位於 如果 | 這表明 例如,如果沒有 |
namespace. name . asan.permitted.paths | 啟用ASan時動態鏈接器可以加載共享庫的目錄的冒號分隔列表。 | 這表明當啟用ASan時, |
namespace. name . visible | 一個布爾值,指示程序(除了 如果 如果 | 這表明 |
鏈接器命名空間創建
在 Android 11 中,鏈接器配置在運行時在/linkerconfig
下創建,而不是使用${android-src}/system/core/rootdir/etc
中的純文本文件。配置是在啟動時根據運行環境生成的,包括以下幾項:
- 如果設備支持 VNDK
- Vendor 分區的目標 VNDK 版本
- 產品分區的 VNDK 版本
- 安裝的 APEX 模塊
鏈接器配置是通過解析鏈接器命名空間之間的依賴關係來創建的。例如,如果 APEX 模塊上有任何包含依賴項更新的更新,則會生成反映這些更改的鏈接器配置。創建鏈接器配置的更多細節可以在${android-src}/system/linkerconfig
中找到。
鏈接器命名空間隔離
共有三種配置類型。根據BoardConfig.mk
中PRODUCT_TREBLE_LINKER_NAMESPACES
和BOARD_VNDK_VERSION
的值,在啟動時會生成相應的配置。
PRODUCT_TREBLE_ LINKER_NAMESPACES | BOARD_VNDK_ VERSION | 選定的配置 | VTS 要求 |
---|---|---|---|
true | current | VNDK | 對於搭載 Android 9 或更高版本的設備必須 |
空的 | VNDK Lite | 對搭載 Android 8.x 的設備強制要求 | |
false | 空的 | Legacy | 對於非高音設備 |
VNDK Lite 配置隔離了 SP-HAL 和 VNDK-SP 共享庫。在 Android 8.0 中,當PRODUCT_TREBLE_LINKER_NAMESPACES
為true
時,這必須是動態鏈接器的配置文件。
VNDK 配置還隔離了 SP-HAL 和 VNDK-SP 共享庫。此外,此配置提供了完整的動態鏈接器隔離。它確保系統分區中的模塊不會依賴於供應商分區中的共享庫,反之亦然。
在 Android 8.1 或更高版本中,VNDK 配置是默認配置,強烈建議通過將BOARD_VNDK_VERSION
設置為current
來啟用完全動態鏈接器隔離。
VNDK 配置
VNDK 配置隔離了系統分區和供應商分區之間的共享庫依賴關係。與上一小節中提到的配置相比,差異概述如下:
框架流程
default
、vndk
、sphal
和rs
命名空間被創建。- 所有命名空間都是隔離的。
- 系統共享庫被加載到
default
命名空間中。 - SP-HAL 被加載到
sphal
命名空間中。 - 加載到
vndk
命名空間中的 VNDK-SP 共享庫。
供應商流程
- 創建
default
、vndk
和system
命名空間。 -
default
命名空間是隔離的。 - 供應商共享庫被加載到
default
命名空間中。 - VNDK 和 VNDK-SP 共享庫被加載到
vndk
命名空間中。 - LL-NDK 及其依賴項被加載到
system
命名空間中。
- 創建
鏈接器命名空間之間的關係如下所示。
![VNDK 配置中描述的鏈接器命名空間圖](https://source.android.google.cn/static/devices/architecture/images/treble_vndk_linker_namespace3.png?authuser=2&hl=zh-tw)
在上圖中, LL-NDK和VNDK-SP代表以下共享庫:
- LL-NDK
-
libEGL.so
-
libGLESv1_CM.so
-
libGLESv2.so
-
libGLESv3.so
-
libandroid_net.so
-
libc.so
-
libdl.so
-
liblog.so
-
libm.so
-
libnativewindow.so
-
libneuralnetworks.so
-
libsync.so
-
libvndksupport.so
-
libvulkan.so
-
- VNDK-SP
-
android.hardware.graphics.common@1.0.so
-
android.hardware.graphics.mapper@2.0.so
-
android.hardware.renderscript@1.0.so
-
android.hidl.memory@1.0.so
-
libRSCpuRef.so
-
libRSDriver.so
-
libRS_internal.so
-
libbase.so
-
libbcinfo.so
-
libc++.so
-
libcutils.so
-
libhardware.so
-
libhidlbase.so
-
libhidlmemory.so
-
libhidltransport.so
-
libhwbinder.so
-
libion.so
-
libutils.so
-
libz.so
-
您可以在設備的/linkerconfig/ld.config.txt
中找到更多詳細信息。
VNDK 精簡版配置
從 Android 8.0 開始,動態鏈接器被配置為隔離 SP-HAL 和 VNDK-SP 共享庫,這樣它們的符號就不會與其他框架共享庫發生衝突。鏈接器命名空間之間的關係如下所示。
![VNDK Lite 配置中描述的鏈接器命名空間圖](https://source.android.google.cn/static/devices/architecture/images/treble_vndk_linker_namespace1.png?authuser=2&hl=zh-tw)
LL-NDK和VNDK-SP代表以下共享庫:
- LL-NDK
-
libEGL.so
-
libGLESv1_CM.so
-
libGLESv2.so
-
libc.so
-
libdl.so
-
liblog.so
-
libm.so
-
libnativewindow.so
-
libstdc++.so
(不在配置中) -
libsync.so
-
libvndksupport.so
-
libz.so
(在配置中移至VNDK-SP )
-
- VNDK-SP
-
android.hardware.graphics.common@1.0.so
-
android.hardware.graphics.mapper@2.0.so
-
android.hardware.renderscript@1.0.so
-
android.hidl.memory@1.0.so
-
libbase.so
-
libc++.so
-
libcutils.so
-
libhardware.so
-
libhidlbase.so
-
libhidlmemory.so
-
libhidltransport.so
-
libhwbinder.so
-
libion.so
-
libutils.so
-
下表列出了框架進程的命名空間配置,摘自 VNDK Lite 配置中的[system]
部分。
命名空間 | 財產 | 價值 |
---|---|---|
default | search.paths | /system/${LIB} /odm/${LIB} /vendor/${LIB} /product/${LIB} |
isolated | false | |
sphal | search.paths | /odm/${LIB} /vendor/${LIB} |
permitted.paths | /odm/${LIB} /vendor/${LIB} | |
isolated | true | |
visible | true | |
links | default,vndk,rs | |
link.default.shared_libs | LL-NDK | |
link.vndk.shared_libs | VNDK-SP | |
link.rs.shared_libs | libRS_internal.so | |
vndk (用於 VNDK-SP) | search.paths | /odm/${LIB}/vndk-sp /vendor/${LIB}/vndk-sp /system/${LIB}/vndk-sp-${VER} |
permitted.paths | /odm/${LIB}/hw /odm/${LIB}/egl /vendor/${LIB}/hw /vendor/${LIB}/egl /system/${LIB}/vndk-sp-${VER}/hw | |
isolated | true | |
visible | true | |
links | default | |
link.default.shared_libs | LL-NDK | |
rs (用於 RenderScript) | search.paths | /odm/${LIB}/vndk-sp /vendor/${LIB}/vndk-sp /system/${LIB}/vndk-sp-${VER} /odm/${LIB} /vendor/${LIB} |
permitted.paths | /odm/${LIB} /vendor/${LIB} /data (用於編譯的 RS 內核) | |
isolated | true | |
visible | true | |
links | default,vndk | |
link.default.shared_libs | LL-NDKlibmediandk.so libft2.so | |
link.vndk.shared_libs | VNDK-SP |
下表顯示了供應商進程的命名空間配置,摘自 VNDK Lite 配置中的[vendor]
部分。
命名空間 | 財產 | 價值 |
---|---|---|
default | search.paths | /odm/${LIB} /odm/${LIB}/vndk /odm/${LIB}/vndk-sp /vendor/${LIB} /vendor/${LIB}/vndk /vendor/${LIB}/vndk-sp /system/${LIB}/vndk-${VER} /system/${LIB}/vndk-sp-${VER} /system/${LIB} (已棄用)/product/${LIB} (已棄用) |
isolated | false |
可以在設備的/linkerconfig/ld.config.txt
中找到更多詳細信息。
文件歷史
Android 11 變化
- 在 Android 11 中,靜態
ld.config.*.txt
文件已從代碼庫中移除,而 LinkerConfig 會在運行時生成它們。
Android 9 的變化
- 在 Android 9 中,
vndk
鏈接器命名空間被添加到供應商進程中,並且 VNDK 共享庫與默認鏈接器命名空間隔離。 - 將
PRODUCT_FULL_TREBLE
替換為更具體的PRODUCT_TREBLE_LINKER_NAMESPACES
。 - Android 9 更改了以下動態鏈接器配置文件的名稱。
安卓 8.x 安卓 9 描述 ld.config.txt.in
ld.config.txt
對於具有運行時鏈接器命名空間隔離的設備 ld.config.txt
ld.config.vndk_lite.txt
對於具有 VNDK-SP 鏈接器命名空間隔離的設備 ld.config.legacy.txt
ld.config.legacy.txt
適用於運行 Android 7.x 或更低版本的舊設備 - 刪除
android.hardware.graphics.allocator@2.0.so
。 - 添加了
product
和odm
分區。