Veri türleri

HIDL veri bildirimleri, C++ standart düzen veri yapıları oluşturur. Bu yapılar, doğal hissettiren herhangi bir yere (yığına, dosyaya veya genel kapsama ya da yığına) yerleştirilebilir ve aynı şekilde derlenebilir. İstemci kodu, HIDL proxy kodunu çağırır ve const referansları ile ilkel türleri iletir. Bu sırada, stub ve proxy kodu, serileştirmenin ayrıntılarını gizler.

Not: Veri yapılarını açıkça serileştirmek veya serileştirmeyi kaldırmak için geliştirici tarafından yazılmış kodun hiçbir zaman kullanılması gerekmez.

Aşağıdaki tabloda HIDL ilkelleri C++ veri türleriyle eşleştirilmiştir:

HIDL türü C++ Türü Başlık/kitaplık
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

Aşağıdaki bölümlerde veri türleri daha ayrıntılı olarak açıklanmaktadır.

enum

HIDL'deki bir enum, C++'da enum olur. Örneğin:

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

… şu hâle gelir:

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

Android 10'dan itibaren, ::android::hardware::hidl_enum_range kullanılarak bir enum üzerinde iterasyon yapılabilir. Bu aralık, ana enumeratörden son alt öğeye kadar HIDL kaynak kodunda göründüğü sıradaki her enumerasyonu içerir. Örneğin, bu kod WRITE, READ, NONE ve COMPARE değerlerini bu sırayla iteratif olarak işler. Yukarıdaki SpecialMode değeri için:

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

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

hidl_enum_range, ters iteratörleri de uygular ve constexpr bağlamlarında kullanılabilir. Bir değer bir sayımda birden çok kez görünüyorsa bu değer aralıkta da birden çok kez görünür.

bitfield<T>

bitfield<T> (T kullanıcı tanımlı bir enum ise), C++'ta bu enum'un temel türü olur. Yukarıdaki örnekte bitfield<Mode>, uint8_t olur.

vec<T>

hidl_vec<T> sınıf şablonu, libhidlbase'un bir parçasıdır ve herhangi bir HIDL türündeki bir vektörü rastgele bir boyutla iletmek için kullanılabilir. Karşılaştırılabilir sabit boyut kapsayıcı: hidl_array. hidl_vec<T>, hidl_vec::setToExternal() işlevi kullanılarak T türündeki harici bir veri arabelleğini işaret edecek şekilde de başlatılabilir.

vec<T> kullanımı, yapıyı oluşturulan C++ başlığına uygun şekilde yayınlamaya/eklemeye ek olarak std::vector ve çıplak T işaretçileri arasında çeviri yapmak için bazı kolaylık işlevleri oluşturur. vec<T> parametre olarak kullanılırsa bu parametreyi kullanan işlev, hem HIDL yapısını hem de ilgili parametre için bir std::vector<T> türünü kabul edip iletmek üzere aşırı yüklenir (iki prototip oluşturulur).

dizi

Hidl'deki sabit diziler, libhidlbase içindeki hidl_array sınıfı tarafından temsil edilir. hidl_array<T, S1, S2, …, SN>, N boyutlu sabit boyutlu bir diziyi temsil ederT[S1][S2]…[SN].

dize

hidl_string sınıfı (libhidlbase'un bir parçasıdır), HIDL arayüzleri üzerinden dize aktarmak için kullanılabilir ve /system/libhidl/base/include/hidl/HidlSupport.h içinde tanımlanır. Sınıftaki ilk depolama konumu, karakter arabelleğinin işaretçisidir.

hidl_string, operator=, örtülü yayınlama ve .c_str() işlevini kullanarak std::string and char* (C tarzı dize) ile arasında dönüşüm yapmayı bilir. HIDL dize yapıları, aşağıdakiler için uygun kopyalama kurucularına ve atama operatörlerine sahiptir:

  • HIDL dizesini bir std::string veya C dizesinden yükleyin.
  • HIDL dizelerinden yeni bir std::string oluşturun.

Ayrıca, HIDL dizelerinde dönüştürme kurucuları bulunur. Böylece, HIDL dizesi alan yöntemlerde C dizeleri (char *) ve C++ dizeleri (std::string) kullanılabilir.

struct

HIDL'de struct yalnızca sabit boyutlu veri türleri içerebilir ve işlev içeremez. HIDL yapı tanımları, C++'da doğrudan standart düzene sahip struct'lerle eşlenir. Bu sayede struct'lerin tutarlı bir bellek düzenine sahip olması sağlanır. Bir yapı, ayrı değişken uzunlukta arabelleklere işaret eden handle, string ve vec<T> gibi HIDL türleri içerebilir.

herkese açık kullanıcı adı

UYARI: Her tür adres (fiziksel cihaz adresleri dahil) hiçbir zaman yerel bir herkese açık kullanıcı adının parçası olmamalıdır. Bu bilgilerin süreçler arasında aktarılması tehlikelidir ve süreçleri saldırılara karşı savunmasız hale getirir. İşlemler arasında iletilen tüm değerler, bir işlemde ayrılan belleği aramak için kullanılmadan önce doğrulanmalıdır. Aksi takdirde, hatalı tutamaç kötü bellek erişimine veya bellek bozulmasına neden olabilir.

handle türü, C++'da hidl_handle yapısıyla temsil edilir. Bu yapı, const native_handle_t nesnesine işaret eden bir işaretçi etrafında basit bir sarmalayıcıdır (Android'de uzun süredir mevcuttur).

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;

