O Android contém uma camada de abstração de hardware (HAL) HIDL automotiva que permite a captura e exibição de imagens no início do processo de inicialização do Android e continua funcionando durante toda a vida útil do sistema. A HAL inclui a pilha do sistema de visualização externa (EVS) e geralmente é usada para oferecer suporte a câmeras retrovisoras e telas de visualização do entorno em veículos com sistemas de infoentretenimento no veículo (IVI) baseados no Android. O EVS também permite a implementação de recursos avançados em apps do usuário.
O Android também inclui uma interface de driver de captura e exibição específica do EVS (em /hardware/interfaces/automotive/evs/1.0
). Embora seja possível criar um app de câmera traseira com base nos serviços de câmera e exibição do Android, é provável que ele seja executado muito tarde no processo de inicialização do Android. Usar 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:

App EVS
Um exemplo de app EVS em C++
(/packages/services/Car/evs/app
) serve como uma implementação
de referência. Esse app é responsável por solicitar frames de vídeo do
EVS Manager e enviar frames concluídos para exibição de volta ao EVS Manager.
Ele espera ser iniciado pelo init assim que o EVS e o serviço de carro estiverem disponíveis,
direcionados em até dois (2) segundos após a inicialização. Os OEMs podem modificar ou substituir o app EVS
como quiserem.
Gerente do EVS
O EVS Manager (/packages/services/Car/evs/manager
) fornece
os blocos de construção necessários para um app de EVS implementar qualquer coisa, desde uma
tela simples de câmera traseira até uma renderização de várias câmeras 6DOF. A interface
é apresentada pelo HIDL e foi criada para aceitar vários clientes simultâneos.
Outros apps e serviços (especificamente o Car Service) podem consultar o estado do EVS
Manager para saber quando o sistema EVS está ativo.
Interface HIDL do EVS
O sistema EVS, tanto a câmera quanto os elementos de exibição, é definido no
pacote android.hardware.automotive.evs
. Uma implementação de amostra
que exercita a interface (gera imagens de teste sintéticas e valida se as
imagens fazem a viagem de ida e volta) é fornecida em
/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áveis por configurar e coletar dados de câmeras físicas e entregá-los por buffers de memória compartilhada reconhecíveis pelo Gralloc. O lado da exibição
da implementação é responsável por fornecer um buffer de memória compartilhada
que pode ser preenchido pelo app (geralmente com renderização EGL) e apresentar
os frames concluídos em vez de qualquer outra coisa que possa aparecer na
tela física. As 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 podem oferecer suporte aos recursos necessários do EVS usando drivers de hardware de câmera ou tela atuais. A reutilização de drivers pode ser vantajosa, especialmente para drivers de tela em que a apresentação de imagens pode exigir coordenação com outras linhas de execução ativas. O Android 8.0 inclui um driver de exemplo baseado em v4l2 (em packages/services/Car/evs/sampleDriver
) que depende do kernel para compatibilidade com v4l2 e do SurfaceFlinger para apresentar a imagem de saída.
Descrição da interface de hardware do EVS
A seção descreve a HAL. Os fornecedores precisam oferecer implementações dessa API adaptadas para o hardware deles.
IEvsEnumerator
Esse objeto é responsável por enumerar o hardware de EVS disponível no sistema (uma ou mais câmeras e o único dispositivo de exibição).
getCameraList() generates (vec<CameraDesc> cameras);
Retorna um vetor que contém descrições de todas as câmeras no sistema. É presumido que o conjunto de câmeras seja fixo e conhecido no momento da inicialização. Para mais detalhes sobre
descrições de câmera, consulte CameraDesc
.
openCamera(string camera_id) generates (IEvsCamera camera);
Recebe um objeto de interface usado para interagir com uma câmera específica
identificada pela string exclusiva camera_id. Retorna NULL em caso de falha.
As tentativas de reabrir uma câmera que já está aberta não podem falhar. Para evitar condições de disputa associadas à inicialização e ao encerramento do app, a reabertura de uma câmera precisa encerrar a instância anterior para que a nova solicitação possa ser atendida. Uma instância de câmera que foi desalojada dessa forma precisa ser colocada em um estado inativo, aguardando a destruição final e respondendo a qualquer solicitação para afetar o estado da câmera com um código de retorno de OWNERSHIP_LOST
.
closeCamera(IEvsCamera camera);
Libera a interface IEvsCamera (e é o oposto da chamada
openCamera()
). O fluxo de vídeo da câmera precisa ser
interrompido chamando stopVideoStream()
antes de chamar closeCamera
.
openDisplay() generates (IEvsDisplay display);
Recebe um objeto de interface usado para interagir exclusivamente com a tela do
EVS do sistema. Apenas um cliente pode ter uma instância funcional de IEvsDisplay por vez. Semelhante ao comportamento de abertura agressiva descrito em openCamera
,
um novo objeto IEvsDisplay pode ser criado a qualquer momento e desativa todas as instâncias
anteriores. As instâncias invalidadas continuam existindo e respondendo a chamadas de função
dos proprietários, mas não podem realizar operações de mutação quando estão inativas. Eventualmente,
o app cliente vai notar os códigos de retorno de erro OWNERSHIP_LOST
e fechar e liberar a interface inativa.
closeDisplay(IEvsDisplay display);
Libera a interface IEvsDisplay (e é o oposto da chamada
openDisplay()
). Os buffers pendentes recebidos com chamadas
getTargetBuffer()
precisam ser retornados à tela antes de
fechar a tela.
getDisplayState() generates (DisplayState state);
Recebe o estado de exibição atual. A implementação da HAL precisa informar o estado atual real, que pode ser diferente do estado solicitado mais recentemente.
A lógica responsável por mudar os estados de exibição precisa estar acima da camada do dispositivo, o que torna indesejável que a implementação da HAL mude espontaneamente os estados de exibição. Se a exibição não estiver sendo mantida por nenhum cliente (por uma chamada para
openDisplay), essa função vai retornar NOT_OPEN
. Caso contrário, ele
vai informar o estado atual da tela EVS (consulte
API IEvsDisplay).
struct CameraDesc { string camera_id; int32 vendor_flags; // Opaque value }
camera_id
: uma string que identifica de forma exclusiva uma determinada câmera. Pode ser o nome do dispositivo do kernel ou um nome para o dispositivo, como rearview. O valor dessa string é escolhido pela implementação da HAL e usado de forma opaca pela pilha acima.vendor_flags
. Um método para transmitir informações especializadas da câmera de forma opaca do driver para um app EVS personalizado. Ele é transmitido sem interpretação do driver para o app EVS, que pode ignorá-lo.
IEvsCamera
Esse objeto representa uma única câmera e é a interface principal para capturar imagens.
getCameraInfo() generates (CameraDesc info);
Retorna o CameraDesc
desta câmera.
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);
Especifica a profundidade da cadeia de buffers que a câmera precisa oferecer suporte. Até
esse número de frames pode ser mantido simultaneamente pelo cliente de IEvsCamera. Se esse número de frames tiver sido entregue ao receptor sem ser retornado por doneWithFrame
, o fluxo vai pular frames até que um buffer seja retornado para reutilização. É legal que essa chamada seja feita a qualquer momento, mesmo enquanto os fluxos já estão em execução. Nesse caso, os buffers devem ser adicionados ou removidos da cadeia conforme apropriado. Se nenhuma chamada for feita para esse ponto de entrada, o IEvsCamera vai oferecer suporte a pelo menos um frame por padrão, com mais aceitáveis.
Se o bufferCount solicitado não puder ser acomodado, a função vai retornar
BUFFER_NOT_AVAILABLE
ou outro código de erro relevante. Nesse caso, o sistema continua operando com o valor definido anteriormente.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Solicita a entrega de frames da câmera EVS. O IEvsCameraStream
começa a receber chamadas periódicas com novos frames de imagem até que
stopVideoStream()
seja chamado. Os frames precisam começar a ser entregues
em até 500 ms da chamada startVideoStream
e, depois de iniciados, precisam
ser gerados a uma taxa mínima de 10 FPS. O tempo necessário para iniciar o fluxo de vídeo conta para qualquer requisito de tempo de inicialização da câmera traseira. Se o
fluxo não for iniciado, um código de erro vai ser retornado. Caso contrário, OK será retornado.
oneway doneWithFrame(BufferDesc buffer);
Retorna um frame entregue ao IEvsCameraStream. Quando terminar de
consumir um frame entregue à interface IEvsCameraStream, ele precisará ser
retornado à IEvsCamera para reutilização. Um número pequeno e finito de buffers está disponível (possivelmente apenas um), e, se o fornecimento se esgotar, nenhum outro frame será entregue até que um buffer seja retornado, o que pode resultar em frames ignorados. Um buffer com um identificador nulo indica o fim de um fluxo e não precisa ser retornado por essa função. Retorna "OK" em caso de sucesso ou
código de erro apropriado, incluindo potencialmente 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 chegando por algum tempo depois que essa chamada é retornada. Cada frame precisa ser retornado até que o fechamento do fluxo seja sinalizado para o IEvsCameraStream. É permitido chamar stopVideoStream
em um fluxo
que já foi interrompido ou nunca iniciado. Nesses casos, a chamada é ignorada.
getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);
Solicita informações específicas do driver da implementação da HAL. Os valores permitidos para opaqueIdentifier
são específicos do driver, mas nenhum valor transmitido pode falhar. O driver precisa retornar 0 para qualquer opaqueIdentifier
não reconhecido.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Envia um valor específico do driver para a implementação da HAL. Essa extensão é
fornecida apenas para facilitar extensões específicas do veículo, e nenhuma implementação de HAL
precisa dessa chamada para funcionar em um estado padrão. Se o
driver reconhecer e aceitar os valores, "OK" será retornado. Caso contrário,
INVALID_ARG
ou outro código de erro representativo 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. O driver HAL é responsável por
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 necessário para usar a imagem com EGL e a extensão
eglCreateImageKHR()
.
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 o padding para alinhamento das linhas. Expressa em pixels para corresponder à 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 passar entre as linhas da imagem (stride
em bytes =stride
em pixels *pixelSize
).format
. O formato de pixel usado pela imagem. O formato fornecido precisa ser compatível com a implementação do OpenGL da plataforma. Para passar no teste de compatibilidade,HAL_PIXEL_FORMAT_YCRCB_420_SP
precisa ser preferido para uso da câmera, eRGBA
ouBGRA
precisam ser preferidos para exibição.usage
. Flags de uso definidas pela implementação da HAL. Espera-se que os clientes HAL transmitam esses dados sem modificação. Para mais detalhes, consulte as flags relacionadasGralloc.h
.bufferId
: um valor exclusivo especificado pela implementação do HAL para permitir que um buffer seja reconhecido após uma viagem de ida e volta pelas APIs HAL. O valor armazenado nesse campo pode ser escolhido arbitrariamente pela implementação da HAL.memHandle
: o identificador do buffer de memória subjacente que contém os dados da imagem. A implementação da HAL pode optar por armazenar um identificador de buffer do Gralloc aqui.
IEvsCameraStream
O cliente implementa essa interface para receber entregas assíncronas de frames de vídeo.
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 precisam ser retornados por chamadas para
IEvsCamera::doneWithFrame()
. Quando o stream de vídeo é interrompido com uma chamada para IEvsCamera::stopVideoStream()
, esse callback pode continuar enquanto o pipeline é drenado. Cada frame ainda precisa ser retornado. Quando o último frame
no stream for entregue, um bufferHandle
NULL será entregue,
indicando o fim do stream e que não haverá mais entregas de frames. O NULL
bufferHandle
não precisa ser enviado de volta com
doneWithFrame()
, mas todos os outros identificadores precisam ser retornados.
Embora seja tecnicamente possível usar formatos de buffer proprietários, o teste de compatibilidade exige que o buffer esteja em um dos quatro formatos compatíveis: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved) e RGBA (32 bits R:G:B:x) e BGRA (32 bits B:G:R:x). O formato selecionado precisa ser uma origem de textura GL válida na implementação GLES da plataforma.
O app não pode depender de nenhuma correspondência entre o campo bufferId
e o memHandle
na estrutura BufferDesc
. Os valores bufferId
são essencialmente particulares à implementação do driver HAL, que pode usá-los (e reutilizá-los) conforme achar adequado.
IEvsDisplay
Esse objeto representa a tela do EVS, controla o estado dela e processa a apresentação real das imagens.
getDisplayInfo() generates (DisplayDesc info);
Retorna informações básicas sobre a tela do EVS fornecida 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 o estado desejado, e a implementação da HAL precisa aceitar normalmente uma solicitação de qualquer estado enquanto estiver em qualquer outro estado, embora a resposta possa ser ignorar a solicitação.
Na inicialização, a exibição é definida para começar no estado
NOT_VISIBLE
. Depois disso, espera-se que o cliente solicite
o estado VISIBLE_ON_NEXT_FRAME
e comece a fornecer vídeo. Quando a
exibição não for mais necessária, o cliente deverá solicitar o estado
NOT_VISIBLE
depois de transmitir o último frame de vídeo.
É válido solicitar qualquer estado a qualquer momento. Se a tela já estiver visível, ela vai continuar assim se for definida como VISIBLE_ON_NEXT_FRAME
. Sempre retorna OK, a menos que o estado solicitado seja um valor de enumeração não reconhecido. Nesse caso, INVALID_ARG
é retornado.
getDisplayState() generates (DisplayState state);
Recebe o estado da tela. A implementação da HAL precisa informar o estado atual real, que pode ser diferente do estado solicitado mais recentemente. A lógica responsável por mudar os estados de exibição precisa estar acima da camada do dispositivo, o que torna indesejável que a implementação da HAL mude espontaneamente os estados de exibição.
getTargetBuffer() generates (handle bufferHandle);
Retorna um handle para um buffer de frame associado à tela. Esse buffer pode ser bloqueado e gravado por software e/ou GL. Esse buffer precisa ser retornado com uma chamada para returnTargetBufferForDisplay()
, mesmo que a tela não esteja mais visível.
Embora formatos de buffer proprietários sejam tecnicamente possíveis, o teste de compatibilidade exige que o buffer esteja em um dos quatro formatos compatíveis: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), RGBA (32 bits R:G:B:x) e BGRA (32 bits B:G:R:x). O formato selecionado precisa ser um destino de renderização GL válido na implementação GLES da plataforma.
Em caso de erro, um buffer com um identificador nulo é retornado, mas esse buffer não precisa ser transmitido de volta para returnTargetBufferForDisplay
.
returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);
Informa à tela que o buffer está pronto para exibição. Somente os buffers recuperados
por uma chamada para getTargetBuffer()
são válidos para uso com essa
chamada, e o conteúdo do BufferDesc
não pode ser modificado pelo
app cliente. Depois dessa chamada, o buffer não é mais válido para uso pelo
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 EVS e é exigido por uma implementação de EVS. A HAL é responsável por preencher essa estrutura para descrever a tela EVS. Pode ser uma tela física ou virtual que é sobreposta ou misturada com outro dispositivo de apresentação.
display_id
. Uma string que identifica o display de forma exclusiva. Pode ser o nome do dispositivo do kernel ou um nome para o dispositivo, como rearview. O valor dessa string é escolhido pela implementação do HAL e usado de maneira opaca pela pilha acima.vendor_flags
. Um método para transmitir informações especializadas da câmera de forma opaca do driver para um app EVS personalizado. Ele é transmitido sem interpretação do driver para o app EVS, que pode ignorá-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 do EVS, que pode ser desativada (não visível para o motorista) ou ativada (mostrando uma imagem para o motorista).
Inclui um estado transitório em que a exibição ainda não está visível, mas está preparada
para ficar visível com a entrega do próximo frame de imagens com a
chamada returnTargetBufferForDisplay()
.
Gerente do EVS
O EVS Manager fornece a interface pública ao sistema EVS para coletar e apresentar visualizações de câmeras externas. Quando 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 EVS principal é o primeiro cliente do EVS Manager e o único cliente permitido a gravar dados de exibição. Outros clientes podem receber acesso somente leitura às imagens da câmera.
O EVS Manager implementa a mesma API que os drivers HAL subjacentes e oferece um serviço expandido com suporte a vários clientes simultâneos. Mais de um cliente pode abrir uma câmera pelo EVS Manager e receber um fluxo de vídeo.

