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
parametresitrue
olarak ayarlıykensetTo(native_handle_t* handle, bool shouldOwn)
yöntemine yapılan çağrının ardından -
hidl_handle
nesnesi başka birhidl_handle
nesnesinden kopya yapısıyla oluşturulduğunda -
hidl_handle
nesnesine başka birhidl_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:
- 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. -
IAllocator::allocate()
HIDL RPC'den geçirilebilen velibhidlmemory
mapMemory
işlevi kullanılarak bir işleme eşlenebilen birhidl_memory
nesnesini döndürür. -
mapMemory
belleğe erişmek için kullanılabilecek birsp<IMemory>
nesnesine bir başvuru döndürür. (IMemory
veIAllocator
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.