Cámara de vehículo HAL

Android contiene una capa de abstracción de hardware (HAL) HIDL automotriz que proporciona captura y visualización de imágenes muy temprano en el proceso de arranque de Android y continúa funcionando durante la vida útil del sistema. El HAL incluye la pila del sistema de vista exterior (EVS) y generalmente se usa para admitir la cámara retrovisora ​​y las pantallas de vista envolvente en vehículos con sistemas de infoentretenimiento en el vehículo (IVI) basados ​​en Android. EVS también permite implementar funciones avanzadas en las aplicaciones de los usuarios.

Android también incluye una interfaz de controlador de visualización y captura específica de EVS (en /hardware/interfaces/automotive/evs/1.0 ). Si bien es posible crear una aplicación de cámara retrovisora ​​sobre los servicios de visualización y cámara de Android existentes, es probable que dicha aplicación se ejecute demasiado tarde en el proceso de arranque de Android. El uso de una HAL dedicada permite una interfaz optimizada y aclara lo que un OEM debe implementar para admitir la pila de EVS.

Componentes del sistema

EVS incluye los siguientes componentes del sistema:

Diagrama de componentes del sistema EVS
Figura 1. Descripción general de los componentes del sistema EVS

aplicación SVE

Una aplicación C++ EVS de muestra ( /packages/services/Car/evs/app ) sirve como implementación de referencia. Esta aplicación es responsable de solicitar cuadros de video de EVS Manager y enviar los cuadros terminados para que se muestren de nuevo en EVS Manager. Se espera que init lo inicie tan pronto como EVS y Car Service estén disponibles, dentro de los dos (2) segundos posteriores al encendido. Los OEM pueden modificar o reemplazar la aplicación EVS según lo deseen.

Gerente de SVE

El administrador de EVS ( /packages/services/Car/evs/manager ) proporciona los componentes básicos que necesita una aplicación de EVS para implementar cualquier cosa, desde una simple pantalla de cámara retrovisora ​​hasta un renderizado de múltiples cámaras de 6DOF. Su interfaz se presenta a través de HIDL y está diseñada para aceptar múltiples clientes concurrentes. Otras aplicaciones y servicios (específicamente Car Service) pueden consultar el estado de EVS Manager para averiguar cuándo está activo el sistema EVS.

Interfaz EVS HIDL

El sistema EVS, tanto la cámara como los elementos de visualización, se definen en el paquete android.hardware.automotive.evs . En /hardware/interfaces/automotive/evs/1.0/default se proporciona una implementación de muestra que ejercita la interfaz (genera imágenes de prueba sintéticas y valida las imágenes para hacer el viaje de ida y vuelta).

El OEM es responsable de implementar la API expresada por los archivos .hal en /hardware/interfaces/automotive/evs . Dichas implementaciones son responsables de configurar y recopilar datos de cámaras físicas y entregarlos a través de búferes de memoria compartida reconocibles por Gralloc. El lado de la pantalla de la implementación es responsable de proporcionar un búfer de memoria compartida que la aplicación puede llenar (generalmente a través de la representación EGL) y presentar los fotogramas terminados con preferencia a cualquier otra cosa que pueda querer aparecer en la pantalla física. Las implementaciones de proveedores de la interfaz EVS se pueden almacenar en /vendor/… /device/… o hardware/… (p. ej., /hardware/[vendor]/[platform]/evs ).

Controladores del núcleo

Un dispositivo que admita la pila EVS requiere controladores de kernel. En lugar de crear nuevos controladores, los OEM tienen la opción de admitir funciones requeridas por EVS a través de controladores de hardware de cámara y/o pantalla existentes. La reutilización de controladores podría ser ventajosa, especialmente para controladores de pantalla donde la presentación de imágenes puede requerir coordinación con otros subprocesos activos. Android 8.0 incluye un controlador de muestra basado en v4l2 (en packages/services/Car/evs/sampleDriver ) que depende del kernel para la compatibilidad con v4l2 y de SurfaceFlinger para presentar la imagen de salida.

Descripción de la interfaz de hardware de EVS

La sección describe la HAL. Se espera que los proveedores proporcionen implementaciones de esta API adaptadas a su hardware.

IEvsEnumerator

Este objeto es responsable de enumerar el hardware EVS disponible en el sistema (una o más cámaras y el único dispositivo de visualización).

