এই পৃষ্ঠায় কীভাবে পরিষেবা রেজিস্টার ও ডিসকভার করতে হয় এবং .hal
ফাইলে ইন্টারফেসে সংজ্ঞায়িত পদ্ধতি কল করে কীভাবে কোনও পরিষেবায় ডেটা পাঠাতে হয় তা বর্ণনা করা হয়েছে।
নিবন্ধকরণ পরিষেবাসমূহ
HIDL ইন্টারফেস সার্ভার (ইন্টারফেস প্রয়োগকারী অবজেক্ট) নামযুক্ত পরিষেবা হিসেবে রেজিস্টার করা যেতে পারে। রেজিস্টার করা নাম ইন্টারফেস বা প্যাকেজের নামের সাথে সম্পর্কিত হতে হবে না। কোনও নাম নির্দিষ্ট করা না থাকলে, "default" নামটি ব্যবহার করা হয়; এটি সেইসব HAL-এর জন্য ব্যবহার করা উচিত যেগুলির একই ইন্টারফেসের দুটি ইমপ্লিমেন্টেশন রেজিস্টার করার প্রয়োজন নেই। যেমন, প্রতিটি ইন্টারফেসে পরিষেবা রেজিস্ট্রেশনের জন্য C++ কল এগুলি হতে পারে:
status_t status = myFoo->registerAsService(); status_t anotherStatus = anotherFoo->registerAsService("another_foo_service"); // if needed
HIDL ইন্টারফেসের ভার্সন ইন্টারফেসেই অন্তর্ভুক্ত থাকে। এটি পরিষেবা রেজিস্ট্রেশনের সাথে
অটোমেটিক যুক্ত থাকে এবং প্রতিটি HIDL ইন্টারফেসে
মেথড কল (android::hardware::IInterface::getInterfaceVersion())
ব্যবহার করে এটি পুনরুদ্ধার করা যেতে পারে। সার্ভার অবজেক্ট রেজিস্টার করার প্রয়োজন নেই এবং HIDL মেথড প্যারামিটারের মাধ্যমে
অন্য প্রসেসে পাস করা যেতে পারে যা সার্ভারে HIDL মেথড কল
করে।
পরিষেবা খুঁজে দেখা
ক্লায়েন্ট কোডের মাধ্যমে করা অনুরোধগুলি নির্দিষ্ট ইন্টারফেসের জন্য নাম ও
ভার্সন অনুযায়ী করা হয়, এর ফলে পছন্দমতো HAL ক্লাসে getService কল করা হয়:
// C++ sp<V1_1::IFooService> service = V1_1::IFooService::getService(); sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service"); // Java V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */); V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);
HIDL ইন্টারফেসের প্রতিটি ভার্সনকে আলাদা ইন্টারফেস হিসেবে বিবেচনা করা হয়। তাই,
IFooService ভার্সন ১.১ এবং IFooService ভার্সন ২.২
দুটিই "foo_service" হিসেবে রেজিস্টার করা যেতে পারে এবং
যেকোনও ইন্টারফেসে getService("foo_service") সেই ইন্টারফেসের জন্য রেজিস্টার করা
পরিষেবা পায়। এই কারণে, বেশিরভাগ ক্ষেত্রে, রেজিস্ট্রেশন বা ডিসকভারির জন্য কোনও নাম প্যারামিটার
প্রদান করার প্রয়োজন নেই (অর্থাৎ নাম "default")।
ফিরে আসা ইন্টারফেসের ট্রান্সপোর্ট পদ্ধতিতে ভেন্ডর ইন্টারফেস অবজেক্টও
ভূমিকা পালন করে। IFoo প্যাকেজে android.hardware.foo@1.0 ইন্টারফেসের জন্য,
IFoo::getService-এর মাধ্যমে রিটার্ন করা ইন্টারফেস,
android.hardware.foo-এর জন্য ডিভাইসের ম্যানিফেস্টে ঘোষণা করা ট্রান্সপোর্ট পদ্ধতি সবসময় ব্যবহার করে যদি এন্ট্রি থাকে;
এবং ট্রান্সপোর্ট পদ্ধতি উপলভ্য না থাকলে, nullptr রিটার্ন করা হয়।
কিছু ক্ষেত্রে, পরিষেবা না পাওয়া সত্ত্বেও অবিলম্বে চালিয়ে যাওয়া প্রয়োজন হতে পারে।
এটি হতে পারে (যেমন) যখন কোনও ক্লায়েন্ট নিজেই বা কোনও ডায়াগনস্টিক প্রোগ্রামে (যেমন
atrace) পরিষেবা বিজ্ঞপ্তি ম্যানেজ করতে চায়, যার জন্য
সমস্ত hwservices পেতে এবং সেগুলি পুনরুদ্ধার করতে হবে। এই
ক্ষেত্রে, অতিরিক্ত API প্রদান করা হয় যেমন tryGetService C++-এ বা
getService("instance-name", false) Java-তে। Java-তে দেওয়া লিগ্যাসি API-ও
getService পরিষেবা
নোটিফিকেশনের সাথে ব্যবহার করতে হবে। এই API ব্যবহার করলে, রেস কন্ডিশন এড়ানো যায় না যেখানে কোনও ক্লায়েন্ট এইসব নো-রিট্রাই API-এর মধ্যে কোনও একটির মাধ্যমে অনুরোধ করার পরে
কোনও সার্ভার নিজেকে রেজিস্টার করে।
পরিষেবা বন্ধ হয়ে যাওয়া সংক্রান্ত বিজ্ঞপ্তি
কোনও পরিষেবা বন্ধ হয়ে গেলে সেই বিষয়ে বিজ্ঞপ্তি পেতে চাইলে, ফ্রেমওয়ার্কের মাধ্যমে ক্লায়েন্টরা মৃত্যু সংক্রান্ত বিজ্ঞপ্তি পেতে পারেন। বিজ্ঞপ্তি পেতে, ক্লায়েন্টকে অবশ্যই:
- HIDL ক্লাস/ইন্টারফেস
hidl_death_recipient-এর সাবক্লাস তৈরি করুন (C++ কোডে, HIDL-এ নয়)। - এর
serviceDied()পদ্ধতি ওভাররাইড করুন৷ hidl_death_recipientসাবক্লাসের একটি অবজেক্ট ইনস্ট্যানশিয়েট করুন।- মনিটর করার জন্য পরিষেবায়
linkToDeath()পদ্ধতি কল করুন,IDeathRecipient-এর ইন্টারফেস অবজেক্টে পাস করুন। মনে রাখবেন যে এই পদ্ধতিটি মৃত্যু প্রাপক বা প্রক্সি যার উপর এটি কল করা হয় তার মালিকানা নেয় না।
সিউডোকোডের উদাহরণ (C++ ও Java একই ধরনের):
class IMyDeathReceiver : hidl_death_recipient { virtual void serviceDied(uint64_t cookie, wp<IBase>& service) override { log("RIP service %d!", cookie); // Cookie should be 42 } }; .... IMyDeathReceiver deathReceiver = new IMyDeathReceiver(); m_importantService->linkToDeath(deathReceiver, 42);
মৃত ব্যক্তির একই নমিনি একাধিক আলাদা আলাদা পরিষেবায় রেজিস্টার করা থাকতে পারেন।
ডেটা ট্রান্সফার
.hal ফাইলে ইন্টারফেসে সংজ্ঞায়িত পদ্ধতি কল করে কোনও পরিষেবায় ডেটা পাঠানো যেতে পারে।
দু'ধরনের পদ্ধতি আছে:
- সার্ভার ফলাফল না দেখানো পর্যন্ত ব্লকিং পদ্ধতি অপেক্ষা করে।
- একমুখী পদ্ধতিতে ডেটা শুধুমাত্র এক দিকে পাঠানো হয় এবং তা ব্লক করা হয় না। RPC কলে ইন-ফ্লাইট ডেটার পরিমাণ প্রয়োগের সীমা অতিক্রম করলে, কলগুলি ব্লক হতে পারে বা ত্রুটির ইঙ্গিত দিতে পারে (আচরণ এখনও নির্ধারিত হয়নি)।
এমন একটি পদ্ধতি যা কোনও ভ্যালু রিটার্ন করে না কিন্তু
oneway হিসেবে ঘোষণা করা হয়নি, সেটি এখনও ব্লক করছে।
HIDL ইন্টারফেসে ঘোষণা করা সব পদ্ধতি একটি দিকেই কল করা হয়, হয় HAL থেকে অথবা HAL-এ। ইন্টারফেসটি কোন দিকে কল করা হয়েছে তা নির্দিষ্ট করে না। HAL থেকে কল অরিজিনেট করার প্রয়োজন হয় এমন আর্কিটেকচারকে HAL প্যাকেজে দুটি (বা তার বেশি) ইন্টারফেস প্রদান করতে হবে এবং প্রতিটি প্রসেস থেকে উপযুক্ত ইন্টারফেস পরিবেশন করতে হবে। ক্লায়েন্ট ও সার্ভার শব্দগুলি ইন্টারফেসের কলিং ডিরেকশনের সাথে সম্পর্কিত (যেমন, HAL একটি ইন্টারফেসের সার্ভার ও অন্য ইন্টারফেসের ক্লায়েন্ট হতে পারে)।
কলব্যাক
কলব্যাক শব্দটি দুটি আলাদা কনসেপ্টকে বোঝায়, যেগুলি সিনক্রোনাস কলব্যাক ও অ্যাসিঙ্ক্রোনাস কলব্যাক হিসেবে আলাদা করা হয়।
কিছু HIDL পদ্ধতিতে সিনক্রোনাস কলব্যাক ব্যবহার করা হয় যেগুলি ডেটা রিটার্ন করে। একটি HIDL পদ্ধতি যা একাধিক ভ্যালু রিটার্ন করে (বা নন-প্রিমিটিভ ধরনের একটি ভ্যালু রিটার্ন করে) সেটি কলব্যাক ফাংশনের মাধ্যমে ফলাফল রিটার্ন করে। যদি শুধুমাত্র একটি মান ফেরত আসে এবং সেটি একটি আদিম ধরন হয়, তাহলে কোনও কলব্যাক ব্যবহার করা হয় না এবং পদ্ধতি থেকে মান ফেরত আসে। সার্ভার HIDL পদ্ধতি প্রয়োগ করে এবং ক্লায়েন্ট কলব্যাক প্রয়োগ করে।
অ্যাসিঙ্ক্রোনাস কলব্যাক HIDL ইন্টারফেসের সার্ভারকে কল শুরু করার অনুমতি দেয়। প্রথম ইন্টারফেসের মাধ্যমে দ্বিতীয় ইন্টারফেসের
একটি ইনস্ট্যান্স পাস করে এটি করা হয়। প্রথম ইন্টারফেসের ক্লায়েন্টকে দ্বিতীয় ইন্টারফেসের
সার্ভার হিসেবে কাজ করতে হবে। প্রথম ইন্টারফেসের সার্ভার দ্বিতীয় ইন্টারফেস অবজেক্টে
মেথড কল করতে পারে। যেমন, কোনও HAL ইমপ্লিমেন্টেশন, যে প্রসেস এটি ব্যবহার করছে সেটিকে অ্যাসিঙ্ক্রোনাসভাবে তথ্য
ফেরত পাঠাতে পারে। এটি করার জন্য, সেই প্রসেস দ্বারা তৈরি ও পরিবেশিত
ইন্টারফেস অবজেক্টের মেথড কল করা হয়। অ্যাসিঙ্ক্রোনাস কলব্যাকের জন্য ইন্টারফেসে ব্যবহৃত পদ্ধতি
ব্লকিং হতে পারে (এবং কলারকে ভ্যালু রিটার্ন করতে পারে)
অথবা oneway। যেমন, HIDL C++-এ "অ্যাসিঙ্ক্রোনাস কলব্যাক" দেখুন।
মেমরি মালিকানা সহজ করতে, মেথড কল ও কলব্যাক শুধুমাত্র
in প্যারামিটার নেয় এবং out বা
inout প্যারামিটার নেয় না।
প্রতিটি ট্রানজ্যাকশনের সীমা
HIDL পদ্ধতি ও কলব্যাকে পাঠানো ডেটার পরিমাণের উপর ট্রানজ্যাকশন-প্রতি সীমা আরোপ করা হয় না। তবে, ট্রানজ্যাকশন পিছু ৪KB-এর বেশি কলকে
অতিরিক্ত হিসেবে বিবেচনা করা হয়। এটি দেখা গেলে, প্রদত্ত HIDL ইন্টারফেসের আর্কিটেকচার আবার তৈরি করার
সাজেশন দেওয়া হয়। আরেকটি সীমাবদ্ধতা হল একাধিক যুগপৎ লেনদেন পরিচালনা করার জন্য HIDL
অবকাঠামোতে উপলব্ধ সংস্থান। প্রসেস বা একাধিক oneway কলে কল পাঠানোর জন্য একাধিক থ্রেড বা
প্রসেসের কারণে একাধিক
ট্রানজ্যাকশন একই সাথে ইন-ফ্লাইট থাকতে পারে যা
গ্রহণকারী প্রসেস দ্রুত হ্যান্ডেল করে না। ডিফল্ট হিসেবে, সব সমবর্তী ট্রানজ্যাকশনের জন্য
উপলভ্য সর্বাধিক মোট স্পেস হল ১ এমবি।
একটি ভালভাবে ডিজাইন করা ইন্টারফেসে, এই রিসোর্স সংক্রান্ত সীমাবদ্ধতা অতিক্রম করা উচিত নয়; যদি এটি হয়, তাহলে যে কলটি সেগুলি অতিক্রম করেছে সেটি রিসোর্স উপলভ্য না হওয়া পর্যন্ত ব্লক করতে পারে বা ট্রান্সপোর্ট সংক্রান্ত সমস্যার সিগন্যাল দিতে পারে। প্রতিটি ক্ষেত্রে ট্রানজ্যাকশন পিছু সীমা অতিক্রম করা বা HIDL প্রয়োগের রিসোর্স ওভারফ্লো করা হলে, তা মোট ইন-ফ্লাইট ট্রানজ্যাকশনের মাধ্যমে লগ করা হয়, যাতে সহজে ডিবাগ করা যায়।
পদ্ধতি প্রয়োগ করা
HIDL, টার্গেট ভাষায় (C++ বা Java) প্রয়োজনীয় ধরন, পদ্ধতি ও কলব্যাক ঘোষণা করে হেডার ফাইল তৈরি করে। ক্লায়েন্ট ও সার্ভার কোড, দু'টির ক্ষেত্রেই HIDL-সংজ্ঞায়িত পদ্ধতি ও কলব্যাকের প্রোটোটাইপ একই। HIDL সিস্টেম, IPC ট্রান্সপোর্টের জন্য ডেটা সাজানো কলার সাইডে পদ্ধতির প্রক্সি ইমপ্লিমেন্টেশন এবং পদ্ধতির ডেভেলপার ইমপ্লিমেন্টেশনে ডেটা পাস করা কলি সাইডে স্টাব কোড প্রদান করে।
ফাংশনের (HIDL পদ্ধতি বা কলব্যাক) কলারের কাছে ফাংশনে পাস করা ডেটা স্ট্রাকচারের মালিকানা থাকে এবং কল করার পরেও মালিকানা বজায় থাকে; সব ক্ষেত্রেই কলি-কে স্টোরেজ খালি বা রিলিজ করতে হয় না।
- C++-এ, ডেটা শুধুমাত্র পাঠযোগ্য হতে পারে (এতে লেখার চেষ্টা করলে সেগমেন্টেশন ত্রুটি হতে পারে) এবং কলের সময়কালের জন্য বৈধ। কলের বাইরে ডেটা শেয়ার করার জন্য ক্লায়েন্ট ডেটার ডিপ-কপি তৈরি করতে পারে।
- Java-তে, কোডটি ডেটার একটি স্থানীয় কপি (একটি সাধারণ Java অবজেক্ট) পায়, যা এটি রাখতে এবং পরিবর্তন করতে পারে বা গার্বেজ-কালেক্ট করার অনুমতি দিতে পারে।
নন-RPC ডেটা ট্রান্সফার
RPC কল ব্যবহার না করে ডেটা ট্রান্সফার করার জন্য HIDL-এর দুটি উপায় আছে: শেয়ার করা মেমরি ও একটি দ্রুত মেসেজ কোয়েরি (FMQ), এই দুটিই শুধুমাত্র C++-এ কাজ করে।
- শেয়ার করা স্মৃতি। বিল্ট-ইন HIDL টাইপ
memoryব্যবহার করা হয় এমন অবজেক্ট পাস করতে যা বরাদ্দ করা শেয়ার করা মেমরিকে দেখায়। শেয়ার করা মেমরি ম্যাপ করার জন্য গ্রহণ করার প্রসেসে ব্যবহার করা যেতে পারে। - ফাস্ট মেসেজ কিউ (FMQ)। HIDL একটি টেমপ্লেটেড মেসেজ
কিউয়ের ধরন প্রদান করে যা কোনও অপেক্ষা না করেই মেসেজ পাস করার সুবিধা প্রয়োগ করে। এটি পাসথ্রু বা বাইন্ডারাইজড মোডে কার্নেল বা শিডিউলার ব্যবহার করে না (ডিভাইস-টু-ডিভাইস কমিউনিকেশনে এই প্রপার্টি থাকে না)। সাধারণত, HAL তার কোয়েরির শেষ অংশ সেট-আপ করে,
একটি অবজেক্ট তৈরি করে যা বিল্ট-ইন
HIDL টাইপের
MQDescriptorSyncবাMQDescriptorUnsyncপ্যারামিটারের মাধ্যমে RPC-তে পাস করা যেতে পারে। এই অবজেক্টটি গ্রহণকারী প্রসেস ব্যবহার করে কিউয়ের অন্য প্রান্ত সেট-আপ করতে পারে।- সিঙ্ক করার কোয়েরি ওভারফ্লো হতে দেওয়া হয় না এবং এতে শুধুমাত্র একটি রিডার থাকতে পারে।
- আনসিঙ্ক করা কিউ ওভারফ্লো হতে পারে এবং এতে অনেক রিডার থাকতে পারে, যার প্রত্যেকটিকে সময়মতো ডেটা পড়তে হবে, না হলে সেটি হারিয়ে যাবে।
FMQ সম্পর্কে আরও জানতে, ফাস্ট মেসেজ কিউ (FMQ) দেখুন।