HIDL

एचएएल इंटरफ़ेस डेफ़िनिशन लैंग्वेज या एचआईडीएल, इंटरफ़ेस की जानकारी देने वाली भाषा (आईडीएल) है. इससे एचएएल और उसके उपयोगकर्ताओं के बीच के इंटरफ़ेस के बारे में पता चलता है. HIDL की मदद से, इंटरफ़ेस और पैकेज में इकट्ठा किए गए टाइप और तरीकों को कॉल किया जा सकता है. आम तौर पर, HIDL एक ऐसा सिस्टम है जिसकी मदद से, अलग-अलग तौर पर कॉम्पाइल किए जा सकने वाले कोडबेस के बीच, जानकारी शेयर की जा सकती है.

HIDL का इस्तेमाल, इंटर-प्रोसेस कम्यूनिकेशन (आईपीसी) के लिए किया जाता है. HDL की मदद से बनाए गए एचएएल को, बाइंडर वाले एचएएल कहा जाता है. ये एचएएल, बाइंडर इंटर-प्रोसेस कम्यूनिकेशन (आईपीसी) कॉल का इस्तेमाल करके, आर्किटेक्चर की अन्य लेयर के साथ कम्यूनिकेट कर सकते हैं. बाइंडर वाले एचएएल, उनका इस्तेमाल करने वाले क्लाइंट से अलग प्रोसेस में चलते हैं. जिन लाइब्रेरी को किसी प्रोसेस से लिंक करना ज़रूरी है उनके लिए पासथ्रू मोड भी उपलब्ध है. हालांकि, यह Java में काम नहीं करता.

HIDL, डेटा स्ट्रक्चर और मेथड सिग्नेचर के बारे में बताता है. इन्हें इंटरफ़ेस में व्यवस्थित किया जाता है, जो क्लास की तरह होते हैं. इन्हें पैकेज में इकट्ठा किया जाता है. HIDL का सिंटैक्स, C++ और Java प्रोग्रामर को जाना-पहचाना लगेगा. हालांकि, इसमें कीवर्ड का एक अलग सेट इस्तेमाल किया जाता है. HIDL, Java-style एनोटेशन का भी इस्तेमाल करता है.

शब्दावली

इस सेक्शन में, HIDL से जुड़े इन शब्दों का इस्तेमाल किया गया है:

