O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Fazendo a transição de ION para DMA-BUF Heaps

No Android 12, o GKI 2.0 substitui o alocador ION por heaps DMA-BUF pelos seguintes motivos:

  • Segurança: Como cada heap DMA-BUF é um dispositivo de caractere separado, o acesso a cada heap pode ser controlado separadamente com sepolicy. Isso não era possível com ION, porque a alocação de qualquer pilha necessário apenas o acesso ao /dev/ion dispositivo.
  • Estabilidade ABI: Ao contrário do ION, a interface IOCTL do framework DMA-BUF heaps tem garantia de estabilidade ABI porque é mantida no kernel Linux upstream.
  • Padronização: A estrutura de heaps DMA-BUF oferece um UAPI bem definido. O ION permitia sinalizadores personalizados e IDs de heap que impediam o desenvolvimento de uma estrutura de teste comum porque a implementação de ION de cada dispositivo poderia se comportar de maneira diferente.

O android12-5.10 ramo dos deficientes Android Comum Kernel CONFIG_ION em 1 de março de 2021.

Fundo

A seguir, uma breve comparação entre os heaps ION e DMA-BUF.

Semelhanças entre a estrutura de heaps ION e DMA-BUF

  • As estruturas de heaps ION e DMA-BUF são exportadores de DMA-BUF baseados em heap.
  • Ambos permitem que cada heap defina seu próprio alocador e operações DMA-BUF.
  • O desempenho de alocação é semelhante porque ambos os esquemas precisam de um único IOCTL para alocação.

Diferenças entre a estrutura de heaps ION e DMA-BUF

ION heaps Montes DMA-BUF
Alocações Todos ION é feito com /dev/ion . Cada pilha DMA-BUF é um dispositivo de caractere que está presente em /dev/dma_heap/<heap_name> .
ION suporta sinalizadores privados de heap. Os heaps DMA-BUF não suportam sinalizadores privados de heap. Cada tipo diferente de alocação é feito a partir de um heap diferente. Por exemplo, as variantes pilha do sistema em cache e uncached são montões separados localizados em /dev/dma_heap/system e /dev/dma_heap/system_uncached .
ID / máscara de heap e sinalizadores precisam ser especificados para alocação. O nome do heap é usado para alocação.

As seções a seguir listam os componentes que lidam com o ION e descrevem como alterná-los para a estrutura de heaps DMA-BUF.

Transição de drivers de kernel de ION para DMA-BUF heaps

Drivers de kernel que implementam ION heaps

Os heaps ION e DMA-BUF permitem que cada heap implemente seus próprios alocadores e operações DMA-BUF. Portanto, você pode alternar de uma implementação de heap ION para uma implementação de heap DMA-BUF usando um conjunto diferente de APIs para registrar o heap. Esta tabela mostra as APIs de registro de heap ION e suas APIs de heap DMA-BUF equivalentes.

ION heaps Montes 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);

Os heaps DMA-BUF não suportam sinalizadores privados de heap. Assim, cada variante da pilha deve ser registrado individualmente usando o dma_heap_add() API. Para facilitar o compartilhamento de código, é recomendável registrar todas as variantes do mesmo heap no mesmo driver. Este dma-buf: system_heap exemplo mostra a implementação das variantes em cache e uncached da pilha do sistema.

Utilize este dma-buf: montes: modelo de exemplo para criar uma pilha DMA-BUF a partir do zero.

Drivers de kernel alocando diretamente de heaps ION

Quadro da DMA-BUF montes também oferece uma interface de alocação para os clientes no kernel. Em vez de especificar a máscara de heap e sinalizadores para selecionar o tipo de alocação, a interface oferecida por heaps DMA-BUF leva um nome de heap como entrada.

O seguinte mostra a API de alocação de ION no kernel e suas APIs de alocação de heap DMA-BUF equivalentes. Drivers do kernel pode usar o dma_heap_find() API para consultar a existência de um heap. A API retorna um ponteiro para uma instância de dma_heap estrutura, que pode então ser transmitido como um argumento para a dma_heap_buffer_alloc() API.

ION heaps Montes 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)

Drivers de kernel que usam DMA-BUFs

