Fahrzeugkamera HAL

Android enthält eine Automotive-HIDL-Hardwareabstraktionsschicht (HAL), die ermöglicht die Aufnahme und Anzeige von Bildern sehr früh im Android-Bootvorgang und funktioniert für die Lebensdauer des Systems. Der HAL enthält die EVS-Stapel (Outdoor View System) und wird in der Regel zur Unterstützung der Rückansicht Kamera- und Surround-View-Displays in Fahrzeugen mit Android-basierten In-Vehicle Infotainmentsysteme (IVI) EVS ermöglicht auch die Implementierung erweiterter Funktionen in Nutzer-Apps.

Android verfügt außerdem über einen EVS-spezifischen Capture- und Display-Treiber. Schnittstelle (in /hardware/interfaces/automotive/evs/1.0). Während es um auf bestehenden Android-Geräten eine Rückkamera-App Kamera- und Displaydienste verwenden, würde eine solche App wahrscheinlich zu spät um den Android-Bootvorgang zu starten. Die Verwendung eines dedizierten HAL ermöglicht eine optimierte Schnittstelle. und macht deutlich, was ein OEM implementieren muss, um den EVS-Stack zu unterstützen.

Systemkomponenten

EVS enthält die folgenden Systemkomponenten:

EVS-System
Komponentendiagramm
Abbildung 1: Übersicht über die EVS-Systemkomponenten

EVS App

C++ EVS-Beispielanwendung (/packages/services/Car/evs/app) dient als Referenz Implementierung. Diese App ist für die Anforderung von Videoframes von und die fertigen Frames zur Anzeige an den EVS-Manager zurücksenden. Es wird voraussichtlich von init gestartet, sobald EVS und Car Service verfügbar sind. innerhalb von zwei (2) Sekunden nach dem Einschalten ausgerichtet ist. OEMs können EVS modifizieren oder ersetzen. wie gewünscht.

EVS-Manager

Der EVS Manager (/packages/services/Car/evs/manager) liefert Bausteine einer EVS-App für die Implementierung von einfaches Rückkameradisplay und ein 6DOF-Multi-Kamera-Rendering. Benutzeroberfläche wird über HIDL dargestellt und ist darauf ausgelegt, mehrere Clients gleichzeitig zu akzeptieren. Andere Apps und Dienste (insbesondere CarService) können den EVS abfragen Managerstatus, um herauszufinden, wann das EVS-System aktiv ist.

EVS HIDL-Schnittstelle

Das EVS-System, sowohl die Kamera als auch die Anzeigeelemente, ist in der android.hardware.automotive.evs-Paket. Eine Beispielimplementierung das die Benutzeroberfläche ausführt (generiert synthetische Testbilder und validiert die Bilder für den Hin- und Rückflug) wird in /hardware/interfaces/automotive/evs/1.0/default

