Caméra de véhicule HAL

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ée 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:

Système EVS
schéma des composants
Figure 1 : Présentation des composants du système EVS

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 connaît 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, et RGBA ou BGRA doivent être à privilégier pour l'affichage.
  • usage Options d'utilisation définies 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 deviennent visibles lors de l'affichage de la prochaine image d'image avec la 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).

EVS Manager et
Schéma de l&#39;API EVS Hardware.
Figure 2. EVS Manager réplique l'EVS sous-jacente API matérielle.

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 sa 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.

Figure 3 : Exemple de logique d'application EVS : obtenir l'appareil photo liste.


Figure 4. Exemple de logique d'application EVS, réception de frame.

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;