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:
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, eRGBA
ouBGRA
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, consulteGralloc.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).
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.
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;