Google 致力于为黑人社区推动种族平等。查看具体举措
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Telecamera per veicoli HAL

Android contiene un HIDL Hardware Abstraction Layer (HAL) automobilistico che fornisce l'acquisizione e la visualizzazione delle immagini nelle prime fasi del processo di avvio di Android e continua a funzionare per la vita del sistema. L'HAL include lo stack del sistema di visualizzazione esterna (EVS) e viene generalmente utilizzato per supportare la telecamera di retrovisione e i display di visualizzazione surround nei veicoli con sistemi di infotainment in-veicolo (IVI) basati su Android. EVS consente inoltre di implementare funzionalità avanzate nelle applicazioni utente.

Android include anche un'interfaccia driver di visualizzazione e acquisizione specifica per EVS (in /hardware/interfaces/automotive/evs/1.0 ). Sebbene sia possibile creare un'applicazione per telecamera posteriore sulla fotocamera Android esistente e sui servizi di visualizzazione, tale applicazione verrebbe probabilmente eseguita troppo tardi nel processo di avvio di Android. L'utilizzo di un HAL dedicato consente un'interfaccia semplificata e chiarisce ciò che un OEM deve implementare per supportare lo stack EVS.

Componenti del sistema

EVS include i seguenti componenti di sistema:

Schema dei componenti del sistema EVS.
Figura 1. Panoramica dei componenti del sistema EVS.

Applicazione SVE

Un'applicazione EVS C ++ di esempio ( /packages/services/Car/evs/app ) funge da implementazione di riferimento. Questa applicazione è responsabile della richiesta di fotogrammi video da EVS Manager e dell'invio di fotogrammi finiti per la visualizzazione a EVS Manager. Si aspetta di essere avviato da init non appena EVS e Car Service saranno disponibili, mirati entro due (2) secondi dall'accensione. Gli OEM possono modificare o sostituire l'applicazione EVS come desiderato.

Responsabile SVE

Il gestore EVS ( /packages/services/Car/evs/manager ) fornisce gli elementi costitutivi necessari a un'applicazione EVS per implementare qualsiasi cosa, da un semplice display di telecamera per retrovisione a un rendering multi-camera 6DOF. La sua interfaccia è presentata tramite HIDL ed è progettata per accettare più client simultanei. Altre applicazioni e servizi (in particolare il servizio auto) possono interrogare lo stato del gestore EVS per scoprire quando il sistema EVS è attivo.

Interfaccia EVS HIDL

Il sistema EVS, sia la fotocamera che gli elementi del display, è definito nel pacchetto android.hardware.automotive.evs . Un'implementazione di esempio che esercita l'interfaccia (genera immagini di test sintetiche e convalida le immagini per il round trip) è fornita in /hardware/interfaces/automotive/evs/1.0/default .

L'OEM è responsabile dell'implementazione dell'API espressa dai file .hal in /hardware/interfaces/automotive/evs . Tali implementazioni sono responsabili della configurazione e della raccolta dei dati dalle telecamere fisiche e della loro distribuzione tramite buffer di memoria condivisa riconoscibili da Gralloc. Il lato di visualizzazione dell'implementazione è responsabile di fornire un buffer di memoria condiviso che può essere riempito dall'applicazione (di solito tramite rendering EGL) e di presentare i fotogrammi finiti rispetto a qualsiasi altra cosa che potrebbe voler apparire sul display fisico. Le implementazioni del fornitore dell'interfaccia EVS possono essere archiviate in /vendor/… /device/… o hardware/… (ad esempio, /hardware/[vendor]/[platform]/evs ).

Driver del kernel

Un dispositivo che supporta lo stack EVS richiede driver del kernel. Invece di creare nuovi driver, gli OEM hanno la possibilità di supportare le funzionalità richieste da EVS tramite i driver hardware della fotocamera e / o del display esistenti. Il riutilizzo dei driver potrebbe essere vantaggioso, soprattutto per i driver video in cui la presentazione dell'immagine potrebbe richiedere il coordinamento con altri thread attivi. Android 8.0 include un driver di esempio basato su v4l2 (in packages/services/Car/evs/sampleDriver ) che dipende dal kernel per il supporto v4l2 e da SurfaceFlinger per presentare l'immagine di output.

