HAL kamery samochodowej

Android zawiera samochodowy układ abstrakcji sprzętowej HIDL (HAL), który umożliwia rejestrowanie i wyświetlanie zdjęć już na wczesnym etapie uruchamiania Androida. i będzie dalej działać przez cały okres istnienia systemu. HAL zawiera system widoku zewnętrznego (EVS) i zwykle służy do aparaty i wyświetlacze przestrzenne w pojazdach z Androidem systemów informacyjno-rozrywkowych (IVI). EVS umożliwia też wdrażanie zaawansowanych funkcji w aplikacjach użytkowników.

Android zawiera też sterownik na potrzeby przechwytywania i wyświetlania specyficzny dla EVS. (w języku /hardware/interfaces/automotive/evs/1.0). Wprawdzie możliwość stworzenia aplikacji do obsługi cofania aparatu na dotychczasowym Androidzie. usług aparatu i wyświetlacza, taka aplikacja prawdopodobnie za późno podczas uruchamiania Androida. Użycie dedykowanej listy HAL usprawnia interfejs. i jasno określa, co producent OEM musi wdrożyć, żeby obsługiwać stos EVS.

Komponenty systemu

EVS obejmuje te komponenty systemu:

System EVS
schemat komponentów
Rysunek 1. Omówienie komponentów systemu EVS.

aplikacja EVS

Przykładowa aplikacja EVS w języku C++ (/packages/services/Car/evs/app) jest plikiem referencyjnym implementacji. Ta aplikacja odpowiada za żądania klatek wideo z: Menedżera EVS i wysyłanie ukończonych klatek na potrzeby wyświetlacza z powrotem do menedżera EVS. Przewiduje się, że rozpocznie się od uruchomienia, gdy tylko będą dostępne EVS i Car Service. są kierowane w ciągu 2 (2) sekund od włączenia. OEM może modyfikować lub zastępować pojazdy elektryczne aplikację zgodnie z potrzebami.

Menedżer EVS

Menedżer EVS (/packages/services/Car/evs/manager) zapewnia elementy składowe potrzebne aplikacji EVS do wdrożenia prosty wyświetlacz tylny z kamerą 6DOF wykorzystującą obraz z kilku aparatów. Interfejs jest prezentowana w ramach HIDL i służy do obsługi wielu klientów jednocześnie. Inne aplikacje i usługi (w szczególności Serwis samochodowy) mogą wysyłać zapytania dotyczące EVS Stan menedżera, który jest używany do sprawdzania, kiedy system EVS jest aktywny.

Interfejs EVS HIDL

System EVS, zarówno kamera, jak i wyświetlacze, jest zdefiniowany w android.hardware.automotive.evs pakiet. Przykładowa implementacja ćwiczący interfejs (generuje syntetyczne obrazy testowe i sprawdza poprawność zdjęć w obie strony) jest dostarczany w /hardware/interfaces/automotive/evs/1.0/default

OEM odpowiada za wdrożenie interfejsu API wyrażonego w plikach .hal. w usłudze /hardware/interfaces/automotive/evs. Takie implementacje są odpowiada za konfigurowanie i gromadzenie danych z kamer fizycznych dostarczanie jej przez współdzielone bufory pamięci rozpoznawalne przez Gralloc. Wyświetlacz która odpowiada za udostępnienie bufora pamięci współdzielonej. które mogą zostać wypełnione przez aplikację (zwykle za pomocą renderowania EGL), a następnie prezentować na gotowych klatkach, w pierwszej kolejności nad innymi, które mogą być wyświetlane na fizycznym wyświetlaczu. Mogą być przechowywane implementacje interfejsu EVS przez dostawcę. w ramach kategorii /vendor/… /device/… lub hardware/… (np. /hardware/[vendor]/[platform]/evs).

Sterowniki jądra systemu

