Jenis data

Bagian ini menjelaskan jenis data HIDL. Untuk detail penerapan, lihat HIDL C++ (untuk C++ implementasi) atau HIDL Java (untuk implementasi Java).

Persamaan dengan C++ meliputi:

  • structs menggunakan sintaksis C++; unions mendukung sintaksis C++ secara {i>default<i}. Keduanya harus diberi nama; struktur dan serikat pekerja anonim tidak didukung.
  • Typedef diizinkan di HIDL (seperti di C++).
  • Komentar bergaya C++ diizinkan dan disalin ke file header yang dihasilkan.

Persamaan dengan Java meliputi:

  • Untuk setiap file, HIDL mendefinisikan namespace gaya Java yang harus diawali dengan android.hardware.. Namespace C++ yang dihasilkan adalah ::android::hardware::….
  • Semua definisi file dimuat dalam gaya Java Wrapper interface.
  • Deklarasi array HIDL mengikuti gaya Java, bukan gaya C++. Contoh:
    struct Point {
        int32_t x;
        int32_t y;
    };
    Point[3] triangle;   // sized array
    
  • Komentar mirip dengan format javadoc.

Representasi data

struct atau union yang terdiri dari Tata Letak Standar (subset dari persyaratan jenis data lama biasa) memiliki memori yang konsisten dalam kode C++ yang dihasilkan, diterapkan dengan atribut perataan eksplisit pada struct dan union anggota.

Jenis HIDL primitif, serta enum dan bitfield (yang selalu berasal dari tipe primitif), memetakan ke tipe C++ standar seperti std::uint32_t dari cstdint.

Karena Java tidak mendukung jenis yang tidak ditandatangani, jenis HIDL yang tidak ditandatangani dipetakan ke tipe Java bertanda tangan yang sesuai. Struct dipetakan ke class Java; arrays dipetakan ke array Java; unions saat ini tidak didukung pada Java. String disimpan secara internal sebagai UTF8. Karena Java mendukung hanya string UTF16, nilai string yang dikirim ke atau dari implementasi Java diterjemahkan, dan mungkin tidak sama persis pada diterjemahkan ulang karena himpunan karakternya tidak selalu memetakan dengan lancar.

Data yang diterima melalui IPC di C++ ditandai const dan berada dalam {i>read-only memory<i} yang bertahan hanya selama durasi panggilan fungsi. Data yang diterima melalui IPC di Java telah disalin ke dalam objek Java, sehingga ia dapat dipertahankan tanpa penyalinan tambahan (dan dapat diubah).

Anotasi

Anotasi bergaya Java dapat ditambahkan ke deklarasi jenis. Anotasi adalah diurai oleh backend Vendor Test Suite (VTS) dari compiler HIDL tetapi tidak ada anotasi yang diuraikan tersebut sebenarnya dipahami oleh kompilator HIDL. Sebagai gantinya, anotasi VTS yang diuraikan ditangani oleh VTS Compiler (VTSC).

Anotasi menggunakan sintaksis Java: @annotation atau @annotation(value) atau @annotation(id=value, id=value…) dengan nilai dapat berupa ekspresi konstanta, string, atau daftar nilai di dalam {}, seperti di Java. Beberapa anotasi dengan nama yang sama dapat dilampirkan ke item yang sama.

Meneruskan pernyataan

Dalam HIDL, struct mungkin tidak akan dideklarasikan ke depan, sehingga membuat jenis data yang merujuk pada diri sendiri tidak mungkin dilakukan (misalnya, Anda tidak dapat menjelaskan daftar tertaut atau pohon dalam HIDL). Sebagian besar HAL yang sudah ada (sebelum Android 8.x) memiliki penggunaan terbatas deklarasi penerusan, yang dapat dihapus dengan mengatur ulang struktur data deklarasi.

Batasan ini memungkinkan struktur data disalin berdasarkan nilai dengan {i>deep-copy<i}, alih-alih melacak nilai-nilai {i>pointer<i} yang mungkin terjadi waktu dalam struktur data yang merujuk pada dirinya sendiri. Jika data yang sama diteruskan dua kali, seperti dengan dua parameter metode atau vec<T> yang mengarah ke data yang sama, dua salinan terpisah dibuat dan dikirim.

Deklarasi bertingkat

HIDL mendukung deklarasi bertingkat ke sebanyak mungkin level yang diinginkan (dengan satu pengecualian yang disebutkan di bawah). Contoh:

interface IFoo {
    uint32_t[3][4][5][6] multidimArray;