बाइंडर इससे पता चलता है कि प्रोसेस के बीच रिमोट प्रोसेस कॉल के लिए, HIDL का इस्तेमाल किया जा रहा है. इसे Binder जैसे तरीके से लागू किया जाता है. पासथ्रू भी देखें.
कॉलबैक, एसिंक्रोनस यह इंटरफ़ेस, एचएएल उपयोगकर्ता की ओर से उपलब्ध कराया जाता है. इसे एचआईडीएल तरीके का इस्तेमाल करके, एचएएल को पास किया जाता है. साथ ही, एचएएल इसे किसी भी समय डेटा दिखाने के लिए कॉल करता है.
कॉलबैक, सिंक्रोनस यह क्लाइंट को, सर्वर के HIDL तरीके से लागू किए गए डेटा को दिखाता है. यह उन तरीकों के लिए इस्तेमाल नहीं किया जाता है जो कोई वैल्यू नहीं दिखाते या एक प्राइमटिव वैल्यू दिखाते हैं.
client किसी खास इंटरफ़ेस के तरीकों को कॉल करने वाली प्रोसेस. HAL या Android फ़्रेमवर्क प्रोसेस, एक इंटरफ़ेस का क्लाइंट और दूसरे का सर्वर हो सकती है. पासथ्रू भी देखें.
ज़्यादा समय तक चलती है किसी ऐसे इंटरफ़ेस के बारे में बताता है जो किसी दूसरे इंटरफ़ेस में तरीके और/या टाइप जोड़ता है. कोई इंटरफ़ेस, सिर्फ़ एक दूसरे इंटरफ़ेस को एक्सटेंड कर सकता है. इसका इस्तेमाल, एक ही पैकेज के नाम में मामूली वर्शन में बढ़ोतरी करने के लिए किया जा सकता है. इसके अलावा, किसी पुराने पैकेज पर आधारित नए पैकेज (जैसे, वेंडर एक्सटेंशन) के लिए भी इसका इस्तेमाल किया जा सकता है.
जनरेट करता है यह इंटरफ़ेस के उस तरीके के बारे में बताता है जो क्लाइंट को वैल्यू दिखाता है. एक नॉन-प्राइमटिव वैल्यू या एक से ज़्यादा वैल्यू दिखाने के लिए, सिंक्रोनस कॉलबैक फ़ंक्शन जनरेट किया जाता है.
इंटरफ़ेस डेटा इकट्ठा करने के तरीके और टाइप. C++ या Java में क्लास में बदला गया. इंटरफ़ेस में मौजूद सभी तरीकों को एक ही दिशा में कॉल किया जाता है: क्लाइंट प्रोसेस, सर्वर प्रोसेस से लागू किए गए तरीकों को लागू करती है.
एकतरफ़ा HIDL तरीके पर लागू होने पर, यह बताता है कि तरीका कोई वैल्यू नहीं दिखाता और ब्लॉक नहीं करता.
पैकेज एक वर्शन शेयर करने वाले इंटरफ़ेस और डेटा टाइप का कलेक्शन.
पास-थ्रू HIDL का वह मोड जिसमें सर्वर एक शेयर की गई लाइब्रेरी होती है, जिसे क्लाइंट dlopenएडिट करता है. पासथ्रू मोड में, क्लाइंट और सर्वर एक ही प्रोसेस होते हैं, लेकिन उनके कोडबेस अलग-अलग होते हैं. इसका इस्तेमाल सिर्फ़ लेगसी कोडबेस को HIDL मॉडल में लाने के लिए किया जाता है. बाइंडर में बदला गया भी देखें.
सर्वर वह प्रोसेस जो किसी इंटरफ़ेस के तरीकों को लागू करती है. पासथ्रू भी देखें.
परिवहन HIDL इंफ़्रास्ट्रक्चर, जो सर्वर और क्लाइंट के बीच डेटा ट्रांसफ़र करता है.
वर्शन पैकेज का वर्शन. इसमें दो पूर्णांक होते हैं, मेजर और माइनर. वर्शन में मामूली बढ़ोतरी करने पर, टाइप और तरीके जोड़े जा सकते हैं, लेकिन उनमें बदलाव नहीं किया जा सकता.

HIDL डिज़ाइन

HIDL का मकसद, एचएएल को फिर से बनाने के बिना Android फ़्रेमवर्क को बदलना है. एचएएल, वेंडर या SoC बनाने वाली कंपनियां बनाती हैं और उन्हें डिवाइस के /vendor सेक्शन में डालती हैं. इससे, Android फ़्रेमवर्क को अपने सेक्शन में, एचएएल को फिर से कंपाइल किए बिना, ओटीए से बदला जा सकता है.

HIDL डिज़ाइन में इन बातों का ध्यान रखा गया है:

  • इंटरऑपरेबिलिटी. अलग-अलग आर्किटेक्चर, टूलचेन, और बिल्ड कॉन्फ़िगरेशन के साथ कॉम्पाइल की जा सकने वाली प्रोसेस के बीच, भरोसेमंद इंटरऑपरेबल इंटरफ़ेस बनाएं. HIDL इंटरफ़ेस के वर्शन होते हैं और पब्लिश होने के बाद, उनमें बदलाव नहीं किया जा सकता.
  • परफ़ॉर्मेंस. HIDL, कॉपी करने के ऑपरेशन की संख्या को कम करने की कोशिश करता है. HIDL से तय किए गए डेटा को C++ कोड में, C++ स्टैंडर्ड लेआउट के डेटा स्ट्रक्चर में डिलीवर किया जाता है. इनका इस्तेमाल, अनपैक किए बिना किया जा सकता है. HIDL, शेयर की गई स्मृति के इंटरफ़ेस भी उपलब्ध कराता है. आरपीसी (रिकॉर्ड किए गए प्रोसेस कॉल) अपने-आप धीमे होते हैं. इसलिए, HIDL आरपीसी कॉल का इस्तेमाल किए बिना, डेटा ट्रांसफ़र करने के दो तरीकों का इस्तेमाल करता है: शेयर की गई स्मृति और फ़ास्ट मैसेज क्यू (एफ़एमक्यू).
  • आसान. HIDL, आरपीसी के लिए सिर्फ़ in पैरामीटर का इस्तेमाल करके, मेमोरी के मालिकाना हक से जुड़ी समस्याओं से बचता है (Android इंटरफ़ेस डेफ़िनिशन लैंग्वेज (AIDL) देखें). जिन वैल्यू को तरीकों से बेहतर तरीके से रिटर्न नहीं किया जा सकता उन्हें कॉलबैक फ़ंक्शन के ज़रिए रिटर्न किया जाता है. डेटा को ट्रांसफ़र करने के लिए HIDL में भेजने या HIDL से डेटा पाने पर, डेटा का मालिकाना हक नहीं बदलता. मालिकाना हक हमेशा कॉल करने वाले फ़ंक्शन के पास रहता है. डेटा को सिर्फ़ कॉल किए गए फ़ंक्शन के दौरान सेव रखना ज़रूरी है. कॉल किए गए फ़ंक्शन के रिटर्न होने के तुरंत बाद, डेटा को मिटाया जा सकता है.