Der OEM ist für die Implementierung der API verantwortlich, die durch die .hal-Dateien ausgedrückt wird. in „/hardware/interfaces/automotive/evs“. Solche Implementierungen sind für die Konfiguration und Erhebung von Daten von physischen Kameras und Puffer für gemeinsamen Arbeitsspeicher, die Gralloc erkennen kann. Das Display Implementierung einen Zwischenspeicher für gemeinsamen Arbeitsspeicher das von der App gefüllt und präsentiert werden kann (normalerweise mit EGL-Rendering) die fertigen Frames und anderen Elementen, die auf das physische Display. Anbieterimplementierungen der EVS-Schnittstelle können unter Umständen unter /vendor/… /device/… oder hardware/… (z.B. /hardware/[vendor]/[platform]/evs.

Kernel-Treiber

Für ein Gerät, das den EVS-Stack unterstützt, sind Kernel-Treiber erforderlich. Anstelle von haben OEMs die Möglichkeit, Funktionen, die für Elektrofahrzeuge erforderlich sind, über vorhandene Kamera- oder Display-Hardwaretreiber. Die Wiederverwendung von Fahrern insbesondere für Displaytreiber, bei denen die Bildpräsentation eine Koordination mit anderen aktiven Threads erfordern. Android 8.0 enthält eine auf Version 4l2 basierende Beispieltreiber (in packages/services/Car/evs/sampleDriver), der ist für v4l2-Unterstützung vom Kernel und für die Darstellung des Ausgabebild.

Beschreibung der EVS-Hardwareschnittstelle

Der Abschnitt beschreibt den HAL. Die Anbieter müssen -Implementierungen dieser API, die für ihre Hardware angepasst wurden.

IEvsEnumerator

Dieses Objekt ist für die Auflistung der verfügbaren EVS-Hardware im System (eine oder mehrere Kameras und ein Anzeigegerät)

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

Gibt einen Vektor zurück, der Beschreibungen für alle Kameras im System enthält. Es ist ging davon aus, dass die Kameras beim Hochfahren festgelegt und bekannt sind. Weitere Informationen zu Kamerabeschreibungen findest du unter CameraDesc.

openCamera(string camera_id) generates (IEvsCamera camera);

Ruft ein Interface-Objekt ab, das für die Interaktion mit einer bestimmten Kamera verwendet wird. camera_id-String enthalten. Gibt bei einem Fehler NULL zurück. Versuche, eine bereits geöffnete Kamera wieder zu öffnen, können nicht fehlschlagen. Um Rennen zu vermeiden Bedingungen im Zusammenhang mit dem Starten und Herunterfahren einer App und dem erneuten Öffnen einer Kamera sollte die vorherige Instanz heruntergefahren werden, damit die neue Anfrage ausgeführt werden kann. A Kamerainstanz, die auf diese Weise vorzeitig beendet wurde, muss in den inaktiven Status versetzt werden auf die endgültige Vernichtung warten und auf jede Anfrage zur Kamerastatus mit dem Rückgabecode OWNERSHIP_LOST.

closeCamera(IEvsCamera camera);

Gibt die IEvsCamera-Oberfläche frei (und ist das Gegenteil von openCamera()-Anruf). Der Videostream der Kamera muss durch Aufrufen von stopVideoStream() vor closeCamera beendet.

openDisplay() generates (IEvsDisplay display);

Ruft ein Interface-Objekt ab, das für die ausschließliche Interaktion mit dem EVS-Display. Nur ein Client kann eine funktionsfähige Instanz von IEvsDisplay unter . Ähnlich wie beim in openCamera beschriebenen aggressiven offenen Verhalten kann jederzeit ein neues IEvsDisplay-Objekt erstellt werden, wodurch alle vorherigen Instanzen. Ungültige Instanzen sind weiterhin vorhanden und reagieren auf Funktionsaufrufe von ihren Eigentümern erhalten, darf jedoch bei Inaktivität keine Änderungsvorgänge ausführen. Schließlich Die Client-App sollte den Fehler OWNERSHIP_LOST erkennen und die inaktive Schnittstelle schließen und freigeben.

closeDisplay(IEvsDisplay display);

Gibt die IEvsDisplay-Oberfläche frei (und ist das Gegenteil von openDisplay()-Anruf). Ausstehende Puffer erhalten mit getTargetBuffer()-Aufrufe müssen vor dem Schließen des Bildschirms.

getDisplayState() generates (DisplayState state);

Ruft den aktuellen Anzeigestatus ab. Die HAL-Implementierung sollte den des aktuellen Status angezeigt, der vom zuletzt angeforderten Status abweichen kann. Die Logik für das Ändern des Anzeigestatus sollte über dem Gerät vorhanden sein sodass die HAL-Implementierung nicht spontan geändert werden kann. Anzeigestatus. Wird das Display derzeit von keinem Kunden gehalten (durch einen Aufruf von openDisplay) eingeben, gibt diese Funktion NOT_OPEN zurück. Andernfalls werden sie meldet den aktuellen Status des EVS-Displays (siehe IEvsDisplay API).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id Ein String, der eine bestimmte Kamera eindeutig identifiziert. Dies kann der Name des Kernel-Geräts oder ein Name für das Gerät sein, z. B. rearview aus. Der Wert für diese Zeichenfolge wird von der HAL-Implementierung ausgewählt und wird vom obigen Stapel intransparent verwendet.
  • vendor_flags Methode zum Übergeben einer speziellen Kamera vom Fahrer bis hin zu einer speziellen EVS-App. Die Prüfung wurde bestanden vom Fahrer bis zur EVS-App übertragen, die Sie ignorieren können. .

IEvsCamera

Dieses Objekt stellt eine einzelne Kamera dar und ist die primäre Schnittstelle für zum Aufnehmen von Bildern.

getCameraInfo() generates (CameraDesc info);

Gibt CameraDesc dieser Kamera zurück.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

Gibt die Tiefe der Pufferkette an, die von der Kamera unterstützt werden soll. Bis zu kann der Client von IEvsCamera diese vielen Frames gleichzeitig halten. Wenn dieses wie viele Frames an den Empfänger geliefert wurden, ohne dass sie doneWithFrame, der Stream überspringt Frames, bis ein Zwischenspeicher zurückgegeben wird zur Wiederverwendung freigegeben werden. Es ist immer zulässig, diesen Anruf zu tätigen, auch wenn Streams bereits ausgeführt wird. In diesem Fall sollten Puffer in die Kette aufgenommen oder aus ihr entfernt werden. . Wenn kein Aufruf an diesen Einstiegspunkt erfolgt, unterstützt IEvsCamera den mindestens einen Frame; mit akzeptableren Antworten.

Wenn der angeforderte bufferCount nicht akzeptiert werden kann, gibt die Funktion BUFFER_NOT_AVAILABLE oder einen anderen relevanten Fehlercode. In diesem Fall Das System arbeitet weiterhin mit dem zuvor festgelegten Wert.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Fordert die Übermittlung von EVS-Kameraframes von dieser Kamera an. „IEvsCameraStream“ beginnt regelmäßige Aufrufe mit neuen Bildframes zu empfangen, bis stopVideoStream() wird aufgerufen. Die Übermittlung der Frames muss beginnen innerhalb von 500 ms nach dem startVideoStream-Aufruf und nach dem Start muss mindestens 10 fps generiert werden. Die zum Starten des Videostreams erforderliche Zeit wird effektiv auf die erforderliche Startzeit der Rückkamera angerechnet. Wenn die Stream nicht gestartet wird, muss ein Fehlercode zurückgegeben werden. Andernfalls wird „OK“ zurückgegeben.

oneway doneWithFrame(BufferDesc buffer);

Gibt einen Frame zurück, der über IEvsCameraStream bereitgestellt wurde. Wenn Sie fertig sind die einen an die IEvsCameraStream-Schnittstelle gelieferten Frame verbraucht, muss der Frame zur Wiederverwendung an „IEvsCamera“ zurückgegeben. Eine kleine, endliche Anzahl von Puffern verfügbar (möglicherweise auch nur eins) und wenn der Vorrat erschöpft ist, werden keine weiteren werden so lange geliefert, bis ein Puffer zurückgegeben wird. Dies kann dazu führen, übersprungen. Ein Puffer mit einem Null-Ziehpunkt kennzeichnet das Ende eines Streams und nicht über diese Funktion zurückgegeben werden. Gibt im Erfolgsfall OK zurück oder Entsprechender Fehlercode, möglicherweise einschließlich INVALID_ARG oder BUFFER_NOT_AVAILABLE.

stopVideoStream();

Beendet die Bereitstellung von EVS-Kameraframes. Da die Übermittlung asynchron ist, Auch nach der Rückkehr dieses Aufrufs können noch einige Zeit Frames eintreffen. Jeder Frame zurückgegeben werden, bis die Schließung des Streams dem IEvsCameraStream. Der Anruf bei stopVideoStream per Stream ist legal die bereits angehalten oder nie gestartet wurde. In diesem Fall wird sie ignoriert.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

Fordert treiberspezifische Informationen aus der HAL-Implementierung an. Werte zulässigen opaqueIdentifier sind treiberspezifisch, aber kein Wert bestanden wurde, kann den Fahrer zum Absturz bringen. Der Treiber sollte 0 für alle nicht erkannten opaqueIdentifier

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

Sendet einen treiberspezifischen Wert an die HAL-Implementierung. Diese Erweiterung ist werden nur bereitgestellt, um fahrzeugspezifische Erweiterungen und ohne HAL zu ermöglichen. -Implementierung erfordert, dass dieser Aufruf in einem Standardzustand funktioniert. Wenn die Treiber erkennt und akzeptiert, sollte OK zurückgegeben werden. sonst Es sollte INVALID_ARG oder ein anderer repräsentativer Fehlercode zurückgegeben werden.

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
}

