Korzystanie z Binder IPC

Ta strona opisuje zmiany w sterowniku bindera w systemie Android 8, zawiera szczegółowe informacje na temat korzystania z protokołu Binder IPC oraz listę wymaganych zasad SELinux.

Zmiany w sterowniku segregatora

Począwszy od systemu Android 8, platforma systemu Android i warstwy HAL komunikują się teraz ze sobą za pomocą spoiwa. Ponieważ ta komunikacja znacznie zwiększa ruch w segregatorach, system Android 8 zawiera kilka ulepszeń mających na celu zapewnienie szybkości IPC w segregatorach. Dostawcy SoC i producenci OEM powinni połączyć się bezpośrednio z odpowiednich gałęzi Androida 4.4, Androida 4.9 i nowszych wersji jądra/wspólnego projektu.

Wiele domen wiążących (konteksty)

Common-4.4 i nowsze, w tym upstream

Aby w przejrzysty sposób podzielić ruch powiązań między kod frameworka (niezależny od urządzenia) i kod dostawcy (specyficzny dla urządzenia), w systemie Android 8 wprowadzono koncepcję kontekstu powiązania . Każdy kontekst powiązania ma swój własny węzeł urządzenia i własnego menedżera kontekstu (usługi). Dostęp do menedżera kontekstu można uzyskać tylko poprzez węzeł urządzenia, do którego on należy, a podczas przekazywania węzła segregatora przez określony kontekst jest on dostępny z tego samego kontekstu tylko przez inny proces, całkowicie izolując w ten sposób domeny od siebie. Aby uzyskać szczegółowe informacje na temat korzystania, zobacz vndbinder i vndservicemanager .

Rozproszenie-zbieranie

Common-4.4 i nowsze, w tym upstream

W poprzednich wersjach Androida każdy fragment danych w wywołaniu segregatora był kopiowany trzykrotnie:

  • Raz, aby serializować go w Parcel w procesie wywoływania
  • Po wejściu do sterownika jądra, aby skopiować Parcel do procesu docelowego
  • Raz, aby odserializować Parcel w procesie docelowym

Android 8 wykorzystuje optymalizację zbierania rozproszenia , aby zmniejszyć liczbę kopii z 3 do 1. Zamiast najpierw serializować dane w Parcel , dane pozostają w oryginalnej strukturze i układzie pamięci, a sterownik natychmiast kopiuje je do procesu docelowego. Po wejściu danych do procesu docelowego struktura i układ pamięci są takie same, a dane można odczytać bez konieczności tworzenia kolejnej kopii.

Blokowanie drobnoziarniste

Common-4.4 i nowsze, w tym upstream

W poprzednich wersjach systemu Android sterownik segregatora korzystał z blokady globalnej w celu ochrony przed równoczesnym dostępem do krytycznych struktur danych. Chociaż rywalizacja o blokadę była minimalna, głównym problemem było to, że jeśli wątek o niskim priorytecie uzyskał blokadę, a następnie został wywłaszczony, mogłoby to poważnie opóźnić wątki o wyższym priorytecie wymagające uzyskania tej samej blokady. To spowodowało Janka na platformie.

Początkowe próby rozwiązania tego problemu polegały na wyłączeniu wywłaszczania przy trzymaniu blokady globalnej. Było to jednak bardziej hackowanie niż prawdziwe rozwiązanie i ostatecznie zostało odrzucone przez firmę upstream i odrzucone. Kolejne próby skupiały się na udoskonaleniu blokowania, czego wersja działa na urządzeniach Pixel od stycznia 2017 r. Choć większość tych zmian została upubliczniona, w kolejnych wersjach wprowadzono istotne ulepszenia.

Po zidentyfikowaniu drobnych problemów w szczegółowej implementacji blokowania opracowaliśmy ulepszone rozwiązanie z inną architekturą blokowania i przesłaliśmy zmiany we wszystkich popularnych gałęziach jądra. Kontynuujemy testowanie tej implementacji na dużej liczbie różnych urządzeń; ponieważ nie jesteśmy świadomi żadnych nierozstrzygniętych problemów, jest to zalecana implementacja dla urządzeń dostarczanych z systemem Android 8.

Dziedziczenie priorytetów w czasie rzeczywistym

Common-4.4 i Common-4.9 (wkrótce upstream)

