Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Transición de montones ION a DMA-BUF

En Android 12, GKI 2.0 reemplaza el asignador ION con montones DMA-BUF por las siguientes razones:

  • Seguridad: debido a que cada montón DMA-BUF es un dispositivo de caracteres independiente, el acceso a cada montón se puede controlar por separado con sepolicy. Esto no era posible con ION porque la asignación de cualquier montón sólo se requiere el acceso a la /dev/ion dispositivo.
  • Estabilidad ABI: a diferencia de ION, se garantiza que la interfaz IOCTL del marco de montones DMA-BUF es estable en ABI porque se mantiene en el kernel de Linux ascendente.
  • Estandarización: el marco de montones DMA-BUF ofrece un UAPI bien definido. ION permitió indicadores personalizados e ID de pila que impidieron el desarrollo de un marco de prueba común porque la implementación de ION de cada dispositivo podría comportarse de manera diferente.

El android12-5.10 rama de las personas con discapacidad Android Común Kernel CONFIG_ION el 1 de marzo 2021.

Fondo

La siguiente es una breve comparación entre los montones de ION y DMA-BUF.

Similitudes entre el marco de montones ION y DMA-BUF

  • Los marcos de montones ION y DMA-BUF son exportadores DMA-BUF basados ​​en montones.
  • Ambos permiten que cada montón defina su propio asignador y operaciones DMA-BUF.
  • El rendimiento de la asignación es similar porque ambos esquemas necesitan un solo IOCTL para la asignación.

Diferencias entre el marco de montones ION y DMA-BUF

Montones de iones Montones de DMA-BUF
Todo asignaciones ION se hacen con /dev/ion . Cada montón DMA-BUF es un dispositivo de caracteres que está presente en /dev/dma_heap/<heap_name> .
ION admite indicadores privados de pila. Los montones DMA-BUF no admiten marcas privadas de montones. En su lugar, cada tipo diferente de asignación se realiza desde un montón diferente. Por ejemplo, las variantes de pila del sistema almacenados en caché y sin almacenar en caché son montones separados situados en /dev/dma_heap/system y /dev/dma_heap/system_uncached .
Es necesario especificar el ID de pila / máscara y los indicadores para la asignación. El nombre del montón se utiliza para la asignación.

Las siguientes secciones enumeran los componentes que tratan con ION y describen cómo cambiarlos al marco de montones DMA-BUF.

Transición de controladores de kernel de montones ION a DMA-BUF

Controladores de kernel que implementan montones de ION

Tanto los montones ION como DMA-BUF permiten que cada montón implemente sus propios asignadores y operaciones DMA-BUF. Por lo tanto, puede cambiar de una implementación de montón ION a una implementación de montón DMA-BUF utilizando un conjunto diferente de API para registrar el montón. Esta tabla muestra las API de registro de montones de ION y sus API de montones DMA-BUF equivalentes.

Montones de iones Montones de 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);

Los montones DMA-BUF no admiten marcas privadas de montones. Así que cada variante de la pila debe ser registrado de forma individual utilizando el dma_heap_add() de la API. Para facilitar el intercambio de código, se recomienda registrar todas las variantes del mismo montón dentro del mismo controlador. Este dma-buf: system_heap ejemplo muestra la aplicación de las variantes en caché y sin almacenar en caché de la pila del sistema.

Utilice esta dma-buf: plantilla de ejemplo: montones para crear un montón DMA-BUF desde cero.

Controladores de kernel que se asignan directamente desde montones de ION

Marco de la DMA-BUF montones también ofrece una interfaz de asignación para los clientes en el kernel. En lugar de especificar la máscara de montón y los indicadores para seleccionar el tipo de asignación, la interfaz que ofrecen los montones DMA-BUF toma un nombre de montón como entrada.

A continuación se muestra la API de asignación de ION en el kernel y sus API de asignación de almacenamiento dinámico DMA-BUF equivalentes. Controladores del núcleo pueden utilizar el dma_heap_find() API para consultar la existencia de un montón. La API devuelve un puntero a una instancia de dma_heap struct, que luego se pueden pasar como un argumento a la dma_heap_buffer_alloc() API.

Montones de iones Montones de 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)

Controladores de kernel que utilizan DMA-BUF

