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:
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, aRGBA
lubBGRA
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 wGralloc.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. ).
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ę.
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;