Descrizione dell'interfaccia hardware EVS

La sezione descrive l'HAL. I fornitori dovrebbero fornire implementazioni di questa API adattate per il loro hardware.

IEvsEnumerator

Questo oggetto è responsabile dell'enumerazione dell'hardware EVS disponibile nel sistema (una o più telecamere e il singolo dispositivo di visualizzazione).

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

Restituisce un vettore contenente le descrizioni per tutte le telecamere nel sistema. Si presume che il set di telecamere sia fisso e conoscibile al momento dell'avvio. Per i dettagli sulle descrizioni delle telecamere, vedere CameraDesc .

openCamera(string camera_id) generates (IEvsCamera camera);

Ottiene un oggetto interfaccia utilizzato per interagire con una telecamera specifica identificata dalla stringa camera_id univoca. Restituisce un NULL in caso di errore. I tentativi di riaprire una telecamera già aperta non possono fallire. Per evitare condizioni di competizione associate all'avvio e all'arresto dell'applicazione, la riapertura di una telecamera dovrebbe arrestare l'istanza precedente in modo che la nuova richiesta possa essere soddisfatta. Un'istanza della telecamera che è stata anticipata in questo modo deve essere messa in uno stato inattivo, in attesa della distruzione finale e rispondere a qualsiasi richiesta di influenzare lo stato della telecamera con un codice di ritorno OWNERSHIP_LOST .

closeCamera(IEvsCamera camera);

Rilascia l'interfaccia IEvsCamera (ed è l'opposto della chiamata openCamera() ). Il flusso video della telecamera deve essere interrotto chiamando stopVideoStream() prima di chiamare closeCamera .

openDisplay() generates (IEvsDisplay display);

Ottiene un oggetto interfaccia utilizzato per interagire esclusivamente con il display EVS del sistema. Solo un client alla volta può contenere un'istanza funzionale di IEvsDisplay. Simile al comportamento aggressivo di apertura descritto in openCamera , un nuovo oggetto IEvsDisplay può essere creato in qualsiasi momento e disabiliterà eventuali istanze precedenti. Le istanze non convalidate continuano a esistere e rispondono alle chiamate di funzione dei rispettivi proprietari, ma quando sono morte non devono eseguire operazioni di mutazione. Alla fine, l'applicazione client è prevista per notare i OWNERSHIP_LOST codici di ritorno di errore e chiudere e rilasciare l'interfaccia inattivo.

closeDisplay(IEvsDisplay display);

Rilascia l'interfaccia IEvsDisplay (ed è l'opposto della chiamata openDisplay() ). I buffer eccezionali ricevuti tramite chiamate getTargetBuffer() devono essere restituiti al display prima di chiudere il display.

getDisplayState() generates (DisplayState state);

Ottiene lo stato di visualizzazione corrente. L'implementazione di HAL dovrebbe riportare lo stato corrente effettivo, che potrebbe differire dallo stato richiesto più di recente. La logica responsabile della modifica degli stati di visualizzazione dovrebbe esistere sopra il livello del dispositivo, rendendo indesiderabile che l'implementazione di HAL cambi spontaneamente gli stati di visualizzazione. Se il display non è attualmente detenuto da alcun client (da una chiamata a openDisplay), questa funzione restituisce NOT_OPEN . In caso contrario, segnala lo stato corrente del display EVS (vedere API IEvsDisplay ).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id . Una stringa che identifica in modo univoco una determinata telecamera. Può essere il nome del dispositivo kernel del dispositivo o un nome per il dispositivo, ad esempio rearview . Il valore di questa stringa viene scelto dall'implementazione di HAL e utilizzato in modo opaco dallo stack precedente.
  • vendor_flags . Un metodo per passare in modo opaco le informazioni specializzate della telecamera dal conducente a un'applicazione EVS personalizzata. Viene passato senza interpretazioni dal driver fino all'applicazione EVS, che è libera di ignorarlo.

