HIDL

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 dlopenedilen 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.

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 ve IFoo* HIDL_FETCH_IFoo(const char* name) işlevini gösterir. Eski cihazlarda bu paket dlopen edilir ve uygulama HIDL_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 veya identifier gibi bir jeton ailesidir (standart C ayrıştırma kuralları).
  • constexpr , C stilinde bir sabit ifadedir (1 + 1 ve 1L << 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