Datentypen

HIDL-Datendeklarationen generieren C++-Datenstrukturen mit Standardlayout. Diese Strukturen können überall dort platziert werden, wo es sich anfühlt (auf dem Stack, der Datei oder globalen Geltungsbereich oder auf dem Heap) und können auf dieselbe Weise zusammengesetzt werden. Kunde HIDL-Proxy-Code aufruft, übergibt Const-Referenzen und primitive Typen, während der Stub und der Proxy-Code die Details der Serialisierung verbergen.

Hinweis:Zu keinem Zeitpunkt gehört der Entwickler-Programmiercode. die Datenstrukturen explizit serialisieren oder deserialisieren müssen.

In der folgenden Tabelle werden HIDL-Primitive den C++-Datentypen zugeordnet:

HIDL-Typ C++-Typ Kopfzeile/Bibliothek
enum enum class
uint8_t..uint64_t uint8_t..uint64_t <stdint.h>
int8_t..int64_t int8_t..int64_t <stdint.h>
float float
double double
vec<T> hidl_vec<T> libhidlbase
T[S1][S2]...[SN] T[S1][S2]...[SN]
string hidl_string libhidlbase
handle hidl_handle libhidlbase
safe_union (custom) struct
struct struct
union union
fmq_sync MQDescriptorSync libhidlbase
fmq_unsync MQDescriptorUnsync libhidlbase

In den folgenden Abschnitten werden die Datentypen ausführlicher beschrieben.

Aufzählung

Aus einer Aufzählung in HIDL wird eine Aufzählung in C++. Hier einige Beispiele:

enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 };
enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };

... wird zu:

enum class Mode : uint8_t { WRITE = 1, READ = 2 };
enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };

Ab Android 10 kann ein Enum iteriert werden. über ::android::hardware::hidl_enum_range. Dieser Bereich enthält jeden Zähler in der Reihenfolge, in der er im HIDL-Quellcode vorkommt: von der übergeordneten Aufzählung bis zum letzten untergeordneten Element. Dieser Code iteriert beispielsweise über WRITE, READ, NONE und COMPARE in dieser Reihenfolge. Angegebener SpecialMode oben:

template <typename T>
using hidl_enum_range = ::android::hardware::hidl_enum_range<T>

for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}

hidl_enum_range implementiert auch umgekehrte Iterationen und kann in constexpr Kontexten verwendet. Wenn ein Wert in einer Aufzählung enthalten ist mehrfach vorhanden ist, erscheint der Wert mehrmals im Bereich.

Bitfield<T>

bitfield<T> (wobei T eine benutzerdefinierte Aufzählung ist) wird zum zugrunde liegenden Typ dieser Aufzählung in C++. Im obigen Beispiel bitfield<Mode> wird zu uint8_t.

vec<T>

Die Klassenvorlage hidl_vec<T> ist Teil von libhidlbase und kann verwendet werden, um einen Vektor eines beliebigen HIDL-Typs mit eine beliebige Größe haben. Der vergleichbare Container mit fester Größe hidl_array Ein hidl_vec<T> kann auch initialisiert, um auf einen externen Datenpuffer vom Typ T zu verweisen, wobei die hidl_vec::setToExternal()-Funktion.

Zusätzlich zum entsprechenden Ausgabe/Einfügen der Struktur in den generierten C++-Header enthält, ist die Verwendung von vec<T> ein wenig praktischer. Funktionen zur Übersetzung in/aus std::vector und ohne T Zeiger zeigen. Wenn vec<T> als Parameter verwendet wird, gibt die Funktion ist es überlastet (zwei Prototypen werden generiert), um die die HIDL-Struktur und einen std::vector<T>-Typ dafür .

Array

Konstantenarrays in „hidl“ werden durch die Klasse hidl_array dargestellt in libhidlbase Ein hidl_array<T, S1, S2, …, SN> steht für ein n-dimensionales Array mit fester Größe T[S1][S2]…[SN].

string

Die Klasse hidl_string (Teil von libhidlbase) kann wird verwendet, um Zeichenfolgen über HIDL-Schnittstellen zu übergeben. /system/libhidl/base/include/hidl/HidlSupport.h Der erste Speicher Bei der Position in der Klasse handelt es sich um einen Zeiger auf den zugehörigen Zeichenpuffer.

hidl_string kann die Umwandlung in und aus std::string and char* (String im C-Stil) mit operator=, implizite Umwandlungen und die Funktion .c_str(). HIDL-Stringstrukturen haben die entsprechenden Kopierkonstruktoren und Zuweisung in:

  • Lädt den HIDL-String aus einem std::string- oder C-String.
  • Erstellt eine neue std::string aus einem HIDL-String.

HIDL-Strings haben Konvertierungskonstruktoren, sodass C-Strings (char *) und C++ Strings (std::string) können verwendet werden für: die einen HIDL-String annehmen.

Struktur

Ein struct in HIDL darf nur Datentypen mit fester Größe enthalten und keine Funktionen. HIDL-Strukturdefinitionen werden dem Standardlayout direkt zugeordnet structs in C++. Dadurch wird sichergestellt, dass structs ein einheitliches Speicherlayout. Eine Struktur kann HIDL-Typen enthalten, darunter: handle, string und vec<T>, die separate Puffer mit variabler Länge.

Alias