IEvsCamera

Questo oggetto rappresenta una singola telecamera ed è l'interfaccia principale per l'acquisizione di immagini.

getCameraInfo() generates (CameraDesc info);

Restituisce CameraDesc di questa fotocamera.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

Specifica la profondità della catena del buffer che la telecamera deve supportare. Fino a questo numero di frame possono essere conservati contemporaneamente dal client di IEvsCamera. Se questo numero di frame è stato consegnato al ricevitore senza essere restituito da doneWithFrame , il flusso salta i frame finché non viene restituito un buffer per il riutilizzo. È legale che questa chiamata arrivi in ​​qualsiasi momento, anche mentre i flussi sono già in esecuzione, nel qual caso i buffer dovrebbero essere aggiunti o rimossi dalla catena come appropriato. Se non viene effettuata alcuna chiamata a questo punto di ingresso, IEvsCamera supporta almeno un fotogramma per impostazione predefinita; con più accettabile.

Se il bufferCount richiesto non può essere soddisfatto, la funzione restituisce BUFFER_NOT_AVAILABLE o un altro codice di errore pertinente. In questo caso il sistema continua a funzionare con il valore precedentemente impostato.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Richiede la consegna dei fotogrammi della telecamera SVE da questa telecamera. IEvsCameraStream inizia a ricevere chiamate periodiche con nuovi fotogrammi dell'immagine finché stopVideoStream() viene chiamato stopVideoStream() . I frame devono iniziare a essere consegnati entro 500 ms dalla chiamata startVideoStream e, dopo l'avvio, devono essere generati a un minimo di 10 FPS. Il tempo necessario per avviare il flusso video viene effettivamente considerato rispetto a qualsiasi requisito di tempo di avvio della telecamera di visione posteriore. Se il flusso non viene avviato, deve essere restituito un codice di errore; altrimenti viene restituito OK.

oneway doneWithFrame(BufferDesc buffer);

Restituisce un fotogramma consegnato da a IEvsCameraStream. Al termine dell'utilizzo di un fotogramma consegnato all'interfaccia IEvsCameraStream, il fotogramma deve essere restituito a IEvsCamera per il riutilizzo. È disponibile un numero limitato e finito di buffer (possibilmente anche solo uno) e, se la fornitura è esaurita, non vengono consegnati ulteriori frame fino a quando non viene restituito un buffer, con il risultato di potenziali frame saltati (un buffer con un handle nullo indica la fine di un flusso e non necessita di essere restituito tramite questa funzione). Restituisce OK in caso di successo o un codice di errore appropriato che include potenzialmente INVALID_ARG o BUFFER_NOT_AVAILABLE .

stopVideoStream();

Interrompe la consegna dei fotogrammi delle telecamere SVE. Poiché la consegna è asincrona, i frame potrebbero continuare ad arrivare per un po 'di tempo dopo il ritorno di questa chiamata. Ogni frame deve essere restituito fino a quando la chiusura del flusso non viene segnalata a IEvsCameraStream. È legale chiamare stopVideoStream su uno stream che è già stato interrotto o non è mai stato avviato, nel qual caso viene ignorato.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

Richiede informazioni specifiche sul driver dall'implementazione di HAL. I valori consentiti per opaqueIdentifier sono specifici del driver, ma nessun valore passato potrebbe causare l'arresto anomalo del driver. Il driver dovrebbe restituire 0 per ogni opaqueIdentifier non opaqueIdentifier .

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

Invia un valore specifico del driver all'implementazione di HAL. Questa estensione viene fornita solo per facilitare estensioni specifiche del veicolo e nessuna implementazione di HAL dovrebbe richiedere che questa chiamata funzioni in uno stato predefinito. Se il driver riconosce e accetta i valori, dovrebbe essere restituito OK; altrimenti INVALID_ARG o un altro codice di errore rappresentativo dovrebbe essere restituito.

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
}

