Veri Türleri

HIDL veri bildirimleri, C++ standart düzeninde veri yapıları oluşturur. Bu yapılar doğal görünen herhangi bir yere yerleştirilebilir (yığında, dosyada, genel kapsamda veya yığında) ve aynı şekilde oluşturulabilir. İstemci kodu, const referansları ve temel türlerden geçen HIDL proxy kodunu çağırırken, saplama ve proxy kodu serileştirmenin ayrıntılarını gizler.

Not: Veri yapılarını açıkça seri hale getirmek veya seri durumdan çıkarmak için geliştirici tarafından yazılan koda hiçbir zaman gerek yoktur.

Aşağıdaki tablo HIDL temel öğelerini C++ veri türleriyle eşler:

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

Sıralama

HIDL'deki bir numaralandırma, C++'da bir numaralandırmaya dönüşür. Örneğin:

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

… şuna dönüşür:

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 başlayarak, bir numaralandırma ::android::hardware::hidl_enum_range kullanılarak yinelenebilir. Bu aralık, ana numaralandırmadan başlayarak son alt öğeye kadar HIDL kaynak kodunda göründüğü sıraya göre her numaralandırıcıyı içerir. Örneğin, bu kod WRITE , READ , NONE ve COMPARE üzerinde bu sırayla yinelenir. Yukarıda SpecialMode verildiğinde:

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

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

hidl_enum_range ayrıca ters yineleyicileri de uygular ve constexpr bağlamlarında kullanılabilir. Bir numaralandırmada bir değer birden çok kez görünüyorsa, değer aralıkta birden çok kez görünür.

bit alanı<T>

bitfield<T> (burada T , kullanıcı tanımlı bir numaralandırmadır), C++'da bu numaralandırmanın temel türü haline gelir. Yukarıdaki örnekte bitfield<Mode> uint8_t olur.

vec<T>

hidl_vec<T> sınıf şablonu libhidlbase bir parçasıdır ve herhangi bir HIDL tipindeki vektörü isteğe bağlı boyutta geçirmek için kullanılabilir. Karşılaştırılabilir sabit boyutlu kapsayıcı hidl_array . Bir hidl_vec<T> ayrıca hidl_vec::setToExternal() işlevi kullanılarak T türünde bir harici veri arabelleğine işaret edecek şekilde başlatılabilir.

Oluşturulan C++ başlığına yapıyı uygun şekilde yaymanın/eklemenin yanı sıra, vec<T> kullanımı, std::vector ve çıplak T işaretçilerine/bunlardan çeviri yapmak için bazı kolaylık işlevleri üretir. Parametre olarak vec<T> kullanılırsa, onu kullanan işlev, o parametre için hem HIDL yapısını hem de std::vector<T> türünü kabul etmek ve iletmek için aşırı yüklenecektir (iki prototip oluşturulacaktır).

sıralamak

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

sicim

hidl_string sınıfı ( libhidlbase bir parçası), dizeleri HIDL arayüzleri üzerinden geçirmek için kullanılabilir ve /system/libhidl/base/include/hidl/HidlSupport.h dosyasında tanımlanır. Sınıftaki ilk depolama konumu, karakter arabelleğine yönelik bir işaretçidir.

hidl_string operator= , örtülü dönüşümler ve .c_str() işlevini kullanarak std::string and char* (C stili dize) arasında nasıl dönüşüm yapılacağını bilir. HIDL dize yapıları aşağıdakiler için uygun kopya oluşturuculara ve atama operatörlerine sahiptir:

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

Ek olarak, HIDL dizeleri dönüştürme oluşturucularına sahiptir; dolayısıyla C dizeleri ( char * ) ve C++ dizeleri ( std::string ), HIDL dizesi alan yöntemlerde kullanılabilir.

yapı

HIDL'deki bir struct yalnızca sabit boyutlu veri türleri içerebilir ve hiçbir işlev içeremez. HIDL yapı tanımları, C++'daki standart düzen struct doğrudan eşleşerek struct tutarlı bir bellek düzenine sahip olmasını sağlar. Bir yapı, değişken uzunluklu arabellekleri ayırmaya işaret eden, handle , string ve vec<T> dahil olmak üzere HIDL türlerini içerebilir.

