Переход от кучи ION к DMA-BUF

В Android 12 GKI 2.0 заменяет распределитель ION кучей DMA-BUF по следующим причинам:

  • Безопасность: поскольку каждая куча DMA-BUF является отдельным символьным устройством, доступ к каждой куче можно контролировать отдельно с помощью sepolicy. Это не было возможно с ION , поскольку выделение из любой кучи требуется только доступ к /dev/ion устройства.
  • Стабильность ABI: в отличие от ION, интерфейс IOCTL фреймворка DMA-BUF кучи гарантированно будет стабильным ABI, потому что он поддерживается в восходящем ядре Linux.
  • Стандартизация: структура кучи DMA-BUF предлагает четко определенный UAPI. ION разрешал настраиваемые флаги и идентификаторы кучи, которые не позволяли разработать общую среду тестирования, поскольку реализация ION на каждом устройстве могла вести себя по-разному.

android12-5.10 ветвь инвалидов Android Общего Kernel CONFIG_ION 1 марта 2021 года.

Фон

Ниже приводится краткое сравнение куч ION и DMA-BUF.

Сходства между инфраструктурой кучи ION и DMA-BUF

  • Обе структуры кучи ION и DMA-BUF являются экспортерами DMA-BUF на основе кучи.
  • Оба они позволяют каждой куче определять свой собственный распределитель и операции DMA-BUF.
  • Производительность распределения аналогична, потому что обе схемы требуют одного IOCTL для распределения.

Различия между фреймворком кучи ION и DMA-BUF

ИОННЫЕ кучи DMA-BUF кучи
Распределение Все ION сделаны с /dev/ion . Каждый DMA-BUF куча представляет собой устройство , символ , который присутствует в /dev/dma_heap/<heap_name> .
ION поддерживает частные флаги кучи. Кучи DMA-BUF не поддерживают частные флаги кучи. Вместо этого каждый другой вид распределения выполняется из другой кучи. Например, кэшированные и Uncached варианты системы кучи отдельные отвалы , расположенные в /dev/dma_heap/system и /dev/dma_heap/system_uncached .
Для выделения необходимо указать идентификатор / маску и флаги кучи. Имя кучи используется для выделения.

В следующих разделах перечислены компоненты, которые имеют дело с ION, и описано, как переключить их на структуру кучи DMA-BUF.

Перевод драйверов ядра из кучи ION в DMA-BUF

Драйверы ядра, реализующие кучи ION

И ION, и DMA-BUF кучи позволяют каждой куче реализовывать свои собственные распределители и операции DMA-BUF. Таким образом, вы можете переключиться с реализации кучи ION на реализацию кучи DMA-BUF, используя другой набор API-интерфейсов для регистрации кучи. В этой таблице показаны API-интерфейсы регистрации кучи ION и их эквивалентные API-интерфейсы кучи DMA-BUF.

ИОННЫЕ кучи DMA-BUF кучи
void ion_device_add_heap(struct ion_heap *heap) struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info);
void ion_device_remove_heap(struct ion_heap *heap) void dma_heap_put(struct dma_heap *heap);

Кучи DMA-BUF не поддерживают частные флаги кучи. Таким образом , каждый вариант кучи должен быть зарегистрирован в индивидуальном порядке с помощью dma_heap_add() API. Чтобы облегчить совместное использование кода, рекомендуется зарегистрировать все варианты одной и той же кучи в одном драйвере. Это ДМА-ЬиЙ: system_heap пример показывает осуществление кэшированных и некэшированных вариантов системы кучи.

Используйте этот ДМА-БУФЫ: кучи: Пример шаблон для создания кучи DMA-BUF с нуля.

Драйверы ядра напрямую выделяются из кучи ION

ДМА-Buf куч система также предлагает интерфейс распределения для в ядре клиентов. Вместо указания маски кучи и флагов для выбора типа распределения, интерфейс, предлагаемый кучей DMA-BUF, принимает имя кучи в качестве входных данных.

Ниже показан API-интерфейс распределения ION в ядре и эквивалентные ему API-интерфейсы распределения кучи DMA-BUF. Драйверы ядра могут использовать dma_heap_find() API для запроса о наличии кучи. API возвращает указатель на экземпляр структуры dma_heap, который затем может быть передан в качестве аргумента в dma_heap_buffer_alloc() API.