    vec<vec<vec<int8_t>>> multidimVector;

    vec<bool[4]> arrayVec;

    struct foo {
        struct bar {
            uint32_t val;
        };
        bar b;
    }
    struct baz {
        foo f;
        foo.bar fb; // HIDL uses dots to access nested type names
    }
    …

Pengecualiannya adalah bahwa jenis antarmuka hanya dapat disematkan dalam vec<T> dan hanya dalam satu tingkat (tidak vec<vec<IFoo>>).

Sintaksis pointer mentah

Bahasa HIDL tidak menggunakan * dan tidak mendukung fleksibilitas penuh dari pointer mentah C/C++. Untuk mengetahui detail tentang cara HIDL mengenkapsulasi pointer dan array/vektor, lihat vec<T> template.

Antarmuka

Kata kunci interface memiliki dua penggunaan.

  • Perintah ini membuka definisi antarmuka dalam file .hal.
  • Ini dapat digunakan sebagai jenis khusus di bidang struct/union, parameter metode, dan pengembalian. Ini dipandang sebagai antarmuka dan sinonim umum untuk android.hidl.base@1.0::IBase.

Misalnya, IServiceManager memiliki metode berikut:

get(string fqName, string name) generates (interface service);

Metode ini berjanji untuk mencari beberapa antarmuka berdasarkan nama. Ini juga identik untuk mengganti antarmuka dengan android.hidl.base@1.0::IBase.

Antarmuka hanya dapat diteruskan dengan dua cara: sebagai parameter tingkat atas, atau sebagai anggota vec<IMyInterface>. Mereka tidak boleh anggota vec, struct, array, atau union bertingkat.

MQDescriptorSync dan MQDescriptorUnsync

Jenis MQDescriptorSync dan MQDescriptorUnsync meneruskan deskriptor Fast Message Queue (FMQ) yang disinkronkan atau tidak disinkronkan di seluruh antarmuka HIDL. Untuk mengetahui detailnya, lihat HIDL C++ (FMQ bukan didukung di Java).

jenis memori

Jenis memory digunakan untuk merepresentasikan memori bersama yang tidak dipetakan di HIDL. Hanya didukung pada C++. Nilai jenis ini dapat digunakan pada pihak penerima untuk menginisialisasi objek IMemory, memetakan memori dan membuatnya dapat digunakan. Untuk mengetahui detailnya, lihat HIDL C++.

Peringatan: Data terstruktur yang ditempatkan di folder bersama memori HARUS berupa jenis yang formatnya tidak pernah berubah sepanjang masa versi antarmuka yang meneruskan memory. Jika tidak, HAL dapat mengalami masalah kompatibilitas yang fatal.

jenis pointer

Jenis pointer hanya untuk penggunaan internal HIDL.

bitfield<T> jenis template

bitfield<T> dengan T adalah enum yang ditentukan pengguna menunjukkan bahwa nilainya adalah bitwise-OR dari nilai enum yang ditentukan dalam T. Dalam kode yang dihasilkan, bitfield<T> muncul sebagai jenis T yang mendasarinya. Contoh:

enum Flag : uint8_t {
    HAS_FOO = 1 << 0,
    HAS_BAR = 1 << 1,
    HAS_BAZ = 1 << 2
};
typedef bitfield<Flag> Flags;
setFlags(Flags flags) generates (bool success);

Compiler menangani jenis Flag yang sama seperti uint8_t.

Mengapa tidak digunakan (u)int8_t/(u)int16_t/(u)int32_t/(u)int64_t? Menggunakan bitfield memberikan informasi HAL tambahan kepada pembaca, yang sekarang mengetahui bahwa setFlags mengambil nilai bitwise-OR dari Flag (yaitu tahu bahwa memanggil setFlags dengan 16 tidak valid). Tanpa bitfield, informasi ini hanya disampaikan melalui dokumentasi. Di beberapa selain itu, VTS sebenarnya dapat memeriksa apakah nilai flag adalah bitwise-OR dari Flag.

Tuas jenis primitif

PERINGATAN: Segala jenis alamat (bahkan alamat fisik alamat perangkat) tidak boleh menjadi bagian dari nama sebutan channel native. Meneruskan ini informasi antar proses berbahaya dan membuat mereka rentan terhadap serangan. Setiap nilai yang diteruskan di antara proses harus divalidasi sebelum digunakan untuk mencari memori yang dialokasikan dalam suatu proses. Jika tidak, penanganan yang buruk dapat menyebabkan masalah akses memori atau kerusakan memori.

Semantik HIDL adalah salin-menurut-nilai, yang menyiratkan bahwa parameter disalin. Setiap potongan data yang besar, atau data yang perlu dibagikan antar-proses (seperti fence sinkronisasi), ditangani dengan meneruskan deskriptor file yang menunjuk ke objek persisten: ashmem untuk memori bersama, file sebenarnya, atau apa pun yang dapat bersembunyi di balik deskriptor file. Driver binder menduplikasi deskriptor file ke proses lain.

native_handle_t

Android mendukung native_handle_t, konsep handle umum ditentukan di libcutils.

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;

Pengendali native adalah kumpulan int dan deskriptor file yang diteruskan berdasarkan nilai. Satu deskriptor file dapat disimpan dalam handle native dengan tanpa int dan satu deskriptor file. Meneruskan handle menggunakan tuas native yang dienkapsulasi dengan jenis primitif handle memastikan bahwa elemen nama sebutan channel secara langsung termasuk dalam HIDL.

Karena memiliki ukuran yang bervariasi, native_handle_t tidak dapat disertakan secara langsung dalam struct. Bidang {i>handle<i} menghasilkan pointer ke native_handle_t yang dialokasikan.

Di versi Android sebelumnya, nama sebutan channel native dibuat menggunakan fungsi yang ada di libcutils. Di Android 8.0 dan yang lebih baru, fungsi ini kini disalin ke android::hardware::hidl atau dipindahkan ke NDK. HIDL kode yang dihasilkan secara otomatis akan melakukan serialisasi dan {i>deserialisasi<i} fungsi ini secara otomatis, tanpa keterlibatan dari kode yang ditulis pengguna.

Menangani dan kepemilikan deskriptor file

Bila Anda memanggil metode antarmuka HIDL yang meneruskan (atau mengembalikan) Objek hidl_handle (baik tingkat atas maupun bagian dari jenis gabungan), kepemilikan deskriptor file yang terkandung di dalamnya adalah sebagai berikut:

  • pemanggil meneruskan objek hidl_handle sebagai mempertahankan kepemilikan deskriptor file yang terdapat dalam native_handle_t wrap wrap; pemanggil harus menutup file ini deskriptor saat hal itu dilakukan dengannya.
  • Proses yang menampilkan hidl_handle (dengan meneruskannya ke fungsi _cb) mempertahankan kepemilikan deskriptor file yang terdapat dalam native_handle_t yang digabungkan oleh objek; proses harus menutup deskriptor file ini jika sudah selesai.
  • Transpor yang menerima hidl_handle memiliki kepemilikan deskriptor file di dalam native_handle_t digabungkan oleh objek; penerima dapat menggunakan deskriptor file ini apa adanya selama callback transaksi, namun harus meng-clone handle native untuk menggunakan file di luar callback. Transportasi otomatis memanggil close() untuk deskriptor file saat transaksi selesai.

HIDL tidak mendukung handle di Java (karena Java tidak mendukung handle di Java semua).

Array berukuran

Untuk array berukuran dalam HIDL, elemennya dapat berupa struct apa pun dapat berisi:

struct foo {
uint32_t[3] x; // array is contained in foo
};

String

String terlihat berbeda di C++ dan Java, tetapi transpor yang mendasarinya adalah struktur C++. Untuk mengetahui detailnya, lihat Jenis Data HiDL C++ atau Jenis Data Java HIDL.

Catatan: Meneruskan string ke atau dari Java melalui Antarmuka HIDL (termasuk Java ke Java) menyebabkan konversi himpunan karakter yang mungkin tidak mempertahankan encoding asli.

vec<T> jenis template

Template vec<T> mewakili buffer berukuran variabel yang berisi instance T.

T dapat berupa salah satu dari hal berikut:

