APIs para gerenciamento de buffer da HAL3 da câmera

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.

Gerenciamento de buffer no Android 9 ou em versões anteriores

Figura 1. Interface HAL da câmera no Android 9 e em versões anteriores

Gerenciamento de buffer no Android 10

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:

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 chamar requestStreamBuffers 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 chamar requestStreamBuffers 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.

Como processar chamadas que chegam atrasadas

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 chamada configureStreams . 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 chamadas processCaptureRequest quando o HAL tem muitas solicitações de captura enfileiradas.

  • A latência da chamada requestStreamBuffers varia muito:há muitos motivos para uma chamada requestStreamBuffers 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++.