Korzystanie z Binder IPC

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

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

Zmiany w sterowniku spinacza

Począwszy od systemu Android 8, platforma systemu Android i warstwy HAL komunikują się teraz ze sobą za pomocą spinacza. Ponieważ ta komunikacja radykalnie zwiększa ruch bindera, Android 8 zawiera kilka ulepszeń zaprojektowanych w celu utrzymania szybkości IPC bindera. Dostawcy SoC i OEM powinni łączyć się bezpośrednio z odpowiednich gałęzi androida-4.4, androida-4.9 i nowszych wersji projektu kernel/common .

Wiele domen wiążących (konteksty)

Common-4.4 i wyższe, w tym upstream

Aby dokładnie podzielić ruch spinacza między framework (niezależny od urządzenia) i kod dostawcy (specyficzny dla urządzenia), w systemie Android 8 wprowadzono koncepcję kontekstu spinacza . Każdy kontekst spinacza ma własny węzeł urządzenia i własnego menedżera kontekstu (usługi). Dostęp do menedżera kontekstu można uzyskać tylko przez węzeł urządzenia, do którego należy, a podczas przekazywania węzła spinacza 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 używania, zobacz vndbinder i vndservicemanager .

Rozpraszaj-zbieraj

Common-4.4 i wyższe, w tym upstream

W poprzednich wersjach Androida każdy element danych w wywołaniu segregatora był kopiowany trzy razy:

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

System Android 8 wykorzystuje optymalizację zbierania danych rozproszonych, 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 tym, jak dane znajdą się w docelowym procesie, struktura i układ pamięci są takie same, a dane można odczytać bez konieczności wykonywania kolejnej kopii.

Blokowanie drobnoziarniste

Common-4.4 i wyższe, w tym upstream

W poprzednich wersjach Androida sterownik bindera wykorzystywał globalną blokadę do 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 zostanie wywłaszczony, może to poważnie opóźnić wątki o wyższym priorytecie, które wymagają uzyskania tej samej blokady. To spowodowało szarpnięcie w platformie.

Pierwsze próby rozwiązania tego problemu polegały na wyłączeniu wywłaszczania podczas utrzymywania blokady globalnej. Jednak było to bardziej włamanie niż prawdziwe rozwiązanie i ostatecznie zostało odrzucone przez upstream i odrzucone. Kolejne próby koncentrowały się na dopracowaniu blokowania, którego wersja działa na urządzeniach Pixel od stycznia 2017 roku. Podczas gdy większość tych zmian została upubliczniona, w kolejnych wersjach wprowadzono znaczne ulepszenia.

Po zidentyfikowaniu drobnych problemów w drobnoziarnistej implementacji blokowania opracowaliśmy ulepszone rozwiązanie z inną architekturą blokowania i przedstawiliśmy zmiany we wszystkich popularnych gałęziach jądra. Nadal testujemy tę implementację na wielu różnych urządzeniach; ponieważ nie znamy ż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 w górę)

Sterownik bindera zawsze wspierał ł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 sens, że jeśli wątek czasu rzeczywistego wykonuje wywołanie spinacza, wątek w procesie, który obsługuje to wywołanie, również działa z priorytetem czasu rzeczywistego . Aby obsługiwać te przypadki użycia, system Android 8 implementuje teraz dziedziczenie priorytetów w czasie rzeczywistym w sterowniku spinacza.

Oprócz dziedziczenia priorytetów na poziomie transakcji, dziedziczenie priorytetów węzła umożliwia węzłowi (obiektowi usługi spinacza) określenie minimalnego priorytetu, z jakim wywołania do tego węzła powinny być wykonywane. Poprzednie wersje systemu Android obsługiwały już dziedziczenie priorytetów węzłów z ładnymi wartościami, ale w systemie Android 8 dodano 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óźniejsze prace rozwojowe przełączyły kontrolę nad dziedziczeniem priorytetów na bardziej szczegółową metodę, która jest oparta na trybie powiązania (a nie na kontekst). Tak więc ioctl nie znajduje się we wspólnej gałęzi Androida i zamiast tego jest przesyłany do naszych wspólnych jąder .

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 bindera, zsynchronizuj z odpowiednim SHA:

  • Zwykłe-3,18
    cc8b90c121de ANDROID: binder: nie sprawdzaj uprawnień priorytetowych podczas przywracania.
  • Wspólne-4.4
    76b376eac7a2 ANDROID: binder: nie sprawdzaj uprawnień priorytetowych podczas przywracania.
  • Wspólne-4,9
    ecd972d4f9b5 ANDROID: binder: nie sprawdzaj uprawnień priorytetowych podczas przywracania.