  • Jenis primitif (misalnya, uint32_t)
  • String
  • Enum yang ditentukan pengguna
  • Struktur yang ditentukan pengguna
  • Antarmuka, atau kata kunci interface (vec<IFoo>, vec<interface> didukung hanya sebagai parameter tingkat teratas)
  • Nama sebutan channel
  • bitfield<U>
  • vec<U>, di mana U ada dalam daftar ini kecuali antarmuka (mis. vec<vec<IFoo>> tidak didukung)
  • U[] (array berukuran U), di mana U ada dalam daftar ini kecuali antarmuka

Jenis yang ditentukan pengguna

Bagian ini menjelaskan jenis yang ditentukan pengguna.

{i>Enumer<i}

HIDL tidak mendukung enum anonim. Jika tidak, enum di HIDL serupa ke C++11:

enum name : type { enumerator , enumerator = constexpr , …  }

Enum dasar didefinisikan dalam kaitannya dengan salah satu jenis bilangan bulat di HIDL. Jika tidak nilai ditentukan untuk enumerator pertama enum berdasarkan bilangan bulat , nilai defaultnya adalah 0. Jika tidak ada nilai yang ditentukan untuk enumerator berikutnya, nilai {i>default<i} ke nilai sebelumnya ditambah satu. Contoh:

// RED == 0
// BLUE == 4 (GREEN + 1)
enum Color : uint32_t { RED, GREEN = 3, BLUE }

Enum juga dapat mewarisi dari enum yang ditentukan sebelumnya. Jika tidak ada nilai yang yang ditentukan untuk enumerator pertama enum turunan (dalam hal ini FullSpectrumColor), nilainya didefaultkan ke nilai terakhir enumerator dari enumerasi induk ditambah satu. Contoh:

// ULTRAVIOLET == 5 (Color:BLUE + 1)
enum FullSpectrumColor : Color { ULTRAVIOLET }

Peringatan: Pewarisan enum bekerja secara mundur dari sebagian besar jenis pewarisan lainnya. Nilai enum turunan tidak dapat digunakan sebagai nilai enum induk. Hal ini karena enum turunan menyertakan lebih banyak nilai daripada orang tua. Namun, nilai enum induk dapat dengan aman digunakan sebagai nilai enum turunan karena nilai enum turunan menurut definisi adalah superset dari nilai enum induk. Ingatlah hal ini saat mendesain antarmuka karena ini berarti jenis-jenis yang mengacu pada enum induk tidak dapat merujuk ke enum turunan di iterasi berikutnya dari dalam antarmuka berbasis web yang sederhana.

Nilai enum disebut dengan sintaks titik dua (bukan sintaks titik sebagai jenis bertingkat). Sintaksisnya adalah Type:VALUE_NAME. Tidak perlu menentukan jika nilainya direferensikan dalam jenis enum atau jenis turunan yang sama. Contoh:

enum Grayscale : uint32_t { BLACK = 0, WHITE = BLACK + 1 };
enum Color : Grayscale { RED = WHITE + 1 };
enum Unrelated : uint32_t { FOO = Color:RED + 1 };

Mulai Android 10, enum memiliki Atribut len yang dapat digunakan dalam ekspresi konstan. MyEnum::len adalah jumlah total entri dalam enumerasi tersebut. Ini berbeda dari jumlah total nilai, yang mungkin lebih kecil ketika nilai diduplikasi.

Struktur

HIDL tidak mendukung struct anonim. Jika tidak, struct dalam HIDL sangat mirip dengan C.

HIDL tidak mendukung struktur data panjang-variabel yang terkandung sepenuhnya di dalam sebuah struct. Termasuk himpunan (array) tak terbatas yang terkadang digunakan sebagai isian terakhir dari {i>struct<i} pada C/C++ (kadang-kadang terlihat [0]). vec<T> HIDL merepresentasikan ukuran dinamis array dengan data yang disimpan dalam buffer terpisah; instance tersebut diwakili dengan instance vec<T> di struct.

Demikian pula, string dapat dimuat dalam struct (buffer terkait terpisah). Dalam C++ yang dihasilkan, instance HIDL jenis handle ditunjukkan melalui pointer ke handle native yang sebenarnya sebagai instance dari jenis data pokok memiliki panjang variabel.

Union

HIDL tidak mendukung serikat anonim. Jika tidak, union akan mirip dengan C.

Gabungan tidak boleh berisi jenis perbaikan (seperti pointer, deskriptor file, binder ). Tabel ini tidak memerlukan {i>field<i} khusus atau jenis terkait, cukup disalin menggunakan memcpy() atau yang setara. Sebuah serikat pekerja mungkin tidak secara langsung berisi (atau berisi menggunakan struktur data lain) apa pun yang memerlukan pengaturan offset binder (yaitu, referensi antarmuka binder atau handle). Contoh:

union UnionType {
uint32_t a;
//  vec<uint32_t> r;  // Error: can't contain a vec<T>
uint8_t b;1
};
fun8(UnionType info); // Legal

Gabungan juga dapat dideklarasikan di dalam struct. Contoh:

struct MyStruct {
    union MyUnion {
      uint32_t a;
      uint8_t b;
    }; // declares type but not member

    union MyUnion2 {
      uint32_t a;
      uint8_t b;
    } data; // declares type but not member
  }