W Androidzie 12 GKI 2.0 zastępuje alokator ION za pomocą stosów DMA-BUF z tych powodów:
- Bezpieczeństwo: każda sterta DMA-BUF jest oddzielnym urządzeniem znakowym, więc dostępem do każdej z nich można oddzielnie kontrolować za pomocą sepolicy. Nie było to możliwe w przypadku ION, ponieważ alokacja z dowolnego stosu wymagała tylko dostępu do urządzenia
/dev/ion
. - Stabilność ABI: w odróżnieniu od ION interfejs IOCTL w ramach platformy stosu DMA-BUF jest stabilny pod względem ABI, ponieważ jest utrzymywany w górnym jądrze systemu Linux.
- Standaryzacja: framework stosów DMA-BUF oferuje dobrze zdefiniowane UAPI. Usługa ION zezwalała na niestandardowe flagi i identyfikatory sterty, które uniemożliwiały opracowanie wspólnej platformy testowania, ponieważ implementacja ION w każdym urządzeniu mogła działać inaczej.
Gałąź android12-5.10
jądra Android Common Kernel została wyłączona CONFIG_ION
1 marca 2021 r..
Tło
Poniżej znajdziesz krótkie porównanie stosów ION i DMA-BUF.
Podobieństwa między strukturą stertów ION i DMA-BUF
- Zarówno platformy sterty ION, jak i DMA-BUF są eksporterami DMA-BUF opartymi na stercie.
- Oba te mechanizmy pozwalają każdej stercie zdefiniować własne funkcje alokacji i DMA-BUF.
- Wydajność przydzielania jest podobna, ponieważ oba schematy wymagają wykonania pojedynczego polecenia IOCTL.
Różnice między frameworkami ION i DMA-BUF
sterty ION | Kopie zapasowe DMA-BUF |
---|---|
Wszystkie alokacje ION są wykonywane za pomocą /dev/ion .
|
Każdy stos DMA-BUF to urządzenie znakowe obecne w miejscu /dev/dma_heap/<heap_name> .
|
ION obsługuje flagi prywatne stosu. | Kopie zapasowe DMA-BUF nie obsługują flag prywatności kopii zapasowej. Każdy rodzaj alokacji jest zamiast tego wykonywany z użyciem innego stosu. Na przykład wersje stosu systemowego z pamięci podręcznej i bez pamięci podręcznej to osobne stosy znajdujące się w miejscach /dev/dma_heap/system i /dev/dma_heap/system_uncached .
|
Na potrzeby alokacji musisz podać identyfikator lub maskę sterty oraz flagi. | Nazwa sterty służy do alokacji. |
W następnych sekcjach wymieniono komponenty, które korzystają z ION, oraz opisano, jak przełączyć je na ramkę stosu DMA-BUF.
Przejście z sterowników jądra z ION na stosy DMA-BUF
Sterowniki jądra implementujące stosy ION
Zarówno stosy ION, jak i DMA-BUF umożliwiają każdemu stosowi implementowanie własnych alokacji i operacji DMA-BUF. Możesz więc przełączyć się z implementacji stosu ION na implementację stosu DMA-BUF, używając innego zestawu interfejsów API do zarejestrowania stosu. Ta tabela przedstawia interfejsy API rejestracji stosu ION i ich odpowiedniki w interfejsach API stosu DMA-BUF.
sterty ION | Kopie zapasowe 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. Dlatego każdy wariant stosu musi być rejestrowany osobno za pomocą interfejsu API dma_heap_add()
. Aby ułatwić udostępnianie kodu, zalecamy rejestrowanie wszystkich wersji tej samej sterty w tym samym sterowniku.
Ten przykład dma-buf: system_heap pokazuje implementację wersji pamięci podręcznej i niezapisanej pamięci podręcznej systemu.
Aby utworzyć stos DMA-BUF od podstaw, użyj tego dma-buf: heaps: example template.
Sterowniki jądra przydzielają bezpośrednio z kupy ION.
Framework stosów DMA-BUF udostępnia też interfejs alokacji dla klientów w rdzeniu. Zamiast określać maskę stosu i flagi służące do wyboru typu alokacji, interfejs oferowany przez sterty DMA-BUF jako dane wejściowe przyjmuje nazwę stosu.
Poniżej przedstawiono interfejs API alokacji ION w rdzeniu i odpowiednie interfejsy API alokacji pamięci DMA-BUF. Sterowniki jądra mogą używać interfejsu API dma_heap_find()
, aby wysyłać zapytania o istnienie sterty. Interfejs API zwraca wskaźnik do instancji struktury dma_heap, którą można następnie przekazać jako argument do interfejsu API dma_heap_buffer_alloc()
.
Stosy ION | Kopie zapasowe DMA-BUF |
---|---|
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
|
|
Sterowniki jądra korzystające z DMA-BUF
W przypadku sterowników, które importują tylko obiekty DMA-BUF, nie są wymagane żadne zmiany, ponieważ bufor przypisany ze sterty ION działa dokładnie tak samo jak bufor przypisany z odpowiedniej sterty DMA-BUF.
Przejście z klientów ION w przestrzeni użytkownika do stosów DMA-BUF
Aby ułatwić przejście klientom ION w przestrzeni użytkownika, udostępniono bibliotekę abstrakcji libdmabufheap
. libdmabufheap
obsługuje alokację w strukturach DMA-BUF i ION. Najpierw sprawdza, czy istnieje stos DMA-BUF o określonej nazwie. Jeśli nie, przechodzi do równoważnego stosu ION (jeśli istnieje).
Klienci powinni zainicjować obiekt BufferAllocator
podczas inicjalizacji zamiast otwierać /dev/ion using
ion_open()
. Dzieje się tak, ponieważ opisami plików utworzonymi przez otwieranie /dev/ion
i /dev/dma_heap/<heap_name>
zarządza wewnętrznie obiekt BufferAllocator
.
Aby przejść z poziomu libion
na poziom libdmabufheap
, zmień zachowanie klientów w ten sposób:
- Zamiast identyfikatora głowy/maski i flagi stosu śledź nazwę stosu, której używasz do alokacji.
- Zastąp interfejs API
ion_alloc_fd()
, który wykorzystuje maskę stosu i argument flagi, interfejsem APIBufferAllocator::Alloc()
, który przyjmuje nazwę stosu.
Tabela ilustruje te zmiany, pokazując, jak libion
i libdmabufheap
wpływają na przydzielanie niewykorzystanego miejsca w systemowym stosie pamięci.
Typ przydziału | libion | libdmabufheap |
---|---|---|
Przydzielenie z bufora pamięci podręcznej z bufora systemowego | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd)
|
allocator->Alloc("system", size)
|
Niebuforowana alokacja z stosu systemowego | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd)
|
allocator->Alloc("system-uncached", size)
|
Niezcacheowany wariant stosu systemowego czeka na zatwierdzenie w głównym gałęzi, ale jest już częścią gałęzi android12-5.10
.
Aby obsługiwać uaktualnianie urządzeń, interfejs MapNameToIonHeap()
API umożliwia mapowanie nazwy sterty na parametry sterty ION (nazwa sterty lub maska i flagi), co umożliwia korzystanie z alokacji na podstawie nazw w tych interfejsach. Oto przykład przydziału na podstawie nazwy.
Dostępna jest dokumentacja każdego interfejsu API udostępnianego przez libdmabufheap
. Biblioteka udostępnia też plik nagłówka do użytku przez klienty C.
Referencyjna implementacja Gralloc
Implementacja gralloc w Hikey960 korzysta z libdmabufheap
, więc możesz ją wykorzystać jako implementację referencyjną.
Wymagane dodane elementy
W przypadku nowych stert DMA-BUF utworzonych na potrzeby konkretnego urządzenia dodaj nowy wpis do pliku ueventd.rc
urządzenia.
Ten przykład konfiguracji obsługi stosu DMA-BUF pokazuje, jak to zrobić w przypadku stosu systemowego DMA-BUF.
Wymagane dodatki do zasad bezpieczeństwa
Dodaj uprawnienia sepolicy, aby umożliwić klientowi w przestrzeni użytkownika dostęp do nowego stosu DMA-BUF. Ten przykład dodawania wymaganych uprawnień pokazuje uprawnienia sepolicy utworzone dla różnych klientów w celu dostępu do stosu systemu DMA-BUF.
Dostęp do stert dostawców z poziomu kodu platformy
Aby zapewnić zgodność z Treble, kod frameworku może przydzielać zasoby tylko z zaaprobowanych kategorii stosów dostawcy.
Na podstawie opinii partnerów zidentyfikowaliśmy 2 kategorie stert dostawców, do których należy uzyskać dostęp za pomocą kodu platformy:
- stosy oparte na stosie systemowym z optymalizacjami wydajności dla konkretnego urządzenia lub układu SoC;
- Stosy do przydzielenia z chronionej pamięci.
stosy oparte na stosie systemowym z optymalizacjami wydajności dla konkretnego urządzenia lub układu SoC;
Aby obsługiwać ten przypadek użycia, można zastąpić implementację stosu domyślnego systemu stosu DMA-BUF.
- Funkcja
CONFIG_DMABUF_HEAPS_SYSTEM
została wyłączona wgki_defconfig
, aby mogła pełnić funkcję modułu dostawcy. - Testy zgodności VTS sprawdzają, czy stos istnieje w miejscu
/dev/dma_heap/system
. Testy sprawdzają też, czy można przydzielić pamięć z kopca i czy zwracany deskryptor pliku (fd
) może być mapowany w pamięci z przestrzeni użytkownika.
Powyższe punkty odnoszą się również do wariantu sterty systemowej bez pamięci podręcznej, chociaż jego istnienie nie jest obowiązkowe w przypadku w pełni spójnych urządzeń we/wy.
stosy do przydzielenia z pamięci chronionej,
Implementacje bezpiecznej sterty muszą być zależne od dostawcy, ponieważ Common Jądro Androida nie obsługuje ogólnej implementacji bezpiecznej sterty.
- Zarejestruj implementacje swojego dostawcy jako
/dev/dma_heap/system-secure<vendor-suffix>
. - Implementacje stosu są opcjonalne.
- Jeśli sterty istnieją, testy VTS sprawdzają, czy można z nich zrobić alokacje.
- Komponenty frameworku mają dostęp do tych stosów, aby umożliwić ich użycie za pomocą interfejsu Codec2 HAL lub interfejsów HAL w ramach tego samego procesu, ale bez użycia Bindera. Ogólne funkcje Android Framework nie mogą jednak być od nich zależne ze względu na zmienność szczegółów ich implementacji. Jeśli w przyszłości do wspólnego jądra systemu Android zostanie dodana ogólna implementacja bezpiecznej stosu, będzie musiała używać innego interfejsu ABI, aby uniknąć konfliktów z uaktualnianiem urządzeń.
Przydzielacz 2 kodery dla stosów DMA-BUF
W AOSP jest dostępny algorytm alokacji codec2 dla interfejsu DMA-BUF heaps.
Interfejs magazynu komponentów, który umożliwia określenie parametrów sterty z C2 HAL, jest dostępny za pomocą algorytmu przydzielającego stertę C2 DMA-BUF.
Przykładowy przepływ danych w przypadku stosu ION
Aby płynnie przejść z kupy ION na kupę DMA-BUF, libdmabufheap
umożliwia przełączanie po jednej kupie naraz. Poniższe kroki przedstawiają sugerowany przepływ pracy dotyczący przejścia na starszą stertę ION o nazwie my_heap
, która obsługuje 1 flagę, ION_FLAG_MY_FLAG
.
Krok 1. Utwórz odpowiedniki stosu ION w ramach interfejsu DMA-BUF. W tym przykładzie sterta ION my_heap
obsługuje flagę ION_FLAG_MY_FLAG
, dlatego rejestrujemy 2 sterty DMA-BUF:
- Zachowanie
my_heap
dokładnie odpowiada działaniu stosu ION z wyłączoną flagąION_FLAG_MY_FLAG
. - Zachowanie funkcji
my_heap_special
jest dokładnie takie samo jak działanie stosu ION z włączoną flagąION_FLAG_MY_FLAG
.
Krok 2. Utwórz nieoczekiwane zmiany dla nowych stert DMA-BUF my_heap
i my_heap_special
. W tym momencie stosy są widoczne jako /dev/dma_heap/my_heap
i /dev/dma_heap/my_heap_special
z odpowiednimi uprawnieniami.
Krok 3. W przypadku klientów, którzy przypisują z poziomu my_heap
, zmodyfikuj ich pliki make, aby zawierały link do libdmabufheap
. Podczas inicjowania klienta utwórz instancję obiektu BufferAllocator
i użyj interfejsu API MapNameToIonHeap()
, aby zmapować kombinację <ION heap name/mask, flag>
na odpowiednie nazwy 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 name i flag, możesz utworzyć mapowanie z <ION heap mask, flag>
na równe sobie nazwy stosu DMA-BUF, ustawiając parametr nazwy stosu ION na pusty.
Krok 4. Zastąp wywołania ion_alloc_fd()
wywołaniami BufferAllocator::Alloc()
, używając odpowiedniej nazwy stosu.
Typ przydziału | Libion | libdmabufheap |
---|---|---|
Przydział z my_heap z nieustawioną flagą 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 ustawioną flagą 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 tym momencie klient działa, ale nadal przydziela pamięć z kupy ION, ponieważ nie ma wymaganych uprawnień sepolicy do otwierania kupy DMA-BUF.
Krok 5. Utwórz uprawnienia sepolicy wymagane, aby klient miał dostęp do nowych stertów DMA-BUF. Klient jest w pełni przygotowany do przydzielania zadań z nowej sterty DMA-BUF.
Krok 6. Sprawdź, czy przydziały są realizowane z nowej sterty DMA-BUF, sprawdzając tag logcat.
Krok 7. Wyłącz stos ION my_heap
w rdzeniu. Jeśli kod klienta nie musi obsługiwać urządzeń z aktualizacją (których jądra mogą obsługiwać tylko stosy ION), możesz też usunąć wywołania MapNameToIonHeap()
.