HAL arayüz tanımlama dili veya HIDL, HAL ile kullanıcıları arasındaki arayüzü belirten bir arayüz açıklama dilidir (IDL). HIDL, arayüzler ve paketler halinde toplanan türleri ve yöntem çağrılarını belirtmenize olanak tanır. Daha geniş bir açıdan bakıldığında HIDL, bağımsız olarak derlenebilecek kod tabanları arasında iletişim kurmak için kullanılan bir sistemdir.
HIDL, işlemler arası iletişim (IPC) için kullanılmak üzere tasarlanmıştır. HDL ile oluşturulan HAL'ler, bağlayıcılar arası iletişim (IPC) çağrılarını kullanarak diğer mimari katmanlarıyla iletişim kurabildikleri için bağlayıcılı HAL'ler olarak adlandırılır. Bağlayıcılı HAL'ler, bunları kullanan istemciden ayrı bir işlemde çalışır. Bir işleme bağlanması gereken kitaplıklar için geçiş modu da kullanılabilir (Java'da desteklenmez).
HIDL, paketler halinde toplanan arayüzlerde (sınıfa benzer) düzenlenen veri yapılarını ve yöntem imzalarını belirtir. HIDL'nin söz dizimi, C++ ve Java programcılarına aşina gelebilir ancak farklı bir anahtar kelime grubuna sahiptir. HIDL, Java tarzı ek açıklamalar da kullanır.
Terminoloji
Bu bölümde HIDL ile ilgili aşağıdaki terimler kullanılır:
ciltlenmiş | İşlemler arasındaki uzak prosedür çağrıları için Binder benzeri bir mekanizma üzerinden uygulanan HIDL'nin kullanıldığını gösterir. Geçiş konusuna da bakın. |
---|---|
geri çağırma, eşzamansız | HAL kullanıcısı tarafından sunulan, HAL'e (HIDL yöntemi kullanılarak) iletilen ve HAL tarafından herhangi bir zamanda veri döndürmek için çağrılan arayüz. |
geri arama, senkronize | Bir sunucunun HIDL yöntemi uygulamasından istemciye veri döndürür. Boş veya tek bir ilkel değer döndüren yöntemler için kullanılmaz. |
client | Belirli bir arayüzün yöntemlerini çağıran işlem. HAL veya Android çerçevesi işlemi, bir arayüzün istemcisi ve başka bir arayüzün sunucusu olabilir. Geçiş özelliğine de bakın. |
extends | Başka bir arayüze yöntem ve/veya tür ekleyen bir arayüzü belirtir. Bir arayüz yalnızca başka bir arayüzü genişletebilir. Aynı paket adında küçük bir sürüm artışı veya eski bir paketin üzerine inşa edilecek yeni bir paket (ör. tedarikçi uzantısı) için kullanılabilir. |
oluşturur | İstemciye değer döndüren bir arayüz yöntemini belirtir. Basit olmayan bir değer veya birden fazla değer döndürmek için senkron bir geri çağırma işlevi oluşturulur. |
arayüz | Yöntem ve türlerin toplanması. C++ veya Java'da bir sınıfa dönüştürülür. Bir arayüzdeki tüm yöntemler aynı yönde çağrılır: Bir istemci işlemi, sunucu işlemi tarafından uygulanan yöntemleri çağırır. |
tek yön | Bir HIDL yöntemine uygulandığında, yöntemin hiçbir değer döndürmediğini ve engellemediğini gösterir. |
paket | Bir sürümü paylaşan arayüz ve veri türleri koleksiyonu. |
geçiş | Sunucunun istemci tarafından dlopen edilen paylaşılan bir kitaplık olduğu HIDL modu. Geçiş modunda istemci ve sunucu aynı işlemdir ancak ayrı kod tabanlarına sahiptir. Yalnızca eski kod tabanlarını HIDL modeline getirmek için kullanılır.
Bağlayıcılı bölümüne de bakın. |
sunucu | Bir arayüzün yöntemlerini uygulayan işlem. Geçiş özelliğine de bakın. |
ulaşım | Sunucu ile istemci arasında veri taşıyan HIDL altyapısı. |
sürüm | Bir paketin sürümü. Büyük ve küçük olmak üzere iki tam sayıda oluşur. Küçük sürüm artışları, tür ve yöntem ekleyebilir (ancak değiştiremez). |
HIDL tasarımı
HIDL'nin amacı, HAL'lerin yeniden derlenmesi gerekmeden Android çerçevesinin değiştirilebilmesidir. HAL'ler, tedarikçiler veya SOC üreticileri tarafından oluşturulur ve cihazdaki bir /vendor
bölümüne yerleştirilir. Bu sayede, Android çerçevesi kendi bölümünde HAL'ler yeniden derlenmeden OTA ile değiştirilebilir.
HIDL tasarımı aşağıdaki endişeleri dengeler:
- Birlikte çalışabilirlik. Çeşitli mimariler, araç zincirleri ve derleme yapılandırmalarıyla derlenebilen süreçler arasında güvenilir bir şekilde birlikte çalışabilen arayüzler oluşturun. HIDL arayüzleri sürümlere sahiptir ve yayınlandıktan sonra değiştirilemez.
- Verimlilik. HIDL, kopyalama işlemlerinin sayısını en aza indirmeye çalışır. HIDL tarafından tanımlanan veriler, paketi açmadan kullanılabilen C++ standart düzen veri yapılarında C++ koduna aktarılır. HIDL, paylaşılan bellek arayüzleri de sağlar. RPC'ler doğası gereği biraz yavaş olduğundan HIDL, RPC çağrısı kullanmadan veri aktarmanın iki yolunu destekler: paylaşılan bellek ve hızlı mesaj kuyruğu (FMQ).
- Sezgisel. HIDL, RPC için yalnızca
in
parametrelerini kullanarak bellek sahipliğiyle ilgili karmaşık sorunları önler (Android Arayüz Tanımlama Dili (AIDL) bölümüne bakın); yöntemlerden verimli bir şekilde döndürülemeyen değerler, geri çağırma işlevleri aracılığıyla döndürülür. Verilerin aktarılması için HIDL'ye aktarılması veya HIDL'den alınması, verilerin sahipliğini değiştirmez. Sahiplik her zaman çağıran işlevde kalır. Verilerin yalnızca çağrılan işlev süresince kalıcı olması gerekir ve çağrılan işlev döndükten hemen sonra veriler silinebilir.
Geçiş modunu kullanma
Android'in önceki sürümlerini çalıştıran cihazları Android O'ya güncellemek için hem geleneksel (hem de eski) HAL'leri, HAL'i bağlayıcılı ve aynı işlem (geçiş) modlarında sunan yeni bir HIDL arayüzüne sarabilirsiniz. Bu sarmalama işlemi hem HAL hem de Android çerçevesi için şeffaftır.
Geçiş modu yalnızca C++ istemcileri ve uygulamaları için kullanılabilir. Android'in önceki sürümlerini çalıştıran cihazlarda Java ile yazılmış HAL'ler bulunmaz. Bu nedenle Java HAL'leri doğal olarak bağlayıcıya sahiptir.
Geçiş üstbilgi dosyaları
Bir .hal
dosyası derlendiğinde hidl-gen
, bağlayıcı iletişimi için kullanılan başlıklara ek olarak BsFoo.h
adlı ek bir geçiş başlığı dosyası oluşturur. Bu başlık, dlopen
edilecek işlevleri tanımlar. Geçiş HAL'leri çağrıldıkları süreçte çalıştırıldığı için çoğu durumda geçiş yöntemleri doğrudan işlev çağrısıyla (aynı iş parçacığı) çağrılır. oneway
yöntemleri, HAL'ın bunları işlemesini beklemek için tasarlanmadığından kendi iş parçacıklarında çalışır (yani, geçiş modunda oneway
yöntemlerini kullanan tüm HAL'ler iş parçacığı açısından güvenli olmalıdır).
IFoo.hal
verildiğinde BsFoo.h
, ek özellikler (ör. oneway
işlemlerinin başka bir iş parçacığında çalıştırılmasını sağlama) sunmak için HIDL tarafından oluşturulan yöntemleri sarar. Bu dosya BpFoo.h
dosyasına benzer ancak binder kullanılarak IPC üzerinden çağrılar iletilmek yerine istenen işlevler doğrudan çağrılır. Gelecekteki HAL uygulamalarında FooFast HAL ve FooAccurate HAL gibi birden fazla uygulama sağlanabilir. Bu gibi durumlarda, her ek uygulama için bir dosya oluşturulur (ör. PTFooFast.cpp
ve
PTFooAccurate.cpp
).
Şeffaf mod HAL'lerini bağlama
Geçiş modunu destekleyen HAL uygulamalarını bağlayıcıya bağlayabilirsiniz. Bir HAL arayüzü a.b.c.d@M.N::IFoo
verildiğinde iki paket oluşturulur:
a.b.c.d@M.N::IFoo-impl
. HAL'ın uygulamasını içerir veIFoo* HIDL_FETCH_IFoo(const char* name)
işlevini gösterir. Eski cihazlarda bu paketdlopen
edilir ve uygulamaHIDL_FETCH_IFoo
kullanılarak örneklenir.hidl-gen
,-Lc++-impl
ve-Landroidbp-impl
kullanarak temel kodu oluşturabilirsiniz.a.b.c.d@M.N::IFoo-service
. Geçiş HAL'ini açar ve kendisini bağlayıcı hizmet olarak kaydeder. Böylece aynı HAL uygulamasının hem geçiş hem de bağlayıcı olarak kullanılmasını sağlar.
IFoo
türüne sahip bir IFoo
örneğine erişmek için sp<IFoo>
IFoo::getService(string name, bool getStub)
'u çağırabilirsiniz. getStub
doğruysa getService
, HAL'i yalnızca geçiş modunda açmaya çalışır. getStub
yanlışsa getService
, bağlayıcı hizmet bulmaya çalışır. Bu işlem başarısız olursa aktarma hizmetini bulmaya çalışır. getStub
parametresi, defaultPassthroughServiceImplementation
dışında hiçbir zaman kullanılmamalıdır. (Android O ile kullanıma sunulan cihazlar tamamen bağlayıcılı cihazlar olduğundan, bir hizmeti geçiş modunda açmaya izin verilmez.)
HIDL dil bilgisi
HIDL dili, tasarım gereği C'ye benzer (ancak C önişleyicisini kullanmaz). Aşağıda açıklanmayan tüm noktalama işaretleri (=
ve |
'un açık kullanımı hariç) dil bilgisinin bir parçasıdır.
Not: HIDL kod stili hakkında ayrıntılı bilgi için Kod Stili Kılavuzu'na bakın.
/** */
, doküman yorumunu gösterir. Bunlar yalnızca tür, yöntem, alan ve enum değer beyanlarına uygulanabilir./* */
, çok satırlı bir yorumu gösterir.//
, satır sonuna kadar olan bir yorumu gösterir.//
dışında, yeni satırlar diğer boşluklarla aynıdır.- Aşağıdaki örnek dil bilgisinde,
//
ile satırın sonu arasındaki metin dil bilgisinin bir parçası değil, dil bilgisiyle ilgili bir yorumdur. [empty]
, terimin boş olabileceği anlamına gelir.- Bir kelimenin veya terimin ardından gelen
?
, isteğe bağlı olduğunu gösterir. ...
, belirtilen ayırıcı noktalama işaretleriyle sıfır veya daha fazla öğe içeren sırayı belirtir. HIDL'de değişken bağımsız değişkenler yoktur.- Virgülleler, sıra öğelerini ayırır.
- Noktalı virgüller, son öğe dahil her öğeyi sonlandırır.
- UPPERCASE sonlu olmayan bir öğedir.
italics
,integer
veyaidentifier
gibi bir jeton ailesidir (standart C ayrıştırma kuralları).constexpr
, C stilinde bir sabit ifadedir (1 + 1
ve1L << 3
gibi).import_name
, HIDL sürümlendirmesinde açıklandığı şekilde niteliklendirilmiş bir paket veya arayüz adıdır.- Küçük harf
words
, gerçek jetonlardır.
Örnek:
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions ITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier; VERSION = integer.integer; PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION; PREAMBLE = interface identifier EXTENDS EXTENDS = <empty> | extends import_name // must be interface, not package GENERATES = generates (FIELD, FIELD ...) // allows the Binder interface to be used as a type // (similar to typedef'ing the final identifier) IMPORTS = [empty] | IMPORTS import import_name; TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string | identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file | memory | pointer | vec<TYPE> | bitfield<TYPE> // TYPE is user-defined enum | fmq_sync<TYPE> | fmq_unsync<TYPE> | TYPE[SIZE] FIELD = TYPE identifier UFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SIZE = // Must be greater than zero constexpr ANNOTATIONS = [empty] | ANNOTATIONS ANNOTATION ANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...) ANNO_ENTRY = identifier=VALUE VALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotations ENUM_ENTRY = identifier | identifier = constexpr