APIs de administración de búfer de la HAL3 de la cámara

Android 10 introduce las API de administración de búfer de cámara de HAL3 opcionales que te permiten implementar la lógica de administración de búferes para lograr diferentes compensaciones de memoria y latencia de captura en las implementaciones de la HAL de cámara.

La HAL de la cámara requiere N solicitudes (donde N es igual a la profundidad de la canalización) en cola en su canalización, pero, a menudo, no requiere todos los conjuntos de búferes de salida al mismo tiempo.

Por ejemplo, la HAL podría tener ocho solicitudes en cola en la canalización, pero solo requiere búferes de salida para las dos solicitudes en las últimas etapas de la canalización. En los dispositivos que ejecutan Android 9 y versiones anteriores, el framework de la cámara asigna búferes cuando la solicitud está en cola en la HAL, por lo que podría haber seis conjuntos de búferes en la HAL que no estén en uso. En Android 10, las APIs de administración de búfer de la HAL3 de la cámara permiten la separación de los búferes de salida para liberar los seis conjuntos de búferes. Esto puede generar cientos de megabytes de ahorro de memoria en dispositivos de alta gama y también puede ser beneficioso para dispositivos con poca memoria.

En la Figura 1, se muestra un diagrama de la interfaz de la HAL de la cámara para dispositivos que ejecutan Android 9 y versiones anteriores. En la Figura 2, se muestra la interfaz de la HAL de la cámara en Android 10 con las APIs de administración de búfer de la HAL3 de la cámara implementadas.

Administración del búfer en Android 9 o versiones anteriores

Figura 1: Interfaz de la HAL de la cámara en Android 9 y versiones anteriores

Administración de búferes en Android 10

Figura 2: Interfaz de la HAL de la cámara en Android 10 con las APIs de administración de búfer

Implementa las APIs de administración de búfer

Para implementar las APIs de administración de búfer, la HAL de la cámara debe hacer lo siguiente:

La HAL de la cámara usa los requestStreamBuffers y returnStreamBuffers métodos en ICameraDeviceCallback.hal para solicitar y mostrar búferes. La HAL también debe implementar el signalStreamFlush método en ICameraDeviceSession.hal para indicarle a la HAL de la cámara que muestre búferes.

requestStreamBuffers

Usa el requestStreamBuffers método para solicitar búferes del framework de la cámara. Cuando se usan las APIs de administración de búfer de la HAL3 de la cámara, las solicitudes de captura del framework de la cámara no contienen búferes de salida, es decir, el campo bufferId en StreamBuffer es 0. Por lo tanto, la HAL de la cámara debe usar requestStreamBuffers para solicitar búferes del framework de la cámara.

El método requestStreamBuffers permite que el llamador solicite varios búferes de varias transmisiones de salida en una sola llamada, lo que permite menos llamadas IPC de HIDL. Sin embargo, las llamadas tardan más cuando se solicitan más búferes al mismo tiempo, y esto podría afectar negativamente la latencia total de solicitud a resultado. Además, debido a que las llamadas a requestStreamBuffers se serializan en el servicio de cámara, se recomienda que la HAL de la cámara use un subproceso de alta prioridad dedicado para solicitar búferes.

Si falla una solicitud de búfer, la HAL de la cámara debe poder controlar correctamente los errores no fatales. En la siguiente lista, se describen los motivos comunes por los que fallan las solicitudes de búfer y cómo debe controlarlas la HAL de la cámara.

  • La app se desconecta de la transmisión de salida: Este es un error no fatal. La HAL de la cámara debe enviar ERROR_REQUEST para cualquier solicitud de captura que apunte a una transmisión desconectada y estar lista para procesar las solicitudes posteriores con normalidad.
  • Tiempo de espera agotado: Esto puede ocurrir cuando una app está ocupada realizando un procesamiento intensivo mientras retiene algunos búferes. La HAL de la cámara debe enviar ERROR_REQUEST para las solicitudes de captura que no se puedan completar debido a un error de tiempo de espera agotado y estar lista para procesar las solicitudes posteriores con normalidad.
  • El framework de la cámara está preparando una nueva configuración de transmisión: La HAL de la cámara debe esperar hasta que se complete la siguiente configureStreams llamada se complete antes de volver a llamar a requestStreamBuffers de nuevo.
  • La HAL de la cámara alcanzó su límite de búfer (el campo maxBuffers): La HAL de la cámara debe esperar hasta que muestre al menos un búfer de la transmisión antes de volver a llamar a requestStreamBuffers.

returnStreamBuffers

Usa el returnStreamBuffers método para mostrar búferes adicionales al framework de la cámara. Por lo general, la HAL de la cámara muestra búferes al framework de la cámara a través del método processCaptureResult , pero solo puede tener en cuenta las solicitudes de captura que se enviaron a la HAL de la cámara. Con el método requestStreamBuffers, es posible que la implementación de la HAL de la cámara retenga más búferes de los que solicitó el framework de la cámara. Es entonces cuando se debe usar el método returnStreamBuffers. Si la implementación de la HAL nunca retiene más búferes de los solicitados, la implementación de la HAL de la cámara no necesita llamar al método returnStreamBuffers.

signalStreamFlush

El framework de la cámara llama al signalStreamFlush método para notificar a la HAL de la cámara que muestre todos los búferes disponibles. Por lo general, se llama cuando el framework de la cámara está a punto de llamar configureStreams y debe vaciar la canalización de captura de la cámara. Al igual que el método returnStreamBuffers, si una implementación de la HAL de la cámara no retiene más búferes de los solicitados, es posible tener una implementación vacía de este método.