Beschreibt ein über die API übergebenes Bild. Das HAL-Laufwerk ist für die folgende Struktur ausfüllen, um den Image-Zwischenspeicher und den HAL-Client zu beschreiben diese Struktur als schreibgeschützt behandeln. Die Felder enthalten genügend Informationen damit der Client ein ANativeWindowBuffer-Objekt rekonstruieren kann, Dies kann erforderlich sein, um das Bild mit EGL mit dem eglCreateImageKHR().

  • width Die Breite des dargestellten Bilds in Pixeln.
  • height Die Höhe des dargestellten Bilds in Pixeln.
  • stride Anzahl der Pixel, die jede Zeile im Speicher tatsächlich belegt unter Berücksichtigung von Abständen für die Ausrichtung der Zeilen. Ausgedrückt in passenden Pixeln der Konvention, die Gralloc für ihre Pufferbeschreibungen angewandt hat.
  • pixelSize Anzahl der von jedem einzelnen Pixel belegten Byte mit der die Berechnung der Größe in Byte ermöglicht wird, die für den Wechsel zwischen den Zeilen im Bild (stride in Byte = stride in Pixeln * pixelSize.
  • format Das vom Bild verwendete Pixelformat. Das angegebene Format muss mit der OpenGL-Implementierung der Plattform kompatibel sein. Um die Prüfung zu bestehen Kompatibilitätstest, HAL_PIXEL_FORMAT_YCRCB_420_SP sollte wird für die Kamera bevorzugt. RGBA oder BGRA sollte für die Anzeige bevorzugt werden.
  • usage Von der HAL-Implementierung festgelegte Nutzungs-Flags. HAL-Clients diese unverändert übergeben werden (Details finden Sie Gralloc.h ähnliche Flags).
  • bufferId Ein eindeutiger Wert, der von der HAL-Implementierung für ermöglichen die Erkennung eines Zwischenspeichers nach einem Umlauf durch die HAL APIs. Die , der in diesem Feld gespeichert ist, kann von der HAL-Implementierung willkürlich gewählt werden.
  • memHandle Der Handle für den zugrunde liegenden Zwischenspeicher die Bilddaten enthält. Die HAL-Implementierung kann entscheiden, eine Gralloc Puffergriff ein.

IEvsCameraStream

Der Client implementiert diese Schnittstelle, um asynchrone Videoframes zu empfangen. Lieferungen.

deliverFrame(BufferDesc buffer);

Erhält jedes Mal Aufrufe vom HAL, wenn ein Videoframe zur Prüfung bereit ist. Von dieser Methode empfangene Zwischenspeicher-Handles müssen über Aufrufe an IEvsCamera::doneWithFrame() Wenn der Videostream mit einer Aufruf von IEvsCamera::stopVideoStream(), dieser Callback wird möglicherweise fortgesetzt wenn sich die Pipeline entleert. Jeder Frame muss trotzdem zurückgegeben werden. wenn der letzte Frame im Stream übergeben wurden, wird ein NULL-bufferHandle-Wert geliefert, das das Ende des Streams angibt und keine weiteren Frame-Lieferungen erfolgen. Der NULL-Wert bufferHandle selbst muss nicht mit doneWithFrame(), aber alle anderen Aliasse müssen zurückgegeben werden.

Obwohl proprietäre Pufferformate technisch möglich sind, Für das Testen muss der Puffer in einem der vier unterstützten Formate vorliegen: NV21 (YCrCb) 4:2:0 Halbplanar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 verschachtelt), RGBA (32-Bit R:G:B:x), BGRA (32-Bit B:G:R:x). Das ausgewählte Format muss ein gültiges Format sein GL-Texturquelle in der GLES-Implementierung der Plattform

