APIs para gerenciamento de buffer da HAL3 da câmera

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.

Gerenciamento de buffer no Android 9 ou versões anteriores

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

Gerenciamento de buffer no Android 10

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:

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

Como lidar com ligações que chegam atrasadas

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 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 na fila.

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