halletmek

UYARI: Her türlü adres (fiziksel cihaz adresleri bile) hiçbir zaman yerel tanıtıcının parçası olmamalıdır. Bu bilgilerin süreçler arasında aktarılması tehlikelidir ve onları saldırıya açık hale getirir. İşlemler arasında iletilen herhangi bir değer, bir işlem içinde tahsis edilen belleği aramak için kullanılmadan önce doğrulanmalıdır. Aksi takdirde hatalı tanıtıcılar hatalı belleğe erişime veya belleğin bozulmasına neden olabilir.

handle türü, C++'daki hidl_handle yapısıyla temsil edilir; bu, const native_handle_t nesnesine yönelik bir işaretçinin etrafındaki basit bir sarmalayıcıdır (bu, 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 , sardığı native_handle_t işaretçisinin sahipliğini almaz . Yalnızca bir işaretçiyi hem 32 hem de 64 bit işlemlerde kullanılabilecek şekilde native_handle_t güvenli bir şekilde depolamak için mevcuttur.

hidl_handle ekteki dosya tanımlayıcılarına sahip olduğu senaryolar şunları içerir:

  • shouldOwn parametresi true olarak ayarlıyken setTo(native_handle_t* handle, bool shouldOwn) yöntemine yapılan çağrının ardından
  • hidl_handle nesnesi başka bir hidl_handle nesnesinden kopya yapısıyla oluşturulduğunda
  • hidl_handle nesnesine başka bir hidl_handle nesnesinden kopya atandığında

hidl_handle native_handle_t* nesnelerine/nesnelerinden hem örtülü 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 arabirimleri üzerinden geçirmektir. Bu nedenle tek bir dosya tanımlayıcı, int s içermeyen ve tek bir fd içeren bir native_handle_t ile temsil edilir. İstemci ve sunucu farklı bir işlemde yaşıyorsa, RPC uygulaması her iki işlemin de aynı dosya üzerinde çalışabilmesini sağlamak için dosya tanımlayıcıyla otomatik olarak ilgilenir.

Bir süreç tarafından hidl_handle alınan bir dosya tanımlayıcı bu süreçte geçerli olsa da, alıcı fonksiyonun ötesinde kalıcı olmayacaktır (fonksiyon geri döndüğünde kapatılacaktır). Dosya tanımlayıcıya kalıcı erişimi korumak isteyen bir işlemin, ekteki dosya tanımlayıcılarını dup() veya hidl_handle nesnesinin tamamını kopyalaması gerekir.

hafıza

HIDL memory türü, eşlenmemiş paylaşılan belleği temsil eden libhidlbase içindeki hidl_memory sınıfıyla eşleşir. Bu, HIDL'de belleği paylaşmak için işlemler arasında geçirilmesi gereken nesnedir. Paylaşılan hafızayı kullanmak için:

  1. Bir IAllocator örneği edinin (şu anda yalnızca "ashmem" örneği mevcuttur) ve bunu paylaşılan belleği ayırmak için kullanın.
  2. IAllocator::allocate() HIDL RPC'den geçirilebilen ve libhidlmemory mapMemory işlevi kullanılarak bir işleme eşlenebilen bir hidl_memory nesnesini döndürür.
  3. mapMemory belleğe erişmek için kullanılabilecek bir sp<IMemory> nesnesine bir başvuru döndürür. ( IMemory ve IAllocator android.hidl.memory@1.0 tanımlanmıştır.)

Belleği ayırmak için bir 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 tarafta veya onu HIDL RPC üzerinden alan tarafta 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 nesneler olarak aktarılabilir. Arayüz sözcüğü, android.hidl.base@1.0::IBase türü için sözdizimsel şeker olarak kullanılabilir; ayrıca geçerli arayüz ve içe aktarılan arayüzler bir tür olarak tanımlanacaktır.

Arayüzleri tutan değişkenler güçlü işaretçiler olmalıdır: sp<IName> . Arayüz parametrelerini 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 silinebilir). Sorunları önlemek için HIDL arayüzlerini her zaman sp<> olarak saklayın.