No se requieren cambios para los controladores que importan solo DMA-BUF, porque un búfer asignado desde un montón ION se comporta exactamente igual que un búfer asignado desde un montón DMA-BUF equivalente.

Transición de los clientes de espacio de usuario de ION a montones DMA-BUF

Para hacer la transición fácil para los clientes de espacio de usuario de ION, una biblioteca de abstracción llamada libdmabufheap está disponible. libdmabufheap asignación soportes en montones DMA-BUF y montones ION. Primero verifica si existe un montón DMA-BUF del nombre especificado y, si no es así, recurre a un montón ION equivalente, si existe.

Los clientes deben inicializar un BufferAllocator objeto durante su inicialización en lugar de abrir /dev/ion using ion_open() . Esto se debe a que los descriptores de archivos creados por la apertura /dev/ion y /dev/dma_heap/<heap_name> son administrados internamente por el BufferAllocator objeto.

Para cambiar de libion a libdmabufheap , modificar el comportamiento de los clientes de la siguiente manera:

  • Realice un seguimiento del nombre del montón que se utilizará para la asignación, en lugar del ID / máscara del cabezal y el indicador del montón.
  • Vuelva a colocar la ion_alloc_fd() API, que toma un argumento de máscara montón y bandera, con la BufferAllocator::Alloc() API, que toma un nombre de pila en su lugar.

Esta tabla ilustra estos cambios, mostrando cómo libion y libdmabufheap hacer una asignación de variables del sistema no está en caché.

Tipo de asignación libion libdmabufheap
Asignación en caché del montón del sistema ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd) allocator->Alloc("system", size)
Asignación sin caché del montón del sistema ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd) allocator->Alloc("system-uncached", size)

La variante de pila del sistema no almacenado en caché está en espera de corriente arriba aprobación, pero ya es parte de la android12-5.10 rama.

Para dispositivos de mejora de apoyo, la MapNameToIonHeap() API permite asignar un nombre de pila para ION montón parámetros (nombre montón / máscara y banderas) para permitir que dichas interfaces a también utilizar las asignaciones basados en nombres. Aquí hay un ejemplo de asignación basada en el nombre .

La documentación de cada API expuesta por libdmabufheap está disponible. La biblioteca también expone un fichero de cabecera para su uso por los clientes C.

Implementación de referencia de Gralloc

Los usos de aplicación Hikey960 gralloc libdmabufheap , para que pueda utilizarlo como implementación de referencia .

Adiciones ueventd requeridas

Para cualquier nuevas pilas de DMA-BUF dispositivo específicos creados, añadir una nueva entrada a del dispositivo ueventd.rc archivo. Esta instalación de ueventd para apoyar DMA-BUF montones ejemplo demuestra cómo este hecho para el montón de sistema de DMA-BUF.

Adiciones de sepolicy requeridas

Agregue permisos de seguridad para permitir que un cliente de espacio de usuario acceda a un nuevo montón DMA-BUF. Esta agregar permisos requeridos ejemplo muestra los permisos sepolicy creados para varios clientes para acceder a la pila del sistema DMA-BUF.

Accediendo a montones de proveedores desde el código del marco

Para garantizar el cumplimiento de Treble, el código marco solo se puede asignar a partir de categorías preaprobadas de montones de proveedores.

Según los comentarios recibidos de los socios, Google identificó dos categorías de montones de proveedores a los que se debe acceder desde el código del marco:

  1. Montones que se basan en el montón del sistema con optimizaciones de rendimiento específicas del dispositivo o de SoC.
  2. Montones para asignar desde la memoria protegida.

Montones basados ​​en el montón del sistema con optimizaciones de rendimiento específicas del dispositivo o de SoC

Para admitir este caso de uso, se puede anular la implementación de montón del sistema de montón DMA-BUF predeterminado.

  • CONFIG_DMABUF_HEAPS_SYSTEM está desactivada en gki_defconfig a permitir que sea un módulo vendedor.
  • Pruebas de conformidad VTS asegurar que existe el montón en /dev/dma_heap/system . Las pruebas también verificar que el montón se puede asignar a partir de, y que el descriptor de archivo devuelto ( fd ) pueden ser asignado en memoria (mmapped) desde el espacio de usuario.

Los puntos anteriores también son válidos para la variante sin caché del montón del sistema, aunque su existencia no es obligatoria para dispositivos totalmente coherentes con E / S.

