Android contient une couche d'abstraction matérielle (HAL) automobile HIDL qui permet de capturer et d'afficher des images très tôt dans le processus de démarrage d'Android. et il continue de fonctionner pendant toute la durée de vie du système. Le HAL inclut EVS et est généralement utilisé pour la vue arrière. Caméras et affichages surround dans les véhicules équipés d'appareils Android intégrés Systèmes d'infoloisirs (IVI). EVS permet également d'implémenter des fonctionnalités avancées dans les applications utilisateur.
Android inclut également un pilote de capture et d'affichage spécifique à EVS.
(dans /hardware/interfaces/automotive/evs/1.0
). Bien qu'il soit
possible de créer une application de caméra de recul par-dessus l'application Android existante
les services d'appareil photo et d'affichage, il est probable qu'une telle application se lance trop tard
le processus de démarrage d'Android. L'utilisation d'une HAL dédiée
permet de simplifier l'interface
et indique clairement ce qu'un OEM doit implémenter pour prendre en charge la pile EVS.
Composants du système
EVS comprend les composants système suivants:
Application EVS
Exemple d'application EVS C++
(/packages/services/Car/evs/app
) sert de référence
la mise en œuvre. Cette appli est chargée de demander des images vidéo aux
EVS Manager et l'envoi des images terminées
pour les afficher à nouveau à EVS Manager.
Il devrait être démarré par init dès qu'EVS et Car Service seront disponibles,
ciblée dans les deux (2) secondes suivant sa mise sous tension. Les OEM peuvent modifier ou remplacer le EVS
l'application comme vous le souhaitez.
EVS Manager
EVS Manager (/packages/services/Car/evs/manager
) fournit
les éléments de base nécessaires à une application EVS pour implémenter quoi que ce soit,
simple d'affichage de la caméra de recul
en un rendu multicaméra 6DOF. Son interface
est présenté via HIDL et est conçu pour accepter plusieurs clients simultanés.
D'autres applications et services (en particulier le service automobile) peuvent interroger l'EVS.
État du gestionnaire pour savoir quand le système EVS est actif.
Interface EVS HIDL
Le système EVS, à la fois les éléments de la caméra et de l'écran, est défini dans le
Package android.hardware.automotive.evs
. Exemple d'implémentation
qui exerce l'interface (qui génère des images de test synthétiques et valide le
les images qui font l'aller-retour) est fournie dans
/hardware/interfaces/automotive/evs/1.0/default
L'OEM est responsable de l'implémentation de l'API exprimée par les fichiers .hal.
dans /hardware/interfaces/automotive/evs
. De telles implémentations sont
est responsable de la configuration et de la collecte des données des caméras physiques et
en la distribuant via des tampons de mémoire
partagée et reconnaissable par Gralloc. L'écran
de l'implémentation doit fournir un tampon de mémoire partagée
pouvant être remplie par l'application (généralement avec un rendu EGL) et présenter
les images finales plutôt que
tout autre élément susceptible de vouloir apparaître sur
l'écran physique. Les implémentations de l'interface EVS par les fournisseurs peuvent être stockées
sous /vendor/… /device/…
ou hardware/…
(par exemple,
/hardware/[vendor]/[platform]/evs
).
Pilotes de kernel
Un périphérique compatible avec la pile EVS nécessite des pilotes de noyau. Au lieu de
créant de nouveaux pilotes, les OEM ont la possibilité de prendre en charge les fonctionnalités EVS requises via
d'appareils photo ou d'écrans existants. Réutiliser des pilotes
pourrait être
avantageuse, en particulier pour les pilotes d'affichage dans lesquels la présentation d'images peut
nécessitent une coordination
avec d'autres fils de discussion actifs. Android 8.0 inclut une version v4l2
exemple de pilote (dans packages/services/Car/evs/sampleDriver
) qui
dépend du noyau pour la compatibilité v4l2 et de SurfaceFlinger pour la présentation du
image de sortie.
Description de l'interface matérielle EVS
Cette section décrit le HAL. Les fournisseurs doivent fournir des implémentations de cette API adaptées à leur matériel.
IEvsEnumerator
Cet objet est chargé d'énumérer le matériel EVS disponible dans (une ou plusieurs caméras et un seul écran).
getCameraList() generates (vec<CameraDesc> cameras);
Renvoie un vecteur contenant des descriptions pour toutes les caméras du système. Il est
en supposant que l'ensemble de caméras est fixe
et que les caméras sont connues au démarrage. Pour en savoir plus sur
pour la description de la caméra, voir CameraDesc
.
openCamera(string camera_id) generates (IEvsCamera camera);
Obtient un objet d'interface utilisé pour interagir avec une caméra spécifique.
identifié par la chaîne unique camera_id. Renvoie une valeur NULL en cas d'échec.
Les tentatives de réouverture d'un appareil photo déjà ouvert ne peuvent pas échouer. Pour éviter la race
conditions associées au démarrage et à l'arrêt de l'application, à la réouverture d'un appareil photo
doit arrêter l'instance précédente
pour que la nouvelle requête puisse être satisfaite. A
l'instance de caméra préemptée de cette façon doit être placée dans
en attente de destruction finale et de réponse à toute requête visant à affecter
l'état de l'appareil photo avec un code renvoyé de OWNERSHIP_LOST
.
closeCamera(IEvsCamera camera);
Libère l'interface IEvsCamera (à l'opposé de
openCamera()
). Le flux vidéo de la caméra doit être
arrêté en appelant stopVideoStream()
avant d'appeler closeCamera
.
openDisplay() generates (IEvsDisplay display);
Obtient un objet d'interface utilisé pour interagir exclusivement avec l'objet
Écran EVS Un seul client peut détenir une instance fonctionnelle d'IEvsDisplay à l'adresse
en temps réel. À l'instar du comportement d'ouverture agressif décrit dans openCamera
,
un objet IEvsDisplay peut être créé à tout moment et désactive tout objet
Compute Engine. Les instances invalidées continuent d'exister et de répondre aux appels de fonction
de leurs propriétaires, mais ne doivent effectuer aucune opération de mutation lorsqu'elles sont inactives. Finalement,
l'application cliente doit remarquer l'erreur OWNERSHIP_LOST
renvoyer des codes et fermer
et libérer l'interface inactive.
closeDisplay(IEvsDisplay display);
Libère l'interface IEvsDisplay (à l'opposé de
openDisplay()
). Tampons en attente reçus avec
Les appels getTargetBuffer()
doivent être renvoyés à l'écran avant
fermer l'écran.
getDisplayState() generates (DisplayState state);
Récupère l'état d'affichage actuel. L'implémentation HAL doit indiquer
l'état actuel réel, qui peut différer de l'état le plus récemment demandé.
La logique permettant de modifier les états d'affichage doit exister au-dessus de l'appareil
de sorte qu'il n'est pas souhaitable que l'implémentation HAL change spontanément
états d'affichage. Si l'écran n'est actuellement détenu par aucun client (par un appel à
openDisplay), cette fonction renvoie NOT_OPEN
. Sinon, il
indique l'état actuel de l'écran EVS (voir
API IEvsDisplay).
struct CameraDesc { string camera_id; int32 vendor_flags; // Opaque value }
camera_id
Chaîne identifiant de manière unique une caméra donnée. Il peut s'agir du nom du noyau ou du nom du périphérique, par exemple rearview. La valeur de cette chaîne est choisie par l'implémentation HAL et utilisé de manière opaque par la pile ci-dessus.vendor_flags
Méthode pour transmettre une caméra spécialisée de manière opaque les informations du conducteur vers une application EVS personnalisée. Il est transmis non interprétées du conducteur jusqu'à l'application EVS, qui peut être ignorée par le conducteur.
IEvsCamera
Cet objet représente une seule caméra et constitue l'interface principale de la capture d'images.
getCameraInfo() generates (CameraDesc info);
Renvoie CameraDesc
de cette caméra.
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);
Spécifie la profondeur de la chaîne de mémoire tampon que la caméra doit prendre en charge. Jusqu'à
ce nombre d'images peut être conservé
simultanément par le client d'IEvsCamera. Si cette
de nombreux frames ont été livrés au récepteur sans être renvoyés par
doneWithFrame
: le flux ignore des frames jusqu'à ce qu'un tampon soit renvoyé
pour les réutiliser. Cet appel peut avoir lieu à tout moment, même lorsque les diffusions sont
déjà en cours d'exécution, auquel cas des tampons doivent être ajoutés à la chaîne ou supprimés
le cas échéant. Si aucun appel n'est effectué vers ce point d'entrée, IEvsCamera prend en charge
au moins une image par défaut ; plus acceptable.
Si le nombre de tampons demandé ne peut être pris en compte, la fonction renvoie
BUFFER_NOT_AVAILABLE
ou tout autre code d'erreur pertinent. Dans ce cas,
le système continue de fonctionner
avec la valeur définie précédemment.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Demande la diffusion d'images EVS de cette caméra. IEvsCameraStream
commence à recevoir des appels périodiques
avec de nouvelles images jusqu'à
stopVideoStream()
est appelé. La livraison des images doit commencer
dans les 500 ms qui suivent l'appel startVideoStream
et après le démarrage, doit
générées à au moins 10 FPS. Temps nécessaire au démarrage du flux vidéo
est pris en compte dans le temps de démarrage de la caméra arrière. Si le
le flux n'est pas démarré, un code d'erreur doit être renvoyé ; sinon OK est renvoyé.
oneway doneWithFrame(BufferDesc buffer);
Renvoie une image envoyée par IEvsCameraStream. Lorsque vous avez terminé
l'image envoyée à l'interface IEvsCameraStream, l'image doit être
renvoyés à IEvsCamera pour réutilisation. Un petit nombre limité
de tampons sont
disponible (peut-être une unité), et si l'offre est épuisée,
les frames sont livrés jusqu'à ce qu'un tampon soit renvoyé, ce qui peut entraîner
des trames ignorées (un tampon avec une poignée Null indique la fin d'un flux et
n'ont pas besoin d'être renvoyées par cette fonction). Renvoie OK en cas de réussite, ou
code d'erreur approprié, qui peut inclure INVALID_ARG
ou
BUFFER_NOT_AVAILABLE
stopVideoStream();
Arrête la diffusion des images de l'appareil photo EVS. La diffusion étant asynchrone,
les frames peuvent continuer à arriver pendant un certain temps après le retour de cet appel. Chaque image
doit être renvoyé jusqu'à ce que la fermeture du flux soit signalée au
IEvsCameraStream. Il est légal d'appeler stopVideoStream
sur un flux
qui a déjà été arrêté ou n'a jamais démarré, auquel cas il est ignoré.
getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);
Demande des informations spécifiques au pilote à l'implémentation HAL. Valeurs
autorisés pour opaqueIdentifier
sont spécifiques aux conducteurs, mais aucune valeur
réussi peut faire planter le conducteur. Le pilote doit renvoyer 0 pour toute information non reconnue.
opaqueIdentifier
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Envoie une valeur spécifique au pilote à l'implémentation HAL. Cette extension est
fournie uniquement pour faciliter les extensions spécifiques aux véhicules, et non pour les exigences HAL
doit permettre à cet appel de fonctionner dans un état par défaut. Si le
le conducteur reconnaît et accepte les valeurs, OK doit être renvoyé. sinon
INVALID_ARG
ou un autre code d'erreur représentatif doit s'afficher.
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 }
Décrit une image transmise via l'API. Le disque HAL est chargé de
remplir cette structure pour décrire le tampon d'image et le client HAL
doit traiter cette structure
en lecture seule. Les champs contiennent suffisamment d'informations
pour permettre au client de reconstruire un objet ANativeWindowBuffer
,
si nécessaire pour utiliser l'image avec EGL avec
eglCreateImageKHR()
.
width
Largeur en pixels de l'image présentée.height
Hauteur en pixels de l'image présentée.stride
Nombre de pixels réellement occupés par chaque ligne en mémoire en tenant compte de tout remplissage pour l'alignement des lignes. Exprimé en pixels pour correspondre la convention adoptée par Gralloc pour ses descriptions de tampons.pixelSize
Le nombre d'octets occupés par chaque pixel permettant de calculer la taille en octets nécessaire pour passer d'une ligne à l'autre dans image (stride
en octets =stride
en pixels *pixelSize
).format
Format de pixel utilisé par l'image. Le format fourni doit être compatible avec l'implémentation OpenGL de la plate-forme. Pour réussir tests de compatibilité,HAL_PIXEL_FORMAT_YCRCB_420_SP
doit être pour l'utilisation de l'appareil photo, etRGBA
ouBGRA
doivent être à privilégier pour l'affichage.usage
Indicateurs d'utilisation définis par l'implémentation HAL. Clients HAL doivent les transmettre telles quelles (pour plus d'informations, options associées àGralloc.h
).bufferId
Une valeur unique spécifiée par l'implémentation HAL pour permettent de reconnaître un tampon après un aller-retour via les API HAL. La la valeur stockée dans ce champ peut être choisie arbitrairement par l'implémentation HAL.memHandle
Poignée du tampon de mémoire sous-jacent qui contenant les données de l'image. L'implémentation HAL peut choisir de stocker un Gralloc de la mémoire tampon ici.
IEvsCameraStream
Le client met en œuvre cette interface pour recevoir des images vidéo asynchrones. livraisons.
deliverFrame(BufferDesc buffer);
Reçoit des appels du HAL chaque fois qu'une image vidéo est prête à être inspectée.
Les poignées de tampon reçues par cette méthode doivent être renvoyées via des appels vers
IEvsCamera::doneWithFrame()
Lorsque le flux vidéo est arrêté par une
appelé IEvsCamera::stopVideoStream()
, il se peut que ce rappel continue
lors du drainage du pipeline. Chaque frame doit quand même être renvoyé. lorsque la dernière image
dans le flux a été envoyé, une valeur bufferHandle
NULL est délivrée,
indiquant la fin du flux et qu'aucune autre
livraison de trame n'a lieu. La valeur NULL
bufferHandle
lui-même n'a pas besoin d'être renvoyé avec
doneWithFrame()
, mais tous les autres identifiants doivent être renvoyés
Bien que les formats de tampon propriétaires soient techniquement possibles, la compatibilité Les tests exigent que le tampon soit dans l'un des quatre formats compatibles: NV21 (YCrCb 4:2:0 semi-plan, YV12 (YCrCb 4:2:0 planaire), YUYV (YCrCb 4:2:2 entrelacé), RVBA (R:G:B:x 32 bits), BGRA (B:G:R:x 32 bits). Le format sélectionné doit être un format valide Source de texture GL sur l'implémentation GLES de la plate-forme.
L'application ne doit pas s'appuyer sur une correspondance
entre le champ bufferId
et le memHandle
dans
BufferDesc
. Les valeurs bufferId
sont
essentiellement privé pour l'implémentation du pilote HAL, et il peut utiliser (et réutiliser)
comme bon lui semble.
IEvsDisplay
Cet objet représente l'écran Evs. Il contrôle l'état de l'écran, et gère la présentation réelle des images.
getDisplayInfo() generates (DisplayDesc info);
Renvoie des informations de base sur l'affichage EVS fourni par le système (voir DisplayDesc).
setDisplayState(DisplayState state) generates (EvsResult result);
Définit l'état d'affichage. Les clients peuvent définir l'état d'affichage pour exprimer l'état souhaité et l'implémentation HAL doit accepter une demande n'importe quel état dans tout autre état, bien que la réponse puisse être d'ignorer requête.
Lors de l'initialisation, l'affichage est configuré pour commencer
l'état NOT_VISIBLE
, après lequel le client doit demander
l'état VISIBLE_ON_NEXT_FRAME
et commencez à fournir la vidéo. Lorsque
l'affichage n'est plus nécessaire, le client doit demander
NOT_VISIBLE
après la transmission de la dernière image vidéo.
Il est valide pour n'importe quel État à demander à tout moment. Si l'écran
déjà visible, elle doit le rester si elle est définie sur
VISIBLE_ON_NEXT_FRAME
Renvoie toujours OK, sauf si l'état demandé
est une valeur d'énumération non reconnue, auquel cas INVALID_ARG
est
renvoyé.
getDisplayState() generates (DisplayState state);
Récupère l'état d'affichage. La mise en œuvre de HAL doit indiquer l'état actuel, qui peut différer de l'état le plus récemment demandé. La la logique responsable du changement des états de l'affichage doit exister au-dessus de l'appareil de sorte qu'il n'est pas souhaitable que l'implémentation HAL change spontanément états d'affichage.
getTargetBuffer() generates (handle bufferHandle);
Renvoie un handle vers un tampon de frame associé à l'écran. Ce tampon
peut être verrouillé et écrit par un logiciel et/ou GL. Ce tampon doit être renvoyé
avec un appel à returnTargetBufferForDisplay()
, même si l'écran
n'est plus visible.
Même si les formats de tampon propriétaires sont techniquement possibles, les tests de compatibilité Le tampon doit respecter l'un des quatre formats compatibles: NV21 (YCrCb 4:2:0 Semi-plan, YV12 (YCrCb 4:2:0 planaire), YUYV (YCrCb 4:2:2 entrelacé), RVBA (R:G:B:x 32 bits), BGRA (B:G:R:x 32 bits). Le format sélectionné doit être un GL valide cible de rendu sur l'implémentation GLES de la plate-forme.
En cas d'erreur, un tampon avec un handle nul est renvoyé, mais un tel tampon n'a pas
doivent être renvoyées à returnTargetBufferForDisplay
.
returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);
Indique à l'écran que le tampon est prêt à être affiché. Seuls les tampons ont été récupérés
via un appel à getTargetBuffer()
peuvent être utilisées avec
et que le contenu de BufferDesc
ne peut pas être modifié par la
l'application cliente. Après cet appel, le tampon ne peut plus être utilisé par
le client. En cas de réussite, renvoie "OK", ou un code d'erreur approprié
y compris INVALID_ARG
ou BUFFER_NOT_AVAILABLE
.
struct DisplayDesc { string display_id; int32 vendor_flags; // Opaque value }
Décrit les propriétés de base d'un écran EVS requises par un EVS la mise en œuvre. Le HAL est chargé de remplir cette structure pour pour décrire l'écran EVS. Il peut s'agir d'un écran physique ou virtuel superposée ou mélangée à un autre périphérique de présentation.
display_id
Chaîne qui identifie l'affichage de manière unique. Il peut s'agir du nom de périphérique du noyau du périphérique, ou du nom du périphérique, comme rearview. La valeur de cette chaîne est choisie par le HAL et utilisé de manière opaque par la pile ci-dessus.vendor_flags
Méthode pour transmettre une caméra spécialisée de manière opaque les informations du conducteur à une application EVS personnalisée. Il est transmis non interprétées du conducteur jusqu'à l'application EVS, qui peut être ignorée par le conducteur.
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 }
Décrit l'état de l'écran EVS, qui peut être désactivé
visible par le conducteur) ou activée (affichage d'une image pour le conducteur).
Inclut un état temporaire où l'écran n'est pas encore visible, mais est prêt
devient visible lors de l'affichage de la prochaine image
returnTargetBufferForDisplay()
appel.
EVS Manager
EVS Manager fournit l'interface publique au système EVS pour en collectant et en présentant des vues de caméras externes. Où les pilotes matériels permettent-ils une seule interface active par ressource (caméra ou écran), EVS Manager et facilite l'accès partagé aux caméras. Une seule application EVS principale est premier client d'EVS Manager. Il s'agit du seul client autorisé à écrire Affichage des données (l'accès en lecture seule à l'appareil photo peut être accordé à d'autres clients images).
EVS Manager implémente la même API que les pilotes HAL sous-jacents et fournit un service étendu en prenant en charge plusieurs clients simultanés (plus de Un client peut ouvrir une caméra via EVS Manager et recevoir une vidéo flux).
Les applications ne constatent aucune différence lorsqu'elles fonctionnent via le HAL matériel EVS ou l'API EVS Manager, à la différence près que l'API EVS Manager permet l'accès simultané au flux de la caméra. EVS Manager est lui-même la personne autorisée client de la couche HAL matérielle EVS et agit en tant que proxy pour le matériel EVS CARL.
Les sections suivantes décrivent uniquement les appels ayant un paramètre (étendue) dans l'implémentation d'EVS Manager. appels restants sont identiques à celles des EVS HAL.
IEvsEnumerator
openCamera(string camera_id) generates (IEvsCamera camera);
Obtient un objet d'interface utilisé pour interagir avec une caméra spécifique.
identifié par la chaîne unique camera_id. Renvoie une valeur NULL en cas d'échec.
Au niveau de la couche EVS Manager, tant que suffisamment de ressources système sont disponibles,
un appareil photo déjà ouvert peut être rouvert par un autre processus,
du flux vidéo vers plusieurs applications grand public. La
Les chaînes camera_id
de la couche EVS Manager sont identiques à celles
transmis à la couche matérielle EVS.
IEvsCamera
EVS Manager a fourni que l'implémentation d'IEvsCamera est virtualisée en interne. Ainsi, les opérations effectuées sur une caméra par un client n'affectent pas les autres, ce qui et conservent un accès indépendant à leurs caméras.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Lance les flux vidéo. Les clients peuvent démarrer et arrêter eux-mêmes des flux vidéo. sur la même caméra sous-jacente. La caméra sous-jacente démarre démarre le client.
doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);
Renvoie un frame. Chaque client doit renvoyer ses frames une fois qu'ils ont terminé, mais sont autorisés à conserver leurs cadres aussi longtemps qu'ils le souhaitent. Lorsque que le nombre de trames détenues par un client atteint la limite configurée, il ne recevra pas d'autres frames jusqu'à ce qu'il en renvoie un. Le saut d'image n'a aucune incidence qui continuent à recevoir tous les frames comme prévu.
stopVideoStream();
Arrête un flux vidéo. Chaque client peut arrêter son flux vidéo à tout moment, sans affectant d'autres clients. Le flux de l'appareil photo sous-jacent au niveau de la couche matérielle s'arrête lorsque le dernier client d'une caméra donnée arrête son flux.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Envoie une valeur spécifique au pilote, ce qui permet potentiellement à un client d'affecter un autre client. Comme EVS Manager ne peut pas comprendre les implications les mots de contrôle définis par le fournisseur, ils ne sont pas virtualisés et aucun effet secondaire s'appliquent à tous les clients d'une caméra donnée. Par exemple, si un fournisseur a utilisé cet appel pour modifier les fréquences d'images, tous les clients de l'appareil photo de la couche matérielle concerné recevoir des images à la nouvelle fréquence.
IEvsDisplay
Un seul propriétaire de l'écran est autorisé, même au niveau du responsable EVS. La Le gestionnaire n'ajoute aucune fonctionnalité et transmet simplement l'interface IEvsDisplay. directement à l'implémentation HAL sous-jacente.
Application EVS
Android inclut une implémentation de référence C++ native d'un EVS. application qui communique avec le gestionnaire EVS et le HAL du véhicule pour fournissent des fonctions de base pour la caméra de recul. L'application devrait démarrer très tôt dans le processus de démarrage du système, avec une vidéo adaptée s'affiche en fonction les caméras disponibles et l'état du véhicule (état des roues dentées et des clignotants) ; Les OEM peuvent modifier ou remplacer l'application EVS par leur propre la logique et la présentation.
Comme les données d'image sont présentées à l'application dans un format graphique standard tampon, l'application se charge de déplacer l'image de la source dans le tampon de sortie. Bien que cela entraîne le coût d'une copie de données, L'application peut aussi afficher l'image le tampon d'affichage comme bon vous semble.
Par exemple, l'application peut choisir de déplacer elle-même les données de pixels, potentiellement avec une opération de mise à l'échelle ou de rotation intégrée. L'application pourrait choisir d'utiliser l'image source comme texture OpenGL pour afficher une image dans le tampon de sortie, y compris des éléments virtuels tels que des icônes, les directives et les animations. Une application plus sophistiquée peut également sélectionner plusieurs caméras d'entrée simultanées et les fusionner en une seule image de sortie (par exemple, pour une vue virtuelle de haut en bas de l'environnement du véhicule).
Utiliser EGL/SurfaceFlinger dans l'HAL de l'écran EVS
Cette section explique comment utiliser EGL pour afficher une implémentation HAL d'écran EVS sur Android 10.
Un EVS
L'implémentation de référence HAL utilise EGL pour afficher l'aperçu de l'appareil photo sur
l'écran et utilise libgui
pour créer la surface de rendu EGL cible. Sous Android 8 (ou version ultérieure), libgui
est classé comme VNDK-privé,
qui fait référence à un groupe de bibliothèques disponibles pour
les bibliothèques VNDK que les processus des fournisseurs ne peuvent pas utiliser.
Étant donné que les implémentations HAL doivent se trouver dans la partition fournisseur, les fournisseurs ne peuvent pas utiliser
Surface dans les implémentations HAL.
Créer libgui pour les processus des fournisseurs
libgui
est la seule option permettant d'utiliser EGL/SurfaceFlinger.
dans les implémentations HAL d'affichage EVS. La méthode la plus simple pour implémenter libgui
est
à
frameworks/native/libs/gui
directement à l'aide d'une cible de compilation supplémentaire dans le script de compilation. Cette cible est exactement la même que
la cible libgui
, à l'exception de deux champs supplémentaires:
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", ], …
Remarque: Les cibles de fournisseurs sont créées avec la macro NO_INPUT
, qui supprime un mot de 32 bits des données cadastrales. Comme SurfaceFlinger s'attend à ce que ce champ ait été supprimé, SurfaceFlinger ne parvient pas à analyser le colis. Ceci est observé comme un échec 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
Pour résoudre ce problème:
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);
Exemple de build
instructions fournies ci-dessous. Attendez-vous à recevoir une
$(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
Utiliser la liaison dans l'implémentation d'une HAL EVS
Sous Android 8 (et versions ultérieures), le nœud d'appareil /dev/binder
est devenu exclusif aux
processus et, par conséquent, inaccessibles
aux processus des fournisseurs. À la place,
Les processus des fournisseurs doivent utiliser /dev/hwbinder
et convertir toutes les interfaces AIDL
en HIDL. Si vous souhaitez continuer à utiliser les interfaces AIDL entre les processus fournisseurs,
utilisez le domaine de liaison /dev/vndbinder
.
Domaine IPC | Description |
---|---|
/dev/binder |
IPC entre les processus du framework/de l'application avec des interfaces AIDL |
/dev/hwbinder |
IPC entre les processus du framework/fournisseur avec des interfaces HIDL IPC entre les processus des fournisseurs avec des interfaces HIDL |
/dev/vndbinder |
IPC entre les processus fournisseur/fournisseur avec des interfaces AIDL |
Alors que SurfaceFlinger définit des interfaces AIDL, les processus des fournisseurs ne peuvent utiliser des interfaces HIDL que pour
de communiquer avec
les processus du cadre. Un volume de travail considérable est nécessaire pour convertir
les interfaces AIDL en HIDL. Heureusement, Android fournit une méthode permettant de sélectionner la liaison
pilote pour libbinder
, auquel les processus de la bibliothèque d'espace utilisateur sont associés.
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));
Remarque: Les processus fournisseurs doivent appeler cela avant d'appeler
Process
ou IPCThreadState
, ou avant d'effectuer des appels de liaison.
Règles SELinux
Si l'implémentation de l'appareil est aiguë complète, SELinux empêche le fournisseur
processus d'utilisation de /dev/binder
. Par exemple, un échantillon EVS HAL
est attribuée au domaine hal_evs_driver
et nécessite
Autorisations de lecture/écriture sur le domaine 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
Cependant, l'ajout de ces autorisations entraîne un échec de compilation, car il ne respecte pas les
jamais les règles définies dans system/sepolicy/domain.te
pour un appareil aigus pleins.
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
est un attribut fourni pour détecter un bug et guider le développement. Il peut également être utilisé pour
résoudre le cas de non-respect d'Android 10 décrit ci-dessus.
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)
Créer une implémentation de référence EVS HAL en tant que processus fournisseur
À titre de référence, vous pouvez appliquer les modifications suivantes aux
packages/services/Car/evs/Android.mk
N'oubliez pas de confirmer que
toutes les modifications décrites fonctionnent
pour votre mise en œuvre.
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;