Urządzenie obsługujące stos EVS wymaga sterowników jądra. Zamiast nowych kierowców, OEM może wspierać funkcje wymagane w przypadku pojazdów elektrycznych od istniejących sterowników sprzętu kamery lub wyświetlacza. Ponowne wykorzystanie sterowników może być zwłaszcza w przypadku sterowników wyświetlacza, w których prezentacja obrazów wymagają koordynacji z innymi aktywnymi wątkami. Android 8.0 obejmuje wersję v4l2 przykładowy kierowca (w: packages/services/Car/evs/sampleDriver), który zależy od jądra obsługującego wersję 4l2 i od SurfaceFlinger do prezentowania obrazu wyjściowego.

Opis interfejsu sprzętu EVS

W tej sekcji opisano zawartość HAL. Dostawcy muszą podać implementacji tego interfejsu API przystosowanych do używanego sprzętu.

Narzędzie IEvsEnumerator

Ten obiekt odpowiada za wyliczanie dostępnego sprzętu EVS w (z jedną lub większą liczbą aparatów i z jednym wyświetlaczem).

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

Zwraca wektor zawierający opisy wszystkich aparatów w systemie. Jest przy założeniu, że zestaw kamer jest stały i rozpoznawalny w momencie uruchomienia. Więcej informacji: opisy aparatów, patrz CameraDesc.

openCamera(string camera_id) generates (IEvsCamera camera);

Pobiera obiekt interfejsu używany do interakcji z określoną kamerą identyfikowany przez unikalny ciąg camera_id. Zwraca wartość NULL w przypadku niepowodzenia. Próby ponownego otwarcia kamery, która jest już otwarta, nie mogą się zakończyć. Aby uniknąć wyścigu warunki związane z uruchamianiem i wyłączaniem aplikacji oraz ponownym uruchamianiem kamery powinno wyłączyć poprzednią instancję, aby można było zrealizować nowe żądanie. O instancja kamery, która została w ten sposób wywłaszczona, musi zostać ustawiona jako nieaktywna oczekuje na ostateczne zniszczenie i odpowiada na wszelkie wnioski dotyczące stan kamery z kodem zwrotu OWNERSHIP_LOST.

closeCamera(IEvsCamera camera);

Otwiera interfejs IEvsCamera (i przeciwieństwem funkcji IEvsCamera openCamera() połączenie). Strumień wideo z kamery musi być zatrzymano przez telefon: stopVideoStream() przed połączeniem z użytkownikiem closeCamera.

openDisplay() generates (IEvsDisplay display);

Pobiera obiekt interfejsu używany wyłącznie do interakcji z interfejsem Wyświetlacz EVS. Tylko jeden klient może mieć funkcjonalną instancję IEvsDisplay w: obecnie się znajdujesz. Podobnie jak w przypadku agresywnego otwartego zachowania opisanego w openCamera, w dowolnym momencie można utworzyć nowy obiekt IEvsDisplay i wyłączyć wszystkie poprzednie instancji. Unieważnione instancje nadal istnieją i odpowiadają na wywołania funkcji swoich właścicieli, ale nie mogą wykonywać żadnych operacji mutacji po ich śmierci. W końcu aplikacja kliencka powinna zauważyć błąd OWNERSHIP_LOST oraz zamknij i zwolnij nieaktywny interfejs.

closeDisplay(IEvsDisplay display);

Udostępnia interfejs IEvsDisplay (i odwrotność funkcji openDisplay() połączenie). Zaległe bufory otrzymane przez getTargetBuffer() połączeń musi zostać zwróconych na wyświetlacz przed Zamknięcie wyświetlacza.

getDisplayState() generates (DisplayState state);