getCameraList() generates (vec<CameraDesc> cameras);

Devuelve un vector que contiene descripciones para todas las cámaras del sistema. Se supone que el conjunto de cámaras está fijo y se puede conocer en el momento del arranque. Para obtener detalles sobre las descripciones de las cámaras, consulte CameraDesc .

openCamera(string camera_id) generates (IEvsCamera camera);

Obtiene un objeto de interfaz utilizado para interactuar con una cámara específica identificada por la cadena única camera_id . Devuelve NULL en caso de error. Los intentos de reabrir una cámara que ya está abierta no pueden fallar. Para evitar las condiciones de carrera asociadas con el inicio y el cierre de la aplicación, la reapertura de una cámara debe cerrar la instancia anterior para que se pueda cumplir con la nueva solicitud. Una instancia de cámara que ha sido reemplazada de esta manera debe ponerse en un estado inactivo, esperando la destrucción final y respondiendo a cualquier solicitud para afectar el estado de la cámara con un código de retorno de OWNERSHIP_LOST .

closeCamera(IEvsCamera camera);

Libera la interfaz IEvsCamera (y es lo opuesto a la llamada openCamera() ). La transmisión de video de la cámara debe detenerse llamando a stopVideoStream() antes de llamar a closeCamera .

openDisplay() generates (IEvsDisplay display);

Obtiene un objeto de interfaz que se utiliza para interactuar exclusivamente con la pantalla EVS del sistema. Solo un cliente puede tener una instancia funcional de IEvsDisplay a la vez. Similar al comportamiento de apertura agresivo descrito en openCamera , se puede crear un nuevo objeto IEvsDisplay en cualquier momento y deshabilitará cualquier instancia anterior. Las instancias invalidadas continúan existiendo y responden a las llamadas de función de sus propietarios, pero no deben realizar operaciones de mutación cuando están muertas. Eventualmente, se espera que la aplicación cliente observe los códigos de retorno de error OWNERSHIP_LOST y cierre y libere la interfaz inactiva.

closeDisplay(IEvsDisplay display);

Libera la interfaz IEvsDisplay (y es lo opuesto a la llamada openDisplay() ). Los búferes pendientes recibidos a través de las llamadas getTargetBuffer() deben devolverse a la pantalla antes de cerrar la pantalla.

getDisplayState() generates (DisplayState state);

Obtiene el estado de visualización actual. La implementación de HAL debe informar el estado actual real, que puede diferir del estado solicitado más recientemente. La lógica responsable de cambiar los estados de visualización debe existir por encima de la capa del dispositivo, por lo que no es deseable que la implementación de HAL cambie espontáneamente los estados de visualización. Si ningún cliente tiene actualmente la pantalla (mediante una llamada a openDisplay), esta función devuelve NOT_OPEN . De lo contrario, informa el estado actual de EVS Display (consulte la API de IEvsDisplay ).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id . Una cadena que identifica de forma única una cámara determinada. Puede ser el nombre del dispositivo del núcleo del dispositivo o un nombre para el dispositivo, como rearview . El valor de esta cadena lo elige la implementación de HAL y la pila de arriba lo usa de forma opaca.
  • vendor_flags . Un método para pasar información de cámara especializada de forma opaca desde el controlador a una aplicación EVS personalizada. Se pasa sin interpretar desde el controlador hasta la aplicación EVS, que es libre de ignorarlo.

IEvsCámara

Este objeto representa una sola cámara y es la interfaz principal para capturar imágenes.

getCameraInfo() generates (CameraDesc info);

Devuelve CameraDesc de esta cámara.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

Especifica la profundidad de la cadena de búfer que se le pide a la cámara que admita. El cliente de IEvsCamera puede mantener hasta esta cantidad de fotogramas simultáneamente. Si se han entregado tantos fotogramas al receptor sin que doneWithFrame los haya devuelto, el flujo omite fotogramas hasta que se devuelve un búfer para su reutilización. Es legal que esta llamada llegue en cualquier momento, incluso mientras las transmisiones ya se están ejecutando, en cuyo caso se deben agregar o eliminar búferes de la cadena, según corresponda. Si no se realiza ninguna llamada a este punto de entrada, IEvsCamera admite al menos un marco de forma predeterminada; con más aceptable.

