Auf dieser Seite werden Änderungen am Binder-Treiber in Android 8 beschrieben, Details zur Verwendung von Binder IPC bereitgestellt und die erforderliche SELinux-Richtlinie aufgeführt.
Änderungen am Binder-Treiber
Ab Android 8 kommunizieren das Android-Framework und die HALs nun über Binder miteinander. Da diese Kommunikation den Binder-Verkehr dramatisch erhöht, enthält Android 8 mehrere Verbesserungen, die den Binder-IPC schnell halten sollen. SoC-Anbieter und OEMs sollten direkt aus den relevanten Zweigen von Android-4.4, Android-4.9 und höher des Kernel-/Common- Projekts fusionieren.
Mehrere Binderdomänen (Kontexte)
Common-4.4 und höher, einschließlich UpstreamUm den Binder-Verkehr sauber zwischen Framework-Code (geräteunabhängig) und Hersteller-Code (gerätespezifisch) aufzuteilen, führte Android 8 das Konzept eines Binder-Kontexts ein. Jeder Binder-Kontext verfügt über einen eigenen Geräteknoten und einen 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 Android-Versionen wurde jedes Datenelement in einem Ordneraufruf dreimal kopiert:
- Einmal, um es im aufrufenden Prozess in ein
Parcel
zu serialisieren - Sobald Sie im Kernel-Treiber sind, 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 zunächst 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 Struktur und Speicherlayout gleich und die Daten können gelesen werden, ohne dass eine weitere Kopie erforderlich ist.
Feinkörnige 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. Zwar gab es nur minimale Konflikte um die Sperre, das Hauptproblem bestand jedoch darin, dass ein Thread mit niedriger Priorität, der die Sperre erhielt und dann vorzeitig freigegeben wurde, Threads mit höherer Priorität, die dieselbe Sperre benötigen, erheblich verzögern konnte. Dies führte zu einem Ruckeln in der Plattform.
Erste Versuche, dieses Problem zu lösen, bestanden darin, die Vorbelegung zu deaktivieren und gleichzeitig die globale Sperre aufrechtzuerhalten. Dies war jedoch eher ein Hack als eine echte Lösung und wurde schließlich von den Upstream-Anbietern abgelehnt und verworfen. Nachfolgende Versuche konzentrierten sich darauf, die Sperrung feiner zu gestalten. Eine Version davon läuft seit Januar 2017 auf Pixel-Geräten. Während die meisten dieser Änderungen veröffentlicht wurden, wurden in nachfolgenden Versionen erhebliche Verbesserungen vorgenommen.
Nachdem wir kleine Probleme in der feinkörnigen Sperrimplementierung identifiziert hatten, entwickelten wir eine verbesserte Lösung mit einer anderen Sperrarchitektur und reichten die Änderungen in allen gängigen Kernelzweigen ein. 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, die mit Android 8 ausgeliefert werden.
Prioritätsvererbung in Echtzeit
Common-4.4 und Common-4.9 (Upstream in Kürze verfügbar)Der Binder-Treiber unterstützt seit jeher die nette Prioritätsvererbung. Da in Android immer mehr Prozesse mit Echtzeitpriorität ausgeführt werden, ist es in einigen Fällen jetzt sinnvoll, dass, wenn ein Echtzeitthread einen Binder-Aufruf 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 eine Echtzeit-Prioritätsvererbung im Binder-Treiber.
Zusätzlich zur Prioritätsvererbung auf Transaktionsebene ermöglicht die Knotenprioritätsvererbung einem Knoten (Binder-Dienstobjekt), eine Mindestpriorität anzugeben, mit der Aufrufe an diesen Knoten ausgeführt werden sollen. Frühere Versionen von Android unterstützten bereits die Knotenprioritätsvererbung mit netten Werten, aber Android 8 bietet Unterstützung für die Knotenvererbung mit Echtzeitplanungsrichtlinien.
Änderungen im Userspace
Android 8 enthält alle Userspace-Änderungen, 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 Echtzeit-Prioritätsvererbung für /dev/binder
verwendete ein ioctl . Bei der späteren Entwicklung wurde die Steuerung der Prioritätsvererbung auf eine differenziertere Methode umgestellt, die pro Bindermodus (und nicht pro Kontext) erfolgt. Daher befindet sich das ioctl nicht im gemeinsamen Android-Zweig, sondern wird stattdessen in unseren gemeinsamen Kerneln übermittelt .
Die Auswirkung dieser Änderung besteht darin, dass die Echtzeit-Prioritätsvererbung standardmäßig für jeden Knoten deaktiviert ist. Das Android-Performance-Team hat festgestellt, dass es von Vorteil ist, die Prioritätsvererbung in Echtzeit für alle Knoten in der hwbinder
Domäne zu aktivieren. Um den gleichen Effekt zu erzielen, wählen Sie diese Änderung im Benutzerbereich aus.
SHAs für gängige Kernel
Um notwendige Änderungen am Binder-Treiber zu erhalten, synchronisieren Sie mit dem entsprechenden SHA:
- Allgemein-3.18
cc8b90c121de ANDROID: Ordner: Prior-Berechtigungen bei der Wiederherstellung nicht überprüfen. - Allgemein-4.4
76b376eac7a2 ANDROID: Ordner: Prior-Berechtigungen bei der Wiederherstellung nicht überprüfen. - Allgemein-4.9
ecd972d4f9b5 ANDROID: Ordner: Prior-Berechtigungen bei der Wiederherstellung nicht überprüfen.
Verwendung von Binder IPC
In der Vergangenheit nutzten Lieferantenprozesse zur Kommunikation die Binder Interprocess Communication (IPC). 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
zugreifen, müssen jedoch 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
und löst gleichzeitig die Stabilitätsgarantien HIDL und /dev/hwbinder
. Informationen zur Verwendung von Stable AIDL finden Sie unter AIDL für HALs .
vndbinder
Android 8 unterstützt eine neue Binder-Domäne zur Verwendung durch Anbieterdienste, auf die über /dev/vndbinder
anstelle von /dev/binder
zugegriffen werden kann. Durch das Hinzufügen von /dev/vndbinder
verfügt Android nun über die folgenden drei IPC-Domänen:
IPC-Domäne | Beschreibung |
---|---|
/dev/binder | IPC zwischen Framework-/App-Prozessen mit AIDL-Schnittstellen |
/dev/hwbinder | IPC zwischen Framework-/Anbieterprozessen mit HIDL-Schnittstellen IPC zwischen Lieferantenprozessen mit HIDL-Schnittstellen |
/dev/vndbinder | IPC zwischen Vendor/Vendor-Prozessen mit AIDL-Schnittstellen |
Damit /dev/vndbinder
angezeigt wird, stellen Sie sicher, dass das Kernel-Konfigurationselement CONFIG_ANDROID_BINDER_DEVICES
auf "binder,hwbinder,vndbinder"
eingestellt ist (dies ist die Standardeinstellung in den gängigen Kernelbä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. Durch das Hinzufügen einer Methode für ::android::ProcessState()
wird der Binder-Treiber für libbinder
ausgewählt. Anbieterprozesse sollten diese Methode aufrufen , bevor sie ProcessState,
IPCThreadState
aufrufen oder allgemein, bevor sie Binderaufrufe durchführen. Platzieren Sie zur Verwendung den folgenden Aufruf nach main()
eines Anbieterprozesses (Client und Server):
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
Zuvor wurden Binder-Dienste bei servicemanager
registriert, wo sie von anderen Prozessen abgerufen werden konnten. In Android 8 wird servicemanager
nun ausschließlich von Framework- und App-Prozessen verwendet und 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. Anbieterprozesse müssen keine Änderungen vornehmen, um mit vndservicemanager
zu kommunizieren. Wenn ein Anbieterprozess / dev/vndbinder
öffnet, werden Dienstsuchen automatisch an vndservicemanager
weitergeleitet.
Die vndservicemanager
Binärdatei ist in den Standard-Geräte-Makefiles von Android enthalten.
SELinux-Richtlinie
Lieferantenprozesse, die die Binder-Funktionalität für die Kommunikation untereinander nutzen möchten, benötigen Folgendes:
- Zugriff auf
/dev/vndbinder
. - Binder
{transfer, call}
hakt sich invndservicemanager
ein. -
binder_call(A, B)
für jede Anbieterdomäne A, die über die Anbieter-Binder-Schnittstelle einen Aufruf in die Anbieterdomäne B durchführen möchte. - Berechtigung zum
{add, find}
von Diensten imvndservicemanager
.
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 der binder_call(A, B)
für die Lieferantenprozesse A und B, die über Binder kommunizieren müssen, an Ort und Stelle 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 gehandhabt 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 einer 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
migriert werden (und die sich bereits in der alten service_contexts
Datei befinden), sollten der neuen vndservice_contexts
Datei hinzugefügt werden.
Serviceetiketten
Zuvor wurden Dienstbezeichnungen 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
ändern und die Regel in die Datei vndservice.te
verschieben. Beispiel:
type atfwd_service, vndservice_manager_type;
Servicemanager-Regeln
Zuvor gewährten Regeln Domänen Zugriff zum Hinzufügen oder Suchen von Diensten im 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;