Przejście z ION na sterty DMA-BUF

W Androidzie 12 GKI 2.0 zastępuje alokator ION DMA-BUF gromadzi się z następujących powodów:

  • Bezpieczeństwo: każda sterta DMA-BUF jest oddzielnym urządzeniem znakowym, więc do każdej sterty można sterować oddzielnie za pomocą metody sepolicy. To nie było możliwe dzięki ION, ponieważ alokacja z dowolnej sterty wymaga dostępu jedynie do urządzenie /dev/ion.
  • Stabilność ABI: w przeciwieństwie do ION, interfejs IOCTL platformy DMA-BUF jest Stabilny interfejs ABI, ponieważ znajduje się w nadrzędnym jądrze Linuksa.
  • Standaryzacja: platforma stert DMA-BUF zapewnia dobrze zdefiniowany interfejs UAPI. jon mogą zawierać niestandardowe flagi i identyfikatory sterty, co uniemożliwiało opracowanie wspólnych testów ponieważ implementacja ION na poszczególnych urządzeniach może działać inaczej.

Gałąź android12-5.10 wspólnego jądra Androida została wyłączona CONFIG_ION 1 marca 2021 r.

Tło

Poniżej znajduje się krótkie porównanie sterty ION i DMA-BUF.

Podobieństwa między strukturą sterty ION i DMA-BUF

  • Zarówno platformy sterty ION, jak i DMA-BUF są eksporterami DMA-BUF opartymi na stercie.
  • Każda sterta definiuje własne operacje przydzielające i operacje DMA-BUF.
  • Wydajność alokacji jest podobna, ponieważ oba schematy wymagają jednego IOCTL do alokacji.

Różnice między strukturą sterty ION i DMA-BUF

Stosy ION Stosy DMA-BUF
Wszystkie przydziały ION są realizowane za pomocą /dev/ion. Każda sterta DMA-BUF to urządzenie znakowe, które znajduje się w /dev/dma_heap/<heap_name>.
ION obsługuje flagi prywatne stosu. Stosy DMA-BUF nie obsługują prywatnych flag sterty. Każdy z nich alokacja jest wykonywana na innej stercie. Na przykład pliki z pamięci podręcznej niebuforowane warianty sterty systemu to osobne sterty znajdujące się na /dev/dma_heap/system i /dev/dma_heap/system_uncached
Na potrzeby alokacji należy określić identyfikator sterty/maskę i flagi. Nazwa sterty służy do alokacji.

W kolejnych sekcjach znajdziesz listę komponentów obsługujących ION na platformę DMA-BUF.

Przejście ze sterowników jądra ION na sterty DMA-BUF

Sterowniki jądra implementujące sterty ION

Dzięki sterom ION i DMA-BUF każda z nich może wdrażać własne alokatory Operacje DMA-BUF. Możesz więc przejść z implementacji sterty ION na stertę DMA-BUF przy użyciu innego zestawu interfejsów API do zarejestrowania stosu. Ta tabela pokazuje interfejsy API rejestracji sterty ION i odpowiadające im interfejsy API sterty DMA-BUF.

Stosy ION Stosy DMA-BUF
void ion_device_add_heap(struct ion_heap *heap) struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info);
void ion_device_remove_heap(struct ion_heap *heap) void dma_heap_put(struct dma_heap *heap);

Stosy DMA-BUF nie obsługują prywatnych flag sterty. Każdy wariant stosu należy zarejestrować indywidualnie za pomocą: dma_heap_add() API. Aby ułatwić udostępnianie kodu, zalecamy zarejestrowanie wszystkich wariantów w ramach tego samego sterownika. Ten przykład dma-buf: system_heap pokazuje implementację wariantów systemu z pamięci podręcznej i z niebuforowanej sterta.

Użyj tego szablonu: dma-buf: heaps: przykładowy szablon aby utworzyć od podstaw stertę DMA-BUF.

Sterowniki jądra bezpośrednio przydzielające ze sterty ION

Platforma stertów DMA-BUF zapewnia również interfejs alokacji dla klientów w jądrze. Zamiast określać maskę stosu i flagi do wyboru typ alokacji, interfejs oferowany przez sterty DMA-BUF przyjmuje nazwę sterty jako dane wejściowe.

Poniżej widać interfejs API alokacji ION w jądrze i odpowiadający mu DMA-BUF interfejsów API alokacji sterty. Sterowniki jądra mogą używać interfejsu API dma_heap_find() do wysyłania zapytań istnienie sterty. Interfejs API zwraca wskaźnik do instancji struct dma_heap, który można następnie przekazać jako argument do funkcji Interfejs API dma_heap_buffer_alloc().

Stosy ION Stosy DMA-BUF
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)

struct dma_heap *dma_heap_find(const char *name)

struct dma_buf *struct dma_buf *dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, unsigned int fd_flags, unsigned int heap_flags)

