HAL da câmera veicular

O Android contém uma camada de abstração de hardware (HAL) HIDL automotiva que oferece captura e exibição de imagens bem no início do processo de inicialização do Android e continua funcionando durante toda a vida útil do sistema. A HAL inclui pilha do sistema de visualização externa (EVS) e geralmente é usada para dar suporte à visualização traseira telas de visão surround e câmera em veículos com Android no veículo Sistemas de infoentretenimento (IVI). O EVS também permite a implementação de recursos avançados nos aplicativos dos usuários.

O Android também inclui um driver de captura e exibição específico para EVS interface (em /hardware/interfaces/automotive/evs/1.0). Embora seja possível criar um app de câmera traseira sobre um dispositivo Android atual serviços de câmera e exibição, um aplicativo assim provavelmente seria executado muito tarde o processo de inicialização do Android. O uso de uma HAL dedicada permite uma interface simplificada e deixa claro o que um OEM precisa implementar para oferecer suporte à pilha EVS.

Componentes do sistema

O EVS inclui os seguintes componentes do sistema:

Sistema EVS
diagrama de componentes
Figura 1. Visão geral dos componentes do sistema EVS.

App de EVS

Um exemplo de app C++ EVS (/packages/services/Car/evs/app) serve como referência implementação. Este app é responsável por solicitar frames de vídeo de o gerenciador de EVS e o envio de frames finalizados para exibição ao gerenciador de EVS. Ele deve ser iniciado pelo init assim que o EVS e o Car Service estiverem disponíveis. dentro de 2 (dois) segundos após ligar. OEMs podem modificar ou substituir VES o aplicativo desejado.

Gerenciador de EVS

O EVS Manager (/packages/services/Car/evs/manager) fornece os elementos básicos de que um app de EVS precisa para implementar qualquer coisa, tela simples de câmera traseira para uma renderização 6DOF de várias câmeras. A interface é apresentado por meio do HIDL e foi criado para aceitar vários clientes simultâneos. Outros apps e serviços (especificamente o Car Service) podem consultar o VES. Estado do gerenciador para descobrir quando o sistema EVS está ativo.

Interface de EVS HIDL

O sistema EVS, tanto a câmera quanto os elementos de exibição, é definido no android.hardware.automotive.evs. Um exemplo de implementação que exercita a interface (gera imagens de teste sintéticas e valida a imagens que fazem a ida e volta) é fornecido /hardware/interfaces/automotive/evs/1.0/default:

O OEM é responsável por implementar a API expressa pelos arquivos .hal em /hardware/interfaces/automotive/evs. Essas implementações são responsável por configurar e coletar dados de câmeras físicas e entregando-o por buffers de memória compartilhada reconhecíveis pelo Gralloc. A tela da implementação é responsável por fornecer um buffer de memória compartilhado que podem ser preenchidas pelo app (geralmente com renderização de EGL) e apresentando os frames finalizados em preferência por qualquer outra coisa que possa querer aparecer na tela física. Implementações do fornecedor da interface EVS podem ser armazenadas em /vendor/… /device/… ou hardware/… (por exemplo, /hardware/[vendor]/[platform]/evs).

Drivers do kernel

Um dispositivo compatível com a pilha EVS exige drivers de kernel. Em vez de criar novos drivers, os OEMs têm a opção de oferecer suporte aos recursos exigidos por EVS por os drivers de hardware de câmera ou tela existentes. Reutilizar motoristas pode ser vantajosa, especialmente para drivers de tela, em que a apresentação de imagens exigem coordenação com outras linhas de execução ativas. O Android 8.0 inclui uma versão 4l2 exemplo de driver (em packages/services/Car/evs/sampleDriver) que depende do kernel para suporte à v4l2 e do SurfaceFlinger para apresentar os imagem de saída.

Descrição da interface de hardware de EVS

A seção descreve a HAL. Os fornecedores devem fornecer implementações dessa API adaptadas para seu hardware.

IEvsEnumerator

Esse objeto é responsável por enumerar o hardware EVS disponível no (uma ou mais câmeras e um único dispositivo de exibição).

getCameraList() generates (vec<CameraDesc> cameras);