Descrive un'immagine passata attraverso l'API. L'unità HAL è responsabile della compilazione di questa struttura per descrivere il buffer dell'immagine e il client HAL dovrebbe trattare questa struttura come di sola lettura. I campi contengono informazioni sufficienti per consentire al client di ricostruire un oggetto ANativeWindowBuffer , come potrebbe essere richiesto per utilizzare l'immagine con EGL tramite l'estensione eglCreateImageKHR() .

  • width . La larghezza in pixel dell'immagine presentata.
  • height . L'altezza in pixel dell'immagine presentata.
  • stride . Numero di pixel che ciascuna riga occupa effettivamente in memoria, tenendo conto dell'eventuale riempimento per l'allineamento delle righe. Espresso in pixel per corrispondere alla convenzione adottata da gralloc per le sue descrizioni del buffer.
  • pixelSize . Numero di byte occupati da ogni singolo pixel, che consente il calcolo della dimensione in byte necessaria per spostarsi tra le righe dell'immagine ( stride in byte = stride in pixel * pixelSize ).
  • format . Il formato pixel utilizzato dall'immagine. Il formato fornito deve essere compatibile con l'implementazione OpenGL della piattaforma. Per superare i test di compatibilità, HAL_PIXEL_FORMAT_YCRCB_420_SP dovrebbe essere preferito per l'utilizzo della fotocamera e RGBA o BGRA dovrebbe essere preferito per la visualizzazione.
  • usage . Flag di utilizzo impostati dall'implementazione di HAL. I client HAL dovrebbero passare questi non modificati (per i dettagli, fare riferimento ai Gralloc.h correlati a Gralloc.h ).
  • bufferId . Un valore univoco specificato dall'implementazione HAL per consentire il riconoscimento di un buffer dopo un round trip tramite le API HAL. Il valore memorizzato in questo campo può essere scelto arbitrariamente dall'implementazione di HAL.
  • memHandle . L'handle per il buffer di memoria sottostante che contiene i dati dell'immagine. L'implementazione di HAL potrebbe scegliere di memorizzare un handle di buffer Gralloc qui.

IEvsCameraStream

Il client implementa questa interfaccia per ricevere consegne di frame video asincrone.

deliverFrame(BufferDesc buffer);

Riceve le chiamate dall'HAL ogni volta che un fotogramma video è pronto per l'ispezione. Gli handle del buffer ricevuti da questo metodo devono essere restituiti tramite chiamate a IEvsCamera::doneWithFrame() . Quando il flusso video viene interrotto tramite una chiamata a IEvsCamera::stopVideoStream() , questo callback potrebbe continuare mentre la pipeline si esaurisce. Ogni frame deve comunque essere restituito; quando l'ultimo frame nello stream è stato consegnato, verrà consegnato un bufferHandle NULL, che indica la fine dello stream e non si verificano ulteriori consegne di frame. Il bufferHandle NULL stesso non deve essere restituito tramite doneWithFrame() , ma tutti gli altri handle devono essere restituiti

Sebbene i formati di buffer proprietari siano tecnicamente possibili, i test di compatibilità richiedono che il buffer sia in uno dei quattro formati supportati: NV21 (YCrCb 4: 2: 0 Semi-Planar), YV12 (YCrCb 4: 2: 0 Planar), YUYV (YCrCb 4: 2: 2 Interleaved), RGBA (32 bit R: G: B: x), BGRA (32 bit B: G: R: x). Il formato selezionato deve essere una fonte di texture GL valida nell'implementazione GLES della piattaforma.

L'applicazione non deve fare affidamento su alcuna corrispondenza tra il campo bufferId e memHandle nella struttura BufferDesc . I valori bufferId sono essenzialmente privati ​​per l'implementazione del driver HAL e può usarli (e riutilizzarli) come meglio crede.

IEvsDisplay

Questo oggetto rappresenta il display Evs, controlla lo stato del display e gestisce la presentazione effettiva delle immagini.

getDisplayInfo() generates (DisplayDesc info);