Sterowniki jądra używające komponentów DMA-BUF

W przypadku sterowników, które importują tylko pliki DMA-BUF, nie są wymagane żadne zmiany, ponieważ przydzielona ze stosu ION działa dokładnie tak samo jak bufor przydzielony z odpowiednią stertę DMA-BUF.

Przenieś klientów przestrzeni użytkownika ION do sterty DMA-BUF

Aby ułatwić przejście klientom w przestrzeni użytkownika ION, biblioteka o nazwie libdmabufheap jest dostępna. libdmabufheap obsługuje alokację na stertach DMA-BUF i sterty ION. Najpierw sprawdza, czy istnieje sterta DMA-BUF o podanej nazwie a w przeciwnym razie wybiera równoważną stertę ION, o ile taka istnieje.

Klienty powinny zainicjować BufferAllocator obiektu podczas inicjowania zamiast otwierania /dev/ion using ion_open(). Dzieje się tak, ponieważ deskryptory plików tworzone przez otwarcie Aplikacje /dev/ion i /dev/dma_heap/<heap_name> są zarządzane wewnętrznie przez obiekt BufferAllocator.

Aby przejść z libion na libdmabufheap, zmodyfikuj działanie klientów jako następujące:

  • Śledź nazwę sterty na potrzeby alokacji, a nie w nagłówku Flaga identyfikatora/maski i sterty.
  • Zastąp interfejs API ion_alloc_fd(), który przyjmuje maskę stosu i argument flagi. za pomocą interfejsu API BufferAllocator::Alloc(), który przyjmuje nazwę stosu.

Ta tabela ilustruje te zmiany, pokazując, jak funkcje libion i libdmabufheap i wykonanie alokacji sterty niebuforowanej w pamięci podręcznej.

Typ przydziału Libion libdmabufheap
Alokacja w pamięci podręcznej ze sterty systemu ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd) allocator->Alloc("system", size)
Niebuforowana alokacja ze sterty systemu ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd) allocator->Alloc("system-uncached", size)

wariant stosu systemu bez pamięci podręcznej oczekuje na zatwierdzenie w hierarchii, ale jest już częścią android12-5.10 gałąź.

Aby ułatwić uaktualnianie urządzeń, interfejs API MapNameToIonHeap() umożliwia mapowanie stosu parametry stosu ION (nazwa sterty lub maska i flagi), aby umożliwić a interfejsy API używają alokacji na podstawie nazw. Tutaj znajdziesz przydział oparty na nazwach przykład.

Dokumentacja każdego interfejsu API udostępnianego przez libdmabufheap jest dostępna. biblioteka udostępnia też plik nagłówkowy do użytku przez klienty w języku C.

Referencyjna implementacja Gralloc

Implementacja Gralloc Hikey960 wykorzystuje pole libdmabufheap, więc można go używać jako odwołanie

Wymagane nieustawione dodatki

Dla każdego nowo utworzonego sterty DMA-BUF dla konkretnego urządzenia dodaj nowy wpis do sekcji ueventd.rc na urządzeniu. Ta konfiguracja przestała obsługiwać sterty DMA-BUF przykład przedstawia sposób wykonania tego działania dla sterty systemu DMA-BUF.

Wymagane dodatki sepolicy

Dodaj uprawnienia Sepolicy, aby umożliwić klientowi przestrzeni użytkownika dostęp do nowego obiektu DMA-BUF sterta. Ta dodanie jest wymagane uprawnienia przykład uprawnień sepolicy utworzonych dla różnych klientów uzyskać dostęp do stosu systemu DMA-BUF.

Dostęp do stert dostawców z poziomu kodu platformy

Aby zapewnić zgodność z Treble, kod platformy można przydzielać tylko ze wstępnie zatwierdzonych i kategoriami stosów dostawców.

Na podstawie opinii partnerów zidentyfikowaliśmy 2 kategorie: sterty dostawców, do których dostęp musi być uzyskiwany za pomocą kodu platformy:

  1. Sterty oparte na stercie systemu z wydajnością specyficzną dla urządzenia lub układu SOC i optymalizacji.
  2. Stert, które mają zostać przydzielone z chronionej pamięci.

Stosy na podstawie stosu systemu z optymalizacją wydajności w zależności od urządzenia lub układu SOC

Aby obsługiwać ten przypadek użycia, implementacja sterty domyślnej sterty DMA-BUF może być zastąpiona.

  • Funkcja CONFIG_DMABUF_HEAPS_SYSTEM została wyłączona w aplikacji gki_defconfig, aby mogła moduł dostawcy.
  • Testy zgodności VTS sprawdzają, czy sterta istnieje pod adresem /dev/dma_heap/system. Testy sprawdzają też, czy stos może zostać przydzielonych i zwrócony deskryptor pliku (fd) może być zmapowany na pamięć (zapisany) przez użytkownika; kosmosu.