Die App sollte sich nicht auf irgendeine Korrespondenz verlassen. zwischen dem Feld bufferId und dem memHandle in der BufferDesc-Struktur. Die bufferId-Werte sind ist im Grunde privat in der HAL-Treiberimplementierung und kann verwendet (und wiederverwendet) wenn es für Sie passt.

Internet Explorer Display

Dieses Objekt stellt die Evs-Anzeige dar, steuert den Anzeigestatus, und übernimmt die eigentliche Präsentation der Bilder.

getDisplayInfo() generates (DisplayDesc info);

Gibt grundlegende Informationen über den vom System bereitgestellten EVS-Bildschirm zurück (siehe DisplayDesc).

setDisplayState(DisplayState state) generates (EvsResult result);

Legt den Anzeigestatus fest. Kunden können den Anzeigestatus so einstellen, dass und die HAL-Implementierung muss eine Anfrage für in einem anderen Zustand angezeigt werden, obwohl die Antwort möglicherweise darin besteht,

Bei der Initialisierung ist festgelegt, dass die Anzeige im NOT_VISIBLE-Status, nach dem der Client voraussichtlich eine Anfrage stellt VISIBLE_ON_NEXT_FRAME und beginnen Sie mit der Bereitstellung des Videos. Wenn der Parameter Display nicht mehr erforderlich ist, wird erwartet, dass der Client NOT_VISIBLE nach dem Übergeben des letzten Videoframes.