Pobiera bieżący stan wyświetlania. Implementacja HAL powinna uwzględniać bieżący stan, który może się różnić od ostatnio żądanego stanu. Logika odpowiedzialna za zmianę stanu wyświetlania powinna znajdować się nad urządzeniem co uniemożliwia spontaniczną zmianę wdrożenia HAL. stanów wyświetlania. Jeśli żaden klient nie trzyma aktualnie wyświetlacza (przez wywołanie openDisplay), to funkcja zwraca NOT_OPEN. W przeciwnym razie zgłasza bieżący stan wyświetlacza EVS (patrz Interfejs API IEvsDisplay).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id Ciąg jednoznacznie identyfikujący daną kamerę. Może to być nazwa jądra urządzenia lub nazwa urządzenia, na przykład a tyle. Wartość tego ciągu jest wybierana przez implementację HAL i nieprzezroczyste przez stos powyżej.
  • vendor_flags Metoda zaliczenia testu specjalistycznego aparatu nieprzejrzyste informacje od kierowcy do niestandardowej aplikacji EVS. Powodzenie niezinterpretowane od kierowcy aż do aplikacji EVS, którą można zignorować. .

Kamera IEVS

Ten obiekt reprezentuje jedną kamerę i jest głównym interfejsem robienie zdjęć.

getCameraInfo() generates (CameraDesc info);

Zwraca CameraDesc tej kamery.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

Określa głębokość łańcucha bufora, który ma obsługiwać kamera. Do tak wiele klatek może być jednocześnie zatrzymana przez klienta IEvsCamera. Jeśli do odbiornika zostało dostarczonych wiele klatek, które nie zostały zwrócone przez doneWithFrame, strumień będzie pomijać klatki do momentu zwrócenia bufora. do ponownego wykorzystania. Można to zrobić w dowolnym momencie, nawet jeśli transmisje są już uruchomione, w którym to przypadku należy dodać bufory do łańcucha lub z niego usunąć w razie potrzeby. Jeśli nie zostanie wykonane żadne wywołanie tego punktu wejścia, IEvsCamera obsługuje domyślnie co najmniej jedna klatka; które są bardziej akceptowalne.

Jeśli nie można uwzględnić żądanej wartości bufferCount, funkcja zwraca BUFFER_NOT_AVAILABLE lub inny odpowiedni kod błędu. W tym przypadku system kontynuuje pracę z ustawioną wcześniej wartością.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Żąda przesyłania z tej kamery klatek EVS. IEvsCameraStream; zaczyna otrzymywać okresowe wywołania z nowymi klatkami obrazu do Funkcja stopVideoStream() jest wywoływana. Musi rozpocząć się przesyłanie ramek w ciągu 500 ms od wywołania funkcji startVideoStream i po jego rozpoczęciu musi generowanych z szybkością co najmniej 10 kl./s. Czas potrzebny do rozpoczęcia strumienia wideo skutecznie wlicza się do wszelkich wymagań dotyczących czasu uruchomienia kamery tylnej. Jeśli strumień nie został uruchomiony, musi zostać zwrócony kod błędu; w przeciwnym razie zwracana jest wartość OK.

oneway doneWithFrame(BufferDesc buffer);

Zwraca klatkę, która została dostarczona przez serwer IEvsCameraStream. Gdy skończysz korzysta z ramki dostarczonej do interfejsu IEvsCameraStream, musi być został zwrócony do IEvsCamera, aby go ponownie użyć. Mała, skończona liczba buforów mogą być bardzo małe, a jeśli ich liczba się wyczerpuje, nie będzie ramki są dostarczane do momentu zwrócenia bufora, co może spowodować, pominięte klatki (bufor z uchwytem o wartości null oznacza koniec strumienia i nie nie muszą być zwracane przez tę funkcję). zwraca wartość OK w przypadku powodzenia lub odpowiedni kod błędu, potencjalnie zawierający INVALID_ARG lub BUFFER_NOT_AVAILABLE

stopVideoStream();

Zatrzymuje przesyłanie klatek kamery EVS. Wyświetlanie jest asynchroniczne, ramki mogą być uwzględniane przez jakiś czas po ponownym wywołaniu tego wywołania. Każda klatka musi być zwracany, dopóki funkcja nie zasygnalizuje zamknięcia strumienia IEvsCameraStream. Wywołanie użytkownika stopVideoStream podczas transmisji jest legalne który został już zatrzymany lub nigdy nie został uruchomiony, w takim przypadku jest ignorowany.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

