Dienste und Datenübertragung

Auf dieser Seite wird beschrieben, wie Sie Dienste registrieren und entdecken Daten an einen Dienst durch Aufrufen von Methoden, die in Schnittstellen in .hal definiert sind Dateien.

Registrierungsdienste

HIDL-Schnittstellenserver (Objekte, die die Schnittstelle implementieren) können registriert werden. als benannte Dienste. Der registrierte Name muss nicht mit der Schnittstelle in Verbindung stehen oder Paketname. Wenn kein Name angegeben ist, lautet der Name „default“. verwendet wird; Dies sollte werden für HALs verwendet, die nicht zwei Implementierungen . Der C++-Aufruf für die Dienstregistrierung, der in den einzelnen ist:

status_t status = myFoo->registerAsService();
status_t anotherStatus = anotherFoo->registerAsService("another_foo_service");  // if needed

Die Version einer HIDL-Schnittstelle ist in der Schnittstelle selbst enthalten. Es ist automatisch mit der Dienstregistrierung verknüpft und kann über eine Methodenaufruf (android::hardware::IInterface::getInterfaceVersion()) auf jeder HIDL-Benutzeroberfläche. Serverobjekte müssen nicht registriert sein und können übergeben werden über HIDL-Methodenparameter zu einem anderen Prozess, der HIDL-Methodenaufrufe durchführt auf dem Server.

Dienste entdecken

Anfragen von Clientcode werden für eine bestimmte Schnittstelle anhand des Namens und Version und rufen getService für die gewünschte HAL-Klasse auf:

// C++
sp<V1_1::IFooService> service = V1_1::IFooService::getService();
sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service");
// Java
V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */);
V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);

Jede Version einer HIDL-Schnittstelle wird als separate Schnittstelle behandelt. Das heißt: IFooService Version 1.1 und IFooService Version 2.2 können beide als „foo_service“ registriert werden und Für getService("foo_service") auf einer der beiden Schnittstelle wird die Registrierung für diese Schnittstelle. Daher ist in den meisten Fällen kein Namensparameter für die Registrierung oder Erkennung bereitgestellt werden soll (d. h. der Name "Standard").

Das Vendor Interface Object spielt auch eine Rolle bei der Transportmethode der zurückgegebene Schnittstelle. Für eine Schnittstelle im Paket IFoo android.hardware.foo@1.0, die von IFoo::getService verwendet immer die Transportmethode, die für android.hardware.foo im Gerätemanifest, wenn der Eintrag vorhanden ist Wenn die Transportmethode nicht verfügbar ist, wird nullptr zurückgegeben.

In einigen Fällen kann es notwendig sein, sofort fortzufahren, den Service zu erhalten. Das kann zum Beispiel passieren, wenn ein Kunde Dienstbenachrichtigungen selbst oder in einem Diagnoseprogramm (z. B. atrace), der alle Hardwaredienste abrufen und abrufen muss. In In diesem Fall werden zusätzliche APIs bereitgestellt, z. B. tryGetService in C++ oder getService("instance-name", false) in Java. Die alte API getService in Java muss auch mit dem Dienst verwendet werden Benachrichtigungen. Die Verwendung dieser API verhindert nicht die Race-Bedingung, bei der ein Server registriert sich selbst, nachdem der Client sie mit einer dieser No-Wiederholungs-APIs anfordert.

Benachrichtigungen bei Dienstmängeln

Kunden, die benachrichtigt werden möchten, wenn ein Dienst stirbt, können die vom Framework gelieferten Benachrichtigungen. Um Benachrichtigungen zu erhalten, muss der Client muss:

  1. Erstellen Sie abgeleitete Klassen der HIDL-Klasse/Schnittstelle hidl_death_recipient (in C++ und nicht in HIDL).
  2. Überschreibt die zugehörige serviceDied()-Methode.
  3. Instanziieren Sie ein Objekt der abgeleiteten hidl_death_recipient-Klasse.
  4. Rufen Sie die Methode linkToDeath() für den zu überwachenden Dienst auf. und übergeben das Interface-Objekt der IDeathRecipient. Beachten Sie, dass dies übernimmt weder den Todempfänger noch den Proxy, aufgerufen wird.