Si no se puede acomodar el bufferCount solicitado, la función devuelve BUFFER_NOT_AVAILABLE u otro código de error relevante. En este caso, el sistema sigue funcionando con el valor previamente configurado.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Solicita la entrega de marcos de cámara EVS de esta cámara. IEvsCameraStream comienza a recibir llamadas periódicas con nuevos marcos de imagen hasta que se llama a stopVideoStream() . Los fotogramas deben comenzar a entregarse dentro de los 500 ms de la llamada startVideoStream y, después de comenzar, deben generarse a un mínimo de 10 FPS. El tiempo requerido para iniciar la transmisión de video efectivamente cuenta contra cualquier requisito de tiempo de inicio de la cámara retrovisora. Si la transmisión no se inicia, se debe devolver un código de error; de lo contrario, se devuelve OK.

oneway doneWithFrame(BufferDesc buffer);

Devuelve un marco entregado por IEvsCameraStream. Cuando termine de consumir un marco entregado a la interfaz IEvsCameraStream, el marco debe devolverse a IEvsCamera para su reutilización. Hay disponible una cantidad pequeña y finita de búferes (posiblemente tan pequeños como uno), y si se agota el suministro, no se envían más tramas hasta que se devuelve una de un flujo y no necesita devolverse a través de esta función). Devuelve OK en caso de éxito o el código de error apropiado que posiblemente incluya INVALID_ARG o BUFFER_NOT_AVAILABLE .

stopVideoStream();

Detiene la entrega de marcos de cámara EVS. Debido a que la entrega es asíncrona, es posible que los marcos continúen llegando durante algún tiempo después de que regrese esta llamada. Cada trama debe devolverse hasta que se señale el cierre de la transmisión a IEvsCameraStream. Es legal llamar a stopVideoStream en una transmisión que ya se detuvo o nunca se inició, en cuyo caso se ignora.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

Solicita información específica del controlador de la implementación de HAL. Los valores permitidos para opaqueIdentifier son específicos del controlador, pero ningún valor pasado puede bloquear el controlador. El controlador debe devolver 0 para cualquier opaqueIdentifier no reconocido.

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

Envía un valor específico del controlador a la implementación de HAL. Esta extensión se proporciona solo para facilitar extensiones específicas del vehículo y ninguna implementación de HAL debería requerir que esta llamada funcione en un estado predeterminado. Si el conductor reconoce y acepta los valores, se debe devolver OK; de lo contrario, se debe devolver INVALID_ARG u otro código de error representativo.

struct BufferDesc {
    uint32  width;      // Units of pixels
    uint32  height;     // Units of pixels
    uint32  stride;     // Units of pixels
    uint32  pixelSize;  // Size of single pixel in bytes
    uint32  format;     // May contain values from android_pixel_format_t
    uint32  usage;      // May contain values from Gralloc.h
    uint32  bufferId;   // Opaque value
    handle  memHandle;  // gralloc memory buffer handle
}

Describe una imagen pasada a través de la API. La unidad HAL es responsable de completar esta estructura para describir el búfer de imagen y el cliente HAL debe tratar esta estructura como de solo lectura. Los campos contienen suficiente información para permitir que el cliente reconstruya un objeto ANativeWindowBuffer , ya que puede ser necesario para usar la imagen con EGL a través de la extensión eglCreateImageKHR() .

  • width El ancho en píxeles de la imagen presentada.
  • height La altura en píxeles de la imagen presentada.
  • stride Número de píxeles que cada fila ocupa realmente en la memoria, teniendo en cuenta cualquier relleno para la alineación de las filas. Expresado en píxeles para coincidir con la convención adoptada por gralloc para sus descripciones de búfer.
  • pixelSize . Número de bytes ocupados por cada píxel individual, lo que permite calcular el tamaño en bytes necesario para pasar de una fila a otra en la imagen ( stride en bytes = stride en píxeles * tamaño de pixelSize ).
  • format El formato de píxel utilizado por la imagen. El formato proporcionado debe ser compatible con la implementación OpenGL de la plataforma. Para pasar las pruebas de compatibilidad, se debe preferir HAL_PIXEL_FORMAT_YCRCB_420_SP para el uso de la cámara, y se debe preferir RGBA o BGRA para la visualización.
  • usage Indicadores de uso establecidos por la implementación de HAL. Se espera que los clientes HAL pasen estos sin modificar (para obtener más detalles, consulte los indicadores relacionados con Gralloc.h ).
  • bufferId . Un valor único especificado por la implementación de HAL para permitir que se reconozca un búfer después de un viaje de ida y vuelta a través de las API de HAL. El valor almacenado en este campo puede ser elegido arbitrariamente por la implementación de HAL.
  • memHandle El identificador del búfer de memoria subyacente que contiene los datos de la imagen. La implementación de HAL podría optar por almacenar un identificador de búfer Gralloc aquí.