Después de que el framework de la cámara llama a signalStreamFlush, el framework deja de enviar solicitudes de captura nuevas a la HAL de la cámara hasta que se devuelvan todos los búferes al framework de la cámara. Cuando se devuelven todos los búferes, fallan las llamadas al método requestStreamBuffers, y el framework de la cámara puede continuar su trabajo en un estado limpio. Luego, el framework de la cámara llama al método configureStreams o processCaptureRequest. Si el framework de la cámara llama al método configureStreams, la HAL de la cámara puede comenzar a solicitar búferes nuevamente después de que la llamada a configureStreams se muestre correctamente. Si el framework de la cámara llama al método processCaptureRequest, la HAL de la cámara puede comenzar a solicitar búferes durante la llamada a processCaptureRequest.

La semántica es diferente para el método signalStreamFlush y el flush método. Cuando se llama al método flush, la HAL puede anular las solicitudes de captura pendientes con ERROR_REQUEST para vaciar la canalización lo antes posible. Cuando se llama al método signalStreamFlush, la HAL debe finalizar todas las solicitudes de captura pendientes con normalidad y mostrar todos los búferes al framework de la cámara.

Otra diferencia entre el método signalStreamFlush y otros métodos es que signalStreamFlush es un método HIDL unidireccional, lo que significa que el framework de la cámara podría llamar a otras APIs de bloqueo antes de que la HAL reciba la llamada a signalStreamFlush. Esto significa que el método signalStreamFlush y otros métodos (específicamente el método configureStreams) podrían llegar a la HAL de la cámara en un orden diferente al orden en que se llamaron en el framework de la cámara. Para abordar este problema de asincronía, se agregó el campo streamConfigCounter a StreamConfiguration y se agregó como argumento al método signalStreamFlush. La implementación de la HAL de la cámara debe usar el argumento streamConfigCounter para determinar si una llamada a signalStreamFlush llega más tarde que su llamada correspondiente a configureStreams. Consulta la Figura 3 para ver un ejemplo.

Cómo controlar las llamadas que llegan tarde

Figura 3: Cómo la HAL de la cámara debe detectar y controlar las llamadas a signalStreamFlush que llegan tarde

Cambios de comportamiento cuando se implementan las APIs de administración de búfer

Cuando uses las APIs de administración de búfer para implementar la lógica de administración de búfer, considera los siguientes posibles cambios de comportamiento en la cámara y la implementación de la HAL de la cámara:

  • Las solicitudes de captura llegan a la HAL de la cámara más rápido y con mayor frecuencia: Sin las APIs de administración de búfer, el framework de la cámara solicita búferes de salida para cada solicitud de captura antes de enviar una solicitud de captura a la HAL de la cámara. Cuando se usan las APIs de administración de búfer, el framework de la cámara ya no necesita esperar los búferes y, por lo tanto, puede enviar solicitudes de captura a la HAL de la cámara antes.

    Además, sin las APIs de administración de búfer, el framework de la cámara deja de enviar solicitudes de captura si una de las transmisiones de salida de la solicitud de captura alcanzó la cantidad máxima de búferes que la HAL puede retener a la vez (este valor se designa con la HAL de la cámara en el campo HalStream::maxBuffers en el valor que muestra una llamada a configureStreams). Con las APIs de administración de búfer, este comportamiento de limitación ya no existe, y la implementación de la HAL de la cámara no debe aceptar llamadas a processCaptureRequest cuando la HAL tiene demasiadas solicitudes de captura en cola.

  • La latencia de la llamada a requestStreamBuffers varía significativamente: Hay muchos motivos por los que una llamada a requestStreamBuffers podría tardar más que el promedio. Por ejemplo:

    • Para los primeros búferes de una transmisión recién creada, las llamadas pueden tardar más porque el dispositivo necesita asignar memoria.
    • La latencia esperada aumenta en proporción a la cantidad de búferes solicitados en cada llamada.
    • La app retiene búferes y está ocupada procesando. Esto puede hacer que las solicitudes de búfer se ralenticen o alcancen un tiempo de espera agotado debido a la falta de búferes o a una CPU ocupada.

Estrategias de administración de búfer

Las APIs de administración de búfer permiten implementar diferentes tipos de estrategias de administración de búfer. Por ejemplo:

  • Retrocompatibilidad: La HAL solicita búferes para una solicitud de captura durante la llamada a processCaptureRequest. Esta estrategia no proporciona ningún ahorro de memoria, pero puede servir como la primera implementación de las APIs de administración de búfer, ya que requiere muy pocos cambios de código en la HAL de la cámara existente.
  • Ahorro de memoria maximizado: La HAL de la cámara solo solicita búferes de salida inmediatamente antes de que se necesite uno para completar. Esta estrategia permite maximizar el ahorro de memoria. La posible desventaja es que la canalización de la cámara se sacuda más cuando las solicitudes de búfer tardan demasiado en finalizar.
  • Almacenamiento en caché: La HAL de la cámara almacena en caché algunos búferes para que sea menos probable que se vea afectada por una solicitud de búfer lenta ocasional.

La HAL de la cámara puede adoptar diferentes estrategias para casos de uso particulares, por ejemplo, usar la estrategia de ahorro de memoria maximizado para casos de uso que usan mucha memoria y usar la estrategia retrocompatible para otros casos de uso.

Implementación de muestra en la HAL de la cámara externa

La HAL de la cámara externa se introdujo en Android 9 y se puede encontrar en el árbol de origen en hardware/interfaces/camera/device/3.5/. En Android 10, se actualizó para incluir ExternalCameraDeviceSession.cpp, una implementación de la API de administración de búfer. Esta HAL de la cámara externa implementa la estrategia de ahorro de memoria maximizado que se menciona en Estrategias de administración de búfer en unos cientos de líneas de código C++.