Korzystanie z segregatora IPC

Historycznie rzecz biorąc, procesy dostawców wykorzystywały do ​​komunikacji międzyprocesową komunikację spinacza (IPC). W systemie Android 8 węzeł urządzenia /dev/binder staje się wyłączny dla procesów struktury, co oznacza, że ​​procesy dostawcy nie mają już do niego dostępu. Procesy dostawcy mogą uzyskać dostęp do /dev/hwbinder , ale muszą przekonwertować swoje interfejsy AIDL, aby używały HIDL. W przypadku dostawców, którzy chcą nadal używać interfejsów AIDL między procesami dostawców, system Android obsługuje IPC spinacza, jak opisano poniżej.

vndbinder

Android 8 obsługuje nową domenę spinacza do użytku przez usługi dostawców, do której dostęp uzyskuje się przy użyciu /dev/vndbinder zamiast /dev/binder . Po dodaniu /dev/vndbinder Android ma teraz następujące trzy domeny IPC:

Domena IPC Opis
/dev/binder IPC między frameworkami/procesami aplikacji z interfejsami AIDL
/dev/hwbinder IPC między procesami framework/dostawca z interfejsami HIDL
IPC między procesami dostawcy z interfejsami HIDL
/dev/vndbinder IPC między procesami dostawcy/dostawcy z interfejsami 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 wartość domyślna we wspólnych drzewach jądra systemu Android).

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

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

vndservicemanager

Wcześniej usługi spinacza 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 struktury i aplikacji, a procesy dostawców nie mają już do niego dostępu.

Jednak usługi dostawców mogą teraz używać vndservicemanager , nowej instancji servicemanager , która używa /dev/vndbinder zamiast /dev/binder i która jest zbudowana z tych samych źródeł, co framework servicemanager . Procesy dostawcy nie muszą wprowadzać zmian, aby rozmawiać z vndservicemanager ; gdy proces dostawcy otwiera / dev/vndbinder , wyszukiwania usług automatycznie przechodzą do vndservicemanager .

Plik binarny vndservicemanager jest zawarty w domyślnych plikach makefile urządzeń Androida.

Polityka SELinux

Procesy dostawców, które chcą używać funkcji spinacza do komunikowania się ze sobą, 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 wywołać domenę dostawcy B za pośrednictwem interfejsu binder dostawcy.
  4. Uprawnienie do {add, find} usług w vndservicemanager .

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

vndbinder_use(some_vendor_process_domain);

Aby spełnić wymaganie 3, binder_call(A, B) dla procesów dostawcy A i B, które muszą omówić spoiwo, może pozostać na swoim 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ł.

Szczegółowe informacje na temat SELinux można znaleźć w artykule Linux z ulepszonymi zabezpieczeniami w systemie Android . Aby uzyskać szczegółowe informacje na temat SELinux w systemie Android 8.0, zobacz SELinux dla systemu Android 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 zamiast tego ładuje plik vndservice_contexts . Usługi dostawcy migrujące do vndservicemanager (które już znajdują się w starym pliku service_contexts ) należy dodać do nowego pliku vndservice_contexts .

Etykiety serwisowe

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 systemie Android 8 należy zmienić typ na vndservice_manager_type i przenieść regułę do pliku vndservice.te . Przykład:

type atfwd_service,      vndservice_manager_type;

Zasady ServiceManagera

Wcześniej reguły przyznawały domenom dostęp do dodawania lub znajdowania usług z servicemanager usług . 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ć na miejscu i używać tej samej klasy. Przykład:

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