Retorna um vetor que contém descrições para todas as câmeras no sistema. É presumiu que o conjunto de câmeras está fixo e conhecido no momento da inicialização. Para detalhes sobre descrições de câmeras, consulte CameraDesc.

openCamera(string camera_id) generates (IEvsCamera camera);

Recebe um objeto de interface usado para interagir com uma câmera específica. identificados pela string camera_id exclusiva. Retorna um NULL em caso de falha. As tentativas de reabrir uma câmera que já está aberta não podem falhar. Para evitar disputas condições associadas à inicialização e ao desligamento do app, ao reabrir uma câmera deve encerrar a instância anterior para que a nova solicitação possa ser atendida. Um instância de câmera interrompida dessa forma deve ser colocada em modo inativo estado, aguardando a destruição final e respondendo a qualquer solicitação para afetar estado da câmera com um código de retorno de OWNERSHIP_LOST.

closeCamera(IEvsCamera camera);

Libera a interface IEvsCamera (e é o oposto do openCamera()). O stream de vídeo da câmera precisa ser interrompido chamando stopVideoStream() antes de closeCamera.

openDisplay() generates (IEvsDisplay display);

Recebe um objeto de interface usado para interagir exclusivamente com o sistema Tela de EVS. Apenas um cliente pode manter uma instância funcional do IEvsDisplay em tempo de resposta. Semelhante ao comportamento de abertura agressivo descrito em openCamera, um novo objeto IEvsDisplay pode ser criado a qualquer momento e desativa qualquer anterior instâncias. As instâncias invalidadas continuam existindo e respondendo a chamadas de função dos proprietários, mas não podem executar operações de mutação quando morto. Em algum momento, o app cliente vai notar o erro OWNERSHIP_LOST retornar códigos, fechar e liberar a interface inativa.

closeDisplay(IEvsDisplay display);

Libera a interface IEvsDisplay (e é o oposto do openDisplay()). Buffers pendentes recebidos com Chamadas getTargetBuffer() precisam ser retornadas à tela antes fechar a tela.

getDisplayState() generates (DisplayState state);

Recupera o estado atual da exibição. A implementação da HAL deve informar o estado atual real, que pode ser diferente do estado solicitado mais recentemente. A lógica responsável por mudar os estados da tela precisa existir acima do dispositivo o que impede que a implementação da HAL mude espontaneamente estados de exibição. Se nenhum cliente estiver usando a tela no momento (por uma chamada para openDisplay), a função retornará NOT_OPEN. Caso contrário, informa o estado atual do visor EVS (consulte API IEvsDisplay).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id: String que identifica exclusivamente uma determinada câmera. Pode ser o nome do dispositivo com kernel ou um nome para o dispositivo, como rearview. O valor dessa string é escolhido pela implementação da HAL. e usada de maneira opaca pela pilha acima.
  • vendor_flags: Um método para transmitir dados de câmera especializados informações opacas do motorista para um app de VES personalizado. Ele é transmitido não interpretada do driver para o app EVS, que pode ser ignorado reimplantá-lo.

IEvsCamera

Este objeto representa uma única câmera e é a interface principal para para capturar imagens.

getCameraInfo() generates (CameraDesc info);

Retorna CameraDesc desta câmera.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

Especifica a profundidade da cadeia do buffer com o qual a câmera precisa oferecer suporte. Até estes frames podem ser mantidos simultaneamente pelo cliente de IEvsCamera. Se esse muitos frames foram entregues ao receptor sem serem retornados pelo doneWithFrame, o stream pula frames até que um buffer seja retornado. para reutilização. É permitido fazer essa chamada a qualquer momento, mesmo durante as transmissões já em execução. Nesse caso, é necessário adicionar ou remover buffers da cadeia. conforme apropriado. Se nenhuma chamada for feita para esse ponto de entrada, o IEvsCamera suporta pelo menos um frame por padrão. com mais aceitáveis.