WARNUNG:Adressen jeder Art (auch physische) Geräteadressen) dürfen niemals Teil eines nativen Alias sein. Bestanden Informationen zwischen Prozessen sind gefährlich und anfällig für Angriffe. Alle zwischen Prozessen übergebenen Werte müssen validiert werden, bevor sie zum Suchen verwendet werden können den zugewiesenen Speicher eines Prozesses. Andernfalls können schlechte Aliasse zu oder eine Beschädigung des Arbeitsspeichers.

Der Typ handle wird durch hidl_handle dargestellt. in C++. Dabei handelt es sich um einen einfachen Wrapper um einen Zeiger auf eine const native_handle_t-Objekt (bereits in Android seit lange Zeit).

typedef struct native_handle
{
    int version;        /* sizeof(native_handle_t) */
    int numFds;         /* number of file descriptors at &data[0] */
    int numInts;        /* number of ints at &data[numFds] */
    int data[0];        /* numFds + numInts ints */
} native_handle_t;

Standardmäßig übernimmt hidl_handle keine Inhaberschaft des native_handle_t-Zeigers ihn umschließt. Es dient lediglich dazu, einen Zeiger auf ein native_handle_t speichern, damit es in 32- und 64-Bit-Prozesse.

Szenarien, in denen hidl_handle Eigentümer der enthaltenen Datei ist Zu den Deskriptoren gehören:

  • Nach einem Aufruf der Methode setTo(native_handle_t* handle, bool shouldOwn), bei der der Parameter shouldOwn auf true
  • Wenn das hidl_handle-Objekt durch die Kopierkonstruktion erstellt wird aus einem anderen hidl_handle-Objekt
  • Wenn das hidl_handle-Objekt von einem anderen kopierten Element zugewiesen wird hidl_handle Objekt

hidl_handle bietet sowohl implizite als auch explizite Conversions. von/zu native_handle_t* Objekten. Der Hauptzweck des Der Typ handle in HIDL besteht darin, Dateideskriptoren über HIDL zu übergeben. Schnittstellen. Ein einzelner Dateideskriptor wird daher durch einen native_handle_t ohne int und eine einzelne fd Wenn sich Client und Server in einem anderen Prozess befinden, wird der RPC -Implementierung übernimmt automatisch den Dateideskriptor, um sicherzustellen, können beide Prozesse an derselben Datei arbeiten.

Obwohl ein Dateideskriptor, der in einem hidl_handle von einem in diesem Prozess gültig ist, bleibt er nicht über den empfangenden -Funktion (sie wird geschlossen, wenn die Funktion zurückkehrt). Ein Prozess, bei dem dauerhaften Zugriff auf den Dateideskriptor beibehalten muss, dup() oder kopieren Sie das gesamte hidl_handle-Objekt.

Speicher

Der HIDL-Typ memory ist der Klasse hidl_memory zugeordnet in libhidlbase, was nicht zugeordnetem freigegebenen Speicher darstellt. Dies ist Das Objekt, das zwischen Prozessen übergeben werden muss, um Arbeitsspeicher in HIDL gemeinsam zu nutzen. Bis gemeinsamen Arbeitsspeicher verwenden:

  1. Instanz von IAllocator abrufen (derzeit nur Instanz „Aschmem“ verfügbar) und verwenden Sie sie, um gemeinsamen Arbeitsspeicher zuzuweisen.
  2. IAllocator::allocate() gibt hidl_memory zurück , das über HIDL RPC übergeben und mithilfe von Die Funktion mapMemory von libhidlmemory.
  3. mapMemory gibt einen Verweis auf eine sp<IMemory>-Objekt, das für den Zugriff auf den Arbeitsspeicher verwendet werden kann. (IMemory und IAllocator sind definiert in android.hidl.memory@1.0)

Eine Instanz von IAllocator kann zum Zuweisen von Arbeitsspeicher verwendet werden:

#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
using ::android::hidl::allocator::V1_0::IAllocator;
using ::android::hidl::memory::V1_0::IMemory;
using ::android::hardware::hidl_memory;
....
  sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
  ashmemAllocator->allocate(2048, [&](bool success, const hidl_memory& mem) {
        if (!success) { /* error */ }
        // now you can use the hidl_memory object 'mem' or pass it around
  }));

Tatsächliche Änderungen am Arbeitsspeicher müssen über einen IMemory vorgenommen werden entweder auf der Seite, auf der mem erstellt wurde, oder auf der Seite, auf der empfängt es über HIDL RPC.

// Same includes as above

sp<IMemory> memory = mapMemory(mem);
void* data = memory->getPointer();
memory->update();
// update memory however you wish after calling update and before calling commit
data[0] = 42;
memory->commit();
// …
memory->update(); // the same memory can be updated multiple times
// …
memory->commit();

interface

Schnittstellen können als Objekte übergeben werden. Das Wort Interface kann verwendet werden, als syntaktischer Zucker für den Typ android.hidl.base@1.0::IBase; Außerdem werden die aktuelle Schnittstelle und alle importierten Schnittstellen definiert. als Typ angezeigt.

Variablen, die Schnittstellen enthalten, sollten starke Hinweise sein: sp<IName> HIDL-Funktionen, die Schnittstellenparameter verwenden Rohzeiger in aussagekräftige Hinweise umwandeln, was zu nicht intuitivem Verhalten führt Der Cursor kann unerwartet gelöscht werden. Zur Vermeidung von Problemen immer HIDL speichern als sp<>.