Android contiene una capa de abstracción de hardware (HAL) HIDL automotriz que Permite la captura y visualización de imágenes en las primeras etapas del proceso de inicio de Android. y sigue funcionando durante toda la vida del sistema. La HAL incluye una pila de sistema de visión exterior (EVS) que, por lo general, se usa para admitir la vista posterior. Pantallas de cámara y vista envolvente en vehículos con vehículos integrados en el vehículo basados en Android Sistemas de infoentretenimiento (IVI). EVS también permite implementar funciones avanzadas en las apps del usuario.
Android también incluye un controlador de captura y pantalla específico de EVS
(en /hardware/interfaces/automotive/evs/1.0
). Mientras esté
Es posible compilar una app de cámara retrovisora sobre una de Android existente.
servicios de cámara y visualización, esa aplicación
probablemente se ejecutaría demasiado tarde
el proceso de inicio de Android. El uso de una HAL dedicada permite una interfaz optimizada
y deja en claro lo que un OEM debe implementar para admitir la pila de EVS.
Componentes del sistema
EVS incluye los siguientes componentes del sistema:
App de EVS
Una app de ejemplo de EVS de C++
(/packages/services/Car/evs/app
) sirve como referencia.
para implementarlos. Esta app se encarga de solicitar fotogramas de video a
el administrador de EVS y enviar los fotogramas finalizados para que se muestren de vuelta al administrador de EVS.
Se espera que se inicie con init en cuanto el EVS y el servicio de vehículos estén disponibles,
orientadas dentro de los dos (2) segundos posteriores al encendido. Los OEM pueden modificar o reemplazar el EVS
app como desees.
Administrador de EVS
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 un
una simple pantalla de cámara posterior hasta una renderización de varias cámaras 6DOF. Su interfaz
se presenta a través de HIDL y está diseñado para aceptar múltiples clientes simultáneos.
Otras apps y servicios (específicamente, el servicio de vehículos) pueden consultar el EVS
Estado del administrador para saber cuándo el sistema EVS está activo.
Interfaz HIDL de EVS
El sistema EVS, tanto los elementos de cámara como los de pantalla, se define en la
android.hardware.automotive.evs
. Una implementación de muestra
que utiliza la interfaz (genera imágenes de prueba sintéticas y valida el
imágenes en el recorrido de ida y vuelta) se proporcionan en
/hardware/interfaces/automotive/evs/1.0/default
El OEM es responsable de implementar la API expresada en los archivos .hal.
en /hardware/interfaces/automotive/evs
. Estas implementaciones son
de configurar y recopilar datos de cámaras físicas y
a través de búferes de memoria compartida reconocibles por Gralloc. La pantalla
de la implementación se encarga de proporcionar un búfer de memoria compartido
que puede completar la app (generalmente con renderización EGL) y presentar
los marcos terminados, en lugar de todo lo que quieras que aparezca
la pantalla física. Las implementaciones de proveedores de la interfaz de EVS pueden almacenarse
en /vendor/… /device/…
o hardware/…
(p.ej.,
/hardware/[vendor]/[platform]/evs
).
Controladores de kernel
Un dispositivo que admite la pila de EVS requiere controladores de kernel. En lugar de
creando nuevos controladores, los OEM tienen la opción de admitir las funciones requeridas por EVS a través de
controladores existentes de hardware de cámara o pantalla. Reutilizar controladores podría ser
ventajoso, especialmente para los controladores de Display, donde la presentación de imágenes puede
que requieran coordinación con otros subprocesos activos. Android 8.0 incluye una versión basada en v4l2
controlador de ejemplo (en packages/services/Car/evs/sampleDriver
) que
depende del kernel para ser compatible con v4l2 y de SurfaceFlinger para presentar la
imagen de salida.
Descripción de la interfaz de hardware de EVS
En esta sección, se describe la HAL. Se espera que los proveedores implementaciones de esta API adaptadas a su hardware.
IEvsEnumerator
Este objeto es responsable de enumerar el hardware de EVS disponible en el (una o más cámaras y un solo dispositivo de visualización).
getCameraList() generates (vec<CameraDesc> cameras);
Devuelve un vector que contiene descripciones de todas las cámaras del sistema. Sí
se supone que el conjunto de cámaras es fijo y se puede conocer al momento del inicio. Para obtener detalles
descripciones de las cámaras, consulta CameraDesc
.
openCamera(string camera_id) generates (IEvsCamera camera);
Obtiene un objeto de interfaz que se usa para interactuar con una cámara específica
que se identifica a través de la cadena única de camera_id. Muestra un valor NULL en caso de error.
Los intentos de volver a abrir una cámara que ya está abierta no pueden fallar. Para evitar carrera
condiciones asociadas con el inicio y el cierre de la app, y la reapertura de una cámara
debería cerrar la instancia anterior para que se pueda entregar la nueva solicitud. R
instancia de cámara interrumpida de esta forma debe colocarse en un estado
a la espera de la destrucción final y respondiendo a cualquier solicitud de afectar al
el estado de la cámara con un código de retorno de OWNERSHIP_LOST
.
closeCamera(IEvsCamera camera);
Libera la interfaz IEvsCamera (y es opuesta la
openCamera()
). La transmisión de video de la cámara se debe
se detuvo llamando a stopVideoStream()
antes de llamar a closeCamera
.
openDisplay() generates (IEvsDisplay display);
Obtiene un objeto de interfaz que se usa para interactuar exclusivamente con la API del sistema
Pantalla de EVS Solo un cliente puede tener una instancia funcional de IEvsDisplay en
tiempo. De manera similar al comportamiento de apertura agresiva que se describe en openCamera
,
se puede crear un objeto IEvsDisplay nuevo en cualquier momento e inhabilita
individuales. Las instancias invalidadas siguen existiendo y responden a llamadas a función
de sus propietarios, pero no debe realizar
operaciones de mutación cuando fallecen. Con el tiempo,
se espera que la app cliente detecte el error OWNERSHIP_LOST
los códigos de retorno y cerrar y liberar la interfaz inactiva.
closeDisplay(IEvsDisplay display);
Libera la interfaz IEvsDisplay (y es opuesto al
openDisplay()
). Los búferes pendientes recibidos con
Las llamadas de getTargetBuffer()
se deben devolver a la pantalla antes
cerrando la pantalla.
getDisplayState() generates (DisplayState state);
Obtiene el estado de visualización actual. La implementación del HAL debe informar
estado actual real, que podría diferir del estado solicitado más recientemente.
La lógica responsable de cambiar los estados de la pantalla debe existir encima del dispositivo.
por lo que no desea que la implementación de HAL cambie espontáneamente
estados de visualización. Si ningún cliente mantiene la pantalla actualmente (mediante una llamada a
openDisplay), esta función muestra NOT_OPEN
. De lo contrario,
informa el estado actual de la pantalla de EVS (consulta
API de IEvsDisplay).
struct CameraDesc { string camera_id; int32 vendor_flags; // Opaque value }
camera_id
Es una cadena que identifica de forma única una cámara determinada. Puede ser el nombre del dispositivo de kernel o un nombre para el dispositivo, como revisión. La implementación de HAL elige el valor de esta cadena y se usa opacamente en la pila de arriba.vendor_flags
Un método para pasar el ID de cámara especializado información opaca desde el conductor hasta una aplicación de EVS personalizada. Se aprueba. no se puede interpretar desde el conductor hasta la app de EVS, que se puede ignorar que la modifica.
IEvsCamera
Este objeto representa una sola cámara y es la interfaz principal de para capturar imágenes.
getCameraInfo() generates (CameraDesc info);
Muestra CameraDesc
de esta cámara.
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);
Especifica la profundidad de la cadena de búfer que se solicita que admita la cámara. Hasta
el cliente de IEvsCamera puede retener esta cantidad de fotogramas al mismo tiempo. Si esta
muchos fotogramas se entregaron al receptor sin ser devueltos por
doneWithFrame
: La transmisión omite fotogramas hasta que se muestra un búfer.
para reutilizarlo. Es legal que esta llamada se realice en cualquier momento, incluso mientras las transmisiones
ya se están ejecutando, en cuyo caso los búferes se deben agregar o quitar de la cadena
según corresponda. Si no se realizan llamadas a este punto de entrada, IEvsCamera admite
al menos un fotograma de forma predeterminada; sea más aceptable.
Si no se puede admitir el bufferCount solicitado, la función muestra
BUFFER_NOT_AVAILABLE
o algún otro código de error relevante. En este caso,
el sistema seguirá funcionando con el valor establecido previamente.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Solicita la entrega de fotogramas de la cámara EVS de esta cámara. IEvsCameraStream
comienza a recibir llamadas periódicas con nuevos marcos de imagen hasta
Se llama a stopVideoStream()
. Los marcos deben comenzar a publicarse
en un plazo de 500 ms desde la llamada a startVideoStream
y después del inicio, debe
generados a un mínimo de 10 FPS. El tiempo necesario para iniciar la transmisión de video por Internet
se considera eficazmente contra cualquier requisito de tiempo de inicio de la cámara retrovisora. Si el botón
no se inicia una transmisión continua, se debe mostrar un código de error. De lo contrario, se muestra OK.
oneway doneWithFrame(BufferDesc buffer);
Devuelve un fotograma que se envió a IEvsCameraStream. Cuando hayas terminado
consumiendo un fotograma entregado a la interfaz IEvsCameraStream, el fotograma debe
se devuelve a IEvsCamera para su reutilización. Una cantidad pequeña y finita de búferes
disponible (posiblemente tan pequeña como una) y, si se agota, no más
las tramas se entregan hasta que se devuelve un búfer, lo que puede dar como resultado
fotogramas omitidos (un búfer con un controlador nulo denota el final de una transmisión y no
no es necesario devolverlos a través de esta función). Devuelve OK si la operación es exitosa, o
código de error adecuado, que posiblemente incluya INVALID_ARG
o
BUFFER_NOT_AVAILABLE
stopVideoStream();
Detiene la publicación de fotogramas de la cámara EVS. Debido a que la entrega es asíncrona,
Es posible que los fotogramas sigan llegando durante un tiempo después de que se regrese esta llamada. Cada marco
se debe devolver hasta que se indique el cierre de la transmisión al
IEvsCameraStream. Es legal llamar a stopVideoStream
en una transmisión
que ya se detuvo o que 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. Valores
permitidos para opaqueIdentifier
son específicos del controlador, pero no tienen valores
que se aprueban podría causar una falla en el controlador. El conductor debe mostrar 0 para cualquier error no reconocido
opaqueIdentifier
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 es
se proporciona solo para facilitar extensiones específicas del vehículo, sin HAL.
implementación debería requerir que esta llamada funcione en un estado predeterminado. Si el botón
el controlador reconoce y acepta los valores, y se debe mostrar OK; de lo contrario
Se debe mostrar INVALID_ARG
o algún 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 que se pasó a través de la API. La unidad HAL es responsable de
esta estructura para describir el búfer de imagen y el cliente HAL
debería tratar esta estructura como de solo lectura. Los campos contienen suficiente información.
para permitir que el cliente reconstruya un objeto ANativeWindowBuffer
,
según sea necesario para usar la imagen con EGL con el
eglCreateImageKHR()
.
width
Es el ancho en píxeles de la imagen presentada.height
Es la altura en píxeles de la imagen presentada.stride
El número de píxeles que cada fila ocupa en la memoria, y considerar el relleno para la alineación de las filas. Expresado en píxeles para coincidir la convención adoptada por gralloc para sus descripciones de búfer.pixelSize
la cantidad de bytes que ocupa cada píxel individual, lo que permite calcular el tamaño en bytes necesarios para pasar de una fila a otra en la imagen (stride
en bytes =stride
en píxeles *pixelSize
).format
Formato de píxeles que usa la imagen. El formato proporcionado Debe ser compatible con la implementación de OpenGL de la plataforma. Para aprobar las pruebas de compatibilidad,HAL_PIXEL_FORMAT_YCRCB_420_SP
debe preferido para el uso de la cámara, yRGBA
oBGRA
deben para la visualización.usage
Marcas de uso establecidas por la implementación de HAL. Clientes HAL se espera que pasen estos sin modificar (para obtener más información, consulta marcas relacionadas conGralloc.h
).bufferId
Un valor único especificado por la implementación de HAL para permiten que se reconozca un búfer después de un recorrido de ida y vuelta a través de las APIs de HAL. El almacenado en este campo puede ser elegido de forma arbitraria por la implementación de HAL.memHandle
El controlador del búfer de memoria subyacente que contiene los datos de la imagen. La implementación de HAL puede optar por almacenar un Gralloc del controlador de búfer.
Novedades de la cámara IEvs
El cliente implementa esta interfaz para recibir fotogramas de video asíncronos entregas.
deliverFrame(BufferDesc buffer);
Recibe llamadas del sistema HAL cada vez que un fotograma está listo para inspeccionarse.
Los controladores del búfer recibidos por este método se deben devolver a través de llamadas a
IEvsCamera::doneWithFrame()
Cuando se detiene la transmisión de video por Internet con un
llamada a IEvsCamera::stopVideoStream()
, es posible que esta devolución de llamada continúe
cuando se agota la canalización. Se debe devolver cada fotograma. cuando el último fotograma
de la transmisión, se entrega un bufferHandle
NULL
que indica el final de la transmisión y no se realizan más entregas de fotogramas. El valor NULL
No es necesario devolver el dispositivo bufferHandle
con
doneWithFrame()
, pero se deben mostrar todos los demás identificadores
Si bien los formatos de búfer de propiedad son técnicamente posibles, la compatibilidad las pruebas requieren que el búfer esté en uno de los cuatro formatos compatibles: NV21 (YCrCb) 4:2:0 semiplanar), 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 Fuente de texturas GL en la implementación de GLES de la plataforma
La app no debe depender de ninguna correspondencia.
entre el campo bufferId
y el memHandle
en el
BufferDesc
. Los valores de bufferId
son
Esencialmente privada para la implementación del controlador de HAL, y puede usar (y reutilizar)
con ellos como estime conveniente.
IEvsDisplay
Este objeto representa la pantalla de 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 de EVS proporcionada por el sistema (consulta 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 deseado, y la implementación de HAL debe aceptar correctamente una solicitud de cualquier estado mientras se encuentre en cualquier otro, aunque la respuesta puede ser ignorar el para cada solicitud.
Después de la inicialización, la pantalla se define para comenzar en la
Estado NOT_VISIBLE
, después del cual se espera que el cliente solicite
el estado VISIBLE_ON_NEXT_FRAME
y comenzará a proporcionar video. Cuando
ya no se requiere visualización, se espera que el cliente solicite el
NOT_VISIBLE
después de pasar el último fotograma de video.
Es válida para cualquier estado que se solicite en cualquier momento. Si la pantalla es
ya está visible, debería permanecer visible si se establece en
VISIBLE_ON_NEXT_FRAME
Siempre devuelve OK, a menos que el estado solicitado
es un valor de enumeración no reconocido, en cuyo caso INVALID_ARG
es
que se devuelven.
getDisplayState() generates (DisplayState state);
Obtiene el estado de visualización. La implementación del HAL debe informar actual, que podría diferir del estado solicitado más recientemente. El La lógica responsable de cambiar los estados de la pantalla debe existir encima del dispositivo. por lo que no desea que la implementación de HAL cambie espontáneamente estados de visualización.
getTargetBuffer() generates (handle bufferHandle);
Devuelve un controlador para un búfer de fotogramas asociado con la pantalla. Este búfer
puede estar bloqueado y escrito por software o GL. Se debe mostrar este búfer
con una llamada a returnTargetBufferForDisplay()
, incluso si la pantalla está
ya no está visible.
Si bien los formatos de búfer de propiedad son técnicamente posibles, las pruebas de compatibilidad requiere que el búfer esté en uno de los cuatro formatos admitidos: NV21 (YCrCb 4:2:0). semiplanar), YV12 (YCrCb 4:2:0 plano), YUYV (YCrCb 4:2:2 intercalado), RGBA (R:G:B:x de 32 bits), BGRA (32 bits B:G:R:x). El formato seleccionado debe ser un GL válido el objetivo de renderización en la implementación de GLES de la plataforma.
En caso de error, se muestra un búfer con un controlador nulo, pero ese búfer no
se deben devolver a returnTargetBufferForDisplay
.
returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);
Indica a la pantalla que el búfer está listo para mostrarse. Solo se recuperaron los búferes
mediante una llamada a getTargetBuffer()
son válidos para usarse con esto
llamada y el contenido de la BufferDesc
no podrá ser modificado por la
app cliente. Después de esta llamada, el búfer ya no es válido para que lo usen
al cliente. Devuelve OK si la operación se realiza correctamente o muestra un código de error adecuado.
incluidos 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 requeridas por un EVS para implementarlos. La HAL es responsable de completar esta estructura para describir la pantalla de EVS. Puede ser una pantalla física o virtual se superpone o mezcla con otro dispositivo de presentación.
display_id
Es una cadena que identifica la visualización de forma exclusiva. Puede ser el nombre del dispositivo de kernel o el nombre del dispositivo, como revisión. La HAL elige el valor de esta cadena y la pila de arriba lo usa opacamente.vendor_flags
Un método para pasar el ID de cámara especializado información opaca desde el conductor hasta una aplicación de EVS personalizada. Se aprueba. no se puede interpretar desde el conductor hasta la app de EVS, que se puede ignorar que la modifica.
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 inhabilitar (no
visibles para el conductor) o habilitadas (mostrando una imagen al conductor).
Incluye un estado transitorio en el que la pantalla aún no es visible, pero está preparada.
sea visible con la entrega del siguiente fotograma de imágenes con el
returnTargetBufferForDisplay()
llamada.
Administrador de EVS
EVS Manager proporciona la interfaz pública al sistema EVS para recopilar y presentar vistas de cámaras externas. Dónde lo permiten los controladores de hardware solo una interfaz activa por recurso (cámara o pantalla), el administrador de EVS facilita el acceso compartido a las cámaras. Una sola aplicación principal de EVS se es el primer cliente del administrador de EVS y es el único cliente con permiso para escribir mostrar datos (se puede otorgar acceso de solo lectura a los clientes adicionales a la cámara imágenes).
El administrador de EVS implementa la misma API que los controladores de HAL subyacentes y proporciona un servicio expandido gracias a la compatibilidad con varios clientes simultáneos (más de un cliente puede abrir una cámara a través de EVS Manager y recibir un video transmisión).
Las apps no experimentan diferencias cuando operan a través de la HAL de hardware de EVS o la API de EVS Manager, excepto que la API de EVS Manager acceso simultáneo a la transmisión de la cámara. El administrador de EVS es el que está permitido cliente de la capa de HAL de hardware de EVS y actúa como proxy para el hardware de EVS HAL.
En las siguientes secciones, solo se describen las llamadas que tienen una definición Comportamiento (extendido) en la implementación de EVS Manager las llamadas restantes son idénticos a las descripciones de la HAL de EVS.
IEvsEnumerator
openCamera(string camera_id) generates (IEvsCamera camera);
Obtiene un objeto de interfaz que se usa para interactuar con una cámara específica
que se identifica a través de la cadena única de camera_id. Muestra un valor NULL en caso de error.
En la capa de EVS Manager, siempre que haya suficientes recursos del sistema disponibles,
una cámara que ya está abierta puede ser abierta de nuevo por otro proceso, lo que permite
de la transmisión de video por Internet a varias apps de consumo. El
Las cadenas camera_id
de la capa de EVS Manager son las mismas que las
informados a la capa de hardware de EVS.
IEvsCamera
La implementación de IEvsCamera que proporcionó EVS Manager se virtualiza internamente por lo que las operaciones en una cámara por parte de un cliente no afectan a otros clientes, lo que conservar el acceso independiente a sus cámaras.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Inicia las transmisiones de video por Internet. Los clientes pueden iniciar y detener transmisiones de video por Internet de forma independiente. en la misma cámara subyacente. La cámara subyacente se inicia cuando iniciar el cliente.
doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);
Muestra un fotograma. Cada cliente debe devolver sus marcos cuando hayan terminado, pero pueden conservar sus marcos el tiempo que deseen. Cuando el recuento de fotogramas retenido por un cliente alcanza su límite configurado, no recibirá más fotogramas hasta que muestre uno. La omisión de este fotograma no afecta a otras que siguen recibiendo todos los marcos como se esperaba.
stopVideoStream();
Detiene una transmisión de video por Internet. Cada cliente puede detener su transmisión de video por Internet en cualquier momento sin afectar a otros clientes. La transmisión de la cámara subyacente en la capa de hardware es 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 podría permitir que un cliente afecte. con otro cliente. Debido a que EVS Manager no puede comprender las implicaciones de palabras de control definidas por el proveedor, no están virtualizadas y tiene efectos 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 y recibirán fotogramas a la nueva tasa.
IEvsDisplay
Solo se permite un propietario de la pantalla, incluso a nivel de EVS Manager. El Manager no agrega ninguna funcionalidad y simplemente pasa la interfaz de IEvsDisplay. directamente a la implementación de la HAL subyacente.
App de EVS
Android incluye una implementación de referencia de C++ nativa de un EVS. app que se comunica con el administrador de EVS y la HAL del vehículo proporcionan funciones básicas de cámara de retroceso. Se espera que la app se inicie al principio del proceso de inicio del sistema, con un video adecuado según las cámaras disponibles y el estado del vehículo (estado de los cambios de velocidad y de la señal de giro). Los OEMs pueden modificar o reemplazar la app de EVS por una app la lógica y la presentación.
Debido a que los datos de imágenes se presentan a la app en un formato gráfico estándar, búfer, la app se encarga de mover la imagen desde el archivo en el búfer de salida. Si bien esto presenta el costo de copiar los datos, también ofrece la oportunidad para que la app renderice la imagen en la de visualización del búfer de la manera que desee.
Por ejemplo, la app puede optar por mover los datos de los píxeles, tal vez con una escala en línea o una operación de rotación. La app podría puedes usar la imagen de origen como textura OpenGL y renderizar de la escena al búfer de salida, incluidos los elementos virtuales, como los íconos, pautas y animaciones. Una aplicación más sofisticada también puede seleccionar varias cámaras de entrada simultáneas y combinarlas en un único marco de salida (por ejemplo, para usarse en una vista virtual cenital del entorno del vehículo).
Usar el EGL/SurfaceFlinger en la HAL de la pantalla de EVS
En esta sección, se explica cómo usar EGL para renderizar una implementación de HAL de pantalla de EVS en Android 10.
Un EVS
La implementación de referencia de HAL usa EGL para renderizar la vista previa de la cámara.
la pantalla y usa libgui
para crear la superficie de renderización de EGL de destino. En Android 8 (y versiones posteriores), libgui
se clasifica como VNDK-private,
que hace referencia a un grupo de bibliotecas disponibles para las bibliotecas del 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
Plataforma en implementaciones de HAL.
Cómo compilar libgui para los procesos de los proveedores
El uso de libgui
es la única opción para utilizar EGL/SurfaceFlinger.
en las implementaciones de HAL de Display de EVS. La forma más directa de implementar libgui
es
a través de
frameworks/native/libs/gui
directamente con un destino de compilación adicional en la secuencia de comandos de compilación. Este objetivo es exactamente el mismo 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 quita una palabra de 32 bits de los datos de parcelas. Debido a que SurfaceFlinger espera que se haya quitado este campo, SurfaceFlinger no puede analizar el paquete. Esto se observa como una falla de 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 solucionar esta condición, sigue estos pasos:
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);
Compilación de ejemplo
más abajo. Debes 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
Cómo usar Binder en la implementación de la HAL de EVS
En Android 8 (y versiones posteriores), el nodo del dispositivo /dev/binder
pasó a ser exclusivo del
del framework y, por lo tanto, inaccesible para los procesos del proveedor. En cambio,
los procesos del proveedor deben usar /dev/hwbinder
y deben convertir cualquier interfaz de AIDL
a HIDL. Para quienes quieran seguir usando las interfaces del AIDL entre los procesos de los proveedores,
usa el dominio de Binder /dev/vndbinder
.
Dominio de IPC | Descripción |
---|---|
/dev/binder |
IPC entre procesos de framework o apps con interfaces AIDL |
/dev/hwbinder |
Es una IPC entre los procesos del framework y del proveedor con interfaces HIDL. IPC entre procesos de proveedores con interfaces HIDL |
/dev/vndbinder |
La IPC entre los procesos del proveedor con interfaces AIDL |
Si bien SurfaceFlinger define las interfaces del AIDL, los procesos del proveedor solo pueden usar interfaces HIDL para
comunicarse con los procesos del framework. Se necesita una cantidad importante de trabajo para convertir
El AIDL se conecta con HIDL. Afortunadamente, Android proporciona un método para seleccionar el Binder.
controlador para libbinder
, al que se vinculan los procesos de la biblioteca de 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 así antes de llamar a
Process
o IPCThreadState
, o antes de realizar llamadas a Binder.
Políticas de SELinux
Si la implementación del dispositivo es de agudo total, SELinux evita que
procesos usen /dev/binder
. Por ejemplo, una muestra de la HAL de EVS
implementación se asigna al dominio hal_evs_driver
y requiere
Permisos de lectura/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 infringe lo siguiente
reglas nunca permiten 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)
Compila una implementación de referencia de la HAL de EVS como un proceso de proveedor
Como referencia, puedes aplicar los siguientes cambios a
packages/services/Car/evs/Android.mk
Asegúrate de confirmar lo siguiente:
todos los cambios descritos funcionan para tu 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;