Poprzednie punkty odnoszą się również do niebuforowanego wariantu sterty systemu, chociaż jego istnienie nie jest obowiązkowe w przypadku w pełni spójnych urządzeń reklamowych.

Stert, które mają zostać przydzielone z chronionej pamięci

Implementacje bezpiecznej sterty muszą być zależne od dostawcy, ponieważ Jądro nie obsługuje ogólnej implementacji bezpiecznej sterty.

  • Zarejestruj implementacje swojego dostawcy jako /dev/dma_heap/system-secure<vendor-suffix>.
  • Te implementacje sterty są opcjonalne.
  • Jeśli sterty istnieją, testy VTS służą do sprawdzania, czy można z nich korzystać przy alokacji.
  • Komponenty platformy mają dostęp do tych stosu, pozwalają używać stosu za pomocą interfejsu HAL Codec2/niepowiązanej listy HAL korzystającej z tego samego procesu. Nie można jednak korzystać z ogólnych funkcji platformy Androida z powodu szczegóły implementacji. W przypadku ogólnej bezpiecznej sterty zostanie w przyszłości dodana do wspólnego jądra systemu Android, musi używać innego interfejsu ABI, aby uniknąć konfliktów z uaktualnianiem urządzeń.
.

Przypisujący kodek 2 dla stert DMA-BUF

Alokator kodeka dla stertów DMA-BUF jest dostępna w usłudze AOSP.

Interfejs magazynu komponentów, który umożliwia określenie parametrów sterty klucz HAL C2 jest dostępny z przydzielającym stertę C2 DMA-BUF.

Przykładowy proces przejścia dla sterty ION

Aby płynnie przejść ze sterty ION na sterty DMA-BUF, libdmabufheap zezwala zmieniać stertę naraz. Poniższe kroki przedstawiają sugerowany przepływ pracy do przejścia na starszą wersję stosu ION o nazwie my_heap, która ją obsługuje flaga, ION_FLAG_MY_FLAG.

Krok 1. Utwórz odpowiedniki sterty ION w ramach DMA-BUF. W tym ponieważ sterta ION my_heap obsługuje flagę ION_FLAG_MY_FLAG, zarejestrować dwie sterty DMA-BUF:

  • Działanie my_heap jest dokładnie takie samo jak działanie sterty ION z parametrem flaga ION_FLAG_MY_FLAG wyłączona.
  • Zachowanie funkcji my_heap_special jest dokładnie takie samo jak działanie sterty ION z włączoną flagą ION_FLAG_MY_FLAG.

Krok 2. Utwórz nieoczekiwane zmiany w nowych my_heap i Stostki DMA-BUF (my_heap_special). W tym momencie sterty są widoczne jako /dev/dma_heap/my_heap i /dev/dma_heap/my_heap_special, z z zamierzonych uprawnień.

Krok 3. W przypadku klientów, którzy przeprowadzają przydzielanie zadań z bazy danych my_heap, zmodyfikuj pliki Maki w celu połączenia z usługą libdmabufheap. Podczas inicjowania klienta utwórz instancję BufferAllocator i użyj interfejsu API MapNameToIonHeap(), aby zmapować <ION heap name/mask, flag> z odpowiadającymi im nazwami sterty DMA-BUF.

Na przykład:

allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )

Zamiast używać interfejsu API MapNameToIonHeap() z parametrami nazwy i flagi, możesz utworzyć mapowanie <ION heap mask, flag> do równoważnej sterty DMA-BUF nazwy ustawiając parametr nazwy sterty ION na pusty.

Krok 4. Zastąp wywołania (ion_alloc_fd()) BufferAllocator::Alloc() za pomocą odpowiedniej nazwy stosu.

Typ przydziału Libion libdmabufheap
Przydział z: my_heap z flagą Usunięto: ION_FLAG_MY_FLAG ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd) allocator->Alloc("my_heap", size)
Przydział z: my_heap z flagą Ustawiono: ION_FLAG_MY_FLAG ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, ION_FLAG_MY_FLAG, &fd) allocator->Alloc("my_heap_special", size)

W tej chwili klient działa, ale nadal przydziela ze sterty ION ponieważ nie ma wymaganych uprawnień sepolicy do otwierania DMA-BUF sterta.

Krok 5. Utwórz uprawnienia sepolicy wymagane, aby klient miał dostęp nowe sterty DMA-BUF. Teraz klient może już Sterta DMA-BUF.

Krok 6. Sprawdź, czy przydziały są realizowane z nowej sterty DMA-BUF sprawdzając logcat.

Krok 7. Wyłącz stertę ION my_heap w jądrze. Jeśli kod klienta nie wymagają uaktualniania urządzeń (które jądra obsługują tylko ION); sterty), możesz też usunąć wywołania MapNameToIonHeap().