リンカー名前空間

ダイナミック リンカーは、Treble VNDK の設計上の 2 つの課題に対応します。

  • SP-HAL 共有ライブラリとその依存関係(VNDK-SP ライブラリを含む)は、フレームワーク プロセスに読み込まれます。そこで、シンボルの競合を防ぐなんらかのメカニズムが必要になります。
  • dlopen()android_dlopen_ext() により、ビルド時に隠れたランタイム依存関係が発生し、静的解析では検出が困難になる場合があります。

これらの 2 つの課題はリンカー名前空間のメカニズムで解決できます。このメカニズムはダイナミック リンカーによってもたらされ、別のリンカー名前空間にある共有ライブラリが分離されるため、シンボルが異なる同名のライブラリが競合しなくなります。

さらに、リンカー名前空間のメカニズムの持つ柔軟性により、あるリンカー名前空間が共有ライブラリをエクスポートし、別のリンカー名前空間がそれを使用するといったことも実現できます。このようにエクスポートされた共有ライブラリは、リンカー名前空間内に実装の詳細を隠しながら、他のプログラムに公開されるアプリケーション プログラミング インターフェースになります。

たとえば、/system/lib[64]/libcutils.so/system/lib[64]/vndk-sp-${VER}/libcutils.so は、2 つの共有ライブラリです。これらの 2 つのライブラリは、異なるシンボルを持つことができます。それぞれのライブラリは異なるリンカー名前空間に読み込まれるため、フレームワーク モジュールは /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 が同じでも、別々のディレクトリを指す 2 つ(または複数)のプロパティが存在する場合があります。

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] 構成に 3 つの名前空間(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.so または libm.so のみを受け入れることを示します。ダイナミック リンカーは、要求されたライブラリ名が libc.so でも libm.so でもない場合、sphal から default への名前空間の代替リンクを無視します。

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

これは、すべてのライブラリ名が、vndk から sphal への名前空間の代替リンクをウォークスルーできることを示します。

名前空間のプロパティ

プロパティ 説明
namespace.name.isolated

共有ライブラリが存在する場所をダイナミック リンカーが確認するべきかどうかを示すブール値。

isolatedtrue の場合、search.paths ディレクトリのいずれか(サブディレクトリを除く)、または permitted.paths ディレクトリのいずれか(サブディレクトリを含む)にある共有ライブラリのみを読み込むことができます。

isolatedfalse(デフォルト)の場合、ダイナミック リンカーは共有ライブラリのパスをチェックしません。

namespace.sphal.isolated = true

これは、search.paths 内または permitted.paths の下の共有ライブラリのみを sphal 名前空間に読み込めることを示します。

namespace.name.search.paths

共有ライブラリを検索するためのディレクトリをコロンで区切ったリスト。

search.paths 内で指定されたディレクトリは、dlopen() への関数呼び出し、または DT_NEEDED エントリでフルパスが指定されていない場合、要求されたライブラリ名の先頭に追加されます。リストの先頭に指定したディレクトリが優先されます。

isolatedtrue の場合、search.paths ディレクトリのいずれか(サブディレクトリを除く)にある共有ライブラリは、permitted.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.paths なしでは、libaudiohal.so/system/${LIB}/hw/audio.a2dp.default.sodefault 名前空間に読み込めません。

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 を返します。共有ライブラリは、この名前空間への代替リンクがある別のリンカー名前空間から要求されている場合、またはこの名前空間の他の共有ライブラリまたは実行可能ファイルから要求されている場合にのみ、この名前空間に読み込むことができます。

namespace.sphal.visible = true

これは、android_get_exported_namespace("sphal") が有効なリンカー名前空間ハンドルを返すことができることを示します。

リンカー名前空間の作成

Android 11 では、リンカー構成は ${android-src}/system/core/rootdir/etc で書式なしテキスト ファイルを使用して作成されるのではなく、実行時に /linkerconfig で作成されます。この構成は、以下の項目を含むランタイム環境に基づいて起動時に生成されます。

  • デバイスが VNDK をサポートしているかどうか
  • ベンダー パーティションの対象 VNDK のバージョン
  • プロダクト パーティションの VNDK のバージョン
  • インストール済みの APEX モジュール

リンカー構成は、リンカー名前空間間の依存関係を解決することで作成されます。たとえば、依存関係のアップデートを含む APEX モジュールにアップデートがある場合、これらの変更を反映したリンカー構成が生成されます。リンカー構成を作成する方法について詳しくは、${android-src}/system/linkerconfig をご覧ください。

リンカー名前空間の分離

構成には次の 3 種類があります。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_VERSIONcurrent に設定することによってダイナミック リンカーの完全分離を有効にすることを強くおすすめします。

VNDK の構成

VNDK の構成は、システム パーティションとベンダー パーティション間の共有ライブラリの依存関係を分離します。前のサブセクションで説明した構成との大まかな違いは次のとおりです。

  • フレームワーク プロセス

    • defaultvndksphalrs の名前空間が作成されます。
    • すべての名前空間は分離されます。
    • システムの共有ライブラリは、default 名前空間に読み込まれます。
    • SP-HAL は、sphal 名前空間に読み込まれます。
    • VNDK-SP 共有ライブラリは、vndk 名前空間に読み込まれます。
  • ベンダー プロセス

    • defaultvndksystem の名前空間が作成されます。
    • default 名前空間は分離されます。
    • ベンダーの共有ライブラリは、default 名前空間に読み込まれます。
    • VNDK および VNDK-SP 共有ライブラリは、vndk 名前空間に読み込まれます。
    • LL-NDK とその依存関係は、system 名前空間に読み込まれます。

リンカー名前空間の関係を以下に示します。

VNDK 構成に記述されているリンカー名前空間のグラフ

図 1. リンカー名前空間の分離(VNDK の構成)。

上記の画像の 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 Lite の構成

Android 8.0 以降、ダイナミック リンカーは、シンボルが他のフレームワーク共有ライブラリと競合しないように、SP-HAL 共有ライブラリと VNDK-SP 共有ライブラリを分離するよう構成されています。リンカー名前空間の関係を以下に示します。

VNDK Lite 構成に記述されているリンカー名前空間のグラフ
図 2. リンカー名前空間の分離(VNDK Lite 構成)

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-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 を削除しています。
  • product パーティションと odm パーティションが追加されています。