Ta strona opisuje zmiany w sterowniku bindera w systemie Android 8, zawiera szczegółowe informacje na temat korzystania z bindera IPC oraz listę wymaganych zasad SELinux.
Zmiany w sterowniku segregatora
Począwszy od systemu Android 8, środowisko systemu Android i warstwy HAL komunikują się teraz ze sobą za pomocą programu wiążącego. Ponieważ ta komunikacja znacznie zwiększa ruch związany z segregatorem, system Android 8 zawiera kilka ulepszeń zaprojektowanych w celu utrzymania szybkości IPC segregatora. Dostawcy SoC i producenci OEM powinni łączyć się bezpośrednio z odpowiednimi gałęziami Androida 4.4, Androida 4.9 i nowszych w jądrze/wspólnym projekcie.
Wiele domen wiążących (konteksty)
Common-4.4 i nowsze, w tym upstreamAby wyraźnie podzielić ruch związany z kodem frameworka (niezależnym od urządzenia) i kodem dostawcy (specyficznym dla urządzenia), w systemie Android 8 wprowadzono koncepcję kontekstu bindera . Każdy kontekst łącznika 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 za pośrednictwem węzła urządzenia, do którego należy, a po przekazaniu węzła wiążącego przez określony kontekst jest on dostępny z tego samego kontekstu tylko przez inny proces, co całkowicie izoluje domeny od siebie. Aby uzyskać szczegółowe informacje na temat używania, zobacz vndbinder i vndservicemanager .
Zbieranie rozproszone
Common-4.4 i nowsze, w tym upstreamW poprzednich wersjach Androida każdy fragment danych w wywołaniu bindera był kopiowany trzy razy:
- Raz, aby serializować go do
Parcel
w procesie wywołującym - Raz w sterowniku jądra, aby skopiować
Parcel
do procesu docelowego - Raz, aby cofnąć serializację
Parcel
w procesie docelowym
Android 8 wykorzystuje optymalizację scatter-gather, 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 umieszczeniu danych w procesie docelowym struktura i układ pamięci są takie same, a dane można odczytać bez konieczności wykonywania kolejnej kopii.
Blokada drobnoziarnista
Common-4.4 i nowsze, w tym upstreamW poprzednich wersjach systemu Android sterownik bindera używał 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 zostanie wywłaszczony, może poważnie opóźnić wątki o wyższym priorytecie, które muszą uzyskać tę samą blokadę. Spowodowało to szarpnięcie na platformie.
Początkowe próby rozwiązania tego problemu polegały na wyłączeniu wywłaszczania podczas utrzymywania blokady globalnej. Było to jednak bardziej włamanie niż prawdziwe rozwiązanie i ostatecznie zostało odrzucone przez upstream i odrzucone. Kolejne próby skupiały się na uszczegółowieniu blokady, której wersja działa na urządzeniach Pixel od stycznia 2017 roku. Chociaż większość tych zmian została upubliczniona, w kolejnych wersjach wprowadzono znaczne 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. Nadal testujemy tę implementację na wielu różnych urządzeniach; ponieważ nie znamy żadnych nierozwiązanych 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 nadrzędne)Sterownik bindera zawsze obsługiwał ładne dziedziczenie priorytetów. Ponieważ coraz więcej procesów w Androidzie działa z priorytetem w czasie rzeczywistym, w niektórych przypadkach sensowne jest teraz, że jeśli wątek w czasie rzeczywistym wykonuje wywołanie bindera, wątek w procesie, który obsługuje to wywołanie, również działa z priorytetem w czasie rzeczywistym . Aby obsłużyć te przypadki użycia, system Android 8 implementuje teraz dziedziczenie priorytetów w czasie rzeczywistym w sterowniku bindera.
Oprócz dziedziczenia priorytetów na poziomie transakcji, dziedziczenie priorytetów węzłów umożliwia węzłowi (obiektowi usługi spinacza) określenie minimalnego priorytetu, z jakim powinny być wykonywane wywołania tego węzła. Poprzednie wersje Androida obsługiwały już dziedziczenie priorytetów węzłów z ładnymi wartościami, ale Android 8 dodaje obsługę dziedziczenia węzłów zasad planowania w czasie rzeczywistym.
Zmiany 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 przełączył kontrolę nad dziedziczeniem priorytetów na bardziej szczegółową metodę, która jest na tryb wiązania (a nie na kontekst). Zatem 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 wspólnych jąder
Aby uzyskać niezbędne zmiany w sterowniku bindera, zsynchronizuj z odpowiednim SHA:
- Wspólne-3.18
cc8b90c121de ANDROID: spoiwo: nie sprawdzaj uprawnień prio podczas przywracania. - Wspólne-4.4
76b376eac7a2 ANDROID: spoiwo: nie sprawdzaj uprawnień prio podczas przywracania. - Wspólne-4,9
ecd972d4f9b5 ANDROID: spoiwo: nie sprawdzaj uprawnień prio podczas przywracania.
Używanie spoiwa IPC
W przeszłości procesy dostawców wykorzystywały do komunikacji komunikację międzyprocesową (IPC). W Androidzie 8 węzeł urządzenia /dev/binder
staje się wyłączny dla procesów ramowych, co oznacza, że procesy dostawców nie mają już do niego dostępu. Procesy dostawcy mogą uzyskiwać dostęp do /dev/hwbinder
, ale muszą przekonwertować swoje interfejsy AIDL, aby używały HIDL. W przypadku dostawców, którzy chcą nadal korzystać z interfejsów AIDL między procesami dostawców, system Android obsługuje spoiwo IPC, jak opisano poniżej. W Androidzie 10, Stable AIDL pozwala wszystkim procesom używać /dev/binder
, jednocześnie rozwiązując problemy gwarantujące stabilność HIDL i /dev/hwbinder
rozwiązane. Aby dowiedzieć się, jak używać stabilnego AIDL, zobacz AIDL dla warstw HAL .
vndbinder
Android 8 obsługuje nową domenę programu wiążącego do użytku przez usługi dostawcy, do której dostęp uzyskuje się 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 między procesami frameworka/aplikacji z interfejsami AIDL |
/dev/hwbinder | IPC między procesami frameworka/dostawcy z interfejsami HIDL IPC między procesami dostawcy z interfejsami HIDL |
/dev/vndbinder | IPC między procesami sprzedawcy/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 ustawienie domyślne we wspólnych drzewach jądra systemu Android).
Zwykle procesy dostawców nie otwierają bezpośrednio sterownika bindera, a 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 dostawców powinny wywoływać tę metodę przed wywołaniem ProcessState,
IPCThreadState
lub przed wykonaniem jakichkolwiek wywołań programu wiążącego. Aby użyć, umieść następujące wywołanie po funkcji main()
procesu dostawcy (klienta i serwera):
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
Wcześniej usługi spinacza były rejestrowane przy użyciu 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 usługi dostawcy mogą teraz używać vndservicemanager
, nowego wystąpienia servicemanager
, które używa /dev/vndbinder
zamiast /dev/binder
i które jest zbudowane z tych samych źródeł co servicemanager
struktury. Procesy dostawcy nie muszą wprowadzać zmian, aby komunikować się 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ądzeń z Androidem.
Polityka SELinuksa
Procesy dostawcy, które chcą używać funkcji wiązania do komunikowania się ze sobą, potrzebują następujących elementów:
- Dostęp do
/dev/vndbinder
. - Binder
{transfer, call}
łączy się zvndservicemanager
. -
binder_call(A, B)
dla dowolnej domeny dostawcy A, która chce nawiązać połączenie z domeną dostawcy B przez interfejs wiązania dostawcy. - Uprawnienie do usług
{add, find}
wvndservicemanager
.
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ą rozmawiać przez program wiążący, może pozostać na swoim miejscu i nie wymaga zmiany nazwy.
Aby spełnić wymaganie 4, musisz wprowadzić zmiany w sposobie obsługi nazw usług, etykiet usług i reguł.
Aby uzyskać szczegółowe informacje na temat SELinux, zobacz Linux z ulepszonymi zabezpieczeniami w systemie Android . Aby uzyskać szczegółowe informacje na temat SELinux w Androidzie 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
zamiast tego ładuje 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 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 musisz zmienić typ na vndservice_manager_type
i przenieść regułę do pliku vndservice.te
. Przykład:
type atfwd_service, vndservice_manager_type;
Zasady kierownika serwisu
Wcześniej reguły przyznawały domenom dostęp do dodawania lub znajdowania usług z 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ć na swoim 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;