Пространство имен компоновщика

Динамический компоновщик решает две проблемы, возникающие при проектировании 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] присутствуют три пространства имен ( 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 обозначают следующие разделяемые библиотеки:

  • ЛЛ-НДК
    • 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
  • ВНДК-СП
    • 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 обозначают следующие разделяемые библиотеки:

  • ЛЛ-НДК
    • 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 в конфигурации)
  • ВНДК-СП
    • 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 ЛЛ-НДК
link.vndk.shared_libs ВНДК-СП
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 ЛЛ-НДК
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 ЛЛ-НДК
libmediandk.so
libft2.so
link.vndk.shared_libs ВНДК-СП

В таблице ниже представлена ​​конфигурация пространств имен для процессов поставщика, взятая из раздела [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 .