連結器命名空間

動態連結器可解決 Treble VNDK 設計中的兩大難題:

  • SP-HAL 共用程式庫及其依附元件 (包括 VNDK-SP 程式庫) 會載入架構程序。應有某些機制可避免符號衝突。
  • dlopen()android_dlopen_ext() 可能會導入一些在建構時看不到的執行階段依附元件,而且很難使用靜態分析偵測到。

這兩個問題可以透過連結器命名空間機制解決。這項機制是由動態連結器提供。這項功能可將共用程式庫隔離在不同的連結器命名空間中,因此名稱相同但符號不同的程式庫不會發生衝突。

另一方面,連結器命名空間機制提供彈性,因此連結器命名空間可以匯出部分共用程式庫,供另一個連結器命名空間使用。這些匯出的共用程式庫可成為其他程式公開的應用程式開發介面,同時隱藏其連結器命名空間內的實作詳細資料。

舉例來說,/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}

設定檔包含:

  • 動態連結器開頭的幾個目錄區段對應屬性,可供選取有效區段。
  • 多個連結器命名空間設定區段:
    • 每個區段都包含多個命名空間 (圖形頂點),以及命名空間之間的數個備援連結 (圖形弧線)。
    • 每個命名空間都有專屬的隔離、搜尋路徑、允許路徑和顯示設定。

下表將詳細說明每個屬性的意義。

目錄區段對應屬性

屬性 說明 範例

dir.name

[name] 區段適用的目錄路徑。

每個屬性都會將目錄下的可執行檔對應至連結器命名空間設定區段。可能會有兩個 (或更多) 屬性具有相同的 name,但指向不同的目錄。

dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin

這表示 [system] 區段中指定的設定,適用於從 /system/bin/system/xbin 載入的可執行檔。

[vendor] 區段中指定的設定會套用至從 /vendor/bin 載入的可執行檔。

關係屬性

屬性 說明 範例
additional.namespaces

以半形逗號分隔的清單,列出該區段的其他命名空間 (除了 default 命名空間)。

additional.namespaces = sphal,vndk

這表示 [system] 設定中有三個命名空間 (defaultsphalvndk)。

namespace.name.links

以半形逗號分隔的備用命名空間清單。

如果動態連結器在目前的命名空間中找不到共用程式庫,就會嘗試從備援命名空間載入共用程式庫。清單開頭指定的命名空間優先順序較高。

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 搭配使用。

namespace.sphal.link.default.shared_libs = libc.so:libm.so

這表示備用連結只接受 libc.solibm.so 做為要求的程式庫名稱。如果要求的程式庫名稱不是 libc.solibm.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 命名空間的回退連結。

命名空間屬性

屬性 說明 範例
namespace.name.isolated

布林值,指出動態連結器是否應檢查共用程式庫所在位置。

如果 isolatedtrue,則只能載入位於其中一個 search.paths 目錄 (不含子目錄) 或位於其中一個 permitted.paths 目錄 (含子目錄) 的共用程式庫。

如果 isolatedfalse (預設值),動態連結器不會檢查共用程式庫的路徑。

namespace.sphal.isolated = true

這表示只有 search.pathspermitted.paths 中的共用程式庫,可以載入 sphal 命名空間。

namespace.name.search.paths

以半形冒號分隔的目錄清單,用於搜尋共用程式庫。

如果對 dlopen()DT_NEEDED 項目進行的函式呼叫未指定完整路徑,系統會在要求的程式庫名稱前加上 search.paths 中指定的目錄。清單開頭指定的目錄優先順序較高。

如果 isolatedtrue,則無論 permitted.paths 屬性為何,系統都會載入 search.paths 目錄 (不含子目錄) 中的共用程式庫。

舉例來說,如果 search.paths/system/${LIB},且 permitted.paths 為空白,則可以載入 /system/${LIB}/libc.so,但無法載入 /system/${LIB}/vndk/libutils.so

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

以半形冒號分隔的目錄清單 (包括子目錄),動態連結器可從中載入共用程式庫 (除了 search.paths 之外),前提是 isolatedtrue

