इंटरफ़ेस

HIDL पैकेज में परिभाषित प्रत्येक इंटरफ़ेस के पैकेज के नेमस्पेस के अंदर अपनी स्वयं की स्वचालित C++ क्लास होती है। क्लाइंट और सर्वर अलग-अलग तरीकों से इंटरफेस से निपटते हैं:

  • सर्वर इंटरफ़ेस लागू करते हैं।
  • ग्राहक इंटरफ़ेस पर विधियों को कॉल करते हैं।

इंटरफेस को या तो सर्वर द्वारा नाम से पंजीकृत किया जा सकता है या एचआईडीएल-परिभाषित तरीकों के पैरामीटर के रूप में पारित किया जा सकता है। उदाहरण के लिए, फ्रेमवर्क कोड एचएएल से एसिंक्रोनस संदेश प्राप्त करने के लिए एक इंटरफ़ेस प्रदान कर सकता है और उस इंटरफ़ेस को पंजीकृत किए बिना सीधे एचएएल को पास कर सकता है।

सर्वर कार्यान्वयन

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();
    }
    ...
};

क्लाइंट के लिए सर्वर इंटरफ़ेस का कार्यान्वयन उपलब्ध कराने के लिए, आप यह कर सकते हैं:

  1. इंटरफ़ेस कार्यान्वयन को hwservicemanager के साथ पंजीकृत करें (नीचे विवरण देखें),

    या

  2. इंटरफ़ेस कार्यान्वयन को इंटरफ़ेस विधि के तर्क के रूप में पास करें (विवरण के लिए, एसिंक्रोनस कॉलबैक देखें)।

इंटरफ़ेस कार्यान्वयन को पंजीकृत करते समय, hwservicemanager प्रक्रिया नाम और संस्करण के आधार पर डिवाइस पर चल रहे पंजीकृत 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 will return 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) के साथ सर्वर कार्यान्वयन को विस्तारित करना होगा ( xy से प्राप्त करना)।

इसके अतिरिक्त विभिन्न इंटरफेस के बीच कास्ट करने के लिए 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() झूठी वापसी करेगा)। ऐसी विफलता से उबरने का एकमात्र तरीका I<InterfaceName>::getService() पर कॉल करके सेवा के एक नए उदाहरण का अनुरोध करना है। यह केवल तभी काम करता है जब क्रैश हुई प्रक्रिया फिर से शुरू हो गई है और servicemanager के साथ अपनी सेवाओं को फिर से पंजीकृत कर लिया है (जो आम तौर पर एचएएल कार्यान्वयन के लिए सच है)।

इससे प्रतिक्रियात्मक रूप से निपटने के बजाय, इंटरफ़ेस के ग्राहक सेवा समाप्त होने पर अधिसूचना प्राप्त करने के लिए मृत्यु प्राप्तकर्ता को भी पंजीकृत कर सकते हैं। पुनर्प्राप्त IFoo इंटरफ़ेस पर ऐसी सूचनाओं के लिए पंजीकरण करने के लिए, ग्राहक निम्नलिखित कार्य कर सकता है:

foo->linkToDeath(recipient, 1481 /* cookie */);

recipient पैरामीटर को HIDL द्वारा प्रदान किए गए android::hardware::hidl_death_recipient इंटरफ़ेस का कार्यान्वयन होना चाहिए, जिसमें एक एकल विधि serviceDied() शामिल है जिसे इंटरफ़ेस होस्ट करने वाली प्रक्रिया समाप्त होने पर RPC थ्रेडपूल में थ्रेड से कॉल किया जाएगा:

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);