IEvsCameraStream

El cliente implementa esta interfaz para recibir entregas de cuadros de video asíncronos.

deliverFrame(BufferDesc buffer);

Recibe llamadas de la HAL cada vez que un cuadro de video está listo para su inspección. Los identificadores de búfer recibidos por este método deben devolverse a través de llamadas a IEvsCamera::doneWithFrame() . Cuando la transmisión de video se detiene a través de una llamada a IEvsCamera::stopVideoStream() , esta devolución de llamada puede continuar mientras se agota la canalización. Cada marco aún debe ser devuelto; cuando se haya entregado el último cuadro de la transmisión, se entregará un NULL bufferHandle, lo que significa el final de la transmisión y no se producirán más entregas de cuadros. El NULL bufferHandle en sí mismo no necesita ser devuelto a través de doneWithFrame() , pero todos los demás identificadores deben devolverse

Si bien los formatos de búfer patentados son técnicamente posibles, las pruebas de compatibilidad requieren que el búfer esté en uno de los cuatro formatos admitidos: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4: 2:2 intercalado), RGBA (32 bits R:G:B:x), BGRA (32 bits B:G:R:x). El formato seleccionado debe ser una fuente de textura GL válida en la implementación GLES de la plataforma.

La aplicación no debe basarse en ninguna correspondencia entre el campo bufferId y memHandle en la estructura BufferDesc . Los valores bufferId son esencialmente privados para la implementación del controlador HAL, y puede usarlos (y reutilizarlos) como mejor le parezca.

IEvsDisplay

Este objeto representa la pantalla Evs, controla el estado de la pantalla y maneja la presentación real de las imágenes.

getDisplayInfo() generates (DisplayDesc info);

Devuelve información básica sobre la pantalla EVS proporcionada por el sistema (consulte DisplayDesc ).

setDisplayState(DisplayState state) generates (EvsResult result);

Establece el estado de visualización. Los clientes pueden configurar el estado de visualización para expresar el estado deseado, y la implementación de HAL debe aceptar correctamente una solicitud para cualquier estado mientras se encuentra en cualquier otro estado, aunque la respuesta puede ser ignorar la solicitud.

Tras la inicialización, la pantalla se define para comenzar en el estado NOT_VISIBLE , después de lo cual se espera que el cliente solicite el estado VISIBLE_ON_NEXT_FRAME y comience a proporcionar video. Cuando ya no se requiere la visualización, se espera que el cliente solicite el estado NOT_VISIBLE después de pasar el último cuadro de video.

Es válido para cualquier estado para ser solicitado en cualquier momento. Si la pantalla ya está visible, debería permanecer visible si se establece en VISIBLE_ON_NEXT_FRAME . Siempre devuelve OK a menos que el estado solicitado sea un valor de enumeración no reconocido, en cuyo caso se devuelve INVALID_ARG .

getDisplayState() generates (DisplayState state);

Obtiene el estado de visualización. La implementación de HAL debe informar el estado actual real, que puede diferir del estado solicitado más recientemente. La lógica responsable de cambiar los estados de visualización debe existir por encima de la capa del dispositivo, por lo que no es deseable que la implementación de HAL cambie espontáneamente los estados de visualización.

getTargetBuffer() generates (handle bufferHandle);

Devuelve un identificador a un búfer de cuadro asociado con la pantalla. Este búfer puede estar bloqueado y escrito por software y/o GL. Este búfer debe devolverse mediante una llamada a returnTargetBufferForDisplay() incluso si la pantalla ya no está visible.

Si bien los formatos de búfer patentados son técnicamente posibles, las pruebas de compatibilidad requieren que el búfer esté en uno de los cuatro formatos admitidos: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4: 2:2 intercalado), RGBA (32 bits R:G:B:x), BGRA (32 bits B:G:R:x). El formato seleccionado debe ser un destino de representación GL válido en la implementación GLES de la plataforma.