Se o bufferCount solicitado não puder ser acomodado, a função retornará BUFFER_NOT_AVAILABLE ou outro código de erro relevante. Nesse caso, o sistema continuará operando com o valor definido anteriormente.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Solicita a entrega de frames da câmera EVS desta câmera. O IEvsCameraStream começa a receber chamadas periódicas com novas molduras de imagem até stopVideoStream() é chamado. Os frames precisam começar a ser entregues em até 500 ms da chamada startVideoStream e depois do início, precisa gerados com no mínimo 10 QPS. O tempo necessário para iniciar o stream de vídeo conta efetivamente para qualquer requisito de tempo de inicialização da câmera de ré. Se o o fluxo não for iniciado, será preciso retornar um código de erro. caso contrário, será retornado OK.

oneway doneWithFrame(BufferDesc buffer);

Retorna um frame que foi entregue pelo IEvsCameraStream. Quando terminar consumindo um frame entregue à interface IEvsCameraStream, o frame deve ser retornados ao IEvsCamera para reutilização. Um número pequeno e finito de buffers é disponível (possivelmente tão pequeno quanto um), e se o suprimento acabar, não haverá mais os frames são entregues até que um buffer seja retornado, o que pode resultar quadros ignorados (um buffer com um identificador nulo indica o fim de um fluxo e não precisam ser retornados por meio dessa função). Retorna OK em caso de sucesso ou código de erro apropriado, incluindo INVALID_ARG ou BUFFER_NOT_AVAILABLE.

stopVideoStream();

Interrompe a entrega de frames da câmera EVS. Como a entrega é assíncrona, os frames podem continuar a chegar por algum tempo após o retorno da chamada. Cada frame deve ser retornado até que o encerramento do fluxo seja sinalizado para o IEvsCameraStream. É permitido chamar stopVideoStream em um stream que já foi interrompido ou nunca iniciado. Nesses casos, ele é ignorado.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

Solicita informações específicas do driver da implementação da HAL. Valores permitidos para opaqueIdentifier são específicos do motorista, mas nenhum valor podem travar o motorista. O motorista deve retornar 0 em caso de chamadas não reconhecidas, opaqueIdentifier:

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

Envia um valor específico do driver para a implementação da HAL. Esta extensão é fornecidos apenas para facilitar as extensões específicas do veículo e sem HAL implementação deve exigir que essa chamada funcione em um estado padrão. Se o driver reconhecer e aceitar os valores, OK deverá ser retornado; caso contrário INVALID_ARG ou outro código de erro representativo deve ser retornado.

struct BufferDesc {
    uint32  width;      // Units of pixels
    uint32  height;     // Units of pixels
    uint32  stride;     // Units of pixels
    uint32  pixelSize;  // Size of single pixel in bytes
    uint32  format;     // May contain values from android_pixel_format_t
    uint32  usage;      // May contain values from Gralloc.h
    uint32  bufferId;   // Opaque value
    handle  memHandle;  // gralloc memory buffer handle
}

Descreve uma imagem transmitida pela API. A unidade HAL é responsável preencher essa estrutura para descrever o buffer de imagem e o cliente HAL deve tratar essa estrutura como somente leitura. Os campos contêm informações suficientes para permitir que o cliente reconstrua um objeto ANativeWindowBuffer. conforme seja necessário para usar a imagem com EGL com o eglCreateImageKHR() extensão.

  • width: A largura em pixels da imagem apresentada.
  • height: A altura em pixels da imagem apresentada.
  • stride: Número de pixels que cada linha ocupa na memória. considerando todos os paddings para o alinhamento das linhas. Definido em pixels para corresponder a convenção adotada pelo gralloc para as descrições de buffer.
  • pixelSize: Número de bytes ocupados por cada pixel individual. permitindo o cálculo do tamanho em bytes necessário para alternar entre as linhas no imagem (stride em bytes = stride em pixels * pixelSize).
  • format: O formato de pixel usado pela imagem. O formato fornecido deve ser compatível com a implementação do OpenGL da plataforma. Para aprovar teste de compatibilidade, HAL_PIXEL_FORMAT_YCRCB_420_SP precisa ser preferencial para uso da câmera, e RGBA ou BGRA precisam preferencial para exibição.
  • usage: Sinalizações de uso definidas pela implementação da HAL. Clientes HAL devem passar essas informações sem modificações (para detalhes, consulte Gralloc.h sinalizações relacionadas).
  • bufferId: Um valor exclusivo especificado pela implementação da HAL para permitem que um buffer seja reconhecido após um retorno por meio das APIs HAL. A valor armazenado nesse campo pode ser escolhido arbitrariamente pela implementação da HAL.
  • memHandle: O identificador do buffer de memória subjacente que que contém os dados da imagem. A implementação da HAL pode optar por armazenar um Gralloc o identificador do buffer.

