Bu bölümde HIDL veri türleri açıklanmaktadır. Uygulama ayrıntıları için HIDL C++'ye (C++ uygulamaları için) veya HIDL Java'ya (Java uygulamaları için) bakın.
C++ ile benzerlikler şunlardır:
structs
C++ söz dizimini kullanır;unions
varsayılan olarak C++ söz dizimini destekler. Her ikisi de adlandırılmış olmalıdır; anonim yapı ve birlikler desteklenmez.- HIDL'de (C++'ta olduğu gibi) tür tanımları desteklenir.
- C++ tarzı yorumlara izin verilir ve oluşturulan başlık dosyasına kopyalanır.
Java ile benzerlikler şunlardır:
- HIDL, her dosya için
android.hardware.
ile başlaması gereken Java tarzı bir ad alanı tanımlar. Oluşturulan C++ ad alanı::android::hardware::…
. - Dosyanın tüm tanımları Java tarzı bir
interface
sarmalayıcı içinde yer alır. - HIDL dizi bildirimleri C++ stilini değil, Java stilini izler. Örnek:
struct Point { int32_t x; int32_t y; }; Point[3] triangle; // sized array
- Yorumlar, javadoc biçimine benzer.
Veri temsili
Standart-Düzen (basit eski veri türleri koşulunun alt kümesi) ile oluşturulan bir struct
veya union
, oluşturulan C++ kodunda tutarlı bir bellek düzenine sahiptir. Bu düzen, struct
ve union
üyelerinde açık hizalama özellikleriyle uygulanır.
Basit HIDL türlerinin yanı sıra enum
ve bitfield
türleri (her zaman basit türlerden türetilir), cstdint'ten std::uint32_t
gibi standart C++ türleriyle eşlenir.
Java, imzalanmamış türleri desteklemediğinden, imzalanmamış HIDL türleri, karşılık gelen imzalı Java türüyle eşlenir. Yapılar Java sınıflarıyla eşlenir; diziler Java dizileriyle eşlenir; birimler şu anda Java'da desteklenmemektedir. Dizeler dahili olarak UTF8 olarak depolanır. Java yalnızca UTF16 dizelerini desteklediğinden, bir Java uygulamasına veya uygulamasından gönderilen dize değerleri çevrilir ve karakter kümeleri her zaman sorunsuz bir şekilde eşleşmediğinden yeniden çeviride aynı olmayabilir.
C++'ta IPC üzerinden alınan veriler const
ile işaretlenir ve yalnızca işlev çağrısı süresince devam eden salt okunur bellekte bulunur. Java'da IPC üzerinden alınan veriler zaten Java nesnelerine kopyalandığından ek kopyalama olmadan saklanabilir (ve değiştirilebilir).
Ek Açıklamalar
Tür beyanlarına Java tarzı ek açıklamalar eklenebilir. Ek açıklamalar, HIDL derleyicisinin Tedarikçi Testi Paketi (VTS) arka ucu tarafından ayrıştırılır ancak ayrıştırılan bu ek açıklamaların hiçbiri HIDL derleyicisi tarafından anlaşılmaz. Bunun yerine, ayrıştırılan VTS ek açıklamaları VTS Derleyici (VTSC) tarafından işlenir.
Ek açıklamalarda Java söz dizimi kullanılır: @annotation
veya
@annotation(value)
veya @annotation(id=value, id=value…)
Burada değer, tıpkı Java'da olduğu gibi {}
içinde sabit bir ifade, dize veya değer listesi olabilir. Aynı öğeye aynı ada sahip birden fazla ek açıklama eklenebilir.
İleriye dönük beyanlar
HIDL'de yapıların ileriye dönük olarak tanımlanması mümkün değildir. Bu nedenle, kullanıcı tanımlı, kendi referans veren veri türleri kullanılamaz (örneğin, HIDL'de bağlı liste veya ağaç tanımlayamazsınız). Mevcut HAL'lerin çoğunda (Android 8.x öncesi) ileri beyanların kullanımı sınırlıdır. Bu beyanlar, veri yapısı beyanları yeniden düzenlenerek kaldırılabilir.
Bu kısıtlama, kendi referans veren bir veri yapısında birden çok kez görünebilecek işaretçi değerlerini takip etmek yerine, veri yapılarının basit bir derin kopyalamayla değere göre kopyalanmasına olanak tanır. Aynı veriler iki kez iletilirse (ör. aynı verileri işaret eden iki yöntem parametresi veya vec<T>
ile) iki ayrı kopya oluşturulur ve yayınlanır.
İç içe yerleştirilmiş tanımlamalar
HIDL, iç içe yerleştirilmiş bildirimleri istediğiniz kadar düzeyde destekler (aşağıda belirtilen bir istisna hariç). Örnek:
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 } …
Bunun istisnası, arayüz türlerinin yalnızca vec<T>
içine ve yalnızca bir düzey derine yerleştirilebilmesidir (vec<vec<IFoo>>
kabul edilmez).
Ham işaretçi söz dizimi
HIDL dilinde * kullanılmaz ve C/C++ ham işaretçilerinin tam esnekliği desteklenmez. HIDL'in işaretçileri ve dizileri/vektörleri nasıl kapsüllediği hakkında ayrıntılı bilgi için vec<T> şablonu başlıklı makaleyi inceleyin.
Arayüzler
interface
anahtar kelimesinin iki kullanımı vardır.
- Bir arayüzün tanımını .hal dosyasında açar.
- Yapı/birleştirme alanlarında, yöntem parametrelerinde ve döndürülen değerlerde özel bir tür olarak kullanılabilir. Genel bir arayüz ve
android.hidl.base@1.0::IBase
ile eş anlamlı olarak kabul edilir.
Örneğin, IServiceManager
aşağıdaki yönteme sahiptir:
get(string fqName, string name) generates (interface service);
Yöntem, bir arayüzü ada göre arayacaktır. Ayrıca, arayüzü android.hidl.base@1.0::IBase
ile değiştirmek için de aynıdır.
Arayüzler yalnızca iki şekilde iletilebilir: üst düzey parametreler olarak veya vec<IMyInterface>
üyelerinin parçası olarak. İç içe yerleştirilmiş vektörlerin, yapıların, dizilerin veya birliklerin üyesi olamaz.
MQDescriptorSync ve MQDescriptorUnsync
MQDescriptorSync
ve MQDescriptorUnsync
türleri, senkronize edilmiş veya senkronize edilmemiş bir Hızlı Mesaj Kuyruğu (FMQ) tanımlayıcısı bir HIDL arayüzünden iletir. Ayrıntılar için HIDL C++'ye bakın (FMQ'ler Java'da desteklenmez).
bellek türü
memory
türü, HIDL'de eşlenmemiş paylaşılan belleği temsil etmek için kullanılır. Yalnızca C++'ta desteklenir. Bu tür bir değer, alıcı tarafta bir IMemory
nesnesini başlatmak, belleği eşlemek ve kullanılabilir hale getirmek için kullanılabilir. Ayrıntılar için HIDL C++ başlıklı makaleyi inceleyin.
Uyarı: Paylaşılan belleğe yerleştirilen yapılandırılmış veriler, memory
ileten arayüz sürümünün kullanım ömrü boyunca biçimi hiçbir zaman değişmeyen bir tür OLMALIDIR. Aksi takdirde, HAL'lerde ciddi uyumluluk sorunları yaşanabilir.
işaretçi türü
pointer
türü yalnızca HIDL'nin dahili kullanımı içindir.
bitfield<T> türü şablonu
T
bir kullanıcı tanımlı enum olan bitfield<T>
, değerin T
içinde tanımlanan enum değerlerinin bitsel VEYA işlemi olduğunu gösterir. Oluşturulan kodda, bitfield<T>
, T'nin temel türü olarak görünür. Örneğin:
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);
Derleyici, Flags türünü uint8_t
ile aynı şekilde işler.
Neden (u)int8_t
/(u)int16_t
/(u)int32_t
/(u)int64_t
kullanmıyorsunuz?
bitfield
kullanılması, okuyucuya ek HAL bilgileri sağlar. Böylece okuyucu, setFlags
'in bir bitsel VEYA işaret değeri aldığını (yani setFlags
'i 16 ile çağırmanın geçersiz olduğunu) bilir. bitfield
olmadan bu bilgiler yalnızca dokümanlar aracılığıyla iletilir. Ayrıca VTS, bayrakların değerinin Flag değerinin bitsel VEYA işlemi olup olmadığını kontrol edebilir.
Basit türdeki herkese açık kullanıcı adları
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.
HIDL semantiği, değere göre kopyalama şeklindedir. Bu, parametrelerin kopyalandığı anlamına gelir.
Büyük veri parçaları veya işlemler arasında paylaşılması gereken veriler (senkronizasyon çiti gibi), kalıcı nesnelere işaret eden dosya tanımlayıcıları ile aktarılır: Paylaşılan bellek, gerçek dosyalar veya dosya tanımlayıcısının arkasına gizlenebilecek başka herhangi bir şey için ashmem
. Bağlayıcı sürücüsü, dosya tanımlayıcısını diğer sürece kopyalar.
native_handle_t
Android, libcutils
'te tanımlanan genel bir herkese açık kullanıcı adı kavramı olan native_handle_t
'ü destekler.
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;
Yerel bir tutamaç, değere göre aktarılan bir int ve dosya tanımlayıcıları koleksiyonudur. Tek bir dosya tanımlayıcısı, int içermeyen ve tek bir dosya tanımlayıcısı olan yerel bir tutamakta depolanabilir. handle
ilkel türüyle kapsüllenmiş yerel imleçleri kullanarak imleçleri iletmek, yerel imleçlerin doğrudan HIDL'ye dahil edilmesini sağlar.
native_handle_t
değişken boyuta sahip olduğundan doğrudan bir yapıya dahil edilemez. Herkese açık kullanıcı adı alanı, ayrı olarak ayrılmış bir native_handle_t
'ye işaretçi oluşturur.
Android'in önceki sürümlerinde yerel tutamaç, libcutils'teki aynı işlevler kullanılarak oluşturuluyordu.
Android 8.0 ve sonraki sürümlerde bu işlevler artık android::hardware::hidl
ad alanına kopyalanır veya NDK'ya taşınır. HIDL tarafından otomatik olarak oluşturulan kod, kullanıcı tarafından yazılan koddan bağımsız olarak bu işlevleri otomatik olarak serileştirir ve seri dışına çıkarır.
Herkese açık kullanıcı adı ve dosya tanımlayıcısının sahipliği
Bir hidl_handle
nesnesi (üst düzey veya bileşik türün bir parçası) ileten (veya döndüren) bir HIDL arayüz yöntemini çağırdığınızda, bu yöntemin içerdiği dosya tanımlayıcılarının sahipliği aşağıdaki gibidir:
- Bir
hidl_handle
nesnesini bağımsız değişken olarak ileten çağrıcı, sarmaladığınative_handle_t
içinde bulunan dosya tanımlayıcılarının sahipliğini korur; çağrıcı, bu dosya tanımlayıcılarını kullanması bittiğinde kapatmalıdır. hidl_handle
nesnesi döndüren (_cb
işlevine ileterek) işlem, nesne tarafından sarmalanmışnative_handle_t
içinde bulunan dosya tanımlayıcılarının sahipliğini korur; işlem, bu dosya tanımlayıcılarını kullanması bittiğinde kapatmalıdır.hidl_handle
alan bir iletişim aracı, nesne tarafından sarmalanmışnative_handle_t
içindeki dosya tanımlayıcılarının sahibidir; alıcı bu dosya tanımlayıcılarını işlem geri çağırması sırasında olduğu gibi kullanabilir ancak dosya tanımlayıcılarını geri çağırma dışında kullanmak için doğal imleci kopyalamalıdır. Aktarım, işlem tamamlandığında dosya tanımlayıcıları içinclose()
işlevini otomatik olarak çağırır.
HIDL, Java'da tutamaçları desteklemez (Java hiç tutamaç desteklemediği için).
Boyutlandırılmış diziler
HIDL struct'larındaki boyutlandırılmış dizilerin öğeleri, struct'un içerebileceği herhangi bir türde olabilir:
struct foo { uint32_t[3] x; // array is contained in foo };
Yaylı Çalgılar
Dizeler C++ ve Java'da farklı görünür ancak temel aktarım depolama türü bir C++ yapısıdır. Ayrıntılar için HIDL C++ Veri Türleri veya HIDL Java Veri Türleri başlıklı makaleyi inceleyin.
Not: Bir dizenin HIDL arayüzü üzerinden Java'ya veya Java'dan Java'ya iletilmesi, orijinal kodlamayı koruyamayabilecek karakter kümesi dönüşümlerine neden olur.
vec<T> türü şablonu
vec<T>
şablonu, T
örnekleri içeren değişken boyutlu bir arabelleği temsil eder.
T
aşağıdakilerden biri olabilir:
- Basit türler (ör. uint32_t)
- Yaylı Çalgılar
- Kullanıcı tanımlı enum'lar
- Kullanıcı tanımlı yapılardır.
- Arayüzler veya
interface
anahtar kelimesi (vec<IFoo>
,vec<interface>
yalnızca üst düzey parametre olarak desteklenir) - Herkese açık kullanıcı adları
- bitfield<U>
- vec<U>. U, arayüz hariç bu listededir (ör.
vec<vec<IFoo>>
desteklenmez). - U[] (boyutlandırılmış U dizisi), burada U, arayüz hariç bu listededir
Kullanıcı tanımlı türler
Bu bölümde kullanıcı tanımlı türler açıklanmaktadır.
Enum
HIDL, anonim enum'ları desteklemez. Aksi takdirde, HIDL'deki enum'lar C++11'e benzer:
enum name : type { enumerator , enumerator = constexpr , … }
Temel enum, HIDL'deki tam sayı türlerinden biri olarak tanımlanır. Tam sayı türüne dayalı bir enum'un ilk dizini için bir değer belirtilmezse değer varsayılan olarak 0 olur. Daha sonraki bir sayımlayıcı için herhangi bir değer belirtilmezse değer varsayılan olarak önceki değere bir eklenerek hesaplanır. Örnek:
// RED == 0 // BLUE == 4 (GREEN + 1) enum Color : uint32_t { RED, GREEN = 3, BLUE }
Bir enum, daha önce tanımlanmış bir enum'dan da miras alabilir. Bir alt enum'un ilk dizini için bir değer belirtilmezse (bu durumda FullSpectrumColor
) varsayılan olarak üst enum'un son dizininin değeri artı bir olur. Örnek:
// ULTRAVIOLET == 5 (Color:BLUE + 1) enum FullSpectrumColor : Color { ULTRAVIOLET }
Uyarı: Enum devralma, diğer devralma türlerinin çoğundan farklı olarak ters çalışır. Alt numaralandırma değeri, üst numaralandırma değeri olarak kullanılamaz. Bunun nedeni, alt öğelerin üst öğeden daha fazla değer içermesidir. Ancak alt enum değerleri, tanımı gereği üst enum değerlerinin bir üst kümesi olduğundan üst enum değeri, alt enum değeri olarak güvenli bir şekilde kullanılabilir. Üst listelere atıfta bulunan türlerin, arayüzünüzün sonraki iterasyonlarında alt listelere atıfta bulunamayacağı anlamına geldiğinden, arayüzleri tasarlarken bunu göz önünde bulundurun.
Listelemelerin değerlerine iki nokta işareti söz dizimi ile (iç içe yerleştirilmiş türler için nokta söz dizimi değil) değinilir. Söz dizimi Type:VALUE_NAME
. Değere aynı enum türünde veya alt türlerde referans veriliyorsa türün belirtilmesi gerekmez. Örnek:
enum Grayscale : uint32_t { BLACK = 0, WHITE = BLACK + 1 }; enum Color : Grayscale { RED = WHITE + 1 }; enum Unrelated : uint32_t { FOO = Color:RED + 1 };
Android 10'dan itibaren enum'larda sabit ifadelerde kullanılabilen bir len
özelliği bulunur.
MyEnum::len
, söz konusu sayımdaki toplam giriş sayısıdır.
Bu, değerler yinelendiğinde daha küçük olabilecek toplam değer sayısından farklıdır.
Struct
HIDL, anonim yapıları desteklemez. Aksi halde, HIDL'deki yapıların C'ye benzerliği çok yüksektir.
HIDL, tamamen bir yapı içinde bulunan değişken uzunluktaki veri yapılarını desteklemez. Bazen C/C++'ta bir yapının son alanı olarak kullanılan (bazen [0]
boyutunda görüldüğü) belirsiz uzunluktaki diziler de buna dahildir. HIDL vec<T>
, verileri ayrı bir arabellekte depolanan dinamik boyutlu dizileri temsil eder; bu tür örnekler, struct
içinde bir vec<T>
örneğiyle temsil edilir.
Benzer şekilde, string
bir struct
içinde bulunabilir (ilişkili arabellekler ayrıdır). Oluşturulan C++'da, HIDL tutamaç türündeki örnekler, temel veri türünün örnekleri değişken uzunlukta olduğundan asıl yerel tutamaç işaretçisi aracılığıyla temsil edilir.
Union
HIDL, anonim birlikleri desteklemez. Aksi takdirde, birleştirme işlemleri C'ye benzer.
Birlikler, düzeltme türleri (ör. işaretçiler, dosya tanımlayıcıları, bağlayıcı nesneleri) içeremez. Özel alanlara veya ilişkili türlere ihtiyaç duymazlar ve memcpy()
veya eşdeğeri kullanılarak kopyalanır. Bir birleştirme, doğrudan bağlayıcı ofsetlerinin (yani, tutamaç veya bağlayıcı arayüzü referanslarının) ayarlanmasını gerektiren hiçbir şeyi doğrudan içeremez (veya başka veri yapıları kullanarak içeremez). Örnek:
union UnionType { uint32_t a; // vec<uint32_t> r; // Error: can't contain a vec<T> uint8_t b;1 }; fun8(UnionType info); // Legal
Birlikler, yapıların içinde de tanımlanabilir. Örnek:
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 }