也可以載入 permitted.paths 子目錄下的共用程式庫。舉例來說,如果 permitted.paths/system/${LIB},則 /system/${LIB}/libc.so/system/${LIB}/vndk/libutils.so 都可以載入。

如果 isolatedfalse,系統就會忽略 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(),在連結器命名空間中開啟共用程式庫。

如果 visibletrue,只要命名空間存在,android_get_exported_namespace() 一律會傳回控制代碼。

如果 visiblefalse (預設值),無論命名空間是否存在,android_get_exported_namespace() 一律會傳回 NULL。只有在下列情況下,共用程式庫才能載入這個命名空間:(1) 另一個連結器命名空間要求載入共用程式庫,且該命名空間具有這個命名空間的回溯連結;(2) 這個命名空間中的其他共用程式庫或可執行檔要求載入共用程式庫。

namespace.sphal.visible = true

這表示 android_get_exported_namespace("sphal") 可以傳回有效的連結器命名空間控制代碼。

建立連結器命名空間

在 Android 11 中,連結器設定是在 /linkerconfig 下的執行階段建立,而不是使用 ${android-src}/system/core/rootdir/etc 中的純文字檔案。設定會在啟動時根據執行階段環境產生,包括下列項目:

  • 如果裝置支援 VNDK
  • 供應商分割區的目標 VNDK 版本
  • 產品劃分的 VNDK 版本
  • 已安裝的 APEX 模組

連結器設定是透過解析連結器命名空間之間的依附元件建立。舉例來說,如果 APEX 模組有任何更新 (包括依附元件更新),系統會產生反映這些變更的連結器設定。如要進一步瞭解如何建立連結器設定,請參閱 ${android-src}/system/linkerconfig

連結器命名空間隔離

設定類型有三種,視 BoardConfig.mkPRODUCT_TREBLE_LINKER_NAMESPACESBOARD_VNDK_VERSION 的值而定,系統會在啟動時產生對應的設定。

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
選取的設定 VTS 規定
true current VNDK 推出時搭載 Android 9 以上版本的裝置必須支援這項功能
空白 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 共用程式庫。此外,這項設定可提供完整的動態連結器隔離功能。這可確保系統分區中的模組不會依附於供應商分區中的共用程式庫,反之亦然。

在 Android 8.1 以上版本中,VNDK 設定是預設設定,強烈建議您將 BOARD_VNDK_VERSION 設為 current,啟用完整的動態連結器隔離功能。

VNDK 設定

VNDK 設定會隔離系統分割區和供應商分割區之間的共用程式庫依附元件。與前一小節提及的設定相比,差異如下:

  • 架構程序

    • 已建立 defaultvndksphalrs 命名空間。
    • 所有命名空間都會隔離。
    • 系統共用程式庫會載入 default 命名空間。
    • SP-HAL 會載入 sphal 命名空間。
    • 載入 vndk 命名空間的 VNDK-SP 共用程式庫。
  • 供應商程序

    • 建立 defaultvndksystem 命名空間。
    • default 命名空間已隔離。
    • 供應商共用程式庫會載入 default 命名空間。
    • VNDK 和 VNDK-SP 共用程式庫會載入 vndk 命名空間。
    • LL-NDK 及其依附元件會載入 system 命名空間。

連結器命名空間之間的關係如下圖所示。

VNDK 設定中說明的連結器命名空間圖表
圖 1. 連結器命名空間隔離 (VNDK 設定)

在上圖中,LL-NDKVNDK-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 Lite 設定

自 Android 8.0 起,動態連結器會設定為隔離 SP-HAL 和 VNDK-SP 共用程式庫,避免符號與其他架構共用程式庫發生衝突。連結器命名空間之間的關係如下所示。

VNDK Lite 設定中說明的連結器命名空間圖表
圖 2. 連結器命名空間隔離 (VNDK Lite 設定)

LL-NDKVNDK-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-NDK
libmediandk.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 會變更下列動態連結器設定檔的名稱。
    Android 8.x Android 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
  • 新增 productodm 分區。