Diese Seite beschreibt Änderungen am Binder-Treiber in Android 8, enthält Details zur Verwendung von Binder IPC und listet die erforderliche SELinux-Richtlinie auf.
Änderungen am Bindertreiber
Ab Android 8 kommunizieren das Android-Framework und HALs nun mithilfe von Binder miteinander. Da diese Kommunikation den Binder-Traffic dramatisch erhöht, enthält Android 8 mehrere Verbesserungen, um Binder IPC schnell zu halten. SoC-Anbieter und OEMs sollten direkt aus den relevanten Zweigen von Android-4.4, Android-4.9 und höher des Kernel/Common -Projekts zusammengeführt werden.
Mehrere Binderdomänen (Kontexte)
Common-4.4 und höher, einschließlich UpstreamUm den Binder-Traffic sauber zwischen Framework- (geräteunabhängigem) und Anbieter- (gerätespezifischem) Code aufzuteilen, wurde mit Android 8 das Konzept eines Binder-Kontexts eingeführt. Jeder Binderkontext hat seinen eigenen Geräteknoten und seinen eigenen Kontext-(Dienst-)Manager. Sie können auf den Kontextmanager nur über den Geräteknoten zugreifen, zu dem er gehört, und wenn ein Binderknoten durch einen bestimmten Kontext geleitet wird, ist er aus demselben Kontext nur für einen anderen Prozess zugänglich, wodurch die Domänen vollständig voneinander isoliert werden. Einzelheiten zur Verwendung finden Sie unter vndbinder und vndservicemanager .
Scatter-Gather
Common-4.4 und höher, einschließlich UpstreamIn früheren Versionen von Android wurde jedes Datenelement in einem Binder-Aufruf dreimal kopiert:
- Einmal, um es im aufrufenden Prozess in ein
Parcel
zu serialisieren - Einmal im Kernel-Treiber kopieren Sie das
Parcel
in den Zielprozess - Einmal, um das
Parcel
im Zielprozess zu deserialisieren
Android 8 verwendet Scatter-Gather-Optimierung , um die Anzahl der Kopien von 3 auf 1 zu reduzieren. Anstatt Daten zuerst in einem Parcel
zu serialisieren, bleiben die Daten in ihrer ursprünglichen Struktur und ihrem Speicherlayout und der Treiber kopiert sie sofort in den Zielprozess. Nachdem sich die Daten im Zielprozess befinden, sind die Struktur und das Speicherlayout gleich und die Daten können gelesen werden, ohne dass eine weitere Kopie erforderlich ist.
Feingranulare Verriegelung
Common-4.4 und höher, einschließlich UpstreamIn früheren Android-Versionen verwendete der Binder-Treiber eine globale Sperre, um vor gleichzeitigem Zugriff auf kritische Datenstrukturen zu schützen. Obwohl es nur minimale Konflikte um die Sperre gab, bestand das Hauptproblem darin, dass, wenn ein Thread mit niedriger Priorität die Sperre erhielt und dann präemptiv wurde, Threads mit höherer Priorität, die dieselbe Sperre erhalten mussten, ernsthaft verzögert werden konnten. Dies verursachte einen Ruck in der Plattform.
Anfängliche Versuche, dieses Problem zu lösen, umfassten das Deaktivieren der Präemption, während die globale Sperre beibehalten wurde. Dies war jedoch eher ein Hack als eine echte Lösung und wurde schließlich von Upstream abgelehnt und verworfen. Nachfolgende Versuche konzentrierten sich darauf, das Sperren feinkörniger zu machen, von dem eine Version seit Januar 2017 auf Pixel-Geräten läuft. Während die meisten dieser Änderungen veröffentlicht wurden, wurden in nachfolgenden Versionen wesentliche Verbesserungen vorgenommen.
Nachdem wir kleine Probleme in der feinkörnigen Sperrimplementierung identifiziert hatten, haben wir eine verbesserte Lösung mit einer anderen Sperrarchitektur entwickelt und die Änderungen in allen gängigen Kernel-Zweigen eingereicht. Wir testen diese Implementierung weiterhin auf einer großen Anzahl verschiedener Geräte. Da uns keine ausstehenden Probleme bekannt sind, ist dies die empfohlene Implementierung für Geräte, die mit Android 8 ausgeliefert werden.
Prioritätsvererbung in Echtzeit
Common-4.4 und common-4.9 (Upstream folgt in Kürze)Der Binder-Treiber hat immer eine nette Prioritätsvererbung unterstützt. Da immer mehr Prozesse in Android mit Echtzeitpriorität ausgeführt werden, ist es in einigen Fällen jetzt sinnvoll, dass, wenn ein Echtzeitthread einen Binderaufruf durchführt, der Thread im Prozess, der diesen Aufruf verarbeitet, ebenfalls mit Echtzeitpriorität ausgeführt wird . Um diese Anwendungsfälle zu unterstützen, implementiert Android 8 jetzt die Echtzeit-Prioritätsvererbung im Binder-Treiber.
Zusätzlich zur Prioritätsvererbung auf Transaktionsebene ermöglicht die Knotenprioritätsvererbung einem Knoten (Binderdienstobjekt), eine Mindestpriorität anzugeben, mit der Aufrufe in diesen Knoten ausgeführt werden sollen. Frühere Versionen von Android unterstützten bereits die Knotenprioritätsvererbung mit netten Werten, aber Android 8 fügt Unterstützung für die Knotenvererbung von Echtzeitplanungsrichtlinien hinzu.
Benutzerbereich ändert sich
Android 8 enthält alle Userspace-Änderungen, die erforderlich sind, um mit dem aktuellen Binder-Treiber im gemeinsamen Kernel zu arbeiten, mit einer Ausnahme: Die ursprüngliche Implementierung zum Deaktivieren der Echtzeit-Prioritätsvererbung für /dev/binder
verwendete ein ioctl . Die nachfolgende Entwicklung hat die Steuerung der Prioritätsvererbung auf eine feinkörnigere Methode umgestellt, die pro Bindemodus (und nicht pro Kontext) gilt. Daher befindet sich ioctl nicht im Android Common Branch und wird stattdessen in unseren Common Kernels übermittelt .
Diese Änderung bewirkt, dass die Echtzeit-Prioritätsvererbung standardmäßig für jeden Knoten deaktiviert ist. Das Android-Leistungsteam hat es für vorteilhaft befunden, die Prioritätsvererbung in Echtzeit für alle Knoten in der hwbinder
Domäne zu aktivieren. Um denselben Effekt zu erzielen, wählen Sie diese Änderung im Benutzerbereich aus.
SHAs für gängige Kernel
Um die erforderlichen Änderungen am Binder-Treiber zu erhalten, synchronisieren Sie mit dem entsprechenden SHA:
- Allgemein-3.18
cc8b90c121de ANDROID: Ordner: Prio-Berechtigungen beim Wiederherstellen nicht prüfen. - Allgemein-4.4
76b376eac7a2 ANDROID: Ordner: Prio-Berechtigungen beim Wiederherstellen nicht prüfen. - Allgemein-4.9
ecd972d4f9b5 ANDROID: Binder: Prio-Berechtigungen beim Wiederherstellen nicht prüfen.
Mit Binder IPC
In der Vergangenheit haben Lieferantenprozesse Binder Interprocess Communication (IPC) zur Kommunikation verwendet. In Android 8 wird der Geräteknoten /dev/binder
exklusiv für Framework-Prozesse, was bedeutet, dass Anbieterprozesse keinen Zugriff mehr darauf haben. Anbieterprozesse können auf /dev/hwbinder
, müssen aber ihre AIDL-Schnittstellen konvertieren, um HIDL zu verwenden. Für Anbieter, die weiterhin AIDL-Schnittstellen zwischen Anbieterprozessen verwenden möchten, unterstützt Android Binder IPC wie unten beschrieben. In Android 10 ermöglicht Stable AIDL allen Prozessen die Verwendung von /dev/binder
, während gleichzeitig die Lösung für die Stabilitätsgarantien HIDL und /dev/hwbinder
gelöst wird. Informationen zur Verwendung von Stable AIDL finden Sie unter AIDL für HALs .
vndbinder
Android 8 unterstützt eine neue Binderdomäne zur Verwendung durch Anbieterdienste, auf die über /dev/vndbinder
statt über /dev/binder
zugegriffen wird. Mit dem Hinzufügen von /dev/vndbinder
hat Android nun die folgenden drei IPC-Domains:
IPC-Domäne | Beschreibung |
---|---|
/dev/binder | IPC zwischen Framework/App-Prozessen mit AIDL-Schnittstellen |
/dev/hwbinder | IPC zwischen Framework/Vendor-Prozessen mit HIDL-Schnittstellen IPC zwischen Lieferantenprozessen mit HIDL-Schnittstellen |
/dev/vndbinder | IPC zwischen Lieferanten-/Lieferantenprozessen mit AIDL-Schnittstellen |
Damit /dev/vndbinder
angezeigt wird, stellen Sie sicher, dass das Kernel-Konfigurationselement CONFIG_ANDROID_BINDER_DEVICES
auf "binder,hwbinder,vndbinder"
ist (dies ist die Standardeinstellung in den allgemeinen Kernel-Bäumen von Android).
Normalerweise öffnen Anbieterprozesse den Binder-Treiber nicht direkt und verknüpfen stattdessen mit der libbinder
Userspace-Bibliothek, die den Binder-Treiber öffnet. Das Hinzufügen einer Methode für ::android::ProcessState()
wählt den Binder-Treiber für libbinder
aus. Anbieterprozesse sollten diese Methode aufrufen, bevor sie ProcessState ProcessState,
IPCThreadState
oder allgemein Binderaufrufe durchführen. Platzieren Sie zur Verwendung den folgenden Aufruf nach main()
eines Anbieterprozesses (Client und Server):
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
Bisher wurden Binder-Services bei servicemanager
registriert, wo sie von anderen Prozessen abgerufen werden konnten. In Android 8 wird der servicemanager
nun ausschließlich von Framework- und App-Prozessen verwendet und Anbieterprozesse können nicht mehr darauf zugreifen.
Anbieterdienste können jetzt vndservicemanager
verwenden, eine neue Instanz von servicemanager
, die /dev/vndbinder
anstelle von /dev/binder
und aus denselben Quellen wie Framework servicemanager
erstellt wurde. Anbieterprozesse müssen keine Änderungen vornehmen, um mit vndservicemanager
zu kommunizieren; Wenn ein Vendor-Prozess / dev/vndbinder
öffnet, gehen Service-Lookups automatisch zu vndservicemanager
.
Die vndservicemanager
Binärdatei ist in den standardmäßigen Geräte-Makefiles von Android enthalten.
SELinux-Richtlinie
Lieferantenprozesse, die die Binderfunktionalität verwenden möchten, um miteinander zu kommunizieren, benötigen Folgendes:
- Zugriff auf
/dev/vndbinder
. - Binder
{transfer, call}
hakt sich invndservicemanager
. -
binder_call(A, B)
für jede Anbieterdomäne A, die die Anbieterdomäne B über die Anbieterbinderschnittstelle aufrufen möchte. - Berechtigung zum
{add, find}
von Diensten invndservicemanager
.
Um die Anforderungen 1 und 2 zu erfüllen, verwenden Sie das Makro vndbinder_use()
:
vndbinder_use(some_vendor_process_domain);
Um Anforderung 3 zu erfüllen, kann binder_call(A, B)
für Anbieterprozesse A und B, die über Binder sprechen müssen, bestehen bleiben und muss nicht umbenannt werden.
Um Anforderung 4 zu erfüllen, müssen Sie Änderungen an der Art und Weise vornehmen, wie Dienstnamen, Dienstbezeichnungen und Regeln behandelt werden.
Einzelheiten zu SELinux finden Sie unter Security-Enhanced Linux in Android . Einzelheiten zu SELinux in Android 8.0 finden Sie unter SELinux für Android 8.0 .
Dienstnamen
Zuvor verarbeitete der Anbieter registrierte Dienstnamen in einer service_contexts
-Datei und fügte entsprechende Regeln für den Zugriff auf diese Datei hinzu. Beispiel service_contexts
-Datei aus 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
In Android 8 lädt vndservicemanager
stattdessen die Datei vndservice_contexts
. Anbieterdienste, die zu vndservicemanager
migrieren (und die sich bereits in der alten service_contexts
-Datei befinden), sollten der neuen vndservice_contexts
-Datei hinzugefügt werden.
Service-Etiketten
Früher wurden Service-Labels wie u:object_r:atfwd_service:s0
in einer service.te
-Datei definiert. Beispiel:
type atfwd_service, service_manager_type;
In Android 8 müssen Sie den Typ in vndservice_manager_type
und die Regel in die Datei vndservice.te
. Beispiel:
type atfwd_service, vndservice_manager_type;
Servicemanager-Regeln
Zuvor gewährten Regeln Domänen Zugriff zum Hinzufügen oder Suchen von Diensten von servicemanager
. Beispiel:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;
In Android 8 können solche Regeln bestehen bleiben und dieselbe Klasse verwenden. Beispiel:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;