Powoduje żądanie informacji dotyczących sterownika do implementacji HAL. Wartości dozwolone w przypadku: opaqueIdentifier są związane z kierowcą, ale nie mają wartości może spowodować awarię kierowcy. Kierowca powinien zwrócić 0 w przypadku każdego nierozpoznanego opaqueIdentifier

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

Wysyła wartość związaną z sterownikiem do implementacji HAL. To rozszerzenie jest udostępniane tylko w celu usprawnienia rozszerzeń dotyczących konkretnego pojazdu, a nie HAL. implementacja powinna wymagać, aby to wywołanie działało w stanie domyślnym. Jeśli sterownik rozpoznaje i akceptuje wartości, powinien zostać zwrócony kod OK; w przeciwnym razie Powinien zostać zwrócony kod INVALID_ARG lub inny reprezentatywny kod błędu.

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
}

Opisuje obraz przekazywany przez interfejs API. Dysk HAL odpowiada za: wypełnienie tej struktury w celu opisania bufora obrazu i klienta HAL powinien traktować tę strukturę jako tylko do odczytu. Pola zawierają wystarczającą ilość informacji aby klient mógł zrekonstruować obiekt ANativeWindowBuffer, co może być wymagane przy korzystaniu z obrazu z EGL z eglCreateImageKHR().

  • width Szerokość prezentowanego obrazu w pikselach.
  • height Wysokość prezentowanego obrazu w pikselach.
  • stride liczbę pikseli, jaką każdy wiersz zajmuje w pamięci, uwzględniając dopełnienie związane z wyrównaniem wierszy. Wyrażona w pikselach w celu dopasowania konwencji przyjętej przez Gralloc dotyczącej opisów buforów.
  • pixelSize liczbę bajtów zajętych przez każdy piksel, co pozwala obliczać w bajtach rozmiar niezbędny do przejścia między wierszami obraz (stride w bajtach = stride w pikselach * pixelSize).
  • format Format w pikselach używany przez obraz. Podany format musi być zgodny z implementacją OpenGL na platformie. Aby zaliczyć testowanie zgodności, wartość HAL_PIXEL_FORMAT_YCRCB_420_SP powinna być preferowana do użycia kamery, a RGBA lub BGRA powinny były preferowane w przypadku reklam displayowych.
  • usage Flagi użytkowania ustawione przez implementację HAL. Klienci HAL powinny przepaść w stanie niezmienionym (szczegółowe informacje znajdziesz w Gralloc.h powiązane flagi).
  • bufferId Unikalna wartość wskazana przez implementację HAL w pozwalają na rozpoznanie bufora po przejściu przez interfejsy API HAL. wartość przechowywana w tym polu może być dowolnie wybrana przez implementację HAL.
  • memHandle Uchwyt bazowego bufora pamięci, który który zawiera dane obrazu. Implementacja HAL może zdecydować się na przechowywanie kodu Gralloc uchwyt bufora.

Strumień kamery IEvs

Klient implementuje ten interfejs, aby odbierać asynchroniczną klatkę wideo i dostarczania produktów.

deliverFrame(BufferDesc buffer);

Odbiera wywołania z interfejsu HAL za każdym razem, gdy klatka wideo jest gotowa do sprawdzenia. Nicki bufora otrzymane przez tę metodę muszą być zwracane w ramach wywołań funkcji IEvsCamera::doneWithFrame() Gdy strumień wideo zostanie zatrzymany przez pod numer IEvsCamera::stopVideoStream(), może ono być kontynuowane podczas opróżniania potoku. Każda klatka musi zostać zwrócona; kiedy ostatnia klatka dostarczono wartość bufferHandle NULL, oznacza koniec transmisji i przesyłanie klatek nie jest już możliwe. Wartość NULL Sam atrybut bufferHandle nie musi być odesłany z doneWithFrame(), ale wszystkie inne nicki muszą zostać zwrócone