Restituisce le informazioni di base sulla visualizzazione EVS fornite dal sistema (vedere DisplayDesc ).

setDisplayState(DisplayState state) generates (EvsResult result);

Imposta lo stato di visualizzazione. I client possono impostare lo stato di visualizzazione per esprimere lo stato desiderato e l'implementazione di HAL deve accettare con garbo una richiesta per qualsiasi stato mentre si trova in qualsiasi altro stato, sebbene la risposta possa essere ignorare la richiesta.

All'inizializzazione, il display è definito per iniziare nello stato NOT_VISIBLE , dopodiché il client dovrebbe richiedere lo stato VISIBLE_ON_NEXT_FRAME e iniziare a fornire il video. Quando la visualizzazione non è più necessaria, il client dovrebbe richiedere lo stato NOT_VISIBLE dopo aver superato l'ultimo fotogramma video.

È valido per qualsiasi stato da richiedere in qualsiasi momento. Se il display è già visibile, dovrebbe rimanere visibile se impostato su VISIBLE_ON_NEXT_FRAME . Restituisce sempre OK a meno che lo stato richiesto non sia un valore enum non riconosciuto, nel qual caso viene restituito INVALID_ARG .

getDisplayState() generates (DisplayState state);

Ottiene lo stato di visualizzazione. L'implementazione di HAL dovrebbe riportare lo stato corrente effettivo, che potrebbe differire dallo stato richiesto più di recente. La logica responsabile della modifica degli stati di visualizzazione dovrebbe esistere al di sopra del livello del dispositivo, rendendo indesiderabile che l'implementazione di HAL cambi spontaneamente gli stati di visualizzazione.

getTargetBuffer() generates (handle bufferHandle);

Restituisce un handle a un frame buffer associato alla visualizzazione. Questo buffer può essere bloccato e scritto da software e / o GL. Questo buffer deve essere restituito tramite una chiamata a returnTargetBufferForDisplay() anche se la visualizzazione non è più visibile.

Sebbene i formati di buffer proprietari siano tecnicamente possibili, i test di compatibilità richiedono che il buffer sia in uno dei quattro formati supportati: NV21 (YCrCb 4: 2: 0 Semi-Planar), YV12 (YCrCb 4: 2: 0 Planar), YUYV (YCrCb 4: 2: 2 Interleaved), RGBA (32 bit R: G: B: x), BGRA (32 bit B: G: R: x). Il formato selezionato deve essere un target di rendering GL valido sull'implementazione GLES della piattaforma.

In caso di errore, viene restituito un buffer con un handle nullo, ma non è necessario restituirlo a returnTargetBufferForDisplay .

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Indica al display che il buffer è pronto per la visualizzazione. Solo i buffer recuperati tramite una chiamata a getTargetBuffer() sono validi per l'utilizzo con questa chiamata e il contenuto di BufferDesc non può essere modificato dall'applicazione client. Dopo questa chiamata, il buffer non è più valido per l'utilizzo da parte del client. Restituisce OK in caso di successo o un codice di errore appropriato che include potenzialmente INVALID_ARG o BUFFER_NOT_AVAILABLE .

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

Descrive le proprietà di base di un display EVS e richieste da un'implementazione EVS. L'HAL è responsabile della compilazione di questa struttura per descrivere il display SVE. Può essere un display fisico o virtuale sovrapposto o combinato con un altro dispositivo di presentazione.

  • display_id . Una stringa che identifica in modo univoco il display. Questo potrebbe essere il nome del dispositivo del kernel del dispositivo o un nome per il dispositivo, come "rearview". Il valore di questa stringa viene scelto dall'implementazione di HAL e utilizzato in modo opaco dallo stack precedente.
  • vendor_flags . Un metodo per passare in modo opaco le informazioni specializzate della telecamera dal conducente a un'applicazione EVS personalizzata. Viene passato senza essere interpretato dal driver fino all'applicazione EVS, che è libera di ignorarlo.
