HIDL पैकेज में बताए गए हर इंटरफ़ेस के पैकेज के नेमस्पेस में, अपने-आप जनरेट हुई C++ क्लास होती है. क्लाइंट और सर्वर, इंटरफ़ेस के साथ अलग-अलग तरीके से काम करते हैं:
- सर्वर इंटरफ़ेस लागू करते हैं.
- क्लाइंट, इंटरफ़ेस पर मौजूद तरीकों को कॉल करते हैं.
इंटरफ़ेस को सर्वर के नाम से रजिस्टर किया जा सकता है या HIDL के तय किए गए तरीकों में पैरामीटर के तौर पर पास किया जा सकता है. उदाहरण के लिए, फ़्रेमवर्क कोड, एचएएल से असिंक्रोनस मैसेज पाने के लिए इंटरफ़ेस उपलब्ध करा सकता है. साथ ही, उस इंटरफ़ेस को रजिस्टर किए बिना सीधे एचएएल को पास कर सकता है.
सर्वर पर लागू करना
IFoo
इंटरफ़ेस लागू करने वाले सर्वर में, अपने-आप जनरेट हुई IFoo
हेडर फ़ाइल शामिल होनी चाहिए:
#include <android/hardware/samples/1.0/IFoo.h>
हेडर को लिंक करने के लिए, IFoo
इंटरफ़ेस की शेयर की गई लाइब्रेरी से हेडर अपने-आप एक्सपोर्ट हो जाता है. उदाहरण के लिए, IFoo.hal
:
// IFoo.hal interface IFoo { someMethod() generates (vec<uint32_t>); ... }
IFoo इंटरफ़ेस को सर्वर पर लागू करने के लिए, स्केलेटन का उदाहरण:
// From the IFoo.h header using android::hardware::samples::V1_0::IFoo; class FooImpl : public IFoo { Return<void> someMethod(foo my_foo, someMethod_cb _cb) { vec<uint32_t> return_data; // Compute return_data _cb(return_data); return Void(); } ... };
किसी क्लाइंट के लिए सर्वर इंटरफ़ेस को लागू करने के लिए, ये काम किए जा सकते हैं:
- इंटरफ़ेस लागू करने के लिए,
hwservicemanager
(यहां जानकारी देखें) के साथ रजिस्टर करें,
या
- इंटरफ़ेस को लागू करने के तरीके को, इंटरफ़ेस के किसी मैथड के आर्ग्युमेंट के तौर पर पास करें. ज़्यादा जानकारी के लिए, असाइनोक्रोनस कॉलबैक देखें.
इंटरफ़ेस लागू करने के लिए रजिस्टर करते समय, hwservicemanager
प्रोसेस, डिवाइस पर नाम और वर्शन के हिसाब से, रजिस्टर किए गए HIDL इंटरफ़ेस को ट्रैक करती है. सर्वर, नाम के हिसाब से HIDL इंटरफ़ेस के लागू होने की जानकारी रजिस्टर कर सकते हैं. साथ ही, क्लाइंट नाम और वर्शन के हिसाब से सेवा के लागू होने का अनुरोध कर सकते हैं. यह प्रोसेस, HIDL इंटरफ़ेसandroid.hidl.manager@1.0::IServiceManager
को दिखाती है.
अपने-आप जनरेट हुई हर HIDL इंटरफ़ेस हेडर फ़ाइल (जैसे कि IFoo.h
) में एक registerAsService()
तरीका होता है. इसका इस्तेमाल, hwservicemanager
के साथ इंटरफ़ेस लागू करने के लिए किया जा सकता है. इंटरफ़ेस लागू करने का नाम ही एक ऐसा ऑर्ग्युमेंट है जो ज़रूरी है. क्लाइंट, hwservicemanager
से इंटरफ़ेस को बाद में वापस पाने के लिए, इस नाम का इस्तेमाल करते हैं:
::android::sp<IFoo> myFoo = new FooImpl(); ::android::sp<IFoo> mySecondFoo = new FooAnotherImpl(); status_t status = myFoo->registerAsService(); status_t anotherStatus = mySecondFoo->registerAsService("another_foo");
hwservicemanager
, [package@version::interface, instance_name]
के कॉम्बिनेशन को यूनीक मानता है, ताकि अलग-अलग इंटरफ़ेस (या एक ही इंटरफ़ेस के अलग-अलग वर्शन) को एक जैसे इंस्टेंस नेम के साथ रजिस्टर किया जा सके. अगर registerAsService()
को ठीक उसी पैकेज वर्शन, इंटरफ़ेस, और इंस्टेंस के नाम के साथ कॉल किया जाता है, तो hwservicemanager
, पहले से रजिस्टर की गई सेवा का रेफ़रंस हटा देता है और नई सेवा का इस्तेमाल करता है.
क्लाइंट लागू करना
ठीक उसी तरह जैसे सर्वर करता है, क्लाइंट को भी #include
हर उस इंटरफ़ेस के लिए
#include <android/hardware/samples/1.0/IFoo.h>
क्लाइंट दो तरीकों से इंटरफ़ेस पा सकता है:
I<InterfaceName>::getService
के ज़रिए (hwservicemanager
के ज़रिए)- इंटरफ़ेस के तरीके से
अपने-आप जनरेट हुई हर इंटरफ़ेस हेडर फ़ाइल में एक स्टैटिक getService
तरीका होता है. इसका इस्तेमाल, hwservicemanager
से सेवा का कोई इंस्टेंस पाने के लिए किया जा सकता है:
// getService returns nullptr if the service can't be found sp<IFoo> myFoo = IFoo::getService(); sp<IFoo> myAlternateFoo = IFoo::getService("another_foo");
अब क्लाइंट के पास IFoo
इंटरफ़ेस है और उसमें मौजूद तरीकों को वैसे ही कॉल किया जा सकता है जैसे कि किसी लोकल क्लास को लागू किया गया हो. असल में, लागू करने की प्रोसेस, एक ही प्रोसेस, किसी दूसरी प्रोसेस या किसी दूसरे डिवाइस पर भी (एचएएल रिमोटिंग की मदद से) चल सकती है. क्लाइंट ने पैकेज के 1.0
वर्शन में शामिल IFoo
ऑब्जेक्ट पर getService
को कॉल किया है. इसलिए, hwservicemanager
सिर्फ़ तब सर्वर लागू करता है, जब वह लागू करने का तरीका 1.0
क्लाइंट के साथ काम करता हो. इसका मतलब है कि सिर्फ़ 1.n
वर्शन वाले सर्वर को लागू किया जा सकता है. किसी इंटरफ़ेस के x.(y+1)
वर्शन को x.y
से एक्सटेंड (इनहेरिट) करना होगा.
इसके अलावा, अलग-अलग इंटरफ़ेस के बीच कास्ट करने के लिए, castFrom
तरीका दिया गया है. यह तरीका, रिमोट इंटरफ़ेस पर आईपीसी कॉल करके काम करता है. इससे यह पक्का किया जाता है कि मौजूदा टाइप, अनुरोध किए गए टाइप से मेल खाता हो. अगर अनुरोध किया गया टाइप उपलब्ध नहीं है, तो nullptr
दिखाया जाता है.
sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService(); sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);
एसिंक्रोनस कॉलबैक
एचएएल के कई मौजूदा वर्शन, एसिंक्रोनस हार्डवेयर के साथ काम करते हैं. इसका मतलब है कि उन्हें एसिंक्रोनस तरीके से क्लाइंट को होने वाले नए इवेंट की सूचना देनी होती है. HIDL इंटरफ़ेस का इस्तेमाल असाइनोक्रोनस कॉलबैक के तौर पर किया जा सकता है, क्योंकि HIDL इंटरफ़ेस फ़ंक्शन, HIDL इंटरफ़ेस ऑब्जेक्ट को पैरामीटर के तौर पर ले सकते हैं.
इंटरफ़ेस फ़ाइल IFooCallback.hal
का उदाहरण:
package android.hardware.samples@1.0; interface IFooCallback { sendEvent(uint32_t event_id); sendData(vec<uint8_t> data); }
IFoo
में नए तरीके का उदाहरण, जो IFooCallback
पैरामीटर लेता है:
package android.hardware.samples@1.0; interface IFoo { struct Foo { int64_t someValue; handle myHandle; }; someMethod(Foo foo) generates (int32_t ret); anotherMethod() generates (vec<uint32_t>); registerCallback(IFooCallback callback); };
IFoo
इंटरफ़ेस का इस्तेमाल करने वाला क्लाइंट, IFooCallback
इंटरफ़ेस का सर्वर होता है. यह IFooCallback
को लागू करने की सुविधा देता है:
class FooCallback : public IFooCallback { Return<void> sendEvent(uint32_t event_id) { // process the event from the HAL } Return<void> sendData(const hidl_vec<uint8_t>& data) { // process data from the HAL } };
इसे IFoo
इंटरफ़ेस के किसी मौजूदा इंस्टेंस पर भी पास किया जा सकता है:
sp<IFooCallback> myFooCallback = new FooCallback(); myFoo.registerCallback(myFooCallback);
IFoo
लागू करने वाले सर्वर को यह sp<IFooCallback>
ऑब्जेक्ट के तौर पर मिलता है. यह कॉलबैक को सेव कर सकता है और जब चाहे, क्लाइंट में कॉलबैक कर सकता है.
मृत व्यक्ति के नाम पर पैसे पाने वाले लोग
सेवा को लागू करने की प्रोसेस, किसी दूसरी प्रोसेस में चल सकती है. इसलिए, ऐसा हो सकता है कि क्लाइंट चालू रहने के दौरान, इंटरफ़ेस को लागू करने वाली प्रोसेस बंद हो जाए.
किसी ऐसी प्रोसेस में होस्ट किए गए इंटरफ़ेस ऑब्जेक्ट पर किए गए किसी भी कॉल को ट्रांसपोर्ट से जुड़ी गड़बड़ी (isOK()
false
दिखाता है) की वजह से पूरा नहीं किया जा सकता. इस तरह की गड़बड़ी से उबरने का एक ही तरीका है, I<InterfaceName>::getService()
को कॉल करके सेवा के नए इंस्टेंस का अनुरोध करना. यह सिर्फ़ तब काम करता है, जब क्रैश हुई प्रोसेस को फिर से शुरू किया गया हो और उसने अपनी सेवाओं को servicemanager
के साथ फिर से रजिस्टर किया हो. आम तौर पर, यह एचएएल लागू करने के लिए सही होता है.
इस समस्या को बाद में ठीक करने के बजाय, इंटरफ़ेस के क्लाइंट डेथ रिसीपेंट को रजिस्टर भी कर सकते हैं, ताकि सेवा बंद होने पर उन्हें सूचना मिल सके.
वापस लाए गए IFoo
इंटरफ़ेस पर ऐसी सूचनाओं के लिए रजिस्टर करने के लिए, क्लाइंट यह तरीका अपना सकता है:
foo->linkToDeath(recipient, 1481 /* cookie */);
recipient
पैरामीटर, HIDL के ज़रिए दिए गए android::hardware::hidl_death_recipient
इंटरफ़ेस का लागू होना चाहिए. इसमें एक मैथड serviceDied()
होता है, जिसे आरपीसी थ्रेडपूल में किसी थ्रेड से तब कॉल किया जाता है, जब इंटरफ़ेस को होस्ट करने वाली प्रोसेस बंद हो जाती है:
class MyDeathRecipient : public android::hardware::hidl_death_recipient { virtual void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) { // Deal with the fact that the service died } }
cookie
पैरामीटर में वह कुकी होती है जिसे linkToDeath()
के साथ पास किया गया था, जबकि who
पैरामीटर में क्लाइंट में सेवा को दिखाने वाले ऑब्जेक्ट का एक कमज़ोर पॉइंटर होता है. ऊपर दिए गए सैंपल कॉल में, cookie
का मान 1481 है और who
का मान foo
है.
किसी व्यक्ति की मौत के बाद, उसके डिवाइस का रजिस्ट्रेशन रद्द भी किया जा सकता है:
foo->unlinkToDeath(recipient);