En caso de error, se devuelve un búfer con un identificador nulo, pero no es necesario devolver dicho búfer a returnTargetBufferForDisplay .

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Le dice a la pantalla que el búfer está listo para mostrarse. Solo los búferes recuperados a través de una llamada a getTargetBuffer() son válidos para usar con esta llamada, y la aplicación cliente no puede modificar el contenido de BufferDesc . Después de esta llamada, el búfer ya no es válido para que lo use el cliente. Devuelve OK en caso de éxito o el código de error apropiado que posiblemente incluya INVALID_ARG o BUFFER_NOT_AVAILABLE .

struct DisplayDesc {
     string  display_id;
     int32   vendor_flags;  // Opaque value
}

Describe las propiedades básicas de una pantalla de EVS y las requeridas por una implementación de EVS. El HAL es responsable de completar esta estructura para describir la pantalla EVS. Puede ser una pantalla física o una pantalla virtual superpuesta o mezclada con otro dispositivo de presentación.

  • display_id . Una cadena que identifica de forma única la pantalla. Este podría ser el nombre del dispositivo del núcleo del dispositivo, o un nombre para el dispositivo, como rearview . El valor de esta cadena lo elige la implementación de HAL y la pila de arriba lo usa de forma opaca.
  • vendor_flags . Un método para pasar información de cámara especializada de forma opaca desde el controlador a una aplicación EVS personalizada. Se pasa sin interpretar desde el controlador hasta la aplicación EVS, que es libre de ignorarlo.
enum DisplayState : uint32 {
    NOT_OPEN,               // Display has not been “opened” yet
    NOT_VISIBLE,            // Display is inhibited
    VISIBLE_ON_NEXT_FRAME,  // Will become visible with next frame
    VISIBLE,                // Display is currently active
    DEAD,                   // Display is not available. Interface should be closed
}

Describe el estado de la pantalla del EVS, que se puede desactivar (no visible para el conductor) o activar (mostrando una imagen al conductor). Incluye un estado transitorio en el que la pantalla aún no está visible, pero está preparada para volverse visible con la entrega del siguiente cuadro de imágenes a través de la llamada returnTargetBufferForDisplay() .

Gerente de SVE

EVS Manager proporciona la interfaz pública al sistema EVS para recopilar y presentar vistas de cámaras externas. Cuando los controladores de hardware permiten solo una interfaz activa por recurso (cámara o pantalla), EVS Manager facilita el acceso compartido a las cámaras. Una sola aplicación EVS principal es el primer cliente de EVS Manager y es el único cliente al que se le permite escribir datos de visualización (a los clientes adicionales se les puede otorgar acceso de solo lectura a las imágenes de la cámara).

EVS Manager implementa la misma API que los controladores HAL subyacentes y proporciona un servicio ampliado al admitir varios clientes simultáneos (más de un cliente puede abrir una cámara a través de EVS Manager y recibir una transmisión de video).

Diagrama de EVS Manager y EVS Hardware API.
Figura 2. EVS Manager duplica la API de hardware de EVS subyacente

Las aplicaciones no ven diferencias cuando operan a través de la implementación HAL de hardware de EVS o la API de EVS Manager, excepto que la API de EVS Manager permite el acceso simultáneo a la transmisión de la cámara. EVS Manager es, en sí mismo, el único cliente permitido de la capa HAL de hardware de EVS y actúa como un proxy para la HAL de hardware de EVS.

Las siguientes secciones describen solo aquellas llamadas que tienen un comportamiento diferente (extendido) en la implementación de EVS Manager; las llamadas restantes son idénticas a las descripciones de EVS HAL.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Obtiene un objeto de interfaz utilizado para interactuar con una cámara específica identificada por la cadena única camera_id . Devuelve NULL en caso de error. En la capa de EVS Manager, siempre que haya suficientes recursos del sistema disponibles, otro proceso puede volver a abrir una cámara que ya está abierta, lo que permite conectar la transmisión de video a múltiples aplicaciones de consumidores. Las cadenas de camera_id en la capa de EVS Manager son las mismas que se informan en la capa de EVS Hardware.

IEvsCámara

