連接器命名空間

動態連結器可解決 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

以冒號分隔的目錄 (包括子目錄) 清單,當 isolatedtrue 時,動態連結器可在此載入共用程式庫 (除了 search.paths 之外)。

也可以載入 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(),在連結器命名空間中開啟共用程式庫。

如果 visibletrueandroid_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.mk 中的 PRODUCT_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. Linker 命名空間隔離 (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. Linker 命名空間隔離 (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 個分區。