Montones para asignar desde la memoria protegida

Las implementaciones de pila segura deben ser específicas del proveedor, ya que el núcleo común de Android no admite una implementación de pila segura genérica.

  • Registro de sus implementaciones de proveedores específicos como /dev/dma_heap/system-secure<vendor-suffix> .
  • Estas implementaciones de montón son opcionales.
  • Si existen los montones, las pruebas de VTS garantizan que se puedan realizar asignaciones a partir de ellos.
  • Los componentes del marco tienen acceso a estos montones para que puedan habilitar el uso de montones a través de Codec2 HAL / HAL del mismo proceso no vinculados. Sin embargo, las características genéricas del marco de trabajo de Android no pueden depender de ellas debido a la variabilidad en sus detalles de implementación. Si una implementación de pila segura genérica se agrega al núcleo común de Android en el futuro, debe usar una ABI diferente para evitar conflictos con la actualización de los dispositivos.

Asignador de códec 2 para montones DMA-BUF

Un asignador codec2 para la interfaz de la DMA-BUF montones está disponible en AOSP.

La interfaz de almacén de componentes que permite especificar los parámetros del montón desde C2 HAL está disponible con el asignador de montón C2 DMA-BUF.

Flujo de transición de muestra para un montón ION

Para suavizar la transición de ION a montones DMA-BUF, libdmabufheap permite la conmutación de un montón en el momento. Los pasos siguientes muestran un flujo de trabajo sugerido para la transición de un nonlegacy ION montón llamado my_heap que soporte uno bandera, ION_FLAG_MY_FLAG .

Paso 1: Crear equivalentes de la pila de iones en el marco de DMA-BUF. En este ejemplo, debido a que el ION montón my_heap soporta una bandera ION_FLAG_MY_FLAG , registramos dos montones DMA-BUF:

  • my_heap comportamiento coincide exactamente con el comportamiento de la pila de iones con la bandera ION_FLAG_MY_FLAG discapacitados.
  • my_heap_special comportamiento coincide exactamente con el comportamiento de la pila de iones con la bandera ION_FLAG_MY_FLAG habilitado.

Paso 2: Crear los cambios ueventd para el nuevo my_heap y my_heap_special montones DMA-BUF. En este punto, los montones son visibles como /dev/dma_heap/my_heap y /dev/dma_heap/my_heap_special , con los permisos previstos.

Paso 3: Para los clientes que asignan a partir my_heap , modificar sus archivos make para enlazar a libdmabufheap . Durante la inicialización del cliente, una instancia de un BufferAllocator objeto y usar la MapNameToIonHeap() API para mapear la <ION heap name/mask, flag> combinación para nombres equivalentes DMA-BUF montón.

Por ejemplo:

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

En lugar de utilizar el MapNameToIonHeap() API con los parámetros nombre y la bandera, puede crear el mapeo de <ION heap mask, flag> a los nombres de DMA-BUF montón equivalentes estableciendo el parámetro de nombre de pila ION para vaciar.

Paso 4: Reemplazar ion_alloc_fd() invocaciones con BufferAllocator::Alloc() con el nombre de pila apropiado.

Tipo de asignación libion libdmabufheap
Asignación de my_heap con la bandera ION_FLAG_MY_FLAG unset ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd) allocator->Alloc("my_heap", size
Asignación de my_heap con la bandera ION_FLAG_MY_FLAG conjunto ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, ION_FLAG_MY_FLAG, &fd) allocator->Alloc("my_heap_special", size)

En este punto, el cliente es funcional pero aún realiza la asignación del montón ION porque no tiene los permisos de sepolicy necesarios para abrir el montón DMA-BUF.

Paso 5: Crear los permisos necesarios para la sepolicy cliente para acceder a las nuevas pilas de DMA-BUF. El cliente ahora está completamente equipado para realizar asignaciones desde el nuevo montón DMA-BUF.

Paso 6: Verificar que las asignaciones están sucediendo desde el nuevo montón DMA-BUF mediante el examen de logcat .

Paso 7: Desactivar la ION montón my_heap en el núcleo. Si el código de cliente no necesita la actualización de dispositivos de soporte (cuyos granos solamente podría apoyar montones de iones), también puede eliminar los MapNameToIonHeap() invocaciones.