Os apps não veem diferenças ao operar pela implementação da HAL de hardware do EVS ou pela API EVS Manager, exceto que a API EVS Manager permite acesso simultâneo ao fluxo de câmera. O EVS Manager é o único cliente permitido da camada HAL de hardware do EVS e atua como um proxy para o HAL de hardware do EVS.
As seções a seguir descrevem apenas as chamadas que têm um comportamento diferente (estendido) na implementação do EVS Manager. As demais chamadas são idênticas às descrições da HAL do EVS.
IEvsEnumerator
openCamera(string camera_id) generates (IEvsCamera camera);
Recebe um objeto de interface usado para interagir com uma câmera específica
identificada pela string exclusiva camera_id. Retorna NULL em caso de falha.
Na camada do EVS Manager, desde que haja recursos suficientes do sistema, uma câmera já aberta pode ser aberta novamente por outro processo, permitindo a ramificação do fluxo de vídeo para vários apps consumidores. As strings camera_id
na camada do EVS Manager são as mesmas informadas à camada de hardware do EVS.
IEvsCamera
A implementação IEvsCamera fornecida pelo EVS Manager é virtualizada internamente. Assim, as operações em uma câmera por um cliente não afetam outros clientes, que mantêm acesso independente às próprias câmeras.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Inicia streams de vídeo. Os clientes podem iniciar e interromper transmissões de vídeo de forma independente na mesma câmera. A câmera subjacente é iniciada quando o primeiro cliente é iniciado.
doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);
Retorna um frame. Cada cliente precisa retornar os frames quando terminar, mas pode manter os frames pelo tempo que quiser. Quando a contagem de frames mantida por um cliente atinge o limite configurado, ele não recebe mais frames até retornar um. Essa ação não afeta outros clientes, que continuam recebendo todos os frames conforme o esperado.
stopVideoStream();
Interrompe um stream de vídeo. Cada cliente pode interromper o stream de vídeo a qualquer momento sem afetar os outros. O stream de câmera na camada de hardware é interrompido quando o último cliente de uma determinada câmera para o stream.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Envia um valor específico do motorista, permitindo que um cliente afete outro. Como o EVS Manager não entende as implicações das palavras de controle definidas pelo fornecedor, elas não são virtualizadas, e todos os efeitos colaterais se aplicam a todos os clientes de uma determinada câmera. Por exemplo, se um fornecedor usasse essa chamada para mudar as taxas de frames, todos os clientes da câmera da camada de hardware afetada receberiam frames na nova taxa.
IEvsDisplay
Só é permitido um proprietário do display, mesmo no nível do EVS Manager. O Manager não adiciona funcionalidade e simplesmente passa a interface IEvsDisplay diretamente para a implementação da HAL subjacente.
App EVS
O Android inclui uma implementação de referência nativa em C++ de um app EVS que se comunica com o EVS Manager e a HAL do veículo para fornecer funções básicas de câmera traseira. O app deve ser iniciado bem no início do processo de inicialização do sistema, com um vídeo adequado mostrado dependendo das câmeras disponíveis e do estado do carro (marcha e estado da seta). Os OEMs podem modificar ou substituir o app EVS pela própria lógica e apresentação específicas do veículo.