Sie kann jederzeit von jedem Bundesstaat angefordert werden. Wenn das Display bereits sichtbar ist, sollte sie sichtbar bleiben, wenn auf VISIBLE_ON_NEXT_FRAME Gibt immer „OK“ zurück, es sei denn, der angeforderte Status ist ein nicht erkannter enum-Wert. In diesem Fall ist INVALID_ARG zurückgegeben.

getDisplayState() generates (DisplayState state);

Ruft den Anzeigestatus ab. Die HAL-Implementierung sollte den tatsächlichen aktueller Status, der sich vom zuletzt angeforderten Status unterscheiden kann. Die Eine Logik für das Ändern des Anzeigestatus muss über dem Gerät vorhanden sein. sodass die HAL-Implementierung nicht spontan geändert werden kann. Anzeigestatus.

getTargetBuffer() generates (handle bufferHandle);

Gibt ein Handle auf einen Frame-Zwischenspeicher zurück, der der Anzeige zugeordnet ist. Dieser Zwischenspeicher können durch Software und/oder GL gesperrt und in sie geschrieben werden. Dieser Zwischenspeicher muss zurückgegeben werden mit einem Aufruf von returnTargetBufferForDisplay(), auch wenn das Display nicht mehr sichtbar.

Während proprietäre Pufferformate technisch möglich sind, erfordert, dass der Puffer in einem der vier unterstützten Formate vorliegt: NV21 (YCrCb 4:2:0) Halbplanar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 verschachtelt), RGBA (32-Bit R:G:B:x), BGRA (32-Bit B:G:R:x). Das ausgewählte Format muss eine gültige GL sein Renderingziel in der GLES-Implementierung der Plattform.

Bei einem Fehler wird ein Puffer mit einem Null-Handle zurückgegeben. müssen an returnTargetBufferForDisplay zurückgegeben werden.

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Teilt dem Display mit, dass der Zwischenspeicher bereit zur Anzeige ist. Nur Zwischenspeicher abgerufen die über einen Aufruf von getTargetBuffer() erstellt wurden, können mit diesem aufrufen, und der Inhalt der BufferDesc darf nicht durch den Client-App. Nach diesem Aufruf ist der Zwischenspeicher nicht mehr gültig für Kundschaft. Gibt im Erfolgsfall OK zurück. Möglicherweise wird der entsprechende Fehlercode zurückgegeben. einschließlich INVALID_ARG oder BUFFER_NOT_AVAILABLE.

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

