इंटरफ़ेस और पैकेज

HIDL, इंटरफ़ेस के आधार पर बनाया गया है. यह एक ऐसा एब्स्ट्रैक्ट टाइप है जिसका इस्तेमाल ऑब्जेक्ट-ओरिएंटेड भाषाओं में, व्यवहार तय करने के लिए किया जाता है. हर इंटरफ़ेस, किसी पैकेज का हिस्सा होता है.

पैकेज

पैकेज के नाम में सब-लेवल हो सकते हैं, जैसे कि package.subpackage. पब्लिश किए गए HIDL पैकेज के लिए रूट डायरेक्ट्री hardware/interfaces या vendor/vendorName होती है. उदाहरण के लिए, Pixel डिवाइसों के लिए vendor/google. पैकेज का नाम, रूट डायरेक्ट्री के नीचे एक या उससे ज़्यादा सबडायरेक्ट्री बनाता है. पैकेज की जानकारी देने वाली सभी फ़ाइलें एक ही डायरेक्ट्री में होती हैं. उदाहरण के लिए, package android.hardware.example.extension.light@2.0 को hardware/interfaces/example/extension/light/2.0 में देखा जा सकता है.

इस टेबल में, पैकेज के प्रीफ़िक्स और जगहों की सूची दी गई है:

पैकेज का प्रीफ़िक्स जगह की जानकारी इंटरफ़ेस के टाइप
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* फ़्रेमवर्क/ मिलते-जुलते
android.system.* system/hardware/interfaces/* system/ related
android.hidl.* system/libhidl/transport/* कोर

पैकेज डायरेक्ट्री में, .hal एक्सटेंशन वाली फ़ाइलें मौजूद हैं. हर फ़ाइल में, package स्टेटमेंट होना चाहिए. इसमें उस पैकेज और वर्शन का नाम होना चाहिए जिसका हिस्सा फ़ाइल है. अगर फ़ाइल types.hal मौजूद है, तो वह किसी इंटरफ़ेस को तय नहीं करती. इसके बजाय, वह पैकेज के हर इंटरफ़ेस के लिए ऐक्सेस किए जा सकने वाले डेटा टाइप तय करती है.

इंटरफ़ेस की परिभाषा

types.hal के अलावा, हर दूसरी .hal फ़ाइल में एक इंटरफ़ेस तय किया जाता है. आम तौर पर, इंटरफ़ेस को इस तरह से परिभाषित किया जाता है:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

साफ़ तौर पर extends एलान किए बिना, कोई इंटरफ़ेस android.hidl.base@1.0::IBase से अपने-आप जुड़ जाता है. यह Java में java.lang.Object की तरह ही होता है. IBase इंटरफ़ेस, चुपचाप इंपोर्ट किया जाता है. इसमें कई ऐसे रिज़र्व किए गए तरीके बताए जाते हैं जिन्हें उपयोगकर्ता के तय किए गए इंटरफ़ेस में फिर से नहीं बताया जाना चाहिए या किसी और तरीके से इस्तेमाल नहीं किया जाना चाहिए. इन तरीकों में ये शामिल हैं:

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

इंपोर्ट करने की प्रोसेस

import स्टेटमेंट, किसी दूसरे पैकेज में पैकेज इंटरफ़ेस और टाइप को ऐक्सेस करने के लिए, एचआईडीएल का तरीका है. import स्टेटमेंट में दो इकाइयों के बारे में जानकारी होती है:

  • इंपोर्टकरने वाली इकाई, जो पैकेज या इंटरफ़ेस हो सकती है
  • इंपोर्टकी गई इकाई, जो पैकेज या इंटरफ़ेस हो सकती है

import स्टेटमेंट की जगह से यह तय होता है कि डेटा को कौनसी इकाई इंपोर्ट कर रही है. जब स्टेटमेंट किसी पैकेज के types.hal में होता है, तो इंपोर्ट किया जा रहा डेटा पूरे पैकेज को दिखता है. इसे पैकेज-लेवल इंपोर्ट कहा जाता है. जब स्टेटमेंट किसी इंटरफ़ेस फ़ाइल में होता है, तो इंपोर्ट करने वाली इकाई इंटरफ़ेस ही होती है. यह इंटरफ़ेस-लेवल इंपोर्ट होता है.

इंपोर्ट की गई इकाई, import कीवर्ड के बाद की वैल्यू से तय होती है. वैल्यू के लिए, पूरी तरह से सही नाम देना ज़रूरी नहीं है. अगर किसी कॉम्पोनेंट को छोड़ा जाता है, तो वह मौजूदा पैकेज की जानकारी से अपने-आप भर जाता है. पूरी तरह से क्वालीफ़ाइड वैल्यू के लिए, इंपोर्ट के ये मामले काम करते हैं:

  • पूरे पैकेज को इंपोर्ट करना. अगर वैल्यू में पैकेज का नाम और वर्शन (सिंटैक्स नीचे बताया गया है) शामिल है, तो पूरा पैकेज, इंपोर्ट करने वाली इकाई में इंपोर्ट हो जाता है.
  • कुछ हिस्से को इंपोर्ट करना. अगर वैल्यू:
    • इंपोर्ट करने वाली इकाई में, इंटरफ़ेस, पैकेज का types.hal, और उस इंटरफ़ेस को इंपोर्ट किया जाता है.
    • types.hal में तय किया गया यूडीटी, तो सिर्फ़ उस यूडीटी को इंपोर्ट करने वाली इकाई में इंपोर्ट किया जाता है (types.hal में मौजूद अन्य टाइप इंपोर्ट नहीं किए जाते).
  • सिर्फ़ टाइप इंपोर्ट करने की सुविधा. अगर वैल्यू में, ऊपर बताए गए आंशिक इंपोर्ट के सिंटैक्स का इस्तेमाल किया गया है, लेकिन इंटरफ़ेस के नाम के बजाय types कीवर्ड का इस्तेमाल किया गया है, तो सिर्फ़ तय किए गए पैकेज के types.hal में मौजूद यूडीटी इंपोर्ट किए जाते हैं.

इंपोर्ट करने वाली इकाई को इनके कॉम्बिनेशन का ऐक्सेस मिलता है:

  • types.hal में बताए गए, इंपोर्ट किए गए पैकेज के सामान्य यूडीटी;
  • इंपोर्ट किए गए पैकेज के इंटरफ़ेस (पूरे पैकेज को इंपोर्ट करने के लिए) या तय किए गए इंटरफ़ेस (कुछ हिस्से को इंपोर्ट करने के लिए). इनका इस्तेमाल, उन्हें कॉल करने, उन्हें हैंडल पास करने, और/या उनसे इनहेरिट करने के लिए किया जाता है.

इंपोर्ट स्टेटमेंट, इंपोर्ट किए जा रहे पैकेज या इंटरफ़ेस का नाम और वर्शन देने के लिए, पूरी तरह से क्वालीफ़ाइड-टाइप-नेम सिंटैक्स का इस्तेमाल करता है:

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

इंटरफ़ेस इनहेरिटेंस

कोई इंटरफ़ेस, पहले से तय किए गए इंटरफ़ेस का एक्सटेंशन हो सकता है. एक्सटेंशन इनमें से किसी एक तरह के हो सकते हैं:

  • इंटरफ़ेस, किसी दूसरे इंटरफ़ेस में नई सुविधाएं जोड़ सकता है. ऐसा करने पर, उसके एपीआई में कोई बदलाव नहीं होता.
  • पैकेज, किसी दूसरे पैकेज में नई सुविधाएं जोड़ सकता है. ऐसा करने पर, उस पैकेज के एपीआई में कोई बदलाव नहीं होता.
  • इंटरफ़ेस, किसी पैकेज या किसी खास इंटरफ़ेस से टाइप इंपोर्ट कर सकता है.

कोई इंटरफ़ेस, सिर्फ़ एक दूसरे इंटरफ़ेस को एक्सटेंड कर सकता है. एक से ज़्यादा इंटरफ़ेस को एक्सटेंड नहीं किया जा सकता. किसी पैकेज में मौजूद हर इंटरफ़ेस का माइनर वर्शन नंबर शून्य से ज़्यादा होना चाहिए. साथ ही, यह पैकेज के पिछले वर्शन में मौजूद इंटरफ़ेस को एक्सटेंड करना चाहिए. उदाहरण के लिए, अगर पैकेज derivative के वर्शन 4.0 में मौजूद इंटरफ़ेस IBar, पैकेज original के वर्शन 1.2 में मौजूद इंटरफ़ेस IFoo पर आधारित (बड़ा) है और पैकेज original का वर्शन 1.3 बनाया गया है, तो IBar का वर्शन 4.1, IFoo का वर्शन 1.3 बड़ा नहीं कर सकता. इसके बजाय, IBar वर्शन 4.1 को IBar वर्शन 4.0 के साथ काम करना चाहिए, जो IFoo वर्शन 1.2 के साथ काम करता है. IBar वर्शन 5.0, IFoo वर्शन 1.3 को बढ़ा सकता है. हालांकि, ऐसा करना ज़रूरी नहीं है.

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

वेंडर एक्सटेंशन

कुछ मामलों में, वेंडर एक्सटेंशन को उस बेस ऑब्जेक्ट के सबक्लास के तौर पर लागू किया जाता है जो उस मुख्य इंटरफ़ेस को दिखाता है जिसे वे एक्सटेंशन देते हैं. एक ही ऑब्जेक्ट को, बेस एचएएल के नाम और वर्शन के साथ-साथ, एक्सटेंशन (वेंडर) एचएएल के नाम और वर्शन के तहत रजिस्टर किया जाता है.

वर्शन

पैकेज के वर्शन होते हैं और इंटरफ़ेस के पैकेज का वर्शन होता है. वर्शन को दो पूर्णांकों में दिखाया जाता है, मेजर.माइनर.

  • मेजर वर्शन, पुराने सिस्टम के साथ काम नहीं करते. मेजर वर्शन की संख्या बढ़ाने पर, माइनर वर्शन की संख्या 0 पर रीसेट हो जाती है.
  • माइनर वर्शन, पुराने सिस्टम के साथ काम करते हैं. माइनर वर्शन की संख्या बढ़ाने का मतलब है कि नया वर्शन, पिछले वर्शन के साथ पूरी तरह से काम करता है. नए डेटा स्ट्रक्चर और तरीके जोड़े जा सकते हैं. हालांकि, किसी भी मौजूदा डेटा स्ट्रक्चर या तरीके के हस्ताक्षर में बदलाव नहीं किया जा सकता.

किसी डिवाइस पर, एक ही समय में एचएएल के कई मेजर या माइनर वर्शन मौजूद हो सकते हैं. हालांकि, मेजर वर्शन के बजाय माइनर वर्शन को प्राथमिकता दी जानी चाहिए. ऐसा इसलिए, क्योंकि किसी इंटरफ़ेस के पिछले माइनर वर्शन के साथ काम करने वाला क्लाइंट कोड, उसी इंटरफ़ेस के बाद के माइनर वर्शन के साथ भी काम करता है. वर्शन और वेंडर एक्सटेंशन के बारे में ज़्यादा जानकारी के लिए, HIDL वर्शन देखें.

इंटरफ़ेस लेआउट की खास जानकारी

इस सेक्शन में, HIDL इंटरफ़ेस पैकेज (जैसे कि hardware/interfaces) को मैनेज करने का तरीका बताया गया है. साथ ही, HIDL सेक्शन में दी गई जानकारी को एक साथ इकट्ठा किया गया है. पढ़ने से पहले, पक्का करें कि आपने HIDL वर्शन, hidl-gen के साथ हैश करने के कॉन्सेप्ट, HIDL के साथ काम करने की जानकारी, और इन परिभाषाओं को पढ़ लिया है:

शब्द परिभाषा
ऐप्लिकेशन बाइनरी इंटरफ़ेस (एबीआई) ऐप्लिकेशन प्रोग्रामिंग इंटरफ़ेस के साथ-साथ, ज़रूरी बाइनरी लिंक.
पूरी तरह क्वालिफ़ाइड नेम (fqName) किसी hidl टाइप को अलग करने के लिए नाम. उदाहरण: android.hardware.foo@1.0::IFoo.
पैकेज HIDL इंटरफ़ेस और टाइप वाला पैकेज. उदाहरण: android.hardware.foo@1.0.
पैकेज रूट रूट पैकेज, जिसमें HIDL इंटरफ़ेस होते हैं. उदाहरण: HIDL इंटरफ़ेसandroid.hardware, पैकेज के रूट में हैandroid.hardware.foo@1.0.
पैकेज का रूट पाथ Android सोर्स ट्री में वह जगह जहां पैकेज का रूट मैप होता है.

ज़्यादा जानकारी के लिए, HIDL के शब्दों का इस्तेमाल देखें.

हर फ़ाइल को पैकेज रूट मैपिंग और उसके फ़ुल्ली क्वालिफ़ाइड नाम से ढूंढा जा सकता है

पैकेज के रूट को hidl-gen के लिए आर्ग्युमेंट के तौर पर तय किया गया है -r android.hardware:hardware/interfaces. उदाहरण के लिए, अगर पैकेज vendor.awesome.foo@1.0::IFoo है और hidl-gen को -r vendor.awesome:some/device/independent/path/interfaces भेजा जाता है, तो इंटरफ़ेस फ़ाइल $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal में होनी चाहिए.

आम तौर पर, हमारा सुझाव है कि awesome नाम के वेंडर या OEM, अपने स्टैंडर्ड इंटरफ़ेस को vendor.awesome में डालें. पैकेज का पाथ चुनने के बाद, उसे नहीं बदला जाना चाहिए, क्योंकि यह इंटरफ़ेस के एबीआई में शामिल होता है.

पैकेज पाथ मैपिंग यूनीक होनी चाहिए

उदाहरण के लिए, अगर आपके पास -rsome.package:$PATH_A और -rsome.package:$PATH_B है, तो इंटरफ़ेस डायरेक्ट्री के लिए $PATH_A और $PATH_B एक जैसे होने चाहिए. इससे इंटरफ़ेस के वर्शन को मैनेज करना भी बहुत आसान हो जाता है.

पैकेज के रूट में, वर्शनिंग फ़ाइल होनी चाहिए

अगर आपने -r vendor.awesome:vendor/awesome/interfaces जैसा पैकेज पाथ बनाया है, तो आपको $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt फ़ाइल भी बनानी चाहिए. इसमें hidl-gen में -Lhash विकल्प का इस्तेमाल करके बनाए गए इंटरफ़ेस के हैश शामिल होने चाहिए. इस बारे में ज़्यादा जानकारी hidl-gen की मदद से हैश करने में दी गई है.

इंटरफ़ेस, डिवाइस पर निर्भर नहीं करने वाली जगहों पर मौजूद होते हैं

हमारा सुझाव है कि आप अलग-अलग शाखाओं के बीच इंटरफ़ेस शेयर करें. इससे, कोड को ज़्यादा से ज़्यादा बार फिर से इस्तेमाल करने और अलग-अलग डिवाइसों और इस्तेमाल के उदाहरणों पर कोड की ज़्यादा से ज़्यादा टेस्टिंग करने की सुविधा मिलती है.