Como os dados de imagem são apresentados ao app em um buffer gráfico padrão, ele é responsável por mover a imagem do buffer de origem para o buffer de saída. Embora isso introduza o custo de uma cópia de dados, também oferece a oportunidade para o app renderizar a imagem no buffer de exibição da maneira que quiser.
Por exemplo, o app pode mover os dados do pixel, talvez com uma operação de escala ou rotação inline. O app também pode usar a imagem de origem como uma textura OpenGL e renderizar uma cena complexa no buffer de saída, incluindo elementos virtuais, como ícones, diretrizes e animações. Um app mais sofisticado também pode selecionar várias câmeras de entrada simultâneas e mesclá-las em um único frame de saída (como para uso em uma visualização virtual de cima para baixo do entorno do veículo).
Usar o EGL/SurfaceFlinger no EVS Display HAL
Esta seção explica como usar o EGL para renderizar uma implementação do HAL de exibição do EVS no Android 10.
Uma implementação de referência do HAL do EVS usa EGL para renderizar a visualização da câmera na tela e usa libgui
para criar a superfície de renderização EGL de destino. No Android 8 (e versões mais recentes), libgui
é 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 precisam estar na partição do fornecedor, os fornecedores não podem usar
Surface nas implementações de HAL.
Como criar libgui para processos de fornecedores
O uso de libgui
serve como a única opção para usar EGL/SurfaceFlinger
em implementações de HAL de exibição do EVS. A maneira mais simples de implementar libgui
é
usando
frameworks/native/libs/gui
diretamente com uma meta de build adicional no script de build. Essa segmentação é exatamente igual à segmentação 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: as segmentações por fornecedor são criadas com a macro NO_INPUT
, que remove uma palavra de 32 bits dos dados do pacote. Como o SurfaceFlinger espera esse campo removido, ele não consegue analisar o pacote. Isso é observado como uma falha de 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);
Confira abaixo um exemplo de instruções de build. Você vai 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 da HAL do EVS
No Android 8 e versões mais recentes, o nó do dispositivo /dev/binder
passou a ser exclusivo para
processos de framework e, portanto, inacessível para processos do fornecedor. Em vez disso, os processos do fornecedor precisam usar /dev/hwbinder
e converter todas as interfaces AIDL para HIDL. Para quem quer continuar usando interfaces AIDL entre processos do fornecedor,
use o domínio do binder, /dev/vndbinder
.
Domínio IPC | Descrição |
---|---|
/dev/binder |
IPC entre processos de framework/app com interfaces AIDL |
/dev/hwbinder |
IPC entre processos de framework/fornecedor com interfaces HIDL IPC entre processos de 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 só podem usar interfaces HIDL para
se comunicar com processos do framework. É necessário um trabalho considerável para converter interfaces AIDL em HIDL. Felizmente, o Android oferece um método para selecionar o driver
do binder para libbinder
, a que os processos da biblioteca do 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 precisam chamar esse antes de chamar
Process
ou IPCThreadState
ou antes de fazer qualquer chamada de binder.
Políticas do SELinux
Se a implementação do dispositivo for treble completo, o SELinux vai impedir que os processos
do fornecedor usem /dev/binder
. Por exemplo, uma implementação de amostra da HAL do EVS é atribuída ao domínio hal_evs_driver
e exige permissões de leitura/gravação no 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, adicionar essas permissões causa uma falha de build porque viola as seguintes regras
neverallow definidas em system/sepolicy/domain.te
para um dispositivo treble completo.
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 uma implementação de referência da HAL do EVS como um processo de fornecedor
Como referência, aplique as seguintes mudanças a
packages/services/Car/evs/Android.mk
. Confirme se todas as mudanças descritas funcionam na 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;