Nenhuma alteração é necessária para drivers que importam apenas DMA-BUFs, porque um buffer alocado de um heap ION se comporta exatamente da mesma forma que um buffer alocado de um heap DMA-BUF equivalente.

Fazendo a transição dos clientes do espaço do usuário do ION para heaps DMA-BUF

Para fazer a transição fácil para os clientes do espaço do usuário de ION, uma biblioteca de abstração chamada libdmabufheap está disponível. libdmabufheap alocação de suportes em montes DMA-BUF e pilhas ION. Ele primeiro verifica se um heap DMA-BUF do nome especificado existe e, caso não exista, retorna para um heap ION equivalente, se houver.

Clientes deve inicializar um BufferAllocator objecto durante a inicialização em vez de abertura /dev/ion using ion_open() . Isso ocorre porque os descritores de arquivo criado pela abertura /dev/ion e /dev/dma_heap/<heap_name> são geridas internamente pelo BufferAllocator objeto.

Para mudar de libion para libdmabufheap , modificar o comportamento dos clientes da seguinte forma:

  • Acompanhe o nome do heap a ser usado para alocação, em vez do ID / máscara do cabeçote e do sinalizador do heap.
  • Substitua o ion_alloc_fd() API, que toma um argumento de máscara de pilha e bandeira, com o BufferAllocator::Alloc() API, que leva um nome de pilha em vez.

Esta tabela ilustra essas mudanças, mostrando como libion e libdmabufheap fazer uma alocação de pilha sistema uncached.

Tipo de alocação libião libdmabufheap
Alocação em cache do heap do sistema ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd) allocator->Alloc("system", size)
Alocação não armazenada em cache do heap do sistema ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd) allocator->Alloc("system-uncached", size)

A variante pilha do sistema uncached aguarda a montante aprovação, mas já faz parte do android12-5.10 ramo.

Para os dispositivos de suporte de melhoramento, o MapNameToIonHeap() API permite o mapeamento de um nome do montão para ION pilha de parâmetros (nome montão / máscara e bandeiras) para permitir que essas interfaces para também utilizar as alocações baseados em nome. Aqui está um exemplo de alocação baseada em nome .

A documentação para cada API exposto por libdmabufheap está disponível. A biblioteca também expõe um arquivo de cabeçalho para uso por clientes C.

Implementação de referência do Gralloc

Os usos de implementação Hikey960 gralloc libdmabufheap , para que você possa usá-lo como uma implementação de referência .

Adições ueventd necessárias

Para quaisquer novas pilhas DMA-BUF específica do dispositivo criado, adicionar uma nova entrada para o dispositivo ueventd.rc arquivo. Esta configuração ueventd para suportar DMA-BUF montes exemplo demonstra como este feito para o heap sistema DMA-BUF.

Adições de sepultura obrigatórias

Adicione permissões sepolicy para permitir que um cliente do espaço do usuário acesse um novo heap DMA-BUF. Esta adicionar permissões necessárias exemplo mostra as permissões sepolicy criados para vários clientes para acessar a pilha do sistema DMA-BUF.

Acessando heaps do fornecedor a partir do código da estrutura

Para garantir a conformidade com o Treble, o código da estrutura só pode alocar categorias pré-aprovadas de pilhas de fornecedores.

Com base no feedback recebido de parceiros, o Google identificou duas categorias de heaps de fornecedores que devem ser acessados ​​a partir do código da estrutura:

  1. Heaps que são baseados no heap do sistema com otimizações de desempenho específicas do dispositivo ou SoC.
  2. Pilhas para alocar da memória protegida.

Heaps com base no heap do sistema com otimizações de desempenho específicas do dispositivo ou SoC

Para oferecer suporte a esse caso de uso, a implementação de heap do sistema de heap DMA-BUF padrão pode ser substituída.

  • CONFIG_DMABUF_HEAPS_SYSTEM é desligado no gki_defconfig para permitir que ele seja um módulo de fornecedor.
  • Testes de conformidade VTS garantir que a pilha existe em /dev/dma_heap/system . Os testes também verificar se a pilha pode ser atribuído a partir, e que o descritor de arquivo retornado ( fd ) pode ser mapeada em memória (mmapped) a partir do espaço do usuário.

Os pontos anteriores também são verdadeiros para a variante sem cache do heap do sistema, embora sua existência não seja obrigatória para dispositivos totalmente coerentes com E / S.

