एचआईडीएल

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

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

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

शब्दावली

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

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

HIDL डिज़ाइन

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

HIDL डिज़ाइन में ये समस्याएं मौजूद हैं:

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

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

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

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

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

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

बाइंडिंग पासथ्रू एचएएल

पासथ्रू मोड के साथ काम करने वाले एचएएल इंप्लिमेंटेशन को बाइंड किया जा सकता है. 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. पासथ्रू HAL को खोलता है और खुद को बाइंडराइज़्ड सेवा के तौर पर रजिस्टर करता है. इससे पास-थ्रू और बाइंडराइज़्ड, दोनों के तौर पर एक ही HAL लागू करने की सुविधा चालू हो जाती है.

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

HIDL व्याकरण

डिज़ाइन के हिसाब से, एचआईडीएल की भाषा C से मिलती-जुलती है. हालांकि, इसमें C प्रीप्रोसेसर का इस्तेमाल नहीं किया जाता. नीचे नहीं दिए गए सभी विराम चिह्न (= और | के साफ़ तौर पर इस्तेमाल को छोड़कर) व्याकरण का हिस्सा हैं.

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

  • /** */, दस्तावेज़ पर की गई टिप्पणी को दिखाता है. इन्हें सिर्फ़ टाइप, तरीका, फ़ील्ड, और ईनम वैल्यू की जानकारी पर लागू किया जा सकता है.
  • /* */, मल्टीलाइन टिप्पणी को दिखाता है.
  • //, लाइन के आखिर तक की गई टिप्पणी को दिखाता है. // के अलावा, नई लाइनें, बाकी खाली सफ़ेद जगह जैसी ही होती हैं.
  • यहां दिए गए व्याकरण के उदाहरण में, // से लेकर लाइन के आखिर तक का टेक्स्ट, व्याकरण का हिस्सा नहीं है. बल्कि यह व्याकरण की एक टिप्पणी है.
  • [empty] का मतलब है कि वह शब्द खाली हो सकता है.
  • लिटरल या टर्म के बाद ? का मतलब है कि यह ज़रूरी नहीं है.
  • ..., शून्य या ज़्यादा आइटम वाले क्रम को दिखाता है जिसमें दिए गए विराम चिह्नों को अलग किया जाता है. HIDL में कोई वैरायडिक आर्ग्युमेंट नहीं हैं.
  • कॉमा, क्रम के एलिमेंट को अलग करते हैं.
  • सेमीकोलन आखिरी एलिमेंट के साथ-साथ हर एलिमेंट को खत्म करते हैं.
  • अपरकेस एक नॉन-टर्मिनल है.
  • italics, टोकन फ़ैमिली है. जैसे, integer या identifier (सी पार्सिंग के स्टैंडर्ड नियम).
  • 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