ИОННЫЕ кучи DMA-BUF кучи
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)

struct dma_heap *dma_heap_find(const char *name)

struct dma_buf *struct dma_buf *dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, unsigned int fd_flags, unsigned int heap_flags)

Драйверы ядра, использующие DMA-BUF

Никаких изменений не требуется для драйверов, которые импортируют только DMA-BUF, потому что буфер, выделенный из кучи ION, ведет себя точно так же, как буфер, выделенный из эквивалентной кучи DMA-BUF.

Перевод клиентов ION из пользовательского пространства в кучи DMA-BUF

Для того, чтобы сделать переход легко для пользовательского пространства клиентов ION, библиотека абстракции под названием libdmabufheap доступен. libdmabufheap распределение поддерживает в DMA-BUF куч и ION куч. Сначала он проверяет, существует ли куча DMA-BUF с указанным именем, а если нет, возвращается к эквивалентной куче ION, если таковая существует.

Клиенты должны инициализировать BufferAllocator объект во время их инициализации вместо открытия /dev/ion using ion_open() с /dev/ion using ion_open() . Это происходит потому , что дескрипторы создается при открытии /dev/ion и /dev/dma_heap/<heap_name> управляются внутренне BufferAllocator объекта.

Для того, чтобы перейти от libion к libdmabufheap , изменять поведение клиентов следующим образом :

  • Следите за именем кучи, которое будет использоваться для выделения, вместо идентификатора / маски головы и флага кучи.
  • Заменить ion_alloc_fd() API, который принимает кучу маски и флаг аргумент, с BufferAllocator::Alloc() API, который принимает кучу имя вместо этого.

Эта таблица иллюстрирует эти изменения, показывая , как libion и libdmabufheap сделать некэшированное выделение системы кучи.

Тип размещения либион libdmabufheap
Кэшированное выделение из системной кучи ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd) allocator->Alloc("system", size)
Некэшированное выделение из системной кучи ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd) allocator->Alloc("system-uncached", size)

Некэшированным вариант системы кучного ожидает одобрения вверх по течению , но уже часть android12-5.10 отрасли.

Для модернизации устройств поддержки, MapNameToIonHeap() API позволяет отображать имя кучи параметров ION Heap (кучу имя / маску и флаги) , чтобы эти интерфейсы также использовать распределение имен на основе. Вот имя на основе примера распределения .

Документация для каждого API выставленного libdmabufheap доступна. Библиотека также предоставляет заголовочный файл для использования клиентами C.

Эталонная реализация Gralloc

Пользы реализации Hikey960 gralloc libdmabufheap , так что вы можете использовать его в качестве эталонной реализации .

Необходимые дополнения до событий

Для любых новых устройств конкретных DMA-BUF отвалов , созданных, добавить новую запись устройства ueventd.rc файла. Эта настройка ueventd для поддержки DMA-Buf куч примера демонстрирует , как это делается для системы динамической памяти DMA-BUF.

Необходимые дополнения к политике

Добавьте разрешения sepolicy, чтобы позволить клиенту пользовательского пространства получить доступ к новой куче DMA-BUF. Это Добавление необходимых разрешения пример показывает sepolicy Права Доступа , созданные для различных клиентов для доступа к системе груды DMA-BUF.

Доступ к куче поставщиков из кода фреймворка

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

На основе отзывов, полученных от партнеров, Google выделил две категории куч поставщиков, к которым необходимо получить доступ из кода фреймворка:

  1. Кучи, основанные на системной куче с оптимизацией производительности для конкретного устройства или SoC.
  2. Куча для выделения из защищенной памяти.

Кучи на основе системной кучи с оптимизацией производительности для конкретного устройства или SoC

Для поддержки этого варианта использования реализация кучи системы кучи DMA-BUF по умолчанию может быть переопределена.

  • CONFIG_DMABUF_HEAPS_SYSTEM выключен в gki_defconfig , чтобы позволить ему быть модулем поставщика.
  • Проверки соответствия СДС убедиться , что куча существует в /dev/dma_heap/system . Тесты также убедиться , что куча может быть выделена из, и что возвращаемый дескриптор файла ( fd ) может быть отображенный в памяти (mmapped) из пространства пользователя.

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