Pilhas para alocar da memória protegida

As implementações de heap seguro devem ser específicas do fornecedor, pois o Android Common Kernel não oferece suporte a uma implementação de heap segura genérica.

  • Registre suas implementações específicas do fornecedor como /dev/dma_heap/system-secure<vendor-suffix> .
  • Essas implementações de heap são opcionais.
  • Se os heaps existirem, os testes VTS garantem que as alocações possam ser feitas a partir deles.
  • Os componentes da estrutura são fornecidos com acesso a esses heaps para que possam habilitar o uso de heaps por meio do Codec2 HAL / HALs não vinculados e do mesmo processo. No entanto, os recursos genéricos da estrutura Android não podem depender deles devido à variabilidade em seus detalhes de implementação. Se uma implementação de heap segura genérica for adicionada ao Android Common Kernel no futuro, ela deverá usar uma ABI diferente para evitar conflitos com a atualização de dispositivos.

Alocador Codec 2 para heaps DMA-BUF

Um alocador codec2 para a interface do DMA-BUF montes está disponível em AOSP.

A interface de armazenamento de componente que permite que parâmetros de heap sejam especificados a partir do C2 HAL está disponível com o alocador de heap C2 DMA-BUF.

Fluxo de transição de amostra para um heap ION

Para suavizar a transição do ION para montões DMA-BUF, libdmabufheap permite comutar uma pilha no momento. Os seguintes passos demonstram um fluxo de trabalho sugerido para a transição de um nonlegacy ION montão chamado my_heap que suporta uma bandeira, ION_FLAG_MY_FLAG .

Passo 1: Criar equivalentes de pilha ION no âmbito DMA-BUF. Neste exemplo, porque o ION pilha my_heap suporta uma bandeira ION_FLAG_MY_FLAG , registramos dois montões DMA-BUF:

  • my_heap comportamento corresponde exatamente o comportamento da pilha ION com a bandeira ION_FLAG_MY_FLAG desativado.
  • my_heap_special comportamento corresponde exatamente o comportamento da pilha ION com a bandeira ION_FLAG_MY_FLAG habilitado.

Passo 2: Criar as mudanças ueventd para o novo my_heap e my_heap_special montes DMA-BUF. Neste ponto, as pilhas são visíveis como /dev/dma_heap/my_heap e /dev/dma_heap/my_heap_special , com as permissões pretendidos.

Passo 3: Para clientes que alocam de my_heap , modificar seus makefiles para link para libdmabufheap . Durante a inicialização do cliente, instanciar um BufferAllocator objeto e use o MapNameToIonHeap() API para mapear o <ION heap name/mask, flag> combinação de DMA-BUF nomes equivalentes heap.

Por exemplo:

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

Em vez de usar o MapNameToIonHeap() API com os parâmetros nome e bandeira, você pode criar o mapeamento de <ION heap mask, flag> aos nomes DMA-BUF pilha equivalentes , definindo o parâmetro de nome de pilha ION para esvaziar.

Passo 4: Substituir ion_alloc_fd() invocações com BufferAllocator::Alloc() usando o nome montão apropriado.

Tipo de alocação libião libdmabufheap
Alocação de my_heap com a bandeira ION_FLAG_MY_FLAG unset ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd) allocator->Alloc("my_heap", size
Alocação de my_heap com a bandeira ION_FLAG_MY_FLAG set ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, ION_FLAG_MY_FLAG, &fd) allocator->Alloc("my_heap_special", size)

Neste ponto, o cliente está funcional, mas ainda alocando do heap ION porque não tem as permissões sepolicy necessárias para abrir o heap DMA-BUF.

Etapa 5: Criar as permissões sepolicy necessários para o cliente para acessar os novos montes DMA-BUF. O cliente agora está totalmente equipado para alocar do novo heap DMA-BUF.

Passo 6: Verifique se as alocações estão acontecendo a partir da nova pilha DMA-BUF examinando logcat .

Passo 7: Desativar o ION pilha my_heap no kernel. Se o código do cliente não precisa de dispositivos oferece suporte à atualização (cujas sementes só poderia apoiar montes Ion), você também pode remover os MapNameToIonHeap() invocações.