La implementación de IEvsCamera proporcionada por EVS Manager se virtualiza internamente, por lo que las operaciones en una cámara por parte de un cliente no afectan a otros clientes, que conservan el acceso independiente a sus cámaras.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Inicia transmisiones de video. Los clientes pueden iniciar y detener transmisiones de video de forma independiente en la misma cámara subyacente. La cámara subyacente se inicia cuando se inicia el primer cliente.

doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);

Devuelve un marco. Cada cliente debe devolver sus marcos cuando haya terminado, pero se les permite conservar sus marcos durante el tiempo que deseen. Cuando el conteo de marcos en poder de un cliente alcanza su límite configurado, no recibirá más marcos hasta que devuelva uno. Este salto de marco no afecta a otros clientes, que continúan recibiendo todos los marcos como se esperaba.

stopVideoStream();

Detiene una transmisión de video. Cada cliente puede detener su transmisión de video en cualquier momento sin afectar a otros clientes. La transmisión de la cámara subyacente en la capa de hardware se detiene cuando el último cliente de una cámara determinada detiene su transmisión.

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

Envía un valor específico del controlador, lo que potencialmente permite que un cliente afecte a otro cliente. Debido a que EVS Manager no puede comprender las implicaciones de las palabras de control definidas por el proveedor, no se virtualizan y los efectos secundarios se aplican a todos los clientes de una cámara determinada. Por ejemplo, si un proveedor utilizó esta llamada para cambiar las velocidades de fotogramas, todos los clientes de la cámara de la capa de hardware afectada recibirían fotogramas a la nueva velocidad.

IEvsDisplay

Solo se permite un propietario de la pantalla, incluso en el nivel de EVS Manager. Manager no agrega ninguna funcionalidad y simplemente pasa la interfaz IEvsDisplay directamente a través de la implementación HAL subyacente.

aplicación SVE

Android incluye una implementación de referencia nativa de C++ de una aplicación EVS que se comunica con EVS Manager y Vehicle HAL para proporcionar funciones básicas de cámara retrovisora. Se espera que la aplicación comience muy temprano en el proceso de arranque del sistema, con un video adecuado que se muestra según las cámaras disponibles y el estado del automóvil (marcha y estado de la señal de giro). Los OEM pueden modificar o reemplazar la aplicación EVS con su propia lógica y presentación específicas del vehículo.

Figura 3. Lógica de muestra de la aplicación EVS, obtener la lista de cámaras.


Figura 4. Lógica de muestra de la aplicación EVS, devolución de llamada del marco de recepción.

Debido a que los datos de la imagen se presentan a la aplicación en un búfer de gráficos estándar, la aplicación es responsable de mover la imagen del búfer de origen al búfer de salida. Si bien esto introduce el costo de una copia de datos, también ofrece la oportunidad de que la aplicación reproduzca la imagen en el búfer de visualización de la forma que desee.

Por ejemplo, la aplicación puede optar por mover los datos del píxel, potencialmente con una escala en línea o una operación de rotación. La aplicación también podría optar por utilizar la imagen de origen como una textura OpenGL y representar una escena compleja en el búfer de salida, incluidos elementos virtuales como iconos, guías y animaciones. Una aplicación más sofisticada también puede seleccionar múltiples cámaras de entrada concurrentes y fusionarlas en un solo marco de salida (como para usar en una vista virtual de arriba hacia abajo de los alrededores del vehículo).

Usar EGL/SurfaceFlinger en EVS Display HAL

En esta sección, se explica cómo usar EGL para representar una implementación de EVS Display HAL en Android 10.

Una implementación de referencia de EVS HAL usa EGL para renderizar la vista previa de la cámara en la pantalla y usa libgui para crear la superficie de renderizado EGL de destino. En Android 8 (y versiones posteriores), libgui se clasifica como VNDK-private , que se refiere a un grupo de bibliotecas disponibles para las bibliotecas VNDK que los procesos de los proveedores no pueden usar. Debido a que las implementaciones de HAL deben residir en la partición del proveedor, los proveedores no pueden usar Surface en implementaciones de HAL.

Creación de libgui para procesos de proveedores

El uso de libgui sirve como la única opción para usar EGL/SurfaceFlinger en implementaciones de EVS Display HAL. La forma más sencilla de implementar libgui es a través de frameworks/native/libs/gui directamente mediante el uso de un objetivo de compilación adicional en el script de compilación. Este destino es exactamente el mismo que el destino libgui excepto por la adición de dos campos:

  • name
  • vendor_available