पासथ्रू मोड का इस्तेमाल करना

Android के पुराने वर्शन पर काम करने वाले डिवाइसों को Android O पर अपडेट करने के लिए, दोनों पारंपरिक (और लेगसी) एचएएल को नए एचआईडीएल इंटरफ़ेस में रैप किया जा सकता है. यह इंटरफ़ेस, एचएएल को बाइंडर और एक ही प्रोसेस (पासथ्रू) मोड में काम करने की सुविधा देता है. यह रैपिंग, एचएएल और Android फ़्रेमवर्क, दोनों के लिए पारदर्शी है.

पासथ्रू मोड सिर्फ़ C++ क्लाइंट और लागू करने के लिए उपलब्ध है. Android के पुराने वर्शन पर काम करने वाले डिवाइसों में, Java में लिखे गए एचएएल नहीं होते. इसलिए, Java एचएएल को डिफ़ॉल्ट रूप से बाइंडर किया जाता है.

जब कोई .hal फ़ाइल कंपाइल की जाती है, तो hidl-gen, बाइंडर कम्यूनिकेशन के लिए इस्तेमाल किए गए हेडर के अलावा, एक अतिरिक्त पासथ्रू हेडर फ़ाइल BsFoo.h बनाता है. यह हेडर, dlopen किए जाने वाले फ़ंक्शन तय करता है. पासथ्रू एचएएल उसी प्रोसेस में चलते हैं जिसमें उन्हें कॉल किया जाता है. ज़्यादातर मामलों में, पासथ्रू तरीकों को डायरेक्ट फ़ंक्शन कॉल (एक ही थ्रेड) से शुरू किया जाता है. oneway तरीके अपनी थ्रेड में चलते हैं, क्योंकि उन्हें प्रोसेस करने के लिए एचएएल (HAL) का इंतज़ार नहीं करना पड़ता. इसका मतलब है कि पासथ्रू मोड में oneway तरीकों का इस्तेमाल करने वाले किसी भी एचएएल (HAL) को थ्रेड-सेफ़ होना चाहिए.

IFoo.hal के लिए, BsFoo.h अतिरिक्त सुविधाएं देने के लिए, HIDL से जनरेट किए गए तरीकों को रैप करता है. जैसे, oneway लेन-देन को किसी दूसरी थ्रेड में चलाना. यह फ़ाइल BpFoo.h जैसी ही है. हालांकि, इसमें बाइंडर का इस्तेमाल करके कॉल आईपीसी को पास करने के बजाय, मनमुताबिक फ़ंक्शन सीधे तौर पर लागू किए जाते हैं. आने वाले समय में, एचएएल के लागू होने के बाद, एक से ज़्यादा एचएएल उपलब्ध हो सकते हैं. जैसे, FooFast HAL और FooAccurate HAL. ऐसे मामलों में, हर अतिरिक्त लागू करने के लिए एक फ़ाइल बनाई जाएगी (उदाहरण के लिए, PTFooFast.cpp और PTFooAccurate.cpp).

पास-थ्रू HAL को बाइंडर करना

