ইন্টারফেস

একটি 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();
    }
    ...
};

একটি ক্লায়েন্টের জন্য উপলব্ধ একটি সার্ভার ইন্টারফেস বাস্তবায়ন করতে, আপনি করতে পারেন:

  1. hwservicemanager এর সাথে ইন্টারফেস বাস্তবায়ন নিবন্ধন করুন (নীচে বিস্তারিত দেখুন),

    বা

  2. একটি ইন্টারফেস পদ্ধতির একটি যুক্তি হিসাবে ইন্টারফেস বাস্তবায়ন পাস করুন (বিস্তারিত জন্য, অ্যাসিঙ্ক্রোনাস কলব্যাক দেখুন)।

ইন্টারফেস বাস্তবায়ন নিবন্ধন করার সময়, 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 ইন্টারফেস রয়েছে এবং এটিতে পদ্ধতিগুলি কল করতে পারে যেন এটি একটি স্থানীয় শ্রেণি বাস্তবায়ন। বাস্তবে, বাস্তবায়ন একই প্রক্রিয়া, একটি ভিন্ন প্রক্রিয়া, বা এমনকি অন্য ডিভাইসেও (HAL রিমোটিং সহ) চলতে পারে। যেহেতু প্যাকেজের সংস্করণ 1.0 থেকে অন্তর্ভুক্ত একটি IFoo অবজেক্টে getService নামক ক্লায়েন্ট, hwservicemanager শুধুমাত্র একটি সার্ভার বাস্তবায়ন প্রদান করে যদি সেই বাস্তবায়ন 1.0 ক্লায়েন্টের সাথে সামঞ্জস্যপূর্ণ হয়। অনুশীলনে, এর অর্থ হল শুধুমাত্র একটি ইন্টারফেসের সংস্করণ 1.n (সংস্করণ x.(y+1) সহ সার্ভার বাস্তবায়নকে অবশ্যই xy প্রসারিত করতে হবে (এর থেকে উত্তরাধিকারী)।

অতিরিক্তভাবে castFrom পদ্ধতিটি বিভিন্ন ইন্টারফেসের মধ্যে কাস্ট করার জন্য প্রদান করা হয়। এই পদ্ধতিটি রিমোট ইন্টারফেসে একটি IPC কল করার মাধ্যমে কাজ করে যাতে নিশ্চিত করা যায় যে অন্তর্নিহিত প্রকারটি অনুরোধ করা হচ্ছে সেই প্রকারের মতোই। যদি অনুরোধকৃত প্রকারটি অনুপলব্ধ হয়, তাহলে nullptr ফেরত দেওয়া হয়।

sp<V1_0::IFoo> foo1_0 = V1_0::IFoo::getService();
sp<V1_1::IFoo> foo1_1 = V1_1::IFoo::castFrom(foo1_0);

অ্যাসিঙ্ক্রোনাস কলব্যাক

অনেক বিদ্যমান HAL বাস্তবায়ন অ্যাসিঙ্ক্রোনাস হার্ডওয়্যারের সাথে কথা বলে, যার অর্থ তাদের ক্লায়েন্টদের যে নতুন ইভেন্টগুলি ঘটেছে তা অবহিত করার জন্য একটি অ্যাসিঙ্ক্রোনাস উপায় প্রয়োজন। একটি 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 (যা সাধারণত HAL বাস্তবায়নের জন্য সত্য) এর সাথে পরিষেবাগুলি পুনরায় নিবন্ধিত করে।

এটিকে প্রতিক্রিয়াশীলভাবে মোকাবেলা করার পরিবর্তে, একটি ইন্টারফেসের ক্লায়েন্টরাও একটি পরিষেবা মারা গেলে একটি বিজ্ঞপ্তি পেতে একটি মৃত্যু প্রাপককে নিবন্ধন করতে পারে। একটি পুনরুদ্ধার করা IFoo ইন্টারফেসে এই ধরনের বিজ্ঞপ্তিগুলির জন্য নিবন্ধন করতে, একজন ক্লায়েন্ট নিম্নলিখিতগুলি করতে পারেন:

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

recipient প্যারামিটারটি অবশ্যই এইচআইডিএল দ্বারা প্রদত্ত 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);