HIDL প্যাকেজে সংজ্ঞায়িত প্রতিটি ইন্টারফেসের নিজস্ব অটো-জেনারেটেড C++ ক্লাস প্যাকেজের নেমস্পেসের মধ্যে থাকে। ক্লায়েন্ট ও সার্ভার ইন্টারফেসের সাথে আলাদা আলাদাভাবে ডিল করে:
- সার্ভার ইন্টারফেস প্রয়োগ করে।
- ইন্টারফেসে ক্লায়েন্ট মেথড কল করে।
ইন্টারফেসকে সার্ভার নাম দিয়ে রেজিস্টার করতে পারে অথবা HIDL-এর মাধ্যমে সংজ্ঞায়িত পদ্ধতিতে প্যারামিটার হিসেবে পাস করতে পারে। যেমন, ফ্রেমওয়ার্ক কোড HAL থেকে অ্যাসিঙ্ক্রোনাস মেসেজ পাওয়ার জন্য একটি ইন্টারফেস পরিবেশন করতে পারে এবং সেই ইন্টারফেসটি রেজিস্টার না করেই সরাসরি HAL-এ পাস করতে পারে।
সার্ভার প্রয়োগ করা
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 ইন্টারফেস আছে এবং এটি
যেন একটি লোকাল ক্লাস ইমপ্লিমেন্টেশন, সেইভাবে এর মেথড কল করতে পারে। বাস্তবে, একই প্রসেস, আলাদা প্রসেস বা এমনকি অন্য ডিভাইসেও
ইমপ্লিমেন্টেশন রান করতে পারে
(HAL রিমোটিং সহ)। কারণ, ক্লায়েন্ট getService কল করেছে এমন একটি
IFoo অবজেক্টে যা প্যাকেজের 1.0 ভার্সন থেকে অন্তর্ভুক্ত করা হয়েছে,
তাই hwservicemanager শুধুমাত্র তখনই সার্ভার ইমপ্লিমেন্টেশন রিটার্ন করে যদি সেই
ইমপ্লিমেন্টেশন 1.0 ক্লায়েন্টের সাথে মানানসই হয়। বাস্তবে, এর অর্থ হল, শুধুমাত্র 1.n ভার্সনের (ইন্টারফেসের x.(y+1) ভার্সন অবশ্যই এক্সটেন্ড (x.y থেকে ইনহেরিট) করতে হবে) সার্ভার ইমপ্লিমেন্টেশন।
এছাড়াও, 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 প্যারামিটারকে অবশ্যই 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-এর মান ১৪৮১ এবং who-এর মান foo
।
এছাড়াও, মৃত্যুর পরে প্রাপক রেজিস্টার করার পরে সেটি আনরেজিস্টার করা সম্ভব:
foo->unlinkToDeath(recipient);