İDL

HAL arayüz tanımlama dili veya HIDL, bir HAL ile kullanıcıları arasındaki arayüzü belirtmek için kullanılan bir arayüz açıklama dilidir (IDL). HIDL, arayüzler ve paketler halinde toplanan türleri ve yöntem çağrılarının belirtilmesini sağlar. Daha genel anlamda ise HIDL, bağımsız olarak derlenebilecek kod tabanları arasında iletişim kuran bir sistemdir.

HIDL, süreçler arası iletişim (IPC) için kullanılmak üzere tasarlanmıştır. HDL ile oluşturulan HAL'lere, bağlayıcı işlemler arası iletişim (IPC) çağrıları kullanarak diğer mimari katmanlarıyla iletişim kurabildikleri için bağlı HAL adı verilir. Binder uygulanmış 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 mevcuttur (Java'da desteklenmez).

HIDL, paketler halinde toplanan arayüzler (sınıflara benzer) halinde düzenlenmiş veri yapılarını ve yöntem imzalarını belirtir. HIDL'nin söz dizimi, C++ ve Java programcılarına tanıdık gelecek ancak farklı bir anahtar kelime grubu içerir. HIDL Java tarzı ek açıklamalar da kullanır.

Terminoloji

Bu bölümde HIDL ile ilgili aşağıdaki terimler kullanılmaktadır:

bağlı HIDL'nin işlemler arasında uzak prosedür çağrıları için Bağlayıcı benzeri bir mekanizma üzerinden uygulanan kullanıldığını belirtir. Ayrıca posta geçiş konusuna da bakın.
geri çağırma, eşzamansız Bir HAL kullanıcısı tarafından sunulan, HAL'ye iletilen (HIDL yöntemi kullanılarak) ve HAL tarafından herhangi bir zamanda veri döndürmesi için çağrılan arayüz.
geri çağırma, eşzamanlı Bir sunucunun HIDL yöntemi uygulamasındaki verileri istemciye döndürür. Boşluk veya tek bir temel değer döndüren yöntemler için kullanılmaz.
istemci Belirli bir arayüze ait yöntemleri çağıran işlem. HAL veya Android çerçevesi işlemi, bir arayüzün istemcisi ile diğerinin sunucusu olabilir. Ayrıca bkz. posta geçiş.
uzatır Başka bir arayüze yöntem ve/veya tür ekleyen bir arayüzü belirtir. Bir arayüz yalnızca diğer bir arayüzü genişletebilir. Aynı paket adındaki küçük bir sürüm artışı için veya eski bir pakette derleme yapmak üzere 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. Temel olmayan bir değer veya birden fazla değer döndürmek için eşzamanlı bir geri çağırma işlevi oluşturulur.
arayüz Yöntem ve tür koleksiyonu. C++ veya Java sınıfa çevrilmişse. Bir arayüzdeki tüm yöntemler aynı yönde çağrılır: 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 belirtir.
paket Bir sürümü paylaşan arayüzler ve veri türleri koleksiyonu.
geçiş Sunucunun, istemci tarafından paylaşılan bir kitaplık olduğu dlopenHIDL modu. Geçiş modunda, istemci ve sunucu aynı işlemdir, ancak ayrı kod tabanları kullanılır. Yalnızca eski kod tabanlarını HIDL modeline taşımak için kullanılır. Bağlanmış bölümüne de bakın.
sunucu Bir arayüzdeki yöntemleri uygulayan işlem. Ayrıca bkz. posta geçiş.
ulaşım Verileri sunucu ile istemci arasında taşıyan HIDL altyapısı.
sürüm Bir paketin sürümü. Büyük ve küçük olmak üzere iki tam sayıdan oluşur. Küçük sürüm artışları tür ve yöntemler ekleyebilir ancak bunları değiştirmez.

HIDL tasarımı

HIDL'nin amacı, Android çerçevesinin HAL'leri yeniden oluşturmak zorunda kalmadan değiştirilebilmesidir. HAL'ler, satıcılar veya SOC üreticileri tarafından oluşturulur ve cihaza /vendor bölümü yerleştirilir. Böylece Android çerçevesi, kendi bölümünde HAL'ler yeniden derlemeden OTA ile değiştirilir.

HIDL tasarımı aşağıdaki endişeleri dengeler:

  • Birlikte çalışabilirlik. Çeşitli mimariler, araç zincirleri ve derleme yapılandırmalarıyla derlenebilecek süreçler arasında güvenilir şekilde birlikte çalışabilen arayüzler oluşturun. HIDL arayüzlerinin sürümü vardır 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 yayınlanır. HIDL ayrıca paylaşılan bellek arayüzleri sağlar. RPC'ler doğası gereği yavaş olduğundan HIDL bir RPC çağrısı kullanmadan veri aktarmak için iki yöntemi destekler: paylaşılan bellek ve Hızlı Mesaj Sırası (FMQ).
  • Sezgiseldir. HIDL, RPC için yalnızca in parametrelerini kullanarak bellek sahipliğiyle ilgili zorlu sorunları önler (bkz. Android Arayüz Tanımlama Dili (AIDL)). 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ım için HIDL'ye aktarılması veya HIDL'den veri alınması veri sahipliğini değiştirmez. Sahiplik her zaman çağrı işlevinde kalır. Verilerin yalnızca çağrılan işlev süresince devam etmesi gerekir ve çağrılan işlev geri döndüğünde hemen yok edilebilir.