enum DisplayState : uint32 {
    NOT_OPEN,               // Display has not been “opened” yet
    NOT_VISIBLE,            // Display is inhibited
    VISIBLE_ON_NEXT_FRAME,  // Will become visible with next frame
    VISIBLE,                // Display is currently active
    DEAD,                   // Display is not available. Interface should be closed
}

Descrive lo stato del display EVS, che può essere disabilitato (non visibile al conducente) o abilitato (mostrando un'immagine al conducente). Include uno stato transitorio in cui il display non è ancora visibile ma è pronto per diventare visibile con la consegna del fotogramma successivo di immagini tramite la chiamata returnTargetBufferForDisplay() .

Responsabile SVE

Il Gestore EVS fornisce l'interfaccia pubblica al sistema SVE per raccogliere e presentare le viste della telecamera esterna. Laddove i driver hardware consentono una sola interfaccia attiva per risorsa (telecamera o display), EVS Manager facilita l'accesso condiviso alle telecamere. Una singola applicazione EVS primaria è il primo client di EVS Manager ed è l'unico client autorizzato a scrivere i dati di visualizzazione (ai client aggiuntivi può essere concesso l'accesso in sola lettura alle immagini della telecamera).

EVS Manager implementa la stessa API dei driver HAL sottostanti e fornisce un servizio esteso supportando più client simultanei (più client possono aprire una telecamera tramite EVS Manager e ricevere un flusso video).

Gestore EVS e diagramma API hardware EVS.
Figura 2. EVS Manager rispecchia l'API hardware EVS sottostante

Le applicazioni non vedono differenze quando operano tramite l'implementazione EVS Hardware HAL o l'API EVS Manager, tranne per il fatto che l'API EVS Manager consente l'accesso simultaneo al flusso della telecamera. Il gestore EVS è di per sé l'unico client consentito del livello HAL hardware EVS e funge da proxy per HAL hardware EVS.

Le sezioni seguenti descrivono solo le chiamate che hanno un comportamento diverso (esteso) nell'implementazione di EVS Manager; le chiamate rimanenti sono identiche alle descrizioni di EVS HAL.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Ottiene un oggetto interfaccia utilizzato per interagire con una telecamera specifica identificata dalla stringa camera_id univoca. Restituisce un NULL in caso di errore. A livello di EVS Manager, fintanto che sono disponibili risorse di sistema sufficienti, una telecamera già aperta può essere riaperta da un altro processo, consentendo il trasferimento del flusso video a più applicazioni consumer. Le stringhe camera_id al livello EVS Manager sono le stesse di quelle riportate al livello EVS Hardware.

IEvsCamera

Il gestore EVS fornito l'implementazione di IEvsCamera è virtualizzato internamente in modo che le operazioni su una telecamera da parte di un client non influiscano sugli altri client, che mantengono l'accesso indipendente alle loro telecamere.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Avvia i flussi video. I client possono avviare e interrompere indipendentemente i flussi video sulla stessa telecamera sottostante. La telecamera sottostante si avvia all'avvio del primo client.

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

Restituisce un frame. Ogni cliente deve restituire i propri fotogrammi quando hanno finito, ma è autorizzato a trattenerli per tutto il tempo che desidera. Quando il numero di frame trattenuto da un client raggiunge il limite configurato, non riceverà più frame finché non ne restituirà uno. Questo salto di frame non influisce sugli altri client, che continuano a ricevere tutti i frame come previsto.

stopVideoStream();

Interrompe un flusso video. Ogni client può interrompere il proprio flusso video in qualsiasi momento senza influire sugli altri client. Il flusso della telecamera sottostante a livello hardware viene interrotto quando l'ultimo client di una determinata telecamera interrompe il flusso.

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

Invia un valore specifico del driver, consentendo potenzialmente a un client di influenzare un altro client. Poiché EVS Manager non è in grado di comprendere le implicazioni delle parole di controllo definite dal fornitore, non vengono virtualizzate e gli effetti collaterali si applicano a tutti i client di una data telecamera. Ad esempio, se un fornitore ha utilizzato questa chiamata per modificare la frequenza dei fotogrammi, tutti i client della telecamera a livello hardware interessato riceveranno i fotogrammi alla nuova velocità.