पासथ्रू मोड के साथ काम करने वाले HAL लागू करने के लिए, बाइंडर का इस्तेमाल किया जा सकता है. किसी HAL इंटरफ़ेस a.b.c.d@M.N::IFoo के लिए, दो पैकेज बनाए जाते हैं:

  • a.b.c.d@M.N::IFoo-impl. इसमें HAL को लागू करने का तरीका शामिल है और IFoo* HIDL_FETCH_IFoo(const char* name) फ़ंक्शन को एक्सपोज़ किया गया है. लेगसी डिवाइसों पर, इस पैकेज को dlopen किया जाता है और HIDL_FETCH_IFoo का इस्तेमाल करके लागू किया जाता है. hidl-gen, -Lc++-impl, और -Landroidbp-impl का इस्तेमाल करके, बेस कोड जनरेट किया जा सकता है.
  • a.b.c.d@M.N::IFoo-service. यह पासथ्रू एचएएल खोलता है और खुद को बाइंडर की गई सेवा के तौर पर रजिस्टर करता है. इससे, एक ही एचएएल को पासथ्रू और बाइंडर की गई, दोनों तरह की सेवाओं के तौर पर इस्तेमाल किया जा सकता है.

IFoo टाइप के लिए, IFoo के किसी इंस्टेंस का ऐक्सेस पाने के लिए, sp<IFoo> IFoo::getService(string name, bool getStub) को कॉल किया जा सकता है. अगर getStub सही है, तो getService सिर्फ़ पास-थ्रू मोड में HAL खोलने की कोशिश करता है. अगर getStub का वैल्यू 'गलत' है, तो getService बाइंडर की गई सेवा ढूंढने की कोशिश करता है. अगर वह सेवा नहीं मिलती है, तो वह पासथ्रू सेवा ढूंढने की कोशिश करता है. getStub पैरामीटर का इस्तेमाल, defaultPassthroughServiceImplementation के अलावा कभी नहीं किया जाना चाहिए. (Android O के साथ लॉन्च होने वाले डिवाइस, पूरी तरह से बाइंडर वाले डिवाइस होते हैं. इसलिए, पासथ्रू मोड में कोई सेवा खोलने की अनुमति नहीं है.)

HIDL ग्रामर

डिज़ाइन के हिसाब से, HIDL भाषा C भाषा से मिलती-जुलती है. हालांकि, इसमें C प्रोसेस करने वाले टूल का इस्तेमाल नहीं किया जाता. यहां बताए गए अलावा, = और | के इस्तेमाल के अलावा, विराम चिह्नों का इस्तेमाल व्याकरण के हिसाब से किया जाता है.

ध्यान दें: HIDL कोड स्टाइल के बारे में जानकारी पाने के लिए, कोड स्टाइल गाइड देखें.

  • /** */, दस्तावेज़ से जुड़ी टिप्पणी के बारे में बताता है. इन्हें सिर्फ़ टाइप, तरीके, फ़ील्ड, और एनम वैल्यू के एलान पर लागू किया जा सकता है.
  • /* */ से पता चलता है कि टिप्पणी में एक से ज़्यादा लाइनें हैं.
  • // से पता चलता है कि लाइन के आखिर में कोई टिप्पणी है. // के अलावा, नई लाइनें किसी भी अन्य खाली जगह की तरह ही होती हैं.
  • नीचे दिए गए व्याकरण के उदाहरण में, // से लेकर लाइन के आखिर तक का टेक्स्ट, व्याकरण का हिस्सा नहीं है. यह व्याकरण पर की गई टिप्पणी है.
  • [empty] का मतलब है कि शब्द खाली हो सकता है.
  • किसी लिटरल या शब्द के बाद ? का इस्तेमाल करने का मतलब है कि वह वैकल्पिक है.
  • ... से पता चलता है कि इसमें शून्य या उससे ज़्यादा आइटम शामिल हैं. साथ ही, इन आइटम को अलग करने के लिए विराम चिह्न का इस्तेमाल किया गया है. HIDL में, वैरिएड आर्ग्युमेंट नहीं होते.
  • कॉमा, क्रम के एलिमेंट को अलग करते हैं.
  • सेमीकोलन, आखिरी एलिमेंट के साथ-साथ हर एलिमेंट को खत्म करते हैं.
  • UPPERCASE एक नॉन-टर्मिनल है.
  • italics एक टोकन फ़ैमिली है, जैसे कि integer या identifier (स्टैंडर्ड C पार्सिंग नियम).
  • constexpr , C स्टाइल का कॉन्स्टेंट एक्सप्रेशन है, जैसे कि 1 + 1 और 1L << 3.
  • import_name, पैकेज या इंटरफ़ेस का नाम है. यह नाम, HIDL के वर्शन में बताए गए तरीके के मुताबिक होना चाहिए.
  • लोअरकेस words लिटरल टोकन होते हैं.

उदाहरण:

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