IEvsCameraStream

O cliente implementa essa interface para receber frames de vídeo assíncronos entregas.

deliverFrame(BufferDesc buffer);

Recebe chamadas da HAL sempre que um frame de vídeo está pronto para inspeção. Os identificadores de buffer recebidos por esse método devem ser retornados por meio de chamadas para IEvsCamera::doneWithFrame(): Quando o stream de vídeo é interrompido com um para IEvsCamera::stopVideoStream(), esse callback pode continuar conforme o pipeline é drenado. Cada frame ainda deve ser retornado. quando o último frame no fluxo foi entregue, um bufferHandle NULL é entregue, indicando o fim da transmissão e nenhuma outra entrega de frames ocorre. O NULL bufferHandle não precisa ser enviado de volta com doneWithFrame(), mas todos os outros identificadores precisam ser retornados

Embora os formatos de buffer reservados sejam tecnicamente possíveis, a compatibilidade o teste exige que o buffer esteja em um dos quatro formatos com suporte: NV21 (YCrCb 4:2:0 SemiPlanar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Intercalado), RGBA (32 bits R:G:B:x), BGRA (32 bits B:G:R:x). O formato selecionado precisa ser válido Fonte da textura GL na implementação do GLES da plataforma.

O app não pode depender de correspondência. entre o campo bufferId e memHandle no BufferDesc. Os valores bufferId são é essencialmente particular para a implementação do driver HAL e pode usar (e reutilizar) conforme achar apropriado.

IEvsDisplay

Esse objeto representa a tela Evs, controla o estado da tela, e lida com a apresentação das imagens.

getDisplayInfo() generates (DisplayDesc info);

Retorna informações básicas sobre a tela EVS fornecidas pelo sistema. Consulte DisplayDesc).

setDisplayState(DisplayState state) generates (EvsResult result);

Define o estado de exibição. Os clientes podem definir o estado de exibição para expressar a estado desejado, e a implementação da HAL deve aceitar graciosamente uma solicitação para qualquer estado enquanto estiver em qualquer outro, embora a resposta possa ser ignorar o solicitação.

Após a inicialização, a tela é definida para iniciar no Estado NOT_VISIBLE, depois do qual o cliente deve solicitar o estado VISIBLE_ON_NEXT_FRAME e começar a fornecer vídeo. Quando o display não for mais necessário, o cliente deverá solicitar o NOT_VISIBLE depois de transmitir o último frame de vídeo.

Qualquer estado pode ser solicitado a qualquer momento. Se a tela estiver já está visível, ele deve permanecer visível se for definido como VISIBLE_ON_NEXT_FRAME: Sempre retorna OK, a menos que o estado solicitado é um valor de tipo enumerado não reconhecido. Nesse caso, INVALID_ARG é retornados.

getDisplayState() generates (DisplayState state);

Recupera o estado de exibição. A implementação da HAL deve informar estado atual, que pode ser diferente do estado solicitado mais recentemente. A a lógica responsável por mudar os estados da tela precisa existir acima do dispositivo o que impede que a implementação da HAL mude espontaneamente estados de exibição.

getTargetBuffer() generates (handle bufferHandle);

Retorna um handle para um buffer de frame associado à exibição. Este buffer podem ser bloqueados e gravados por software e/ou GL. Este buffer precisa ser retornado com uma chamada para returnTargetBufferForDisplay(), mesmo que a tela não estará mais visível.

Embora os formatos de buffer reservados sejam tecnicamente possíveis, os testes de compatibilidade exige que o buffer esteja em um dos quatro formatos compatíveis: NV21 (YCrCb 4:2:0 Semiplanar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 intercalado), RGBA (32 bits R:G:B:x), BGRA (32 bits B:G:R:x). O formato selecionado precisa ser um GL válido destino de renderização do GLES da plataforma.