Beschreibt die grundlegenden Eigenschaften eines EVS-Displays, die von einem EVS benötigt werden. Implementierung. Der HAL ist für das Ausfüllen dieser Struktur EVS-Display beschreiben. Es kann sich um eine physische oder virtuelle Anzeige handeln, als Overlay oder Kombination mit einem anderen Präsentationsgerät.

  • display_id Ein String, der den Bildschirm eindeutig identifiziert. Dies kann der Name des Kernel-Geräts oder ein Name für das Gerät sein. wie Rückansicht. Der Wert für diese Zeichenfolge wird vom HAL ausgewählt Implementierung und wird vom obigen Stapel intransparent verwendet.
  • vendor_flags Methode zum Übergeben einer speziellen Kamera vom Fahrer bis zur eigenen EVS-App undurchsichtig. Die Prüfung wurde bestanden vom Fahrer bis zur EVS-App übertragen, die Sie ignorieren können. .
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
}

Beschreibt den Status des EVS-Displays, der deaktiviert werden kann, nicht aktiviert, d. h. ein Bild für den Fahrer, angezeigt. Enthält einen vorübergehenden Status, bei dem die Anzeige noch nicht sichtbar ist, aber vorbereitet ist mit der Lieferung des nächsten Bild-Frames mit dem returnTargetBufferForDisplay() Anruf.

EVS-Manager

Der EVS Manager bietet die öffentliche Schnittstelle zum EVS-System für Erfassen und Präsentieren von Ansichten von externen Kameras. Wo Hardwaretreiber es erlauben nur eine aktive Schnittstelle pro Ressource (Kamera oder Display), verwendet der EVS Manager den gemeinsamen Zugriff auf die Kameras ermöglichen. Eine einzige primäre EVS-App ist der erste Client des EVS Manager und ist der einzige Client, der Anzeigedaten (zusätzlichen Clients kann Lesezugriff auf die Kamera gewährt werden Bilder).

Der EVS Manager implementiert dieselbe API wie die zugrunde liegenden HAL-Treiber und bietet erweiterten Service, indem mehrere Clients gleichzeitig unterstützt werden (mehr als Ein Kunde kann eine Kamera über den EVS Manager öffnen und ein Video Stream).

<ph type="x-smartling-placeholder">
</ph> EVS-Manager und
Diagramm der EVS Hardware API
Abbildung 2: EVS Manager spiegelt den zugrunde liegenden EVS wider Hardware API

Apps erkennen keine Unterschiede, wenn sie über den EVS-Hardware-HAL ausgeführt werden oder die EVS Manager API, außer dass die EVS Manager API die gleichzeitigen Zugriff auf den Kamerastream. Der EVS-Manager selbst ist derjenige, der Client der EVS-Hardware-HAL-Schicht und agiert als Proxy für die EVS-Hardware HAL.

In den folgenden Abschnitten werden nur die Aufrufe beschrieben, die eine andere (erweitertes) Verhalten in der EVS Manager-Implementierung; verbleibende Anrufe sind sind mit den EVS HAL-Beschreibungen identisch.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Ruft ein Interface-Objekt ab, das für die Interaktion mit einer bestimmten Kamera verwendet wird. camera_id-String enthalten. Gibt bei einem Fehler NULL zurück. Auf der EVS Manager-Ebene, solange genügend Systemressourcen verfügbar sind, kann eine bereits geöffnete Kamera durch einen anderen Prozess wieder geöffnet werden, Ausrichtung des Videostreams auf mehrere Nutzer-Apps. Die camera_id-Strings auf EVS Manager-Ebene sind identisch mit denen an die EVS-Hardwareschicht gemeldet.

IEvsCamera