Zastrzeżone formaty buforów są technicznie możliwe, jednak zgodność wymaga, aby bufor był w jednym z czterech obsługiwanych formatów: NV21 (YCrCb). 4:2:0, półplanar, YV12 (YCrCb 4:2:0 planar), YUYV (YCrCb 4:2:2 przeplatany), RGBA (32-bitowy R:G:B:x), BGRA (32-bitowy B:G:R:x). Wybrany format musi być prawidłowy Źródło tekstury GL w implementacji GLES na platformie.

Aplikacja nie powinna opierać się na żadnej korespondencji między polem bufferId a polem memHandle w funkcji BufferDesc. Wartości bufferId to zasadniczo prywatne w odniesieniu do implementacji sterownika HAL i może wykorzystywać (i wykorzystywać ją ponownie) według własnego uznania.

IEvsDisplay

Ten obiekt reprezentuje wyświetlacz Evs i steruje jego stanem, i zajmuje się prezentacją obrazów.

getDisplayInfo() generates (DisplayDesc info);

Zwraca podstawowe informacje o wyświetlaczu EVS dostarczone przez system (patrz DisplayDesc).

setDisplayState(DisplayState state) generates (EvsResult result);

Ustawia stan wyświetlania. Klienci mogą ustawić stan wyświetlania, aby wyrazić żądanego stanu, a implementacja HAL musi płynnie zaakceptować żądanie w dowolnym stanie w dowolnym innym stanie, chociaż odpowiedzią może być zignorowanie użytkownika.

Po zainicjowaniu wyświetlany jest NOT_VISIBLE stan, po którym ma wystąpić klient stan VISIBLE_ON_NEXT_FRAME i zacznij udostępniać film. Gdy wyświetlanie reklam nie jest już wymagane, klient powinien zażądać Stan NOT_VISIBLE po przekroczeniu ostatniej klatki wideo.

Obowiązuje w przypadku każdego stanu, o którego żądanie można poprosić w dowolnym momencie. Jeśli wyświetlacz jest już widoczne, powinno pozostać widoczne, jeśli jest ustawione na VISIBLE_ON_NEXT_FRAME Zawsze zwraca wartość OK, chyba że zażądano żądanego stanu to nierozpoznana wartość enum, w którym to przypadku INVALID_ARG jest .

getDisplayState() generates (DisplayState state);

Pobiera stan wyświetlania. Implementacja HAL powinna uwzględniać bieżący stan, który może się różnić od ostatniego żądanego stanu. logika odpowiedzialna za zmianę stanu wyświetlania powinna znajdować się nad urządzeniem co uniemożliwia spontaniczną zmianę wdrożenia HAL. stanów wyświetlania.

getTargetBuffer() generates (handle bufferHandle);

Zwraca uchwyt do bufora ramki powiązanego z wyświetlaczem. Ten bufor mogą być zablokowane i zapisywane w oprogramowaniu lub GL. Ten bufor musi być zwrócony z wywołaniem funkcji returnTargetBufferForDisplay(), nawet jeśli ekran jest nie jest już widoczny.

Choć zastrzeżone formaty buforów są technicznie możliwe, testowanie zgodności wymaga, aby bufor był w jednym z czterech obsługiwanych formatów: NV21 (YCrCb 4:2:0) półplanarowy), YV12 (YCrCb 4:2:0 planar), YUYV (YCrCb 4:2:2 przeplatany), RGBA (32-bitowy R:G:B:x), BGRA (32-bitowy B:G:R:x). Wybrany format musi być prawidłowym GL środowiska docelowego renderowania w implementacji GLES na platformie.