Em caso de erro, um buffer com identificador nulo é retornado, mas esse buffer não precisam ser retornados para returnTargetBufferForDisplay.

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Informa à tela que o buffer está pronto para ser exibido. Somente buffers recuperados por chamada para getTargetBuffer() são válidos para uso com este chamada, e o conteúdo de BufferDesc não pode ser modificado pelo app cliente. Após essa chamada, o buffer não é mais válido para uso pelo para o cliente. Retorna OK em caso de sucesso ou o código de erro apropriado. incluindo INVALID_ARG ou BUFFER_NOT_AVAILABLE.

struct DisplayDesc {
    string  display_id;
    int32   vendor_flags;  // Opaque value
}

Descreve as propriedades básicas de uma tela de EVS e exigidas por um EVS implementação. A HAL é responsável por preencher essa estrutura para que descrevem a tela de EVS. Pode ser uma tela física ou virtual que seja sobrepostos ou misturados com outro dispositivo de apresentação.

  • display_id: String que identifica exclusivamente a exibição. Pode ser o nome do dispositivo com kernel ou um nome para o dispositivo, como rearview. O valor dessa string é escolhido pela HAL implementação e usada de forma opaca pela pilha acima.
  • vendor_flags: Um método para transmitir dados de câmera especializados informações opacas do motorista para um app de EVS personalizado. Ele é transmitido não interpretada do driver para o app EVS, que pode ser ignorado reimplantá-lo.
enum DisplayState : uint32 {
    NOT_OPEN,               // Display has not been “opened” yet
    NOT_VISIBLE,            // Display is inhibited
    VISIBLE_ON_NEXT_FRAME,  // Will become visible with next frame
    VISIBLE,                // Display is currently active
    DEAD,                   // Display is not available. Interface should be closed
}

Descreve o estado da tela EVS, que pode ser desativado (não visível ao motorista) ou ativada (mostrando uma imagem ao motorista). Inclui um estado temporário em que a tela ainda não está visível, mas está preparada fique visível com a entrega do próximo frame de imagens returnTargetBufferForDisplay().

Gerenciador de EVS

O EVS Manager fornece a interface pública para o sistema EVS para coletar e apresentar visualizações da câmera externa. Onde os drivers de hardware permitem apenas uma interface ativa por recurso (câmera ou tela), o EVS Manager facilita o acesso compartilhado às câmeras. Um único app de EVS principal o primeiro cliente do EVS Manager, e é o único cliente com permissão para gravar dados de exibição (clientes adicionais podem receber acesso somente leitura à câmera imagens).

O EVS Manager implementa a mesma API que os drivers de HAL subjacentes e fornece serviço expandido com suporte a vários clientes simultâneos (mais de um cliente pode abrir uma câmera pelo gerenciador EVS e receber um vídeo stream).

Gerenciador de EVS e
Diagrama da API EVS Hardware.
Figura 2. O EVS Manager espelha o EVS subjacente API Hardware.

Os apps não têm diferenças ao operar com a HAL de hardware EVS ou a API EVS Manager, mas essa API permite acesso simultâneo ao stream da câmera. O EVS Manager é, por si só, o que permite e atua como proxy do hardware EVS HAL

As seções a seguir descrevem apenas as chamadas que têm uma comportamento (estendido) na implementação do gerenciador de EVS; chamadas restantes são idênticas às descrições da HAL de EVS.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Recebe um objeto de interface usado para interagir com uma câmera específica. identificados pela string camera_id exclusiva. Retorna um NULL em caso de falha. Na camada do EVS Manager, se houver recursos suficientes do sistema disponíveis, uma câmera que já está aberta pode ser aberta novamente por outro processo, permitindo a transmissão do stream de vídeo para vários aplicativos para o consumidor. A As strings camera_id na camada do gerenciador EVS são iguais às informados à camada de hardware EVS.

IEvsCamera