Hier ein Pseudocode-Beispiel (C++ und Java sind ähnlich):

class IMyDeathReceiver : hidl_death_recipient {
  virtual void serviceDied(uint64_t cookie,
                           wp<IBase>& service) override {
    log("RIP service %d!", cookie);  // Cookie should be 42
  }
};
....
IMyDeathReceiver deathReceiver = new IMyDeathReceiver();
m_importantService->linkToDeath(deathReceiver, 42);

Ein Todesempfänger kann bei mehreren verschiedenen Diensten registriert werden.

Datenübertragung

Daten können an einen Dienst gesendet werden, indem Methoden aufgerufen werden, die in Schnittstellen in .hal-Dateien. Es gibt zwei Arten von Methoden:

  • Blocking-Methoden warten, bis der Server einen Fehler ausgegeben hat. Ergebnis.
  • Einwegmethoden senden Daten nur in eine Richtung und blockieren. Wenn die Menge der laufenden Daten in RPC-Aufrufen die Implementierung überschreitet können die Aufrufe entweder blockieren oder eine Fehlermeldung zurückgeben (Verhalten ist noch nicht festgelegt).

Eine Methode, die keinen Wert zurückgibt, aber nicht als deklariert oneway wird immer noch blockiert.

Alle in einer HIDL-Schnittstelle deklarierten Methoden werden in eine Richtung aufgerufen. entweder aus dem HAL oder in den HAL. In der Schnittstelle wird nicht angegeben, in welcher Richtung sie aufgerufen wird. Architekturen, von denen Aufrufe stammen müssen sollte der HAL zwei (oder mehr) Schnittstellen im HAL-Paket bereitstellen und den Schnittstelle von jedem Prozess aus. Die Wörter client und server werden in Bezug auf die Aufrufrichtung der Schnittstelle verwendet. (d.h., der HAL kann ein Server der einen Schnittstelle und ein Client einer anderen Schnittstelle sein) .

Rückrufe

Das Wort Callback bezieht sich auf zwei verschiedene Konzepte, die sich synchroner Callback und asynchroner Callback.

Synchrone Callbacks werden in einigen HIDL-Methoden verwendet, die Daten. Eine HIDL-Methode, die mehr als einen Wert (oder einen Wert von nicht primitiven Typ) gibt seine Ergebnisse über eine Callback-Funktion zurück. Wenn nur eines zurückgegeben und es sich um einen primitiven Typ handelt, wird kein Callback verwendet und der Parameter wird von der Methode zurückgegeben. Der Server implementiert die HIDL-Methoden und implementiert der Client die Callbacks.

Asynchrone Rückrufe ermöglichen dem Server einer HIDL-Schnittstelle Folgendes: Anrufe zu generieren. Dazu wird eine Instanz einer zweiten Schnittstelle übergeben. über die erste Benutzeroberfläche. Der Client der ersten Schnittstelle muss als des zweiten Servers. Der Server der ersten Schnittstelle kann Methoden im zweiten Schnittstellenobjekts. Beispielsweise kann eine HAL-Implementierung Informationen asynchron zurück zu dem Prozess, der sie verwendet, indem Methoden auf einem das durch diesen Prozess erstellt und bereitgestellt wird. Methoden in verwendeten Schnittstellen für einen asynchronen Callback möglicherweise blockiert (und Werte an den Aufrufer zurückgeben). oder oneway. Ein Beispiel finden Sie unter „Asynchrone Callbacks“. in HIDL C++:

Um die Inhaberschaft von Arbeitsspeicher zu vereinfachen, benötigen Methodenaufrufe und Callbacks nur in-Parameter und unterstützen nicht out oder inout-Parameter.

Limits pro Transaktion

