Пространство имен связывания

Динамический компоновщик решает две проблемы, связанные с архитектурой VNDK в Treble:

  • Общие библиотеки SP-HAL и их зависимости, в том числе библиотеки VNDK-SP, загружаются в процессы фреймворка. Необходимо предусмотреть механизмы, предотвращающие конфликты символов.
  • dlopen() и android_dlopen_ext() могут создавать зависимости времени выполнения, которые не видны во время сборки и которые сложно обнаружить с помощью статического анализа.

Эти две проблемы можно решить с помощью пространства имен связывателя. Этот механизм предоставляется динамическим компоновщиком. Она позволяет изолировать общие библиотеки в разных пространствах имен компоновщика, чтобы библиотеки с одинаковыми названиями, но разными символами не конфликтовали.

С другой стороны, механизм пространств имен компоновщика обеспечивает гибкость, позволяя экспортировать некоторые общие библиотеки с помощью одного пространства имен компоновщика и использовать их в другом. Экспортированные общие библиотеки могут стать общедоступными API, скрывающими детали реализации в своих пространствах имен компоновщика.

Например, /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] есть три пространства имен (default, sphal и vndk).

namespace.name.links

Список резервных пространств имен, разделенных запятыми.

Если общая библиотека не найдена в текущем пространстве имен, динамический компоновщик пытается загрузить ее из резервных пространств имен. Пространство имен, указанное в начале списка, имеет более высокий приоритет.

namespace.sphal.links = default,vndk

Если общая библиотека или исполняемый файл запрашивает общую библиотеку, которую нельзя загрузить в пространство имен sphal, динамический компоновщик пытается загрузить ее из пространства имен default.

Если общую библиотеку не удается загрузить из пространства имен default, динамический компоновщик пытается загрузить ее из пространства имен vndk.

Если все попытки завершатся неудачей, динамический компоновщик вернет ошибку.

namespace.name.link.other.shared_libs

Разделенный двоеточиями список общих библиотек, в которых можно выполнять поиск в пространствах имен other, если эти библиотеки не удается найти в пространстве имен name.

Это свойство нельзя использовать с namespace.name.link.other.allow_all_shared_libs.

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

Это означает, что резервная ссылка принимает только libc.so или libm.so в качестве названия библиотеки. Динамический компоновщик игнорирует резервную ссылку из пространства имен sphal в default, если запрошенное название библиотеки не libc.so или libm.so.

namespace.name.link.other.allow_all_shared_libs

Логическое значение, которое указывает, можно ли искать все общие библиотеки в пространстве имен other, если они не найдены в пространстве имен name.

Это свойство нельзя использовать вместе с namespace.name.link.other.shared_libs.

namespace.vndk.link.sphal.allow_all_shared_libs = true

Это означает, что все названия библиотек могут переходить по резервной ссылке из пространства имен vndk в пространство имен sphal.

Свойства пространства имен

Свойство Описание Пример
namespace.name.isolated

Логическое значение, указывающее, должен ли динамический компоновщик проверять, где находится общая библиотека.

Если isolated – true, можно загружать только общие библиотеки, которые находятся в одном из каталогов search.paths (исключая подкаталоги) или вложены в один из каталогов permitted.paths (включая подкаталоги).

Если для переменной isolated задано значение false (по умолчанию), динамический компоновщик не проверяет путь к общим библиотекам.

namespace.sphal.isolated = true

Это означает, что в пространство имен sphal можно загрузить только общие библиотеки из search.paths или permitted.paths.

namespace.name.search.paths

Список каталогов, разделенных двоеточием, в которых нужно искать общие библиотеки.

Каталоги, указанные в правиле search.paths, добавляются в начало названия запрашиваемой библиотеки, если в вызовах функций для записей dlopen() или DT_NEEDED не указан полный путь. Указанный в начале списка каталог имеет более высокий приоритет.

Если для параметра isolated задано значение true, общие библиотеки, которые находятся в одном из каталогов 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).

namespace.name.search.paths игнорируется, когда включен ASan.

namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}

Это означает, что при включенном ASan динамический компоновщик сначала ищет /data/asan/system/${LIB}, а затем – /system/${LIB}.

namespace.name.permitted.paths

Разделенный двоеточиями список каталогов (включая подкаталоги), из которых динамический компоновщик может загружать общие библиотеки (в дополнение к search.paths), если для isolated задано значение true.

Также можно загрузить общие библиотеки, которые находятся в подкаталогах permitted.paths. Например, если для параметра permitted.paths задано значение /system/${LIB}, то могут загружаться как /system/${LIB}/libc.so, так и /system/${LIB}/vndk/libutils.so.

Если isolated имеет значение false, то permitted.paths игнорируются и выводится предупреждение.

namespace.default.permitted.paths = /system/${LIB}/hw

Это означает, что общие библиотеки в пространстве имен /system/${LIB}/hw можно загрузить в изолированное пространство имен default.

Например, без permitted.paths libaudiohal.so не может загрузить /system/${LIB}/hw/audio.a2dp.default.so в пространство имен default.

namespace.name.asan.permitted.paths

Список каталогов, разделенных двоеточием, в которых динамический компоновщик может загружать общие библиотеки, когда включен ASan.

namespace.name.permitted.paths игнорируется, если включен ASan.

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().

Если visible имеет значение true, функция android_get_exported_namespace() всегда возвращает дескриптор, если пространство имен существует.

Если visible имеет значение false (по умолчанию), 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.

Изоляция пространства имен компоновщика

Существует три типа конфигураций. В зависимости от значений PRODUCT_TREBLE_LINKER_NAMESPACES и BOARD_VNDK_VERSION в BoardConfig.mk при загрузке генерируется соответствующая конфигурация.

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_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-SP, загруженные в пространство имен vndk.
  • Процессы поставщика

    • Создаются пространства имен default, vndk и system.
    • Пространство имен 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

В таблице ниже приведены конфигурации пространств имен для процессов фреймворка, извлеченные из раздела [system] конфигурации VNDK Lite.

Пространство имен Свойство Значение
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 (для скомпилированного ядра RenderScript)
isolated true
visible true
links default,vndk
link.default.shared_libs LL-NDK
libmediandk.so
libft2.so
link.vndk.shared_libs VNDK-SP

В таблице ниже показана конфигурация пространств имен для процессов поставщиков, которая взята из раздела [vendor] в конфигурации VNDK Lite.

Пространство имен Свойство Значение
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.