Mit Binder IPC

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

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 Upstream

Um 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 Upstream

In 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 Upstream

In 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 sollten. 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.

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:

  1. Zugriff auf /dev/vndbinder .
  2. Binder {transfer, call} hakt sich in vndservicemanager .
  3. binder_call(A, B) für jede Anbieterdomäne A, die die Anbieterdomäne B über die Anbieterbinderschnittstelle aufrufen möchte.
  4. Berechtigung zum {add, find} von Diensten in vndservicemanager .

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;