Кучи для выделения из защищенной памяти

Реализации безопасной кучи должны зависеть от поставщика, поскольку общее ядро ​​Android не поддерживает общую реализацию безопасной кучи.

  • Зарегистрировать поставщика конкретных реализаций в /dev/dma_heap/system-secure<vendor-suffix> .
  • Эти реализации кучи не являются обязательными.
  • Если кучи существуют, тесты VTS гарантируют, что из них можно сделать выделение.
  • Компоненты платформы получают доступ к этим кучам, чтобы они могли использовать кучи через HAL Codec2 / без биндеризации HAL одного процесса. Однако общие функции платформы Android не могут зависеть от них из-за различий в деталях их реализации. Если в будущем к общему ядру Android будет добавлена ​​общая реализация безопасной кучи, она должна использовать другой ABI, чтобы избежать конфликтов с обновлением устройств.

Распределитель кодека 2 для куч DMA-BUF

Codec2 Распределитель для DMA-Buf куч интерфейса доступен в AOSP.

Интерфейс хранилища компонентов, который позволяет указывать параметры кучи из C2 HAL, доступен с распределителем кучи C2 DMA-BUF.

Пример потока перехода для кучи ION

Для того, чтобы сгладить переход от иона к ДМА-BUF кучах, libdmabufheap позволяет переключать одну кучу в момент времени. Следующие шаги демонстрируют предлагаемый технологический процесс для перехода на nonlegacy ION вороха по имени my_heap , который поддерживает один флаг, ION_FLAG_MY_FLAG .

Шаг 1: Создание эквивалентов ION кучи в рамках DMA-BUF. В этом примере, поскольку ION кучного my_heap поддерживает флаг ION_FLAG_MY_FLAG , мы зарегистрировать два DMA-BUF куч:

  • my_heap поведение в точности совпадает с поведением ION кучи с флагом ION_FLAG_MY_FLAG инвалидов.
  • my_heap_special поведение в точности совпадает с поведением ION кучи с флагом ION_FLAG_MY_FLAG включен.

Шаг 2: Создание ueventd изменений для нового my_heap и my_heap_special DMA-BUF куч. На данный момент, кучи видны как /dev/dma_heap/my_heap и /dev/dma_heap/my_heap_special , с предполагаемым разрешениями.

Шаг 3: Для клиентов , которые выделяют из my_heap , изменять их мейкфайлы в связи с libdmabufheap . Во время инициализации клиента, экземпляр BufferAllocator объекта и использовать MapNameToIonHeap() API для отображения <ION heap name/mask, flag> комбинации для эквивалентных DMA BUF кучи имен.

Например:

allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )

Вместо того , чтобы использовать MapNameToIonHeap() API с именем и флагом параметров, вы можете создать отображение <ION heap mask, flag> в эквивалентных DMA-Buf куче имен , установив параметр ION имя кучи пустой.

Шаг 4: Заменить ion_alloc_fd() вызовы с BufferAllocator::Alloc() , используя соответствующее имя кучи.

Тип размещения либион libdmabufheap
Выделения из my_heap с флагом ION_FLAG_MY_FLAG UNSET ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd) allocator->Alloc("my_heap", size
Выделения из my_heap с флагом ION_FLAG_MY_FLAG набора ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, ION_FLAG_MY_FLAG, &fd) allocator->Alloc("my_heap_special", size)

На данный момент клиент работает, но все еще выполняет выделение из кучи ION, потому что у него нет необходимых разрешений sepolicy для открытия кучи DMA-BUF.

Шаг 5: Создание разрешения sepolicy , необходимое для клиента , чтобы получить доступ к новому DMA-Buf куч. Теперь клиент полностью готов к выделению из новой кучи DMA-BUF.

Шаг 6: Убедитесь в том, что распределение происходит от нового DMA-BUF кучи путем изучения LogCat .

Шаг 7: отключить ION кучного my_heap в ядре. Если код клиента не нужен модернизация поддержки устройств (ядра которых может поддерживать только ION кучи), вы можете также удалить MapNameToIonHeap() вызовы.