Sterownik segregatora zawsze obsługiwał ładne dziedziczenie priorytetów. Ponieważ coraz większa liczba procesów w systemie Android działa z priorytetem czasu rzeczywistego, w niektórych przypadkach ma teraz sens, że jeśli wątek w czasie rzeczywistym wywołuje segregator, wątek w procesie, który obsługuje to wywołanie, również działa z priorytetem czasu rzeczywistego . Aby obsłużyć te przypadki użycia, system Android 8 implementuje teraz dziedziczenie priorytetów w czasie rzeczywistym w sterowniku spoiwa.

Oprócz dziedziczenia priorytetów na poziomie transakcji, dziedziczenie priorytetów węzła umożliwia węzłowi (obiektowi usługi spoiwa) określenie minimalnego priorytetu, z jakim powinny być wykonywane wywołania do tego węzła. Poprzednie wersje Androida obsługiwały już dziedziczenie priorytetów węzłów z ładnymi wartościami, ale Android 8 dodał obsługę dziedziczenia węzłów zasad planowania w czasie rzeczywistym.

Zmiany w przestrzeni użytkownika

Android 8 zawiera wszystkie zmiany w przestrzeni użytkownika wymagane do pracy z bieżącym sterownikiem bindera we wspólnym jądrze z jednym wyjątkiem: oryginalna implementacja wyłączająca dziedziczenie priorytetów w czasie rzeczywistym dla /dev/binder używała ioctl . Późniejszy rozwój zmienił kontrolę dziedziczenia priorytetów na bardziej precyzyjną metodę, czyli w trybie spoiwa (a nie w kontekście). Zatem ioctl nie znajduje się we wspólnej gałęzi Androida i zamiast tego jest przesyłany w naszych wspólnych jądrach .

Efektem tej zmiany jest to, że dziedziczenie priorytetów w czasie rzeczywistym jest domyślnie wyłączone dla każdego węzła. Zespół ds. wydajności systemu Android uznał za korzystne włączenie dziedziczenia priorytetów w czasie rzeczywistym dla wszystkich węzłów w domenie hwbinder . Aby osiągnąć ten sam efekt, wybierz tę zmianę w przestrzeni użytkownika.

SHA dla popularnych jąder

Aby uzyskać niezbędne zmiany w sterowniku segregatora, zsynchronizuj się z odpowiednim SHA:

  • Wspólne-3.18
    cc8b90c121de ANDROID: spoiwo: nie sprawdzaj uprawnień priorytetowych podczas przywracania.
  • Wspólne-4.4
    76b376eac7a2 ANDROID: spoiwo: nie sprawdzaj uprawnień priorytetowych podczas przywracania.
  • Często-4,9
    ecd972d4f9b5 ANDROID: spoiwo: nie sprawdzaj uprawnień priorytetowych podczas przywracania.

Korzystanie ze spoiwa IPC

Historycznie rzecz biorąc, procesy dostawców do komunikacji wykorzystywały komunikację między procesami spoiw (IPC). W systemie Android 8 węzeł urządzenia /dev/binder staje się dostępny wyłącznie dla procesów platformy, co oznacza, że ​​procesy dostawców nie mają już do niego dostępu. Procesy dostawców mogą uzyskać dostęp do /dev/hwbinder , ale muszą przekonwertować swoje interfejsy AIDL na używanie HIDL. W przypadku dostawców, którzy chcą nadal korzystać z interfejsów AIDL między procesami dostawców, system Android obsługuje protokół IPC w sposób opisany poniżej. W systemie Android 10 stabilny AIDL umożliwia wszystkim procesom korzystanie z /dev/binder , jednocześnie rozwiązując problemy gwarantujące stabilność HIDL i /dev/hwbinder . Aby dowiedzieć się, jak używać stabilnego AIDL, zobacz AIDL dla HAL .

vndbinder

Android 8 obsługuje nową domenę bindera do użytku przez usługi dostawców, do której dostęp można uzyskać za pomocą /dev/vndbinder zamiast /dev/binder . Po dodaniu /dev/vndbinder Android ma teraz następujące trzy domeny IPC:

Domena IPC Opis
/dev/binder IPC pomiędzy procesami frameworku/aplikacji z interfejsami AIDL
/dev/hwbinder IPC pomiędzy procesami frameworku/dostawcy z interfejsami HIDL
IPC pomiędzy procesami dostawców za pomocą interfejsów HIDL
/dev/vndbinder IPC pomiędzy procesami dostawcy/dostawcy za pomocą interfejsów AIDL

Aby pojawił się /dev/vndbinder , upewnij się, że element konfiguracji jądra CONFIG_ANDROID_BINDER_DEVICES jest ustawiony na "binder,hwbinder,vndbinder" (jest to ustawienie domyślne w popularnych drzewach jądra systemu Android).