IEvsDisplay

È consentito un solo proprietario del display, anche a livello di gestore EVS. Il Manager non aggiunge alcuna funzionalità e passa semplicemente l'interfaccia IEvsDisplay direttamente all'implementazione HAL sottostante.

Applicazione SVE

Android include un'implementazione di riferimento C ++ nativa di un'applicazione EVS che comunica con EVS Manager e Vehicle HAL per fornire funzioni di base della telecamera per la visione posteriore. L'applicazione dovrebbe essere avviata molto presto nel processo di avvio del sistema, con un video appropriato mostrato a seconda delle telecamere disponibili e dello stato dell'auto (marcia e stato degli indicatori di direzione). Gli OEM possono modificare o sostituire l'applicazione EVS con la propria logica e presentazione specifica per il veicolo.

Figura 3. Logica di esempio dell'applicazione EVS, ottenere l'elenco delle telecamere.


Figura 4. Logica di esempio dell'applicazione EVS, ricezione della richiamata del frame.

Poiché i dati dell'immagine vengono presentati all'applicazione in un buffer grafico standard, l'applicazione è responsabile dello spostamento dell'immagine dal buffer di origine al buffer di output. Sebbene ciò introduca il costo di una copia dei dati, offre anche l'opportunità all'applicazione di eseguire il rendering dell'immagine nel buffer di visualizzazione in qualsiasi modo desideri.

Ad esempio, l'applicazione può scegliere di spostare i dati dei pixel stessi, potenzialmente con un'operazione di scala o rotazione in linea. L'applicazione può anche scegliere di utilizzare l'immagine sorgente come texture OpenGL e di eseguire il rendering di una scena complessa nel buffer di output, inclusi elementi virtuali come icone, linee guida e animazioni. Un'applicazione più sofisticata può anche selezionare più telecamere di input simultanee e unirle in un unico frame di output (ad esempio per l'uso in una vista virtuale dall'alto verso il basso dei dintorni del veicolo).

Usa EGL / SurfaceFlinger nel display EVS HAL

Questa sezione spiega come utilizzare EGL per eseguire il rendering di un'implementazione HAL display EVS in Android 10.

Un'implementazione di riferimento HAL EVS utilizza EGL per eseguire il rendering dell'anteprima della telecamera sullo schermo e utilizza libgui per creare la superficie di rendering EGL di destinazione. In Android 8 (e versioni successive), libgui è classificato come VNDK-private , che si riferisce a un gruppo di librerie disponibili per le librerie VNDK che i processi del fornitore non possono utilizzare. Poiché le implementazioni di HAL devono risiedere nella partizione del fornitore, ai fornitori viene impedito di utilizzare Surface nelle implementazioni di HAL.

Creazione di libgui per i processi del fornitore

L'uso di libgui serve come unica opzione per utilizzare EGL / SurfaceFlinger nelle implementazioni di EVS Display HAL. Il modo più semplice per implementare libgui è tramite frameworks / native / libs / gui utilizzando direttamente un target di build aggiuntivo nello script di build. Questo obiettivo è esattamente lo stesso dell'obiettivo libgui tranne per l'aggiunta di due campi:

  • name
  • vendor_available
