O Android 10 introduz APIs opcionais de gerenciamento de buffer da HAL3 da câmera, que permitem implementar a lógica de gerenciamento de buffer para ter diferentes memórias e capturar trocas de latência nas implementações de HAL da câmera.
O HAL da câmera exige N solicitações (em que N é igual à profundidade do pipeline) enfileiradas no pipeline, mas geralmente não exige todos os N conjuntos de buffers de saída ao mesmo tempo.
Por exemplo, a HAL pode ter oito solicitações enfileiradas no pipeline, mas só precisa de buffers de saída para as duas solicitações nas últimas etapas do pipeline. Em dispositivos com o Android 9 e versões anteriores, o framework da câmera aloca buffers quando a solicitação é enfileirada na HAL. Portanto, pode haver seis conjuntos de buffers na HAL que não estão em uso. No Android 10, as APIs de gerenciamento de buffer da HAL3 da câmera permitem a separação dos buffers de saída para liberar os seis conjuntos de buffers. Isso pode levar a centenas de megabytes de economia de memória em dispositivos de ponta e também pode ser benéfico para dispositivos com pouca memória.
A Figura 1 mostra um diagrama da interface HAL da câmera para dispositivos com Android 9 e versões anteriores. A Figura 2 mostra a interface HAL da câmera no Android 10 com as APIs de gerenciamento de buffer HAL3 da câmera implementadas.
Figura 1. Interface HAL da câmera no Android 9 e em versões anteriores
Figura 2. Interface HAL da câmera no Android 10 usando as APIs de gerenciamento de buffer
Implementar as APIs de gerenciamento de buffer
Para implementar as APIs de gerenciamento de buffer, a HAL da câmera precisa:
- Implemente HIDL
ICameraDevice@3.5
. - Defina a chave de características da câmera
android.info.supportedBufferManagementVersion
comoHIDL_DEVICE_3_5
.
O HAL da câmera usa os métodos
requestStreamBuffers
e
returnStreamBuffers
em
ICameraDeviceCallback.hal
para solicitar e retornar buffers. A HAL também precisa implementar o método
signalStreamFlush
em
ICameraDeviceSession.hal
para sinalizar à HAL da câmera que retorne buffers.
requestStreamBuffers
Use o método
requestStreamBuffers
para solicitar buffers do framework da câmera. Ao usar as APIs de gerenciamento de buffer da HAL3 da câmera, as solicitações de captura do framework da câmera não contêm buffers de saída. Ou seja, o campo bufferId
em StreamBuffer
é 0
. Portanto, o HAL da câmera precisa usar requestStreamBuffers
para solicitar
buffers do framework da câmera.
O método requestStreamBuffers
permite que o caller solicite vários buffers
de vários fluxos de saída em uma única chamada, reduzindo as chamadas
de IPC HIDL. No entanto, as chamadas levam mais tempo quando mais buffers são solicitados ao mesmo tempo, o que pode afetar negativamente a latência total da solicitação para o resultado.
Além disso, como as chamadas para requestStreamBuffers
são serializadas no serviço
de câmera, é recomendável que a HAL da câmera use uma linha de execução dedicada de alta prioridade
para solicitar buffers.
Se uma solicitação de buffer falhar, a HAL da câmera precisará processar corretamente erros não fatais. A lista a seguir descreve os motivos comuns para falhas nas solicitações de buffer e como elas devem ser processadas pela HAL da câmera.
- O app se desconecta do fluxo de saída:Esse é um erro não fatal. O HAL da câmera precisa enviar
ERROR_REQUEST
para qualquer solicitação de captura destinada a um stream desconectado e estar pronto para processar as solicitações subsequentes normalmente. - Tempo limite:isso pode ocorrer quando um app está ocupado fazendo
processamento intenso enquanto mantém alguns buffers. A HAL da câmera precisa
enviar
ERROR_REQUEST
para solicitações de captura que não podem ser atendidas devido a um erro de tempo limite e estar pronta para processar as solicitações subsequentes normalmente. - O framework da câmera está preparando uma nova configuração de stream:o HAL da câmera precisa aguardar até que a próxima
chamada
configureStreams
seja concluída antes de chamarrequestStreamBuffers
novamente. - A HAL da câmera atingiu o limite de buffer (o campo
maxBuffers
): A HAL da câmera precisa esperar até retornar pelo menos um buffer do stream antes de chamarrequestStreamBuffers
novamente.
returnStreamBuffers
Use o método
returnStreamBuffers
para retornar buffers extras ao framework da câmera. Normalmente, a HAL da câmera
retorna buffers ao framework da câmera pelo método
processCaptureResult
, mas só pode considerar as solicitações de captura enviadas à
HAL da câmera. Com o método requestStreamBuffers
, é possível que a implementação da HAL da câmera retenha mais buffers do que o solicitado pelo framework da câmera. É quando o método returnStreamBuffers
deve ser usado. Se a implementação da HAL nunca armazenar mais buffers do que o solicitado, ela não precisará chamar o método returnStreamBuffers
.
signalStreamFlush
O método
signalStreamFlush
é chamado pelo framework da câmera para notificar a HAL da câmera a retornar todos os
buffers disponíveis. Normalmente, isso é chamado quando a estrutura da câmera está prestes a
chamar
configureStreams
e precisa esvaziar o pipeline de captura da câmera. Assim como o método returnStreamBuffers
, se uma implementação de HAL da câmera não tiver mais buffers do que o solicitado, é possível ter uma implementação vazia desse método.
Depois que o framework da câmera chamar
signalStreamFlush
,
ele vai parar de enviar novas solicitações de captura para o HAL da câmera até que todos os
buffers sejam retornados ao framework. Quando todos os buffers são retornados, as chamadas do método requestStreamBuffers
falham, e o framework da câmera pode continuar o trabalho em um estado limpo. A estrutura da câmera chama o método
configureStreams
ou
processCaptureRequest
. Se o framework de câmera chamar o método configureStreams
, o HAL da câmera poderá começar a solicitar buffers novamente depois que a chamada configureStreams
retornar com sucesso. Se o framework da câmera chamar o método processCaptureRequest
,
a HAL da câmera poderá começar a solicitar buffers durante a chamada processCaptureRequest
.
A semântica é diferente para o método signalStreamFlush
e o
flush
método. Quando o método flush
é chamado, o HAL pode cancelar solicitações de captura pendentes com ERROR_REQUEST
para esvaziar o pipeline o mais rápido possível. Quando o método
signalStreamFlush
é chamado, a HAL precisa concluir todas as solicitações de
captura pendentes normalmente e retornar todos os buffers ao framework da câmera.
Outra diferença entre o método signalStreamFlush
e outros métodos é que signalStreamFlush
é um método HIDL unidirecional. Isso significa que a estrutura da câmera pode chamar outras APIs de bloqueio antes que a HAL receba a chamada signalStreamFlush
. Isso significa que
o método signalStreamFlush
e outros métodos (especificamente o
método configureStreams
) podem chegar à HAL da câmera em uma ordem diferente
da ordem em que foram chamados no framework da câmera. Para resolver esse problema de assincronia, o campo streamConfigCounter
foi adicionado a StreamConfiguration
e como um argumento ao método signalStreamFlush
. A implementação do HAL da câmera precisa usar o argumento streamConfigCounter
para determinar se uma chamada signalStreamFlush
chega depois da
chamada configureStreams
correspondente. Confira um exemplo na Figura 3.
Figura 3. Como a HAL da câmera deve detectar e processar chamadas signalStreamFlush que chegam atrasadas
Mudanças de comportamento ao implementar as APIs de gerenciamento de buffer
Ao usar as APIs de gerenciamento de buffer para implementar a lógica de gerenciamento de buffer, considere as seguintes possíveis mudanças de comportamento na câmera e na implementação da HAL da câmera:
As solicitações de captura chegam ao HAL da câmera mais rápido e com mais frequência:sem as APIs de gerenciamento de buffer, a estrutura da câmera solicita buffers de saída para cada solicitação de captura antes de enviar uma solicitação de captura ao HAL da câmera. Ao usar as APIs de gerenciamento de buffer, o framework da câmera não precisa mais esperar pelos buffers e, portanto, pode enviar solicitações de captura para a HAL da câmera antes.
Além disso, sem as APIs de gerenciamento de buffer, o framework de câmera para de enviar solicitações de captura se um dos fluxos de saída da solicitação de captura atingir o número máximo de buffers que o HAL pode manter por vez. Esse valor é designado pelo HAL da câmera no campo
HalStream::maxBuffers
no valor de retorno de uma chamadaconfigureStreams
. Com as APIs de gerenciamento de buffer, esse comportamento de limitação não existe mais, e a implementação do HAL da câmera não pode aceitar chamadasprocessCaptureRequest
quando o HAL tem muitas solicitações de captura enfileiradas.A latência da chamada
requestStreamBuffers
varia muito:há muitos motivos para uma chamadarequestStreamBuffers
demorar mais do que a média. Exemplo:- Nos primeiros buffers de um stream recém-criado, as chamadas podem demorar mais porque o dispositivo precisa alocar memória.
- A latência esperada aumenta proporcionalmente ao número de buffers solicitados em cada chamada.
- O app está mantendo buffers e está ocupado processando. Isso pode fazer com que as solicitações de buffer fiquem mais lentas ou atinjam um tempo limite devido à falta de buffers ou a uma CPU ocupada.
Estratégias de gerenciamento de buffer
As APIs de gerenciamento de buffer permitem implementar diferentes tipos de estratégias. Por exemplo:
- Compatibilidade com versões anteriores:o HAL solicita buffers para uma solicitação de captura
durante a chamada
processCaptureRequest
. Essa estratégia não oferece economia de memória, mas pode servir como a primeira implementação das APIs de gerenciamento de buffer, exigindo pouquíssimas mudanças no código da HAL da câmera atual. - Economia máxima de memória:a HAL da câmera solicita buffers de saída imediatamente antes de um precisar ser preenchido. Essa estratégia permite maximizar a economia de memória. O possível problema é mais instabilidade no pipeline da câmera quando as solicitações de buffer levam muito tempo para serem concluídas.
- Em cache:a HAL da câmera armazena em cache alguns buffers para que seja menos provável que ela seja afetada por uma solicitação de buffer lenta ocasional.
O HAL da câmera pode adotar diferentes estratégias para casos de uso específicos. Por exemplo, usar a estratégia de economia de memória maximizada para casos de uso que usam muita memória e a estratégia compatível com versões anteriores para outros casos de uso.
Exemplo de implementação na HAL da câmera externa
A HAL da câmera externa foi introduzida no Android 9 e pode ser encontrada na
árvore de origem em
hardware/interfaces/camera/device/3.5/
.
No Android 10, ele foi atualizado para incluir
ExternalCameraDeviceSession.cpp
,
uma implementação da API de gerenciamento de buffers. Esse HAL de câmera externa
implementa a estratégia de economia de memória maximizada mencionada em Estratégias de gerenciamento de buffer em algumas centenas de linhas de
código C++.