W przypadku błędu zwracany jest bufor z uchwytem o wartości null, ale taki bufor nie muszą być zwracane do returnTargetBufferForDisplay.

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Informuje wyświetlacz, że bufor jest gotowy do wyświetlenia. Pobrano tylko bufory przez połączenie z getTargetBuffer() można używać z tym , a zawartość BufferDesc nie może być modyfikowana przez aplikacji klienckiej. Po tym wywołaniu bufor nie może już być używany przez do klienta. Zwraca kod OK w przypadku powodzenia lub potencjalnie odpowiedni kod błędu w tym INVALID_ARG lub BUFFER_NOT_AVAILABLE.

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

Opisuje podstawowe właściwości wyświetlacza EVS i wymagane przez EVS. implementacji. HAL odpowiada za wypełnienie tego formularza opis wyświetlacza EVS. Może to być wyświetlacz fizyczny lub wirtualny, nałożonych lub połączonych z innym urządzeniem do prezentacji.

  • display_id Ciąg jednoznacznie identyfikujący wyświetlacz. Może to być nazwa jądra urządzenia lub nazwa urządzenia, takie jak cofanie się. Wartość tego ciągu jest wybierana przez HAL i nieprzezroczyste przez stos powyżej.
  • vendor_flags Metoda zaliczenia testu specjalistycznego aparatu nieprzejrzyste informacje od kierowcy do niestandardowej aplikacji EVS. Powodzenie niezinterpretowane od kierowcy aż do aplikacji EVS, którą można zignorować. .
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
}

Opisuje stan wyświetlacza EVS, który można wyłączyć (nie widoczne dla sterownika) lub enabled (wyświetlanie obrazu dla sterownika). Zawiera stan przejściowy, w którym ekran nie jest jeszcze widoczny, ale jest gotowy są widoczne przy przesyłaniu kolejnej klatki, returnTargetBufferForDisplay() połączenie.

Menedżer EVS

Menedżer EVS udostępnia publiczny interfejs systemu EVS dla zbieranie i prezentowanie zewnętrznych widoków z kamery. Gdzie pozwalają na to sterowniki sprzętu tylko jeden aktywny interfejs na zasób (kamerę lub wyświetlacz), menedżer EVS ułatwia wspólny dostęp do kamer. Jedna główna aplikacja EVS jest pierwszy klient menedżera EVS i jedyny klient uprawniony do zapisu wyświetlanie danych (dodatkowym klientom można przyznać dostęp tylko do odczytu do kamery) zdjęcia).

Menedżer EVS implementuje ten sam interfejs API co bazowe sterowniki HAL. zapewnia rozszerzoną usługę dzięki obsłudze wielu równoczesnych klientów (ponad jeden klient może otworzyć kamerę za pomocą menedżera EVS i odebrać obraz wideo. ).

Menedżer EVS
Diagram interfejsu EVS Hardware API.
Rysunek 2. Menedżer EVS odzwierciedla bazowe EVS Hardware API.

Aplikacje nie różnią się od siebie w przypadku korzystania z HAL sprzętu EVS. lub interfejsu EVS Manager API, z wyjątkiem tego, że interfejs EVS Manager API zezwala jednoczesny dostęp do strumienia danych z kamery. Menedżer EVS sam jest tym, klient warstwy HAL sprzętu EVS i działa jako serwer proxy dla sprzętu EVS HAL.

W sekcjach poniżej opisano tylko wywołania, które różnią się (rozszerzone) zachowanie w implementacji menedżera EVS; pozostałe połączenia to są identyczne z opisami EVS HAL.

Narzędzie IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Pobiera obiekt interfejsu używany do interakcji z określoną kamerą identyfikowany przez unikalny ciąg camera_id. Zwraca wartość NULL w przypadku niepowodzenia. W warstwie menedżera EVS, o ile dostępna jest wystarczająca ilość zasobów systemowych, już otwarta kamera może zostać otwarta przez inny proces, co pozwala i udostępniania strumienia wideo wielu użytkownikom. Ciągi znaków (camera_id) w warstwie menedżera EVS są takie same jak te do warstwy sprzętowej EVS.

Kamera IEVS