Geçiş modunu kullanma

Android'in önceki sürümlerini çalıştıran cihazları Android O'ya güncellemek için hem geleneksel (ve eski) HAL'leri, hem bağlama dayalı hem de aynı işlem (geçiş) modlarında HAL sunan yeni bir HIDL arayüzünde sarmalayabilirsiniz. Bu sarmalama 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'da yazılmış HAL'ler yoktur. Bu nedenle Java HAL'ler doğası gereği birbirine bağlanır.

Bir .hal dosyası derlendiğinde hidl-gen, bağlayıcı iletişimi için kullanılan başlıklara ek olarak BsFoo.h ek bir geçiş başlık dosyası oluşturur. Bu başlık, dlopen kullanılacak işlevleri tanımlar. Geçiş HAL'leri, çağrıldıkları işlemde çalıştıklarından ç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'nin bunları işlemesini beklemesi amaçlanmadığı için kendi iş parçacıklarında çalışır. Bu, geçiş modunda oneway yöntemlerini kullanan tüm HAL'lerin iş parçacığı açısından güvenli olması gerektiği anlamına gelir.

Bir IFoo.hal olduğunda BsFoo.h, ek özellikler (oneway işlemlerini başka bir iş parçacığında çalıştırma gibi) sağlamak için HIDL tarafından oluşturulan yöntemleri sarmalar. Bu dosya BpFoo.h işlevine benzer ancak bağlayıcı kullanarak IPC çağrıları iletmek yerine, istenen işlevler doğrudan çağrılır. Gelecekteki HAL uygulamaları, FooFast HAL ve FooRight HAL gibi birden fazla uygulama sağlayabilir. Bu gibi durumlarda, ek her uygulama için bir dosya oluşturulur (ör. PTFooFast.cpp ve PTFooAccurate.cpp).

Geçiş HAL'lerini bağlama

Geçiş modunu destekleyen HAL uygulamalarını bağlayabilirsiniz. Bir HAL arayüzü a.b.c.d@M.N::IFoo ile iki paket oluşturulur:

  • a.b.c.d@M.N::IFoo-impl. HAL uygulamasını içerir ve IFoo* HIDL_FETCH_IFoo(const char* name) işlevini ortaya çıkarır. Eski cihazlarda bu paket dlopen biçimindedir ve uygulama, HIDL_FETCH_IFoo kullanılarak başlatılır. Temel kodu hidl-gen, -Lc++-impl ve -Landroidbp-impl kullanarak oluşturabilirsiniz.
  • a.b.c.d@M.N::IFoo-service. Geçiş HAL'sini açar ve kendisini bağlayıcı hizmet olarak kaydeder. Böylece aynı HAL uygulamasının hem geçiş hem de bağlama işlemi olarak kullanılabilmesini sağlar.

IFoo türünü göz önünde bulundurarak, bir IFoo örneğine erişmek için sp<IFoo> IFoo::getService(string name, bool getStub) yöntemini çağırabilirsiniz. getStub doğru değerine ayarlanırsa getService, HAL'yi yalnızca geçiş modunda açmaya çalışır. getStub değeri yanlışsa getService bağlantılı bir hizmeti bulmaya çalışır. Bu başarısız olursa geçiş 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ğlı cihazlardır. Bu nedenle, hizmetlerin geçiş modunda açılmasına izin verilmez.)

HIDL dil bilgisi

HIDL dili tasarımı gereği C'ye benzer (ancak C ön işlemcisini kullanmaz). Aşağıda açıklanmayan tüm noktalama işaretleri (= ve | açıkça belirtilmiş kullanımları dışında) dil bilgisi kapsamındadır.

Not: HIDL kod stili hakkında ayrıntılar için Kod Stil Kılavuzu'na bakın.

  • /** */, doküman açıklamasını gösterir. Bunlar yalnızca tür, yöntem, alan ve numaralandırma değeri bildirimlerine uygulanabilir.
  • /* */, çok satırlı bir yorumu gösterir.
  • //, satırın sonundaki yorumu gösterir. // dışındaki yeni satırlar, diğer tüm boşluklarla aynıdır.
  • Aşağıdaki örnek dilbilgisinde, // ile satırın sonuna kadar olan metin, dilbilgisinin bir parçası değildir, bunun yerine dil bilgisi ile ilgili bir yorumdur.
  • [empty], terimin boş olabileceği anlamına gelir.
  • ? harfinin veya terimin ardından gelen kelime isteğe bağlı olduğu anlamına gelir.
  • ..., belirtildiği gibi noktalama işaretleriyle sıfır veya daha fazla öğe içeren diziyi gösterir. HIDL'de değişken argümanlar yoktur.
  • Sıra öğelerini virgülle ayırın.
  • Noktalı virgüller, son öğe de dahil olmak üzere her öğeyi sonlandırır.
  • BÜYÜK HARF, terminal olmayan bir ifadedir.
  • italics, integer veya identifier (standart C ayrıştırma kuralları) gibi bir jeton ailesidir.
  • constexpr , C stili bir sabit ifadedir (1 + 1 ve 1L << 3 gibi).
  • import_name, HIDL Sürüm Oluşturma bölümünde açıklandığı şekilde bir paket veya arayüz adıdır.
  • Küçük words harfi, düz simgedir.

Ö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