O gerenciador EVS fornecido à implementação do IEvsCamera é virtualizado internamente para que as operações de um cliente em uma câmera não afetem os outros clientes, o que mantêm o acesso independente às câmeras.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Inicia os streams de vídeo. Os clientes podem iniciar e interromper os streams de vídeo de forma independente na mesma câmera subjacente. A câmera subjacente inicia quando a primeira cliente é iniciado.

doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);

Retorna um frame. Cada cliente deve retornar seus frames quando terminar, mas têm permissão para manter seus frames pelo tempo que desejarem. Quando o a contagem de frames de um cliente atingir o limite configurado, ele não receberá mais frames até retornar um. Esse salto de frame não afeta outros que continuam a receber todos os frames conforme esperado.

stopVideoStream();

Interrompe um stream de vídeo. Cada cliente pode interromper a transmissão de vídeo a qualquer momento sem afetar outros clientes. O stream da câmera na camada do hardware é interrompido quando o último cliente de uma determinada câmera interrompe o stream

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

Envia um valor específico do driver, potencialmente permitindo que um cliente afete outro cliente. Como o EVS Manager não entende as implicações palavras de controle definidas pelo fornecedor, elas não são virtualizadas e quaisquer efeitos colaterais se aplicam a todos os clientes de uma determinada câmera. Por exemplo, se um fornecedor usasse esta chamada para mudar os frame rates, todos os clientes da câmera da camada de hardware afetada e receber frames na nova taxa.

IEvsDisplay

Apenas um proprietário da tela é permitido, mesmo no nível do EVS Manager. A O gerenciador não adiciona nenhuma funcionalidade e simplesmente passa a interface IEvsDisplay diretamente para a implementação da HAL subjacente.

App de EVS

O Android inclui uma implementação de referência C++ nativa de um EVS que se comunica com o gerenciador de EVS e a HAL do veículo para fornecem funções básicas para a câmera traseira. O app deve ser iniciado logo no início do processo de inicialização do sistema, com exibição de vídeos adequados dependendo as câmeras disponíveis e o estado do carro (estado da marcha e do indicador de direção). Os OEMs podem modificar ou substituir o app de VES por uma versão específica do veículo. lógica e apresentação.

Figura 3. Lógica de exemplo do app EVS, acessar a câmera lista.


Figura 4. Lógica de amostra do app EVS, receber callback do frame.

Como os dados de imagem são apresentados ao app em gráficos padrão o aplicativo é responsável por mover a imagem da origem no buffer de saída. Embora isso gere o custo de uma cópia de dados, ela também oferece ao app a oportunidade de renderizar a imagem na o buffer de exibição da maneira que quiser.

Por exemplo, o app pode mover os dados de pixel, com uma operação de rotação ou escala em linha. O app conseguiu usar a imagem de origem como uma textura OpenGL e renderizar uma imagem complexa para o buffer de saída, incluindo elementos virtuais, como ícones, diretrizes e animações. Um aplicativo mais sofisticado também pode selecionar várias câmeras de entrada simultâneas e mesclá-las no único frame de saída Por exemplo, para uso em uma visualização virtual de cima para baixo dos arredores do veículo.

Usar o EGL/SurfaceFlinger na HAL da tela EVS

Esta seção explica como usar o EGL para renderizar uma implementação da HAL de display EVS no Android 10.

Um EVS A implementação de referência da HAL usa EGL para renderizar a visualização da câmera no na tela e usa libgui para criar a superfície de renderização de EGL de destino. No Android 8 (e mais recentes), libgui está classificado como VNDK-private, que se refere a um grupo de bibliotecas disponíveis para bibliotecas VNDK que os processos do fornecedor não podem usar. Como as implementações de HAL devem residir na partição do fornecedor, os fornecedores são impedidos de usar Exiba implementações de HAL.

Criação de libgui para processos do fornecedor

O uso de libgui serve como a única opção para usar EGL/SurfaceFlinger em implementações de HAL de exibição de EVS. A maneira mais direta de implementar libgui é através frameworks/native/libs/gui (em inglês) diretamente usando um destino de build adicional no script de build. Essa meta é exatamente igual à o destino libgui, exceto pela adição de dois campos:

  • name
  • vendor_available