Varsayılan olarak hidl_handle, sarmaladığı native_handle_t işaretçisinin sahipliğini almaz. Yalnızca bir native_handle_t işaretçisini hem 32 hem de 64 bit işlemlerde kullanılabilecek şekilde güvenli bir şekilde depolamak için vardır.

hidl_handle'nin ekteki dosya tanımlayıcılarına sahip olduğu senaryolar şunlardır:

  • shouldOwn parametresi true olarak ayarlanmışken setTo(native_handle_t* handle, bool shouldOwn) yönteminin çağrılmasından sonra
  • hidl_handle nesnesi, başka bir hidl_handle nesnesinden kopya oluşturma işlemiyle oluşturulduğunda
  • hidl_handle nesnesi başka bir hidl_handle nesnesinden kopya atandığında

hidl_handle, native_handle_t* nesnelerine/native_handle_t* nesnelerinden hem dolaylı hem de açık dönüşümler sağlar. HIDL'deki handle türünün ana kullanımı, dosya tanımlayıcılarını HIDL arayüzleri üzerinden iletmektir. Bu nedenle, tek bir dosya tanımlayıcısı int içermeyen bir native_handle_t ve tek bir fd ile temsil edilir. İstemci ve sunucu farklı bir işlemdeyse RPC uygulaması, her iki işlemin de aynı dosyada çalışabilmesini sağlamak için dosya tanımlayıcıyla otomatik olarak ilgilenir.

Bir işlem tarafından hidl_handle içinde alınan dosya tanımlayıcısı söz konusu işlemde geçerli olsa da alıcı işlevin ötesinde devam etmez (işlev döndürüldüğünde kapatılır). Dosya tanımlayıcısına kalıcı erişim elde etmek isteyen bir işlemin, kapalı dosya tanımlayıcılarını dup() veya hidl_handle nesnesinin tamamını kopyalaması gerekir.

bellek

HIDL memory türü, eşlenmemiş paylaşılan belleği temsil eden libhidlbase'deki hidl_memory sınıfına eşlenir. Bu, HIDL'de belleği paylaşmak için işlemler arasında aktarılması gereken nesnedir. Paylaşılan belleği kullanmak için:

  1. IAllocator örneği edinin (şu anda yalnızca "ashmem" örneği kullanılabilir) ve paylaşılan bellek ayırmak için kullanın.
  2. IAllocator::allocate(), HIDL RPC üzerinden iletilebilecek ve libhidlmemory'nin mapMemory işlevi kullanılarak bir işlemle eşlenebilecek bir hidl_memory nesnesi döndürür.
  3. mapMemory, belleğe erişmek için kullanılabilecek bir sp<IMemory> nesnesine referans döndürür. (IMemory ve IAllocator, android.hidl.memory@1.0 içinde tanımlanır.)

Bellek ayırmak için IAllocator örneği kullanılabilir:

#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
  }));

Bellekteki gerçek değişiklikler, mem'ı oluşturan taraftaki veya HIDL RPC üzerinden alan taraftaki bir IMemory nesnesi aracılığıyla yapılmalıdır.

// 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();

arayüz

Arayüzler nesne olarak iletilebilir. Arayüz kelimesi, android.hidl.base@1.0::IBase türü için söz dizimi şekeri olarak kullanılabilir. Ayrıca, mevcut arayüz ve içe aktarılan tüm arayüzler bir tür olarak tanımlanır.

Arayüzleri barındıran değişkenler güçlü işaretçiler olmalıdır: sp<IName>. Arayüz parametreleri alan HIDL işlevleri, ham işaretçileri güçlü işaretçilere dönüştürerek sezgisel olmayan davranışlara neden olur (işaretçi beklenmedik bir şekilde temizlenebilir). Sorun yaşamamak için HIDL arayüzlerini her zaman sp<> olarak saklayın.