Na tej stronie opisujemy zmiany w sterowniku bindera w Androidzie 8, przedstawiamy szczegóły dotyczące korzystania z binder IPC oraz podajemy wymagane zasady SELinux.
Zmiany w sterowniku wiązania
Począwszy od Androida 8, platforma Android i interfejsy HAL komunikują się ze sobą za pomocą bindera. Ponieważ taka komunikacja znacznie zwiększa ruch bindera, Android 8 zawiera kilka ulepszeń, które mają na celu zapewnienie szybkiego działania interfejsu binder IPC. Dostawcy SoC i OEM-y powinni bezpośrednio łączyć odpowiednie gałęzie projektu kernel/common w wersjach android-4.4, android-4.9 lub nowszych.
Wiele domen bindera (kontekstów)
Wersja wspólna 4.4 i nowsze, w tym wsteczAby wyraźnie rozdzielić ruch bindera między kod frameworku (niezależny od urządzenia) a kod dostawcy (specyficzny dla urządzenia), w Androidzie 8 wprowadzono pojęcie kontekstu bindera. Każdy kontekst bindera ma własny węzeł urządzenia i własny menedżer kontekstu (usługi). Dostęp do menedżera kontekstu można uzyskać tylko przez węzeł urządzenia, do którego należy. Po przekazaniu węzła bindera w ramach określonego kontekstu jest on dostępny z tego samego kontekstu tylko przez inny proces, co pozwala na całkowite oddzielenie domen od siebie. Szczegółowe informacje o używaniu tych narzędzi znajdziesz w artykułach vndbinder i vndservicemanager.
Rozproszenie-zbieranie
Wersja wspólna 4.4 i nowsze, w tym wsteczW poprzednich wersjach Androida każdy element danych w połączeniu było kopiowany trzykrotnie:
- Po zserializowaniu go w
Parcel
w procesie wywoływania - W sterowniku jądra skopiuj
Parcel
do procesu docelowego. - raz, aby zdeserializować obiekt
Parcel
w docelowym procesie;
Android 8 korzysta z optymalizacji rozpraszania i gromadzenia, aby zmniejszyć liczbę kopii z 3 do 1. Zamiast serializacji danych w Parcel
, dane pozostają w pierwotnej strukturze i układzie pamięci, a sterownik od razu kopiuje je do procesu docelowego. Gdy dane znajdą się w docelowym procesie, ich struktura i układ pamięci pozostaną takie same, a dane będą mogły być odczytywane bez konieczności tworzenia kopii.
Szczegółowy blokowanie
Wersja wspólna 4.4 i nowsze, w tym wsteczW poprzednich wersjach Androida sterownik bindera używał globalnego blokowania w celu ochrony przed jednoczesnym 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ł zablokowany, mogło to znacznie opóźnić wątki o wyższym priorytecie, które potrzebowały tej samej blokady. Powodowało to zakłócenia w działaniu platformy.
Początkowe próby rozwiązania tego problemu polegały na wyłączeniu zatrzymywania i utrzymaniu blokady globalnej. Było to jednak raczej obejście problemu niż prawdziwe rozwiązanie, które zostało ostatecznie odrzucone przez źródło i odrzucone. Kolejne próby skupiały się na bardziej szczegółowym blokowaniu. Wersja, która jest używana na urządzeniach Pixel, działa od stycznia 2017 roku. Chociaż większość tych zmian została opublikowana, w kolejnych wersjach wprowadzono istotne ulepszenia.
Po wykryciu drobnych problemów w implementacji szczegółowego blokowania opracowaliśmy ulepszone rozwiązanie z inną architekturą blokowania i przesłaliśmy zmiany we wszystkich typowych gałęziach jądra. Nadal testujemy tę implementację na wielu różnych urządzeniach. Nie wiemy o żadnych nierozwiązanych problemach, dlatego jest to zalecana implementacja na urządzeniach z Androidem 8.
Dziedziczenie priorytetu w czasie rzeczywistym
Common-4.4 i common-4.9 (upstream wkrótce)Sterownik bindera zawsze obsługiwał ładne dziedziczenie priorytetów. W miarę jak rośnie liczba procesów w Androidzie, które działają z priorytetem czasu rzeczywistego, w niektórych przypadkach ma to sens, jeśli wątek w czasie rzeczywistym wywołuje binder, 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, Android 8 wdraża dziedziczenie priorytetów w czasie rzeczywistym w sterowniku bindera.
Oprócz dziedziczenia priorytetu na poziomie transakcji dziedziczenie priorytetu węzła pozwala węzłowi (obiekt usługi bindera) określić minimalny priorytet, z jakim powinny być wykonywane wywołania tego węzła. W poprzednich wersjach Androida dziedziczenie priorytetu węzła było obsługiwane za pomocą wartości ładnych, ale Android 8 umożliwia dziedziczenie węzła zasad harmonogramowania w czasie rzeczywistym.
Zmiany w przestrzeni użytkownika
Android 8 zawiera wszystkie zmiany w przestrzeni użytkownika wymagane do działania z obecnym sterownikiem bindera w ramach wspólnego jądra z jednym wyjątkiem: pierwotna implementacja wyłączania dziedziczenia priorytetu w czasie rzeczywistym w przypadku /dev/binder
używała polecenia ioctl. W kolejnych wersjach kontrola dziedziczenia priorytetów została zastąpiona bardziej szczegółową metodą, która jest zależna od trybu bindera (a nie od kontekstu). Dlatego ioctl nie znajduje się w gałęzi wspólnej Androida, a zamiast tego jest przesyłany w ramach naszych wspólnych jąder.
W efekcie dziedziczenie priorytetu w czasie rzeczywistym jest domyślnie wyłączone w przypadku każdego węzła. Zespół ds. wydajności Androida stwierdził, że korzystne jest włączenie dziedziczenia priorytetów w czasie rzeczywistym we wszystkich węzłach w domenie hwbinder
. Aby uzyskać ten sam efekt, wybierz tą zmianę w przestrzeni użytkownika.
SHA dla typowych jąder
Aby wprowadzić niezbędne zmiany w sterowniku bindera, zsynchronizuj się z odpowiednim identyfikatorem SHA:
- Common-3.18
cc8b90c121de ANDROID: binder: don't check prio permissions on restore. - Common-4.4
76b376eac7a2 ANDROID: binder: don't check prio permissions on restore. - Common-4.9
ecd972d4f9b5 ANDROID: binder: don't check prio permissions on restore.
Praca z interfejsem IPC notesektu
W przeszłości procesy dostawców korzystały z komunikacji międzyprocesowej bindera (IPC). W Androidzie 8 węzeł urządzenia /dev/binder
staje się dostępny wyłącznie dla procesów frameworka, 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 na interfejsy HIDL. Dostawcy, którzy chcą nadal używać interfejsów AIDL między procesami dostawcy, mogą korzystać z interfejsu binder IPC w sposób opisany poniżej. W Androidzie 10 interfejs Stable AIDL pozwala wszystkim procesom korzystać z interfejsu /dev/binder
, a także zapewnia stabilność, gwarantując zgodność z HIDL i interfejsem /dev/hwbinder
. Informacje o używaniu stabilnej wersji AIDL znajdziesz w artykule AIDL dla HAL-i.
vndbinder
Android 8 obsługuje nową domenę bindera na potrzeby usług dostawców. Dostęp do niej uzyskuje się za pomocą /dev/vndbinder
zamiast /dev/binder
. Dzięki dodaniu /dev/vndbinder
Android ma teraz 3 domeny IPC:
Domena IPC | Opis |
---|---|
/dev/binder |
IPC między procesami frameworku/aplikacji a interfejsami AIDL |
/dev/hwbinder |
IPC między procesami frameworku lub dostawcy za pomocą interfejsów HIDL
IPC między procesami dostawcy za pomocą interfejsów HIDL |
/dev/vndbinder |
IPC między dostawcami lub procesami dostawców za pomocą interfejsów AIDL |
Aby opcja /dev/vndbinder
była widoczna, sprawdź, czy element konfiguracji jądra CONFIG_ANDROID_BINDER_DEVICES
ma wartość "binder,hwbinder,vndbinder"
(jest to wartość domyślna w powszechnie stosowanych drzewach jądra Androida).
Zazwyczaj procesy dostawcy nie otwierają bezpośrednio sterownika bindera, lecz łączą się z biblioteką libbinder
w przestrzeni użytkownika, która otwiera sterownik bindera. Dodanie metody dla ::android::ProcessState()
wybiera sterownik złącza dla libbinder
. Procesy dostawcy powinny wywoływać tę metodę przed wywołaniem funkcji ProcessState,
IPCThreadState
lub przed wywołaniem dowolnej funkcji bindera. Aby
go użyć, wykonaj to wywołanie po main()
procesu dostawcy (klient i serwer):
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
Wcześniej usługi binder były rejestrowane w servicemanager
, gdzie mogły być pobierane przez inne procesy. W Androidzie 8 zmienna servicemanager
jest używana wyłącznie przez procesy frameworku i aplikacji, a procesy dostawców nie mają już do niej dostępu.
Usługi dostawcy mogą jednak teraz używać vndservicemanager
, nowej instancji servicemanager
, która korzysta z /dev/vndbinder
zamiast z /dev/binder
i która jest tworzona z tych samych źródeł co framework servicemanager
. Procesy dostawcy nie wymagają wprowadzania zmian, aby komunikować się z poziomem vndservicemanager
. Gdy proces dostawcy otwiera się w poziomie /dev/vndbinder
, wyszukiwanie usług jest automatycznie kierowane do poziomu vndservicemanager
.
Plik binarny vndservicemanager
jest dołączony do domyślnych plików make urządzenia Android.
Zasady SELinux
Procesy dostawcy, które chcą korzystać z funkcji bindera do komunikacji ze sobą, muszą spełniać te wymagania:
- Dostęp do usługi
/dev/vndbinder
. - Segregator
{transfer, call}
jest podłączony dovndservicemanager
. binder_call(A, B)
dla domeny dostawcy A, która chce wywołać domenę dostawcy B za pomocą interfejsu dostawcy.- Uprawnienia do usług
{add, find}
wvndservicemanager
.
Aby spełnić wymagania 1 i 2, użyj makro vndbinder_use()
:
vndbinder_use(some_vendor_process_domain);
Aby spełnić wymagania 3, usługa binder_call(A, B)
dla procesów dostawcy A i B, które muszą się komunikować za pomocą usługi binder, może pozostać na swoim miejscu i nie wymaga zmiany nazwy.
Aby spełnić wymóg 4, musisz wprowadzić zmiany w sposobie obsługi nazw usług, etykiet usług i zasad.
Szczegółowe informacje o SELinux znajdziesz w artykule SELinux (Security-Enhanced Linux) w Androidzie. Więcej informacji o SELinux w Androidzie 8.0 znajdziesz w artykule SELinux w Androidzie 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 poziomu 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 Androidzie 8 polecenie vndservicemanager
wczytuje zamiast tego plik vndservice_contexts
. Usługi dostawcy migrujące do pliku vndservicemanager
(i znajdujące się już w starym pliku service_contexts
) należy dodać do nowego pliku vndservice_contexts
.
Etykiety usług
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;
reguły servicemanagera,
Wcześniej reguły przyznawały domenom dostęp do dodawania i wyszukiwania 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 korzystać z tej samej klasy. Przykład:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;