Die vom EVS Manager bereitgestellte IEvsCamera-Implementierung ist intern virtualisiert. So wirken sich Vorgänge auf einer Kamera durch einen Client nicht auf andere Clients aus. und haben weiterhin unabhängigen Zugriff auf ihre Kameras.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Startet Videostreams. Clients können Videostreams unabhängig starten und stoppen. auf derselben zugrunde liegenden Kamera. Die zugrunde liegende Kamera startet, wenn die erste die Kundschaft beginnt.

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

Gibt einen Frame zurück. Jeder Client muss seine Frames zurückgeben, wenn sie fertig sind. dürfen ihren Rahmen so lange halten, wie sie es wünschen. Wenn der Parameter die von einem Client gehaltene Frame-Anzahl erreicht hat, erhält er keine bis ein Frame zurückgegeben wird. Das Überspringen dieses Frames wirkt sich nicht auf andere die weiterhin erwartungsgemäß alle Frames empfangen.

stopVideoStream();

Stoppt einen Video-Stream. Jeder Client kann seinen Videostream jederzeit beenden, die andere Kundschaft betreffen. Der zugrunde liegende Kamerastream auf der Hardwareschicht Wird beendet, wenn der letzte Client einer bestimmten Kamera den Stream beendet.

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

Sendet einen treiberspezifischen Wert, der möglicherweise einem Kunden die Möglichkeit gibt, einen anderen Client. Weil der EVS-Manager die Auswirkungen von herstellerdefinierte Steuerwörter, sie sind nicht virtualisiert, für alle Kunden einer bestimmten Kamera gelten. Wenn ein Anbieter diesen Aufruf z. B. verwendet hat, würden alle Clients der betroffenen Hardware-Kamera Frames mit der neuen Rate empfangen.

Internet Explorer Display

Es ist nur ein Inhaber des Displays zulässig, auch auf EVS Manager-Ebene. Die Manager bietet keine Funktionalität und übergibt lediglich die IEvsDisplay-Oberfläche. direkt zur zugrunde liegenden HAL-Implementierung weiterleiten.

EVS App

Android enthält eine native C++-Referenzimplementierung eines EVS. App, die mit dem EVS-Manager und dem Fahrzeug-HAL kommuniziert, bieten grundlegende Funktionen der Rückkamera. Die App wird voraussichtlich gestartet sehr früh im Systemstartprozess. Je nach die verfügbaren Kameras und den Zustand des Autos (Zahnrad- und Blinkerstatus). OEMs können die EVS-App durch eigene fahrzeugspezifische Logik und Präsentation.

Abbildung 3: EVS-App-Beispiellogik, Kamera abrufen Liste.


Abbildung 4: EVS-App-Beispiellogik, empfangen Frame-Callback.

Weil die Bilddaten in einer Standardgrafik Zwischenspeichern, ist die Anwendung dafür zuständig, das Bild aus der Quelle Ausgabepuffer. Dies bringt zwar Kosten für eine Datenkopie mit sich, Es bietet der App auch die Möglichkeit, das Bild in den kann der Zwischenspeicher beliebig dargestellt werden.

Beispielsweise kann die App die Pixeldaten selbst verschieben, mit Inline-Skalierung oder Rotation. Die App könnte das Quellbild auch als OpenGL-Textur verwenden und ein komplexes Ausgabepuffer einschließlich virtueller Elemente wie Symbole, Richtlinien und Animationen. Eine komplexere App kann auch mehrere Kameras gleichzeitig verwenden und zu einem einzigen Ausgabe-Frame zusammenführen (z. B. in einer virtuellen Draufsicht der Fahrzeugumgebung).

EGL/SurfaceFlinger im EVS-Display-HAL verwenden

In diesem Abschnitt wird erläutert, wie Sie mit EGL eine EVS-Display-HAL-Implementierung rendern können. für Android 10.

Ein EVS HAL-Referenzimplementierung verwendet EGL zum Rendern der Kameravorschau auf und verwendet libgui um die Ziel-EGL-Renderingoberfläche zu erstellen. Ab Android 8: libgui als VNDK-privat klassifiziert ist, das sich auf eine Gruppe von Bibliotheken bezieht, die für VNDK-Bibliotheken verfügbar sind, die von Anbieterprozessen nicht verwendet werden können. Da sich HAL-Implementierungen in der Anbieterpartition befinden müssen, wird verhindert, dass Anbieter Oberfläche in HAL-Implementierungen

