Auf dieser Seite werden Änderungen am Binder-Treiber in Android 8 beschrieben, es werden Details zur Verwendung von Binder-IPC angegeben und die erforderliche SELinux-Richtlinie aufgeführt.
Änderungen am Binder-Treiber
Ab Android 8 kommunizieren das Android-Framework und die HALs jetzt über den Binder miteinander. Da diese Kommunikation den Binder-Traffic drastisch erhöht, enthält Android 8 mehrere Verbesserungen, die die Geschwindigkeit des Binder-IPC aufrechterhalten sollen. SoC-Anbieter und OEMs sollten direkt aus den entsprechenden Zweigen von android-4.4, android-4.9 und höher des Projekts kernel/common zusammenführen.
Mehrere Binder-Domains (Kontexte)
Common-4.4 und höher, einschließlich UpstreamUm den Binder-Traffic sauber zwischen Framework-Code (geräteunabhängig) und Anbietercode (gerätespezifisch) aufzuteilen, wurde in Android 8 das Konzept eines Binder-Kontexts eingeführt. Jeder Binder-Kontext hat einen eigenen Geräteknoten und einen eigenen Kontext- bzw. Dienstmanager. Sie können nur über den Geräteknoten, zu dem er gehört, auf den Context Manager zugreifen. Wenn ein Binderknoten durch einen bestimmten Kontext übergeben wird, ist er nur über diesen Kontext für einen anderen Prozess zugänglich. So werden die Domains vollständig voneinander isoliert. Weitere Informationen zur Verwendung finden Sie unter vndbinder und vndservicemanager.
Scatter-Gather
Common-4.4 und höher, einschließlich UpstreamIn früheren Android-Releases wurden alle Daten in einem Binderaufruf dreimal kopiert:
- Einmal, um es im Aufrufprozess in eine
Parcel
zu serialisieren - Im Kerneltreiber die
Parcel
in den Zielprozess kopieren - Einmal, um die
Parcel
im Zielprozess zu deserialisieren
Android 8 verwendet die Scatter-Gather-Optimierung, um die Anzahl der Kopien von 3 auf 1 zu reduzieren. Anstatt Daten zuerst in einem Parcel
zu serialisieren, bleiben sie in ihrer ursprünglichen Struktur und ihrem ursprünglichen Speicherlayout und der Treiber kopiert sie sofort in den Zielprozess. Nachdem sich die Daten im Zielprozess befinden, sind Struktur und Speicherlayout identisch und die Daten können gelesen werden, ohne dass eine weitere Kopie erforderlich ist.
Detaillierte Sperrung
Common-4.4 und höher, einschließlich UpstreamIn früheren Android-Releases wurde vom Binder-Treiber eine globale Sperre verwendet, um vor gleichzeitigem Zugriff auf kritische Datenstrukturen zu schützen. Es gab zwar nur wenig Konkurrenz um die Sperre, das Hauptproblem war jedoch, dass ein Thread mit niedriger Priorität, der die Sperre erhalten und dann vorzeitig beendet wurde, Threads mit höherer Priorität, die dieselbe Sperre benötigen, erheblich verzögern konnte. Das führte zu Rucklern auf der Plattform.
Erste Versuche, dieses Problem zu beheben, beinhalteten die Deaktivierung der Voraktivierung bei gleichzeitigem Halten der globalen Sperre. Dies war jedoch eher ein Hack als eine echte Lösung und wurde schließlich von der Vorverarbeitung abgelehnt und verworfen. Bei den nachfolgenden Versuchen lag der Schwerpunkt darauf, die Sperrung detaillierter zu gestalten. Eine Version dieser Funktion wird seit Januar 2017 auf Pixel-Geräten ausgeführt. Die meisten dieser Änderungen wurden veröffentlicht, in den nachfolgenden Versionen wurden jedoch erhebliche Verbesserungen vorgenommen.
Nachdem wir kleine Probleme bei der nutzungsorientierten Sperrimplementierung festgestellt hatten, haben wir eine verbesserte Lösung mit einer anderen Sperrarchitektur entwickelt und die Änderungen in allen gängigen Kernel-Branches eingereicht. Wir testen diese Implementierung weiterhin auf einer großen Anzahl verschiedener Geräte. Da uns keine offenen Probleme bekannt sind, ist dies die empfohlene Implementierung für Geräte mit Android 8.
Echtzeitprioritätsübernahme
Common-4.4 und Common-4.9 (bald verfügbar)Der Binder-Treiber hat schon immer eine schöne Prioritätsübernahme unterstützt. Da immer mehr Prozesse in Android mit Echtzeitpriorität ausgeführt werden, ist es in einigen Fällen sinnvoll, dass ein Thread im Prozess, der diesen Aufruf verarbeitet, auch mit Echtzeitpriorität ausgeführt wird, wenn ein Echtzeit-Thread einen Binderaufruf ausführt. Um diese Anwendungsfälle zu unterstützen, wird in Android 8 jetzt die Echtzeitprioritätsübernahme im Binder-Treiber implementiert.
Zusätzlich zur Prioritätsübernahme auf Transaktionsebene ermöglicht die Knotenprioritätsübernahme einem Knoten (Binder-Dienstobjekt) die Angabe einer Mindestpriorität, mit der Aufrufe an diesen Knoten ausgeführt werden sollen. Bisherige Android-Versionen unterstützten bereits die Übernahme der Knotenpriorität mit Nice-Werten. Android 8 unterstützt zusätzlich die Übernahme von Knoten durch Echtzeit-Planungsrichtlinien.
Änderungen im Userspace
Android 8 enthält alle Änderungen im Userspace, die für die Arbeit mit dem aktuellen Binder-Treiber im gemeinsamen Kernel erforderlich sind, mit einer Ausnahme: Die ursprüngliche Implementierung zum Deaktivieren der Echtzeitprioritätsübernahme für /dev/binder
verwendete einen ioctl. Bei der nachfolgenden Entwicklung wurde die Steuerung der Prioritätsübernahme auf eine detailliertere Methode umgestellt, die pro Binder-Modus (und nicht pro Kontext) erfolgt. Daher befindet sich das ioctl nicht im Android Common-Branch, sondern wird stattdessen in unseren gemeinsamen Kerneln eingereicht.
Durch diese Änderung ist die Echtzeitprioritätsübernahme standardmäßig für alle Knoten deaktiviert. Das Android-Leistungsteam hat festgestellt, dass es vorteilhaft ist, die Echtzeitprioritätsübernahme für alle Knoten in der hwbinder
-Domain zu aktivieren. Um denselben Effekt zu erzielen, können Sie diese Änderung im Userspace auswählen.
SHAs für gängige Kernel
Wenn Sie die erforderlichen Änderungen am Binder-Treiber erhalten möchten, synchronisieren Sie ihn mit der entsprechenden 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.
Mit Binder-IPC arbeiten
Bisher haben Anbieterprozesse die Binder-IPC (Inter-Process Communication) für die Kommunikation verwendet. Unter Android 8 ist der Geräteknoten /dev/binder
nur noch für Framework-Prozesse verfügbar. Anbieterprozesse haben keinen Zugriff mehr darauf. Anbieterprozesse können auf /dev/hwbinder
zugreifen, müssen ihre AIDL-Schnittstellen jedoch in HIDL konvertieren. Anbieter, die weiterhin AIDL-Schnittstellen zwischen Anbieterprozessen verwenden möchten, können die unten beschriebene Binder-IPC-Funktion von Android nutzen. In Android 10 ermöglicht Stable AIDL allen Prozessen die Verwendung von /dev/binder
und erfüllt gleichzeitig die Stabilitätsgarantien, die HIDL und /dev/hwbinder
bieten. Informationen zur Verwendung von Stable-AIDL finden Sie unter AIDL für HALs.
vndbinder
Android 8 unterstützt eine neue Binder-Domain für die Verwendung durch Anbieterdienste, auf die über /dev/vndbinder
statt /dev/binder
zugegriffen wird. Mit der Hinzufügung von /dev/vndbinder
gibt es in Android jetzt die folgenden drei IPC-Domains:
IPC-Domain | Beschreibung |
---|---|
/dev/binder |
IPC zwischen Framework-/App-Prozessen mit AIDL-Schnittstellen |
/dev/hwbinder |
IPC zwischen Framework-/Anbieterprozessen mit HIDL-Schnittstellen
IPC zwischen Anbieterprozessen mit HIDL-Schnittstellen |
/dev/vndbinder |
IPC zwischen Anbieter-/Anbieterprozessen mit AIDL-Schnittstellen |
Damit /dev/vndbinder
angezeigt wird, muss der Kernelkonfigurationselement CONFIG_ANDROID_BINDER_DEVICES
auf "binder,hwbinder,vndbinder"
festgelegt sein. Dies ist die Standardeinstellung in den gemeinsamen Kernelbäumen von Android.
Normalerweise öffnen Anbieterprozesse den Bindertreiber nicht direkt, sondern verknüpfen ihn stattdessen mit der libbinder
-Userspace-Bibliothek, die den Bindertreiber öffnet. Wenn Sie eine Methode für ::android::ProcessState()
hinzufügen, wird der Binder-Treiber für libbinder
ausgewählt. Anbieterprozesse sollten diese Methode vor dem Aufruf von ProcessState,
IPCThreadState
oder vor dem Ausführen von Binderaufrufen allgemein aufrufen. Führe dazu den folgenden Aufruf nach dem main()
eines Anbieterprozesses (Client und Server) aus:
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
Bisher wurden Binderdienste bei servicemanager
registriert, wo sie von anderen Prozessen abgerufen werden konnten. Unter Android 8 wird servicemanager
jetzt ausschließlich von Framework- und App-Prozessen verwendet. Anbieterprozesse können nicht mehr darauf zugreifen.
Anbieterdienste können jetzt jedoch vndservicemanager
verwenden, eine neue Instanz von servicemanager
, die /dev/vndbinder
anstelle von /dev/binder
verwendet und aus denselben Quellen wie das Framework servicemanager
erstellt wird. Bei Anbieterprozessen müssen keine Änderungen vorgenommen werden, um mit vndservicemanager
zu kommunizieren. Wenn ein Anbieterprozess /dev/vndbinder
öffnet, werden Dienstabfragen automatisch an vndservicemanager
weitergeleitet.
Die vndservicemanager
-Binärdatei ist in den Standard-Geräte-Makefiles von Android enthalten.
SELinux-Richtlinie
Anbieterprozesse, die die Binder-Funktionen zur Kommunikation miteinander verwenden möchten, benötigen Folgendes:
- Zugriff auf
/dev/vndbinder
- Binder
{transfer, call}
wird anvndservicemanager
angehängt. binder_call(A, B)
für jede Anbieterdomain A, die über die Anbieterbinder-Benutzeroberfläche auf die Anbieterdomain B zugreifen möchte.- Berechtigung für
{add, find}
-Dienste invndservicemanager
Verwenden Sie das Makro vndbinder_use()
, um die Anforderungen 1 und 2 zu erfüllen:
vndbinder_use(some_vendor_process_domain);
Um Anforderung 3 zu erfüllen, kann die binder_call(A, B)
für die Anbieterprozesse A und B, die über den Binder kommunizieren müssen, unverändert bleiben und muss nicht umbenannt werden.
Um Anforderung 4 zu erfüllen, müssen Sie Änderungen an der Verarbeitung von Dienstnamen, Dienstlabels und Regeln vornehmen.
Weitere Informationen zu SELinux finden Sie unter Security-Enhanced Linux in Android. Weitere Informationen zu SELinux in Android 8.0 finden Sie unter SELinux für Android 8.0.
Dienstnamen
Bisher verarbeitete der Anbieter registrierte Dienstnamen in einer service_contexts
-Datei und fügte entsprechende Zugriffsregeln für diese Datei hinzu. Beispiel für eine 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
Unter Android 8 wird unter vndservicemanager
stattdessen die Datei vndservice_contexts
geladen. Anbieterdienste, die zu vndservicemanager
migrieren und sich bereits in der alten service_contexts
-Datei befinden, sollten der neuen vndservice_contexts
-Datei hinzugefügt werden.
Dienstlabels
Bisher wurden Dienstlabels wie u:object_r:atfwd_service:s0
in einer service.te
-Datei definiert. Beispiel:
type atfwd_service, service_manager_type;
Unter Android 8 müssen Sie den Typ in vndservice_manager_type
ändern und die Regel in die Datei vndservice.te
verschieben. Beispiel:
type atfwd_service, vndservice_manager_type;
servicemanager rules
Bisher gewährten Regeln Domains Zugriff, um Dienste über servicemanager
hinzuzufügen oder zu finden. Beispiel:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;
Unter Android 8 können solche Regeln beibehalten und dieselbe Klasse verwendet werden. Beispiel:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;