Implementacja IEvsCamera, dostępna w menedżerze EVS, jest wewnętrznie wirtualizowana. więc operacje wykonywane przez jednego klienta nie wpływają na pozostałe, i umożliwiają zachowanie niezależnego dostępu do swoich kamer.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Uruchamia strumienie wideo. Klienci mogą samodzielnie rozpoczynać i zatrzymywać strumienie wideo. za pomocą tej samej kamery. Kamera bazowa uruchamia się, gdy

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

Zwraca ramkę. Każdy klient musi po zakończeniu pracy zwrócić swoje ramki, ale mogą przechowywać ramki tak długo, jak to konieczne. Gdy liczba klatek przechowywanych przez klienta osiągnie skonfigurowany limit, nie otrzyma kolejnych klatek, aż zostanie zwrócona. To pomijanie klatek nie wpływa na inne które nadal otrzymują wszystkie klatki zgodnie z oczekiwaniami.

stopVideoStream();

Zatrzymuje strumień wideo. Każdy klient może zatrzymać strumień wideo w dowolnym momencie bez co ma wpływ na innych klientów. Strumień z kamery w warstwie sprzętowej jest zatrzymuje się, gdy ostatni klient danej kamery zatrzyma przesyłanie strumieniowe.

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

Wysyła wartość związaną z sterownikiem, potencjalnie umożliwiając jednemu klientowi do innego klienta. Ponieważ menedżer EVS nie jest w stanie zrozumieć konsekwencje słowa kontrolne zdefiniowane przez dostawcę, nie są wirtualizowane ani nie mają żadnych efektów ubocznych będzie dotyczyć wszystkich klientów danej kamery. Jeśli na przykład dostawca użył tego połączenia aby zmienić liczbę klatek, wszystkie klienty kamery w warstwie sprzętowej z nową liczbą klatek.

IEvsDisplay

Dozwolony jest tylko 1 właściciel wyświetlacza, nawet na poziomie menedżera EVS. Menedżer nie dodaje żadnych funkcji i przekazuje interfejs IEvsDisplay. bezpośrednio aż do bazowej implementacji HAL.

aplikacja EVS

Android zawiera natywną referencyjną implementację plików EVS w języku C++. aplikacja komunikująca się z menedżerem EVS i HAL pojazdu, udostępniać podstawowe funkcje tylnej kamery. Aplikacja powinna się uruchomić na wczesnym etapie uruchamiania systemu. Odpowiedni film jest wyświetlany w zależności od dostępne kamery i stan samochodu (stan kół zębatki i sygnału kierunkowego). OEM może zmodyfikować lub zastąpić aplikację EVS własną, specyficzną dla pojazdu logikę i prezentację.

Rysunek 3. Logika próbki EVS z kamery z listy.


Rysunek 4. Logika przykładowej aplikacji EVS, odbiór wywołanie zwrotne ramki.

Dane obrazu są prezentowane w aplikacji w standardowej grafice bufora, to aplikacja odpowiada za przeniesienie obrazu ze źródła do bufora wyjściowego. Chociaż wiąże się to z kosztami kopiowania danych, umożliwia też aplikacji wyrenderowanie obrazu bufor wyświetlania w dowolny sposób.

Na przykład aplikacja może przenieść dane piksela, z wbudowaną skalą lub operacją obracania. Aplikacja może również użyć obrazu źródłowego jako tekstury OpenGL i wyrenderować złożone do bufora wyników, w tym elementów wirtualnych, takich jak ikony, wytyczne i animacje. Bardziej zaawansowana aplikacja może też wybrać wiele równoczesnych kamer wejściowych i łączenie ich w jedną ramkę wyjściową np. do wyświetlania z góry w wirtualnym widoku otoczenia pojazdu.

Używaj EGL/SurfaceFlinger w HAL wyświetlacza EVS

Ta sekcja wyjaśnia, jak używać EGL do renderowania implementacji HAL EVS w sieci reklamowej. na Androidzie 10.