cc_library_shared {
    name: "libgui_vendor",
    vendor_available: true,
    vndk: {
        enabled: false,
    },
    double_loadable: true,

defaults: ["libgui_bufferqueue-defaults"],
srcs: [ … // bufferhub is not used when building libgui for vendors target: { vendor: { cflags: [ "-DNO_BUFFERHUB", "-DNO_INPUT", ], …

Observação: os destinos de fornecedores são criados com a macro NO_INPUT, que remove uma palavra de 32 bits dos dados de lotes. Como o SurfaceFlinger espera que esse campo tenha sido removido, o SurfaceFlinger não analisa o pacote. Isso é observado como uma falha fcntl:

W Parcel  : Attempt to read object from Parcel 0x78d9cffad8 at offset 428 that is not in the object list
E Parcel  : fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 0, fds[i] is 0, fd_count is 20, error: Unknown error 2147483647
W Parcel  : Attempt to read object from Parcel 0x78d9cffad8 at offset 544 that is not in the object list

Para resolver essa condição:

diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 6066421fa..25cf5f0ce 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -54,6 +54,9 @@ status_t layer_state_t::write(Parcel& output) const
    output.writeFloat(color.b);
#ifndef NO_INPUT
    inputInfo.write(output);
+#else
+    // Write a dummy 32-bit word.
+    output.writeInt32(0);
#endif
    output.write(transparentRegion);
    output.writeUint32(transform);

Exemplo de build instruções são fornecidas abaixo. Você receberá um $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so:

$ cd <your_android_source_tree_top>
$ . ./build/envsetup.
$ lunch <product_name>-<build_variant>
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
TARGET_PRODUCT=<product_name>
TARGET_BUILD_VARIANT=<build_variant>
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv7-a-neon
TARGET_2ND_CPU_VARIANT=cortex-a9
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=<host_linux_version>
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QT
OUT_DIR=out
============================================

$ m -j libgui_vendor … $ find $ANDROID_PRODUCT_OUT/system -name "libgui_vendor*" .../out/target/product/hawk/system/lib64/libgui_vendor.so .../out/target/product/hawk/system/lib/libgui_vendor.so

Usar binder na implementação de EVS HAL

No Android 8 e versões mais recentes, o nó do dispositivo /dev/binder se tornou exclusivo para e, portanto, inacessíveis aos processos do fornecedor. Em vez disso, os processos do fornecedor precisam usar /dev/hwbinder e converter qualquer interface AIDL ao HIDL. Para aqueles que quiserem continuar usando interfaces AIDL entre processos do fornecedor, use o domínio de vinculação, /dev/vndbinder.

Domínio de IPC Descrição
/dev/binder IPC entre processos de framework/app com interfaces AIDL
/dev/hwbinder IPC entre processos do fornecedor/framework com interfaces HIDL
IPC entre processos do fornecedor com interfaces HIDL
/dev/vndbinder IPC entre processos de fornecedor/fornecedor com interfaces AIDL

Embora o SurfaceFlinger defina interfaces AIDL, os processos do fornecedor podem usar apenas interfaces HIDL para se comunicar com os processos do framework. É necessário muito trabalho para converter interfaces AIDL para HIDL. Felizmente, o Android oferece um método para selecionar o binder Driver para libbinder, a que os processos da biblioteca de espaço do usuário estão vinculados.

diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb3166..5fd02935 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include <utils/Log.h>
+#include <binder/ProcessState.h>

#include "ServiceNames.h"
#include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
int main() {
    ALOGI("EVS Hardware Enumerator service is starting");


+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+


    // Start a thread to listen to video device addition events.
    std::atomic<bool> running { true };
    std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));

Observação: os processos do fornecedor devem chamar isso antes da chamada para o Process ou IPCThreadState ou antes de fazer qualquer chamada de vinculação.

Políticas do SELinux

Se a implementação do dispositivo for aguda total, o SELinux impede que o fornecedor processos usem /dev/binder. Por exemplo, um exemplo de EVS HAL é atribuída ao domínio hal_evs_driver e exige permissões de leitura/gravação para o domínio binder_device.

W ProcessState: Opening '/dev/binder' failed: Permission denied
F ProcessState: Binder driver could not be opened. Terminating.
F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 9145 (android.hardwar), pid 9145 (android.hardwar)
W android.hardwar: type=1400 audit(0.0:974): avc: denied { read write } for name="binder" dev="tmpfs" ino=2208 scontext=u:r:hal_evs_driver:s0 tcontext=u:object_r:binder_device:s0 tclass=chr_file permissive=0

No entanto, a adição dessas permissões causa uma falha no build porque viola o seguinte regras de nunca permitir definidas em system/sepolicy/domain.te para um dispositivo de agudos completos.

libsepol.report_failure: neverallow on line 631 of system/sepolicy/public/domain.te (or line 12436 of policy.conf) violated by allow hal_evs_driver binder_device:chr_file { read write };
libsepol.check_assertions: 1 neverallow failures occurred
full_treble_only(`
neverallow {
    domain
    -coredomain
    -appdomain
    -binder_in_vendor_violators
} binder_device:chr_file rw_file_perms;
')

binder_in_vendor_violators é um atributo fornecido para detectar um bug e orientar o desenvolvimento. Ele também pode ser usado para resolver a violação do Android 10 descrita acima.

diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9fc..6ee67d88e 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain;
hal_server_domain(hal_evs_driver, hal_evs)
hal_client_domain(hal_evs_driver, hal_evs)

+# Allow to use /dev/binder
+typeattribute hal_evs_driver binder_in_vendor_violators;
+
# allow init to launch processes in this context
type hal_evs_driver_exec, exec_type, file_type, system_file_type;
init_daemon_domain(hal_evs_driver)

Criar a implementação de referência EVS HAL como um processo do fornecedor

Como referência, você pode aplicar as seguintes alterações ao packages/services/Car/evs/Android.mk: Confirme se todas as alterações descritas funcionam para sua implementação.

diff --git a/evs/sampleDriver/Android.mk b/evs/sampleDriver/Android.mk
index 734feea7d..0d257214d 100644
--- a/evs/sampleDriver/Android.mk
+++ b/evs/sampleDriver/Android.mk
@@ -16,7 +16,7 @@ LOCAL_SRC_FILES := \
LOCAL_SHARED_LIBRARIES := \
    android.hardware.automotive.evs@1.0 \
    libui \
-    libgui \
+    libgui_vendor \
    libEGL \
    libGLESv2 \
    libbase \
@@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_INIT_RC := android.hardware.automotive.evs@1.0-sample.rc

LOCAL_MODULE := android.hardware.automotive.evs@1.0-sample
+LOCAL_PROPRIETARY_MODULE := true

LOCAL_MODULE_TAGS := optional
LOCAL_STRIP_MODULE := keep_symbols
@@ -40,6 +41,7 @@ LOCAL_STRIP_MODULE := keep_symbols
LOCAL_CFLAGS += -DLOG_TAG=\"EvsSampleDriver\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Iframeworks/native/include

#NOTE:  It can be helpful, while debugging, to disable optimizations
#LOCAL_CFLAGS += -O0 -g
diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb31669..5fd029358 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include <utils/Log.h>
+#include <binder/ProcessState.h>

#include "ServiceNames.h"
#include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
int main() {
    ALOGI("EVS Hardware Enumerator service is starting");
+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+
     // Start a thread to listen video device addition events.
    std::atomic<bool> running { true };
    std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9fc..632fc7337 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain;
hal_server_domain(hal_evs_driver, hal_evs)
hal_client_domain(hal_evs_driver, hal_evs)

+# allow to use /dev/binder
+typeattribute hal_evs_driver binder_in_vendor_violators;
+
# allow init to launch processes in this context
type hal_evs_driver_exec, exec_type, file_type, system_file_type;
init_daemon_domain(hal_evs_driver)
@@ -22,3 +25,7 @@ allow hal_evs_driver ion_device:chr_file r_file_perms;

# Allow the driver to access kobject uevents
allow hal_evs_driver self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl;
+
+# Allow the driver to use the binder device
+allow hal_evs_driver binder_device:chr_file rw_file_perms;