cc_library_shared {
    name: "libgui_vendor",
    vendor_available: true,
    vndk: {
        enabled: false,
    },
    double_loadable: true,

defaults: ["libgui_bufferqueue-defaults"],
srcs: [ … // bufferhub is not used when building libgui for vendors target: { vendor: { cflags: [ "-DNO_BUFFERHUB", "-DNO_INPUT", ], …

Nota: gli obiettivi del fornitore vengono creati con la macro NO_INPUT , che rimuove una parola a 32 bit dai dati del lotto. Poiché SurfaceFlinger si aspetta che questo campo sia stato rimosso, SurfaceFlinger non riesce ad analizzare il lotto. Questo è osservato come un errore 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

Per risolvere questa condizione:

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

Di seguito vengono fornite istruzioni di costruzione di esempio. Aspettati di ricevere un $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so .

$ cd <your_android_source_tree_top>
$ . ./build/envsetup.
$ lunch <product_name>-<build_variant>
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
TARGET_PRODUCT=<product_name>
TARGET_BUILD_VARIANT=<build_variant>
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv7-a-neon
TARGET_2ND_CPU_VARIANT=cortex-a9
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=<host_linux_version>
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QT
OUT_DIR=out
============================================

$ m -j libgui_vendor … $ find $ANDROID_PRODUCT_OUT/system -name "libgui_vendor*" .../out/target/product/hawk/system/lib64/libgui_vendor.so .../out/target/product/hawk/system/lib/libgui_vendor.so

Utilizzo di binder in un'implementazione EVS HAL

In Android 8 (e versioni successive), il nodo del dispositivo /dev/binder è diventato esclusivo per i processi del framework e, quindi, inaccessibile ai processi del fornitore. Invece, i processi del fornitore dovrebbero usare /dev/hwbinder e devono convertire qualsiasi interfaccia AIDL in HIDL. Per coloro che desiderano continuare a utilizzare le interfacce AIDL tra i processi del fornitore, utilizzare il dominio binder, /dev/vndbinder .

Dominio IPC Descrizione
/dev/binder IPC tra processi framework / app con interfacce AIDL
/dev/hwbinder IPC tra processi framework / fornitore con interfacce HIDL
IPC tra i processi del fornitore con interfacce HIDL
/dev/vndbinder IPC tra processi vendor / vendor con interfacce AIDL

Mentre SurfaceFlinger definisce le interfacce AIDL, i processi del fornitore possono utilizzare solo interfacce HIDL per comunicare con i processi del framework. È necessaria una quantità di lavoro non banale per convertire le interfacce AIDL esistenti in HIDL. Fortunatamente, Android fornisce un metodo con cui selezionare il driver binder per libbinder , a cui sono collegati i processi della libreria dello libbinder utente.

diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb3166..5fd02935 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 #include <utils/Log.h>
+#include <binder/ProcessState.h>

 #include "ServiceNames.h"
 #include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
 int main() {
     ALOGI("EVS Hardware Enumerator service is starting");


+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+


     // Start a thread to listen to video device addition events.
     std::atomic<bool> running { true };
     std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));

Nota: i processi del fornitore devono chiamarlo prima di chiamare Process o IPCThreadState o prima di effettuare chiamate di binder.

Politiche di SELinux

Se l'implementazione del dispositivo è completamente tripla, SELinux impedisce ai processi del fornitore di utilizzare /dev/binder . Ad esempio, un'implementazione di esempio di EVS HAL viene assegnata al dominio hal_evs_driver e richiede autorizzazioni r / w per il dominio binder_device .

W ProcessState: Opening '/dev/binder' failed: Permission denied
F ProcessState: Binder driver could not be opened. Terminating.
F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 9145 (android.hardwar), pid 9145 (android.hardwar)
W android.hardwar: type=1400 audit(0.0:974): avc: denied { read write } for name="binder" dev="tmpfs" ino=2208 scontext=u:r:hal_evs_driver:s0 tcontext=u:object_r:binder_device:s0 tclass=chr_file permissive=0

L'aggiunta di queste autorizzazioni, tuttavia, causa un errore di compilazione perché viola le seguenti regole neverallow definite in system/sepolicy/domain.te per un dispositivo full-treble.

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 è un attributo fornito per binder_in_vendor_violators un bug e guidare lo sviluppo. Può anche essere utilizzato per risolvere la violazione di Android 10 sopra descritta.

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)

Creazione dell'implementazione di riferimento EVS HAL come processo del fornitore

Come riferimento, puoi applicare le seguenti modifiche a packages/services/Car/evs/Android.mk . Assicurati di confermare che tutte le modifiche descritte funzionino per la tua implementazione.

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;