EVS, Implementacja referencyjna HAL używa EGL do renderowania podglądu kamery ekran i korzysta z usługi libgui aby utworzyć docelową powierzchnię renderowania EGL. Na urządzeniach z Androidem 8 (lub nowszym): libgui jest sklasyfikowany jako VNDK-private, który odnosi się do grupy bibliotek dostępnych dla bibliotek VNDK, których dostawca nie może wykorzystać. Implementacje HAL muszą znajdować się w partycji dostawcy, dlatego nie mogą oni używać Platforma w implementacjach HAL.

Tworzenie biblioteki libgui na potrzeby procesów dostawcy

Użycie interfejsu libgui to jedyna opcja użycia EGL/SurfaceFlinger. w implementacjach HAL EVS. Najprostszy sposób implementacji funkcji libgui to Przez frameworks/native/libs/gui bezpośrednio przy użyciu dodatkowego miejsca docelowego kompilacji w skrypcie kompilacji. Ta wartość docelowa jest dokładnie taka sama jak wartość docelową libgui oprócz 2 pól dodanych:

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

Uwaga: cele dostawców są tworzone za pomocą makra NO_INPUT, które usuwa z danych działki jedno 32-bitowe słowo. Ponieważ SurfaceFlinger oczekuje, że to pole zostanie usunięte, SurfaceFlinger nie może przeanalizować paczki. Jest to obserwowane jako błąd 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

Aby rozwiązać ten 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);

Przykładowa kompilacja instrukcje znajdziesz poniżej. Oczekuj $(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

Używaj powiązania w implementacji HAL EVS

W Androidzie 8 (i nowszych) węzeł urządzenia /dev/binder stał się dostępny wyłącznie i są niedostępne dla procesów dostawcy. Zamiast tego: procesy dostawcy powinny używać interfejsu /dev/hwbinder i muszą konwertować wszystkie interfejsy AIDL na HIDL. Jeśli chcesz w dalszym ciągu używać interfejsów AIDL między procesami dostawcy, użyj domeny separatora (/dev/vndbinder).

Domena IPC Opis
/dev/binder IPC między platformą/procesami aplikacji z interfejsami AIDL
/dev/hwbinder IPC między platformą/procesami dostawcy z interfejsami HIDL
IPC między procesami dostawcy z interfejsami HIDL
/dev/vndbinder Protokół IPC między procesami dostawcy/dostawcy z interfejsami AIDL

SurfaceFlinger definiuje interfejsy AIDL, a procesy dostawcy mogą używać interfejsów HIDL tylko do komunikacji z procesami platformy. Do konwersji istniejących potrzeba niezwykła praca Interfejs AIDL do HIDL. Na szczęście Android udostępnia metodę wyboru separatora, sterownik dla systemu libbinder, z którym są połączone procesy biblioteki przestrzeni użytkownika.

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

Uwaga: procedury dostawcy powinny wywołać tę funkcję przed wywołaniem usługi Process lub IPCThreadState, a także przed wykonaniem jakichkolwiek wywołań funkcji Binder.

Zasady SELinux

Jeśli implementacja urządzenia to wysoki poziom, SELinux uniemożliwia dostawcy. procesów korzystających z /dev/binder. Na przykład próbka EVS HAL implementacja jest przypisana do domeny hal_evs_driver i wymaga uprawnienia r/w w domenie 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

Dodanie tych uprawnień powoduje jednak błąd kompilacji, ponieważ narusza następujące zasady nigdy nie zezwalaj na reguły zdefiniowane w system/sepolicy/domain.te dla urządzeń z pełnym sondem.

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 to atrybut służący do wychwytywania błędu i pomagania w tworzeniu aplikacji. Można jej też używać do: usunąć opisane powyżej naruszenie związane z Androidem 10.

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)

Tworzenie implementacji referencyjnej HAL EVS jako proces dostawcy

W ramach odniesienia możesz wprowadzić następujące zmiany do: packages/services/Car/evs/Android.mk Pamiętaj, aby potwierdzić wszystkie opisane zmiany będą działać w Twojej implementacji.

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;