Android contiene una capa de abstracción de hardware (HAL) HIDL para automóviles que permite la captura y visualización de imágenes muy temprano en el proceso de inicio de Android y continúa funcionando durante la vida útil del sistema. El HAL incluye la pila del sistema de visión exterior (EVS) y normalmente se utiliza para admitir cámaras de visión trasera y pantallas de visión envolvente en vehículos con sistemas de información y entretenimiento 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 un HAL dedicado permite una interfaz optimizada y deja claro lo que un OEM necesita implementar para admitir la pila EVS.
Componentes del sistema
EVS incluye los siguientes componentes del sistema:
Figura 1. Descripción general de los componentes del sistema EVS.
aplicación SVE
Una aplicación EVS de C++ de muestra ( /packages/services/Car/evs/app
) sirve como implementación de referencia. Esta aplicación es responsable de solicitar fotogramas de vídeo del EVS Manager y enviar fotogramas terminados para su visualización al 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
EVS Manager ( /packages/services/Car/evs/manager
) proporciona los componentes básicos que necesita una aplicación EVS para implementar cualquier cosa, desde una simple pantalla de cámara retrovisora hasta una representación multicámara de 6DOF. Su interfaz se presenta a través de HIDL y está diseñada para aceptar múltiples clientes simultáneos. Otras aplicaciones y servicios (específicamente Car Service) pueden consultar el estado del EVS Manager para saber cuándo el sistema EVS está activo.
Interfaz EVS HIDL
El sistema EVS, tanto la cámara como los elementos de visualización, está definido 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 que las imágenes realicen el recorrido de ida y vuelta).
El OEM es responsable de implementar la API expresada en 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 buffers de memoria compartida reconocibles por Gralloc. El lado de visualización de la implementación es responsable de proporcionar un búfer de memoria compartida que la aplicación puede llenar (generalmente mediante renderizado EGL) y presentar los fotogramas terminados con preferencia a cualquier otra cosa que quiera aparecer en la pantalla física. Las implementaciones de proveedores de la interfaz EVS pueden almacenarse en /vendor/… /device/…
o hardware/…
(por ejemplo, /hardware/[vendor]/[platform]/evs
).
Controladores del núcleo
Un dispositivo que admita la pila EVS requiere controladores del 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 resultar ventajosa, especialmente para los 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 EVS
La sección describe el HAL. Se espera que los proveedores proporcionen implementaciones de esta API adaptadas a su hardware.
IEvsEnumerador
Este objeto es responsable de enumerar el hardware EVS disponible en el sistema (una o más cámaras y el dispositivo de visualización único).
getCameraList() generates (vec<CameraDesc> cameras);
Devuelve un vector que contiene descripciones de todas las cámaras del sistema. Se supone que el conjunto de cámaras está fijo y es reconocible 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 un NULL en caso de error. Los intentos de reabrir una cámara que ya está abierta no pueden fallar. Para evitar condiciones de carrera asociadas con el inicio y el cierre de la aplicación, al reabrir una cámara se 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 estado inactivo, esperando su 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 stopVideoStream()
antes de llamar closeCamera
.
openDisplay() generates (IEvsDisplay display);
Obtiene un objeto de interfaz utilizado para interactuar exclusivamente con la pantalla EVS del sistema. Sólo un cliente puede tener una instancia funcional de IEvsDisplay a la vez. De manera 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 llamadas de función de sus propietarios, pero no deben realizar operaciones de mutación cuando están muertas. Con el tiempo, se espera que la aplicación cliente note 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 buffers pendientes recibidos a través de llamadas getTargetBuffer()
deben devolverse a la pantalla antes de cerrarla.
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 HAL cambie espontáneamente los estados de visualización. Si ningún cliente mantiene actualmente la pantalla (mediante una llamada a openDisplay), entonces esta función devuelve NOT_OPEN
. De lo contrario, informa el estado actual de EVS Display (consulte API 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 kernel del dispositivo o un nombre para el dispositivo, como rearview . El valor de esta cadena lo elige la implementación HAL y la pila anterior lo utiliza de forma opaca. -
vendor_flags
. Un método para pasar información de cámara especializada de forma opaca desde el conductor a una aplicación EVS personalizada. El conductor lo pasa sin interpretar a la aplicación EVS, que puede 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 la cámara debe soportar. El cliente de IEvsCamera puede mantener hasta esta cantidad de fotogramas simultáneamente. Si se han entregado tantas tramas al receptor sin que doneWithFrame
las devuelva, la transmisión omite tramas hasta que se devuelve un búfer para su reutilización. Es legal que esta llamada se produzca en cualquier momento, incluso mientras las transmisiones ya se están ejecutando, en cuyo caso se deben agregar o eliminar buffers de la cadena según corresponda. Si no se realiza ninguna llamada a este punto de entrada, IEvsCamera admite al menos un fotograma 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 continúa funcionando con el valor previamente establecido.
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 fotogramas de imagen hasta que se llama stopVideoStream()
. Los fotogramas deben comenzar a entregarse dentro de los 500 ms posteriores a la llamada startVideoStream
y, después de comenzar, deben generarse a un mínimo de 10 FPS. El tiempo necesario para iniciar la transmisión de vídeo cuenta efectivamente 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 fotograma entregado a IEvsCameraStream. Cuando termine de consumir un fotograma entregado a la interfaz IEvsCameraStream, el fotograma debe devolverse a IEvsCamera para su reutilización. Hay disponible un número pequeño y finito de buffers (posiblemente tan pequeños como uno) y, si el suministro se agota, no se entregan más fotogramas hasta que se devuelve un buffer, lo que puede resultar en fotogramas omitidos (un buffer con un identificador nulo denota el final). de una secuencia y no es necesario devolverlo a través de esta función). Devuelve OK en caso de éxito o un código de error apropiado que potencialmente incluye INVALID_ARG
o BUFFER_NOT_AVAILABLE
.
stopVideoStream();
Detiene la entrega de marcos de cámara EVS. Debido a que la entrega es asincrónica, es posible que las tramas sigan llegando durante algún tiempo después de que regrese esta llamada. Cada fotograma debe devolverse hasta que se indique el cierre de la transmisión a IEvsCameraStream. Es legal llamar stopVideoStream
en una transmisión que ya se ha detenido 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 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 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 imágenes y el cliente HAL debe tratar esta estructura como de solo lectura. Los campos contienen suficiente información para permitir al cliente reconstruir un objeto ANativeWindowBuffer
, como 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 entre filas de la imagen (stride
en bytes =stride
en píxeles *pixelSize
). -
format
. El formato de píxeles 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 preferirHAL_PIXEL_FORMAT_YCRCB_420_SP
para el uso de la cámara y se debe preferirRGBA
oBGRA
para la visualización. -
usage
. Indicadores de uso establecidos por la implementación HAL. Se espera que los clientes HAL los pasen sin modificar (para obtener más detalles, consulte los indicadores relacionados conGralloc.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 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 aquí un identificador de búfer Gralloc.
IEvsCameraStream
El cliente implementa esta interfaz para recibir entregas de fotogramas de vídeo asíncronas.
deliverFrame(BufferDesc buffer);
Recibe llamadas de HAL cada vez que un fotograma de vídeo está listo para su inspección. Los identificadores de búfer recibidos por este método deben devolverse mediante llamadas a IEvsCamera::doneWithFrame()
. Cuando la transmisión de video se detiene mediante una llamada a IEvsCamera::stopVideoStream()
, esta devolución de llamada podría continuar a medida que se drena la canalización. Cada cuadro aún debe devolverse; cuando se haya entregado el último fotograma de la secuencia, se entregará un NULL bufferHandle, lo que indica el final de la secuencia y no se producirán más entregas de fotogramas. No es necesario devolver el NULL bufferHandle a través de doneWithFrame()
, pero se deben devolver todos los demás identificadores.
Si bien los formatos de búfer propietarios 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 entrelazado), 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 depender de 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.
IEvsPantalla
Este objeto representa la visualización de Evs, controla el estado de la visualización 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 HAL debe aceptar con gracia 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 visualización está definida 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 la visualización ya no es necesaria, se espera que el cliente solicite el estado NOT_VISIBLE
después de pasar el último fotograma de vídeo.
Es válido para cualquier estado que se solicite 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 HAL cambie espontáneamente los estados de visualización.
getTargetBuffer() generates (handle bufferHandle);
Devuelve un identificador a un búfer de fotogramas asociado con la pantalla. Este búfer puede estar bloqueado y escrito en él mediante software y/o GL. Este búfer debe devolverse mediante una llamada a returnTargetBufferForDisplay()
incluso si la pantalla ya no es visible.
Si bien los formatos de búfer propietarios 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 entrelazado), 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 buffers recuperados a través de una llamada a getTargetBuffer()
son válidos para su uso 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 utilice el cliente. Devuelve OK en caso de éxito o un código de error apropiado que potencialmente incluye INVALID_ARG
o BUFFER_NOT_AVAILABLE
.
struct DisplayDesc { string display_id; int32 vendor_flags; // Opaque value }
Describe las propiedades básicas de una pantalla EVS y las requeridas por una implementación de EVS. El HAL es responsable de completar esta estructura para describir la visualización del 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 kernel del dispositivo o un nombre para el dispositivo, como rearview . El valor de esta cadena lo elige la implementación HAL y la pila anterior lo utiliza de forma opaca. -
vendor_flags
. Un método para pasar información de cámara especializada de forma opaca desde el conductor a una aplicación EVS personalizada. El conductor lo pasa sin interpretar a la aplicación EVS, que puede 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 puede estar deshabilitada (no visible para el conductor) o habilitada (mostrando una imagen al conductor). Incluye un estado transitorio en el que la pantalla aún no es visible pero está preparada para volverse visible con la entrega del siguiente fotograma de imágenes a través de la llamada returnTargetBufferForDisplay()
.
Gerente de SVE
El EVS Manager proporciona la interfaz pública del 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 única 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 múltiples 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).
Las aplicaciones no ven diferencias cuando funcionan 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 cámaras. EVS Manager es, en sí mismo, el único cliente permitido de la capa HAL de hardware de EVS y actúa como proxy para 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.
IEvsEnumerador
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 un NULL en caso de error. En la capa de EVS Manager, siempre que haya suficientes recursos del sistema disponibles, otro proceso puede abrir nuevamente una cámara que ya está abierta, lo que permite la transmisión de la transmisión de video a múltiples aplicaciones de consumo. Las cadenas camera_id
en la capa de EVS Manager son las mismas que las reportadas a la capa de hardware de EVS.
IEvsCámara
La implementación de IEvsCamera proporcionada por EVS Manager está virtualizada internamente para que las operaciones en una cámara realizadas por un cliente no afecten a otros clientes, que conservan 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 le permite conservarlos durante el tiempo que desee. Cuando el recuento de fotogramas retenido por un cliente alcanza su límite configurado, no recibirá más fotogramas hasta que devuelva uno. Esta omisión de fotogramas no afecta a otros clientes, que continúan recibiendo todos los fotogramas 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 están virtualizadas y los efectos secundarios se aplican a todos los clientes de una cámara determinada. Por ejemplo, si un proveedor utilizara esta llamada para cambiar la velocidad de fotogramas, todos los clientes de la cámara de la capa de hardware afectada recibirían fotogramas a la nueva velocidad.
IEvsPantalla
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 la implementación HAL subyacente.
aplicación SVE
Android incluye una implementación de referencia nativa en 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 se inicie muy temprano en el proceso de arranque del sistema, mostrando el video adecuado según las cámaras disponibles y el estado del automóvil (estado de la marcha y las señales 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 lista de cámaras.
Figura 4. Lógica de muestra de la aplicación EVS, recepción de devolución de llamada de trama.
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 para que la aplicación represente 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 de píxeles por sí misma, 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, pautas y animaciones. Una aplicación más sofisticada también puede seleccionar varias cámaras de entrada simultáneas y fusionarlas en un único cuadro de salida (como para usar en una vista virtual de arriba hacia abajo del entorno del vehículo).
Utilice EGL/SurfaceFlinger en EVS Display HAL
Esta sección explica cómo usar EGL para representar una implementación EVS Display HAL en Android 10.
Una implementación de referencia de EVS HAL usa EGL para representar la vista previa de la cámara en la pantalla y usa libgui
para crear la superficie de procesamiento EGL de destino. En Android 8 (y versiones posteriores), libgui
se clasifica como VNDK-privado , que se refiere a un grupo de bibliotecas disponibles para las bibliotecas VNDK que los procesos del proveedor 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.
Construyendo libgui para procesos de proveedores
El uso de libgui
sirve como la única opción para usar EGL/SurfaceFlinger en implementaciones 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 objetivo es exactamente igual que el objetivo 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 destinos de proveedores se crean con la macro NO_INPUT
, que elimina una palabra de 32 bits de los datos del paquete. Debido a 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 construcció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
Usar carpeta en una implementación EVS HAL
En Android 8 (y versiones posteriores), el nodo del dispositivo /dev/binder
se volvió exclusivo para los procesos del marco y, por lo tanto, inaccesible para los procesos del proveedor. En su lugar, los procesos del proveedor deben usar /dev/hwbinder
y deben convertir cualquier interfaz AIDL a HIDL. Para aquellos que quieran seguir usando interfaces AIDL entre procesos de proveedores, utilice el dominio de carpeta, /dev/vndbinder
.
Dominio IPC | 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 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 para 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 a la carpeta.
Políticas SELinux
Si la implementación del dispositivo es triple, 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 utilizar 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)
Cree una implementación de referencia de EVS HAL como 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;