Libgui für Anbieterprozesse erstellen

Die Verwendung von libgui ist die einzige Option für die Nutzung von EGL/SurfaceFlinger in EVS-Display-HAL-Implementierungen. Die einfachste Methode zur Implementierung von libgui ist bis frameworks/native/libs/gui indem Sie ein zusätzliches Build-Ziel im Build-Skript verwenden. Dieses Ziel ist identisch mit dem Ziel libgui, mit Ausnahme der Hinzufügung von zwei Feldern:

  • 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", ], …

Hinweis: Anbieterziele werden mit dem NO_INPUT-Makro erstellt, mit dem ein 32-Bit-Wort aus den Paketdaten entfernt wird. Da SurfaceFlinger davon ausgeht, dass dieses Feld entfernt wurde, kann SurfaceFlinger das Paket nicht parsen. Dies wird als fcntl-Fehler beobachtet:

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

So beheben Sie dieses Problem:

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);

Beispiel-Build finden Sie unten. Sie erhalten eine $(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

Binder in der EVS HAL-Implementierung verwenden

In Android 8 (und höher) wurde der /dev/binder-Geräteknoten exklusiv für Framework-Prozessen und daher für Zulieferunternehmen nicht zugänglich. Stattdessen Anbieterprozesse sollten /dev/hwbinder verwenden und alle AIDL-Schnittstellen konvertieren zu HIDL. Wenn Sie weiterhin AIDL-Schnittstellen zwischen Anbieterprozessen verwenden möchten, Verwenden Sie die Binder-Domain /dev/vndbinder.

IPC-Domain Beschreibung
/dev/binder IPC zwischen Framework-/App-Prozessen mit AIDL-Schnittstellen
/dev/hwbinder IPC zwischen Framework-/Anbieterprozessen mit HIDL-Schnittstellen
IPC zwischen Anbieterprozessen mit HIDL-Schnittstellen
/dev/vndbinder IPC zwischen Anbieter-/Anbieterprozessen mit AIDL Interfaces

SurfaceFlinger definiert AIDL-Schnittstellen, aber Prozesse von Anbietern können nur HIDL-Schnittstellen verwenden, um mit Framework-Prozessen kommunizieren. Ein nicht unwesentlicher Aufwand ist erforderlich, um bestehende AIDL verbindet sich in HIDL. Glücklicherweise bietet Android eine Methode, mit der der Binder ausgewählt werden kann. Treiber für libbinder, mit dem die Prozesse der Userspace-Bibliothek verknüpft sind.

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));

Hinweis: Dieser Aufruf sollte bei den Prozessen des Anbieters erfolgen, bevor die Anfrage an Process oder IPCThreadState oder vor Binder-Aufrufen.

SELinux-Richtlinien

Beträgt die Geräteimplementierung volle Höhen, verhindert SELinux den Anbieter Prozesse aus der Verwendung von /dev/binder. Beispiel: Ein EVS HAL-Beispiel Die Implementierung ist der Domain hal_evs_driver zugewiesen und erfordert Nutzerberechtigungen für die Domain 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

Das Hinzufügen dieser Berechtigungen führt jedoch zu einem Build-Fehler, da dies gegen die folgenden „Niezulassen“-Regeln, die in system/sepolicy/domain.te für ein Gerät mit vollen Höhen definiert wurden.

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 ist ein Attribut, das bereitgestellt wird, um einen Fehler zu erkennen und die Entwicklung zu unterstützen. Es kann auch verwendet werden, um den oben beschriebenen Android 10-Verstoß beheben.

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)

EVS HAL-Referenzimplementierung als Anbieterprozess erstellen

Als Referenz können Sie die folgenden Änderungen auf packages/services/Car/evs/Android.mk Achten Sie darauf, dass alle beschriebenen Änderungen für Ihre Implementierung funktionieren.

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;