O Android 10 apresenta APIs opcionais de gerenciamento de buffer da HAL3 da câmera. Elas permitem implementar a lógica de gerenciamento de buffer para ter diferentes memórias e capturar compensações de latência nas implementações de HAL da câmera.
O HAL da câmera requer N solicitações (em que N é igual à profundidade do pipeline) na fila do pipeline, mas geralmente não exige todos os N conjuntos de buffers de saída ao mesmo tempo.
Por exemplo, o HAL pode ter oito solicitações na fila do pipeline, mas requer apenas buffers de saída para as duas solicitações nos últimos estágios do pipeline. Em dispositivos com o Android 9 e versões anteriores, o framework da câmera aloca buffers quando a solicitação é enfileirada no HAL. Assim, pode haver seis conjuntos de buffers no HAL que não estão em uso. No Android 10, as APIs para gerenciamento de buffer da HAL3 da câmera permitem o desacoplamento 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 última geração 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 da HAL da câmera no Android 10 com as APIs de gerenciamento de buffer da HAL3 da câmera implementadas.
Figura 1. Interface HAL da câmera no Android 9 e versões mais antigas
Figura 2. Interface da 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 o 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 a HAL da câmera para retornar buffers.
requestStreamBuffers
Use o método
requestStreamBuffers
para solicitar buffers do framework da câmera. Ao usar as APIs de gerenciamento de buffer
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 autor da chamada solicite vários buffers
de vários streams de saída em uma única chamada, permitindo menos chamadas IPC
HIDL. No entanto, as chamadas levam mais tempo quando mais buffers são solicitados ao
mesmo tempo, e isso 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
da câmera, é recomendável que o HAL da câmera use uma linha de execução
de alta prioridade dedicada para solicitar buffers.
Se uma solicitação de buffer falhar, a HAL da câmera precisará ser capaz de processar corretamente erros não fatais. A lista a seguir descreve motivos comuns para falhas nas solicitações de buffer e como elas precisam ser processadas pela HAL da câmera.
- O app se desconecta do stream de saída:este é um erro não fatal. O HAL da câmera precisa enviar
ERROR_REQUEST
para qualquer solicitação de captura com segmentação para um fluxo desconectado e estar pronto para processar solicitações posteriores normalmente. - Tempo limite:isso pode ocorrer quando um app está ocupado fazendo
processamento intenso enquanto mantém alguns buffers. O 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 pronto para processar solicitações subsequentes normalmente. - O framework da câmera está preparando uma nova configuração de stream:o HAL da câmera precisa esperar 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. A HAL da câmera normalmente
retorna buffers para o framework da câmera pelo método
processCaptureResult
, mas só pode considerar solicitações de captura que foram enviadas para a
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
precisa ser
usado. Se a implementação da HAL nunca armazenar mais buffers do que o solicitado, a
implementação da HAL da câmera 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 para retornar todos
os buffers disponíveis. Isso normalmente é chamado quando o framework da câmera está prestes a
chamar
configureStreams
e precisa drenar o pipeline de captura da câmera. Assim como no método returnStreamBuffers
, se uma implementação da 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 chama
signalStreamFlush
,
ele para de enviar novas solicitações de captura para o HAL da câmera até que todos
os buffers sejam retornados ao framework da câmera. Quando todos os buffers são
retornados, as chamadas de método requestStreamBuffers
falham, e o framework
da câmera pode continuar o trabalho em um estado limpo. O framework da câmera chama
o método
configureStreams
ou
processCaptureRequest
. Se o framework da 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
. Quando o método flush
é chamado, o HAL pode abortar solicitações de captura
pendentes com
ERROR_REQUEST
para esvaziar o pipeline o mais rápido possível. Quando
o método signalStreamFlush
é chamado, o HAL precisa finalizar 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 de mão única, o que significa que o framework 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
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 adicionado 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. Consulte a Figura 3 para conferir um exemplo.
Figura 3. Como a HAL da câmera precisa detectar e processar chamadas StreamFlush com sinal 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 mudanças de comportamento possíveis na implementação da HAL da câmera e da câmera:
As solicitações de captura chegam à HAL da câmera mais rápido e com mais frequência:sem APIs de gerenciamento de buffer, o framework da câmera solicita buffers de saída para cada solicitação de captura antes de enviar uma solicitação de captura para a HAL da câmera. Ao usar as APIs de gerenciamento de buffer, o framework da câmera não precisa mais esperar por buffers e, portanto, pode enviar solicitações de captura para a HAL da câmera mais cedo.
Além disso, sem APIs de gerenciamento de buffer, o framework da câmera para de enviar solicitações de captura se um dos streams de saída da solicitação de captura tiver atingido o número máximo de buffers que o HAL pode conter 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 na fila.A latência da chamada
requestStreamBuffers
varia significativamente:há muitos motivos pelos quais uma chamadarequestStreamBuffers
pode levar mais tempo do que a média. Exemplo:- Para os 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á segurando 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 que diferentes tipos de estratégias de gerenciamento de buffer sejam implementadas. Por exemplo:
- Compatível com versões anteriores:a HAL solicita buffers para uma solicitação de captura
durante a chamada
processCaptureRequest
. Essa estratégia não oferece nenhum poupança de memória, mas pode servir como a primeira implementação das APIs de gerenciamento de buffer, exigindo poucas mudanças de código no HAL da câmera atual. - Economia de memória maximizada:a HAL da câmera só solicita buffers de saída imediatamente antes de precisar ser preenchido. Essa estratégia permite maximizar a economia de memória. A desvantagem potencial é mais instabilidade do pipeline da câmera quando as solicitações de buffer levam um tempo anormalmente longo para serem concluídas.
- Em cache:a HAL da câmera armazena alguns buffers em cache para que seja menos provável que seja afetada por uma solicitação de buffer lenta ocasional.
O HAL da câmera pode adotar estratégias diferentes para casos de uso específicos, por exemplo, usando a estratégia de economia de memória maximizada para casos de uso que usam muita memória e usando 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 buffer. Essa 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++.