Zwykle procesy dostawców nie otwierają bezpośrednio sterownika segregatora, lecz zamiast tego łączą się z biblioteką przestrzeni użytkownika libbinder , która otwiera sterownik segregatora. Dodanie metody dla ::android::ProcessState() wybiera sterownik spoiwa dla libbinder . Procesy dostawców powinny wywoływać tę metodę przed wywołaniem ProcessState, IPCThreadState lub ogólnie przed wykonaniem jakichkolwiek wywołań segregatorów. Aby skorzystać, umieść następujące wywołanie po funkcji main() procesu dostawcy (klienta i serwera):

ProcessState::initWithDriver("/dev/vndbinder");

vndservicemanager

Wcześniej usługi segregatorów były rejestrowane w servicemanager , skąd mogły być pobierane przez inne procesy. W systemie Android 8 servicemanager jest teraz używany wyłącznie przez procesy platformy i aplikacji, a procesy dostawców nie mają już do niego dostępu.

Jednakże usługi dostawców mogą teraz używać vndservicemanager , nowej instancji servicemanager korzystającej z /dev/vndbinder zamiast /dev/binder i zbudowanej z tych samych źródeł, co framework servicemanager . Procesy dostawców nie muszą wprowadzać zmian, aby porozmawiać z vndservicemanager ; kiedy proces dostawcy otwiera / dev/vndbinder , wyszukiwanie usług automatycznie przechodzi do vndservicemanager .

Plik binarny vndservicemanager jest zawarty w domyślnych plikach makefile urządzenia z systemem Android.

Polityka SELinuksa

Procesy dostawców, które chcą używać funkcji segregatorów do wzajemnej komunikacji, potrzebują następujących elementów:

  1. Dostęp do /dev/vndbinder .
  2. Binder {transfer, call} łączy się z vndservicemanager .
  3. binder_call(A, B) dla dowolnej domeny dostawcy A, która chce nawiązać połączenie z domeną dostawcy B za pośrednictwem interfejsu bindera dostawcy.
  4. Zezwolenie na usługi {add, find} w vndservicemanager .

Aby spełnić wymagania 1 i 2, użyj makra vndbinder_use() :

vndbinder_use(some_vendor_process_domain);

Aby spełnić wymaganie 3, funkcja binder_call(A, B) dla procesów dostawcy A i B, które muszą omówić segregator, może pozostać na miejscu i nie wymaga zmiany nazwy.

Aby spełnić wymaganie 4, należy wprowadzić zmiany w sposobie obsługi nazw usług, etykiet usług i reguł.

Aby uzyskać szczegółowe informacje na temat SELinuksa, zobacz Linux ze zwiększonymi zabezpieczeniami w systemie Android . Aby uzyskać szczegółowe informacje na temat SELinux w systemie Android 8.0, zobacz SELinux dla Androida 8.0 .

Nazwy usług

Wcześniej dostawca przetwarzał zarejestrowane nazwy usług w pliku service_contexts i dodawał odpowiednie reguły dostępu do tego pliku. Przykładowy plik service_contexts z device/google/marlin/sepolicy :

AtCmdFwd                              u:object_r:atfwd_service:s0
cneservice                            u:object_r:cne_service:s0
qti.ims.connectionmanagerservice      u:object_r:imscm_service:s0
rcs                                   u:object_r:radio_service:s0
uce                                   u:object_r:uce_service:s0
vendor.qcom.PeripheralManager         u:object_r:per_mgr_service:s0

W systemie Android 8 vndservicemanager ładuje zamiast tego plik vndservice_contexts . Usługi dostawcy migrujące do vndservicemanager (które znajdują się już w starym pliku service_contexts ) należy dodać do nowego pliku vndservice_contexts .

Etykiety usługowe

Wcześniej etykiety usług, takie jak u:object_r:atfwd_service:s0 były definiowane w pliku service.te . Przykład:

type atfwd_service,      service_manager_type;

W Androidzie 8 musisz zmienić typ na vndservice_manager_type i przenieść regułę do pliku vndservice.te . Przykład:

type atfwd_service,      vndservice_manager_type;

Zasady menedżera serwisu

Wcześniej reguły zapewniały domenom dostęp do dodawania i wyszukiwania usług w servicemanager . Przykład:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;

W Androidzie 8 takie reguły mogą pozostać niezmienione i używać tej samej klasy. Przykład:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;