Für die Datenmenge, die im HIDL gesendet wird, gibt es keine Limits pro Transaktion Methoden und Callbacks verwenden. Aufrufe mit mehr als 4 KB pro Transaktion werden jedoch als übertrieben empfunden werden. In diesem Fall wird die vorhandene HIDL-Schnittstelle wird empfohlen. Eine weitere Einschränkung sind die für die HIDL verfügbaren Ressourcen um mehrere Transaktionen gleichzeitig abzuwickeln. Mehrere Transaktionen können aufgrund mehrerer Threads oder das Senden von Aufrufen an einen Prozess oder mehrere oneway-Aufrufe, vom Empfangsprozess nicht schnell verarbeitet werden. Der maximale Gesamtspeicher ist standardmäßig 1 MB groß.

In einer gut gestalteten Oberfläche sollte das Überschreiten dieser Ressourcenbeschränkungen passieren, Ist dies der Fall, kann der entsprechende Aufruf blockiert werden, bis Ressourcen verfügbar werden oder einen Transportfehler signalisieren. Bei jedem Auftreten von das Überschreiten von Transaktionslimits oder überlaufende HIDL-Implementierungsressourcen, aggregierte In-Flight-Transaktionen protokolliert, um die Fehlerbehebung zu erleichtern.

Methodenimplementierungen

HIDL generiert Header-Dateien, in denen die erforderlichen Typen, Methoden und -Callbacks in der Zielsprache (C++ oder Java) zu erstellen. Der Prototyp eines HIDL-definierten und Callbacks sind für Client- und Servercode identisch. Das HIDL Proxy-Implementierungen der Methoden im Aufruferseite, die die Daten für den IPC-Transport organisiert, und Stub Code auf der Seite des aufgerufenen Nutzers, der die Daten an Methoden.

Der Aufrufer einer Funktion (HIDL-Methode oder Callback) ist Eigentümer der Daten. an die Funktion übergebene Strukturen und behält nach dem Aufruf die Inhaberschaft. in In allen Fällen muss der Aufgerufene den Speicherplatz nicht freigeben oder freigeben.

  • In C++ sind die Daten möglicherweise schreibgeschützt (Versuche, in sie zu schreiben, Segmentierungsfehler) und sind für die Dauer des Aufrufs gültig. Der Kunde kann die Daten tief kopieren, um sie über den Aufruf hinaus zu verbreiten.
  • In Java empfängt der Code eine lokale Kopie der Daten (ein normales Java-Objekt). die möglicherweise beibehalten und änderbar sind oder die automatische Speicherbereinigung erlaubt.

Nicht-RPC-Datenübertragung

HIDL bietet zwei Möglichkeiten, Daten ohne einen RPC-Aufruf zu übertragen: freigegeben Arbeitsspeicher und eine Fast Message Queue (FMQ), die beide nur in C++ unterstützt werden.

  • Gemeinsamer Speicher: Der integrierte HIDL-Typ memory wird verwendet, um ein Objekt zu übergeben, das den zugewiesenen gemeinsamen Speicher darstellt. Kann in einem Empfangsprozess verwendet werden, um den gemeinsamen Speicher zuzuordnen.
  • Fast Message Queue (FMQ): HIDL stellt eine Vorlagennachricht bereit, Warteschlangentyp, der die Übergabe von Nachrichten ohne Warteschleifen implementiert. Es verwendet nicht den Kernel Planer im Passthrough- oder binderized-Modus (die geräteübergreifende Kommunikation diese Eigenschaften haben). In der Regel richtet der HAL das Ende der Warteschlange ein. Erstellen eines Objekts, das über RPC über einen Parameter der integrierten HIDL-Typ MQDescriptorSync oder MQDescriptorUnsync. Dieses -Objekt kann vom empfangenden Prozess zum Einrichten des anderen Endes der Warteschlange verwendet werden.
    • Synchronisierungswarteschlangen dürfen nicht überlaufen und dürfen nur eine enthalten Leser.
    • Unsync-Warteschlangen können überlaufen und viele Leser umfassen. von denen jeder Daten rechtzeitig lesen oder verlieren muss.
    Keiner der Typen darf einen Unterlauf durchlaufen (das Lesen aus einer leeren Warteschlange schlägt fehl) und kann jeder Typ nur einen Autor haben.

Weitere Informationen zu FMQ finden Sie unter Fast Message Queue (FMQ):