Android 10 introduce las APIs opcionales de administración de búfer de la HAL3 de la cámara 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 la cámara.
El 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 N conjuntos de búferes de salida al mismo tiempo.
Por ejemplo, el sistema 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 se pone en cola en el HAL, por lo que podría haber seis conjuntos de búferes en el 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 desacoplar 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 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.
Figura 1: Interfaz de la HAL de la cámara en Android 9 y versiones anteriores
Figura 2: Interfaz de la HAL de la cámara en Android 10 con las APIs de administración de búferes
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:
- Implementa HIDL
ICameraDevice@3.5
. - Establece la clave de características de la cámara
android.info.supportedBufferManagementVersion
enHIDL_DEVICE_3_5
.
El sistema HAL de la cámara usa los métodos requestStreamBuffers
y returnStreamBuffers
en ICameraDeviceCallback.hal
para solicitar y mostrar búferes. El HAL también debe implementar el método signalStreamFlush
en ICameraDeviceSession.hal
para indicarle al HAL de la cámara que muestre los búferes.
requestStreamBuffers
Usa el método requestStreamBuffers
para solicitar búferes del framework de la cámara. Cuando se usan las APIs de administración de búferes 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 a HIDL IPC. Sin embargo, las llamadas tardan más tiempo cuando se solicitan más búferes al mismo tiempo, lo que podría afectar negativamente la latencia total de solicitud a resultado.
Además, como las llamadas a requestStreamBuffers
se serializan en el servicio de la cámara, se recomienda que el HAL de la cámara use un subproceso dedicado de alta prioridad para solicitar búferes.
Si falla una solicitud de búfer, la HAL de la cámara debe poder administrar correctamente los errores recuperables. En la siguiente lista, se describen los motivos habituales por los que fallan las solicitudes de búfer y cómo debe controlarlas el HAL de la cámara.
- La app se desconecta del flujo de salida: Este es un error recuperable. La HAL de la cámara debe enviar
ERROR_REQUEST
para cualquier solicitud de captura segmentada a una transmisión desconectada y estar lista para procesar las solicitudes posteriores de forma normal. - Tiempo de espera: Esto puede ocurrir cuando una app está ocupada realizando un procesamiento intensivo mientras mantiene algunos búferes. La HAL de la cámara debe enviar
ERROR_REQUEST
para las solicitudes de captura que no se pueden completar debido a un error de tiempo de espera y estar lista para procesar las solicitudes posteriores de manera normal. - El framework de la cámara está preparando una nueva configuración de transmisión:
El HAL de la cámara debe esperar hasta que se complete la próxima llamada a
configureStreams
antes de volver a llamar arequestStreamBuffers
. - 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 arequestStreamBuffers
.
returnStreamBuffers
Usa el método returnStreamBuffers
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 registrar 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 que los solicitados por el framework de la cámara. En ese momento, se debe usar el método returnStreamBuffers
. Si la implementación de HAL nunca contiene más búferes de los solicitados, la implementación de HAL de la cámara no necesita llamar al método returnStreamBuffers
.
signalStreamFlush
El framework de la cámara llama al método signalStreamFlush
para notificar a la HAL de la cámara que devuelva todos los búferes disponibles. Por lo general, se llama a esta función cuando el framework de la cámara está a punto de llamar a configureStreams
y debe agotar el flujo de captura de la cámara. Al igual que con el método returnStreamBuffers
, si una implementación de HAL de la cámara no contiene 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 al HAL de la cámara hasta que se devuelven todos los búferes al framework de la cámara. Cuando se muestran todos los búferes, las llamadas al método requestStreamBuffers
fallan 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
, el HAL de la cámara puede comenzar a solicitar búferes nuevamente después de que la llamada a configureStreams
se devuelva correctamente. Si el framework de la cámara llama al método processCaptureRequest
, el HAL de la cámara puede comenzar a solicitar búferes durante la llamada a processCaptureRequest
.
La semántica es diferente para los métodos signalStreamFlush
y flush
. Cuando se llama al método flush
, el HAL puede abortar las solicitudes de captura pendientes con ERROR_REQUEST
para agotar la canalización lo antes posible. Cuando se llama al método signalStreamFlush
, el sistema HAL debe finalizar todas las solicitudes de captura pendientes de forma normal y devolver 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 el HAL reciba la llamada a signalStreamFlush
. Esto significa que el método signalStreamFlush
y otros métodos (en particular, el método configureStreams
) pueden llegar a la HAL de la cámara en un orden diferente al que se les llamó en el framework de la cámara. Para abordar este problema de asincronía, se agregó el campo streamConfigCounter
a StreamConfiguration
y 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 a configureStreams
correspondiente. Consulta la Figura 3 para ver un ejemplo.
Figura 3: Cómo debe detectar y controlar las llamadas de signalStreamFlush que llegan tarde la HAL de la cámara
Cambios de comportamiento cuando se implementan las APIs de administración de búferes
Cuando uses las APIs de administración de búferes para implementar la lógica de administración de búferes, ten en cuenta los siguientes cambios de comportamiento posibles en la implementación de la cámara y 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úferes, 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úferes, 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 el HAL puede contener a la vez (este valor lo designa el HAL de la cámara en el campo
HalStream::maxBuffers
en el valor que se muestra de una llamadaconfigureStreams
). 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 aprocessCaptureRequest
cuando la HAL tiene demasiadas solicitudes de captura en cola.La latencia de llamadas de
requestStreamBuffers
varía significativamente: Hay muchos motivos por los que una llamada arequestStreamBuffers
puede tardar más tiempo que el promedio. Por ejemplo:- En 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 tiene búferes y está ocupado procesando. Esto puede hacer que las solicitudes de búfer se ralenticen o se agote el tiempo de espera debido a la falta de búferes o a una CPU ocupada.
Estrategias de administración del búfer
Las APIs de administración de búferes permiten implementar diferentes tipos de estrategias de administración de búferes. Por ejemplo:
- Retrocompatible: 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úferes, lo que requiere muy pocos cambios de código en el HAL de la cámara existente. - Ahorro de memoria maximizado: El HAL de la cámara solo solicita búferes de salida inmediatamente antes de que se necesite uno para llenarse. Esta estrategia permite maximizar los ahorros de memoria. La posible desventaja es que se produce un mayor bloqueo en la canalización de la cámara cuando las solicitudes de búfer tardan más tiempo en completarse.
- Almacenados en caché: El HAL de la cámara almacena en caché algunos búferes para que sea menos probable que se vea afectado por una solicitud de búfer lenta ocasional.
El HAL de la cámara puede adoptar diferentes estrategias para casos de uso particulares, por ejemplo, usar la estrategia de ahorro de memoria maximizada para casos de uso que usan mucha memoria y usar la estrategia retrocompatible para otros casos de uso.
Ejemplo de implementación 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 fuentes 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úferes. Esta HAL de cámara externa implementa la estrategia de ahorro de memoria maximizada que se menciona en Estrategias de administración de búferes en unas pocas cientos de líneas de código C++.