cc_library_shared {
    name: "libgui_vendor",
    vendor_available: true,
    vndk: {
        enabled: false,
    },
    double_loadable: true,

defaults: ["libgui_bufferqueue-defaults"],
srcs: [ … // bufferhub is not used when building libgui for vendors target: { vendor: { cflags: [ "-DNO_BUFFERHUB", "-DNO_INPUT", ], …

Nota: Los objetivos de proveedores se construyen con la macro NO_INPUT , que elimina una palabra de 32 bits de los datos de la parcela. Dado que SurfaceFlinger espera que este campo se haya eliminado, SurfaceFlinger no puede analizar la parcela. Esto se observa como una falla fcntl :

W Parcel  : Attempt to read object from Parcel 0x78d9cffad8 at offset 428 that is not in the object list
E Parcel  : fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 0, fds[i] is 0, fd_count is 20, error: Unknown error 2147483647
W Parcel  : Attempt to read object from Parcel 0x78d9cffad8 at offset 544 that is not in the object list

Para resolver esta condición:

diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 6066421fa..25cf5f0ce 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -54,6 +54,9 @@ status_t layer_state_t::write(Parcel& output) const
     output.writeFloat(color.b);
 #ifndef NO_INPUT
     inputInfo.write(output);
+#else
+    // Write a dummy 32-bit word.
+    output.writeInt32(0);
 #endif
     output.write(transparentRegion);
     output.writeUint32(transform);

A continuación se proporcionan instrucciones de compilación de muestra. Espere recibir un $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so .

$ cd <your_android_source_tree_top>
$ . ./build/envsetup.
$ lunch <product_name>-<build_variant>
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
TARGET_PRODUCT=<product_name>
TARGET_BUILD_VARIANT=<build_variant>
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv7-a-neon
TARGET_2ND_CPU_VARIANT=cortex-a9
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=<host_linux_version>
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QT
OUT_DIR=out
============================================

$ m -j libgui_vendor … $ find $ANDROID_PRODUCT_OUT/system -name "libgui_vendor*" .../out/target/product/hawk/system/lib64/libgui_vendor.so .../out/target/product/hawk/system/lib/libgui_vendor.so

Uso de binder en una implementación de EVS HAL

En Android 8 (y versiones posteriores), el nodo del dispositivo /dev/binder pasó a ser exclusivo de los procesos del marco y, por lo tanto, inaccesible para los procesos de los proveedores. En su lugar, los procesos del proveedor deben usar /dev/hwbinder y deben convertir cualquier interfaz AIDL a HIDL. Para aquellos que deseen continuar usando interfaces AIDL entre procesos de proveedores, use el dominio de enlace, /dev/vndbinder .

Dominio CIP Descripción
/dev/binder IPC entre procesos de marco/aplicación con interfaces AIDL
/dev/hwbinder IPC entre procesos de marco/proveedor con interfaces HIDL
IPC entre procesos de proveedores con interfaces HIDL
/dev/vndbinder IPC entre procesos proveedor/proveedor con interfaces AIDL

Si bien SurfaceFlinger define las interfaces AIDL, los procesos de proveedores solo pueden usar interfaces HIDL para comunicarse con los procesos del marco. Se requiere una cantidad de trabajo no trivial para convertir las interfaces AIDL existentes en HIDL. Afortunadamente, Android proporciona un método con el que seleccionar el controlador de carpeta para libbinder , al que están vinculados los procesos de la biblioteca del espacio de usuario.

diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb3166..5fd02935 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 #include <utils/Log.h>
+#include <binder/ProcessState.h>

 #include "ServiceNames.h"
 #include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
 int main() {
     ALOGI("EVS Hardware Enumerator service is starting");


+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+


     // Start a thread to listen to video device addition events.
     std::atomic<bool> running { true };
     std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));

Nota: los procesos del proveedor deben llamar a esto antes de llamar a Process o IPCThreadState , o antes de realizar cualquier llamada de enlace.

Políticas de SELinux

Si la implementación del dispositivo es triple completa, SELinux evita que los procesos del proveedor utilicen /dev/binder . Por ejemplo, una implementación de muestra de EVS HAL se asigna al dominio hal_evs_driver y requiere permisos de lectura y escritura para el dominio binder_device .

W ProcessState: Opening '/dev/binder' failed: Permission denied
F ProcessState: Binder driver could not be opened. Terminating.
F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 9145 (android.hardwar), pid 9145 (android.hardwar)
W android.hardwar: type=1400 audit(0.0:974): avc: denied { read write } for name="binder" dev="tmpfs" ino=2208 scontext=u:r:hal_evs_driver:s0 tcontext=u:object_r:binder_device:s0 tclass=chr_file permissive=0

Sin embargo, agregar estos permisos provoca un error de compilación porque viola las siguientes reglas de nunca permitir definidas en system/sepolicy/domain.te para un dispositivo de agudos completos.

libsepol.report_failure: neverallow on line 631 of system/sepolicy/public/domain.te (or line 12436 of policy.conf) violated by allow hal_evs_driver binder_device:chr_file { read write };
libsepol.check_assertions: 1 neverallow failures occurred
full_treble_only(`
  neverallow {
    domain
    -coredomain
    -appdomain
    -binder_in_vendor_violators
  } binder_device:chr_file rw_file_perms;
')

binder_in_vendor_violators es un atributo proporcionado para detectar un error y guiar el desarrollo. También se puede usar para resolver la infracción de Android 10 descrita anteriormente.

diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9fc..6ee67d88e 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain;
 hal_server_domain(hal_evs_driver, hal_evs)
 hal_client_domain(hal_evs_driver, hal_evs)

+# Allow to use /dev/binder
+typeattribute hal_evs_driver binder_in_vendor_violators;
+
 # allow init to launch processes in this context
 type hal_evs_driver_exec, exec_type, file_type, system_file_type;
 init_daemon_domain(hal_evs_driver)

Creación de la implementación de referencia de EVS HAL como un proceso de proveedor

Como referencia, puede aplicar los siguientes cambios a packages/services/Car/evs/Android.mk . Asegúrese de confirmar que todos los cambios descritos funcionan para su implementación.

diff --git a/evs/sampleDriver/Android.mk b/evs/sampleDriver/Android.mk
index 734feea7d..0d257214d 100644
--- a/evs/sampleDriver/Android.mk
+++ b/evs/sampleDriver/Android.mk
@@ -16,7 +16,7 @@ LOCAL_SRC_FILES := \
 LOCAL_SHARED_LIBRARIES := \
     android.hardware.automotive.evs@1.0 \
     libui \
-    libgui \
+    libgui_vendor \
     libEGL \
     libGLESv2 \
     libbase \
@@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \
 LOCAL_INIT_RC := android.hardware.automotive.evs@1.0-sample.rc

 LOCAL_MODULE := android.hardware.automotive.evs@1.0-sample
+LOCAL_PROPRIETARY_MODULE := true

 LOCAL_MODULE_TAGS := optional
 LOCAL_STRIP_MODULE := keep_symbols
@@ -40,6 +41,7 @@ LOCAL_STRIP_MODULE := keep_symbols
 LOCAL_CFLAGS += -DLOG_TAG=\"EvsSampleDriver\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Iframeworks/native/include

 # NOTE:  It can be helpful, while debugging, to disable optimizations
 #LOCAL_CFLAGS += -O0 -g
diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb31669..5fd029358 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 #include <utils/Log.h>
+#include <binder/ProcessState.h>

 #include "ServiceNames.h"
 #include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
 int main() {
     ALOGI("EVS Hardware Enumerator service is starting");
+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+
     // Start a thread to listen video device addition events.
     std::atomic<bool> running { true };
     std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9fc..632fc7337 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain;
 hal_server_domain(hal_evs_driver, hal_evs)
 hal_client_domain(hal_evs_driver, hal_evs)

+# allow to use /dev/binder
+typeattribute hal_evs_driver binder_in_vendor_violators;
+
 # allow init to launch processes in this context
 type hal_evs_driver_exec, exec_type, file_type, system_file_type;
 init_daemon_domain(hal_evs_driver)
@@ -22,3 +25,7 @@ allow hal_evs_driver ion_device:chr_file r_file_perms;

 # Allow the driver to access kobject uevents
 allow hal_evs_driver self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl;
+
+# Allow the driver to use the binder device
+allow hal_evs_driver binder_device:chr_file rw_file_perms;