পরিষেবা এবং ডেটা স্থানান্তর

এই পৃষ্ঠাটি বর্ণনা করে যে কীভাবে পরিষেবাগুলি নিবন্ধন এবং আবিষ্কার করতে হয় এবং কীভাবে .hal ফাইলের ইন্টারফেসে সংজ্ঞায়িত পদ্ধতিগুলি কল করে একটি পরিষেবাতে ডেটা পাঠাতে হয়৷

সেবা নিবন্ধন

HIDL ইন্টারফেস সার্ভার (ইন্টারফেস বাস্তবায়নকারী বস্তু) নামযুক্ত পরিষেবা হিসাবে নিবন্ধিত হতে পারে। নিবন্ধিত নাম ইন্টারফেস বা প্যাকেজ নামের সাথে সম্পর্কিত হতে হবে না। যদি কোনো নাম উল্লেখ না করা হয়, তাহলে "ডিফল্ট" নামটি ব্যবহার করা হয়; এটি 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 সংস্করণ 1.1 এবং IFooService সংস্করণ 2.2 উভয়ই ইন্টারফেসের জন্য "foo_service" এবং getService("foo_service") হিসাবে নিবন্ধিত হতে পারে সেই ইন্টারফেসের জন্য নিবন্ধিত পরিষেবা পায়৷ এই কারণেই, বেশিরভাগ ক্ষেত্রে, নিবন্ধন বা আবিষ্কারের জন্য কোনও নামের প্যারামিটার সরবরাহ করার প্রয়োজন হয় না (অর্থাৎ নাম "ডিফল্ট")।

বিক্রেতা ইন্টারফেস অবজেক্ট ফেরত ইন্টারফেসের পরিবহন পদ্ধতিতেও একটি ভূমিকা পালন করে। android.hardware.foo@1.0 প্যাকেজে IFoo ইন্টারফেসের জন্য, IFoo::getService দ্বারা প্রত্যাবর্তিত ইন্টারফেসটি সর্বদা ডিভাইস ম্যানিফেস্টে android.hardware.foo এর জন্য ঘোষিত পরিবহন পদ্ধতি ব্যবহার করে যদি এন্ট্রি বিদ্যমান থাকে; এবং পরিবহন পদ্ধতি উপলব্ধ না হলে, nullptr ফেরত দেওয়া হয়।

কিছু ক্ষেত্রে, পরিষেবা না পেয়েও অবিলম্বে চালিয়ে যাওয়ার প্রয়োজন হতে পারে। এটি ঘটতে পারে (উদাহরণস্বরূপ) যখন কোনও ক্লায়েন্ট নিজেই পরিষেবা বিজ্ঞপ্তিগুলি পরিচালনা করতে চায় বা একটি ডায়াগনস্টিক প্রোগ্রামে (যেমন atrace ) যা সমস্ত hwservice পেতে এবং সেগুলি পুনরুদ্ধার করতে চায়। এই ক্ষেত্রে, C++-এ tryGetService বা Java-তে getService("instance-name", false) এর মতো অতিরিক্ত API প্রদান করা হয়। জাভাতে প্রদত্ত লিগ্যাসি API getService ও পরিষেবা বিজ্ঞপ্তিগুলির সাথে ব্যবহার করা আবশ্যক৷ এই API ব্যবহার করা রেস অবস্থা এড়ায় না যেখানে একটি সার্ভার ক্লায়েন্ট অনুরোধ করার পরে এই নো-ট্রাই APIগুলির মধ্যে একটির সাথে নিজেকে নিবন্ধন করে।

পরিষেবা মৃত্যুর বিজ্ঞপ্তি

ক্লায়েন্ট যারা একটি পরিষেবা মারা গেলে বিজ্ঞপ্তি পেতে চান তারা ফ্রেমওয়ার্ক দ্বারা বিতরণ করা মৃত্যুর বিজ্ঞপ্তি পেতে পারেন। বিজ্ঞপ্তি পেতে, ক্লায়েন্টকে অবশ্যই:

  1. HIDL ক্লাস/ইন্টারফেস hidl_death_recipient সাবক্লাস করুন (C++ কোডে, HIDL-এ নয়)।
  2. এর serviceDied() পদ্ধতি ওভাররাইড করুন।
  3. hidl_death_recipient সাবক্লাসের একটি অবজেক্ট ইনস্ট্যান্টিয়েট করুন।
  4. IDeathRecipient এর ইন্টারফেস অবজেক্টে পাস করে নিরীক্ষণের জন্য পরিষেবার linkToDeath() পদ্ধতিতে কল করুন। মনে রাখবেন যে এই পদ্ধতিটি মৃত্যু প্রাপক বা প্রক্সির মালিকানা নেয় না যার উপর এটি বলা হয়।

একটি সিউডোকোড উদাহরণ (C++ এবং জাভা একই রকম):

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 একটি ইন্টারফেসের একটি সার্ভার এবং অন্য ইন্টারফেসের একটি ক্লায়েন্ট হতে পারে)।

কলব্যাক

কলব্যাক শব্দটি দুটি ভিন্ন ধারণাকে বোঝায়, সিঙ্ক্রোনাস কলব্যাক এবং অ্যাসিঙ্ক্রোনাস কলব্যাক দ্বারা আলাদা।

কিছু HIDL পদ্ধতিতে সিঙ্ক্রোনাস কলব্যাক ব্যবহার করা হয় যা ডেটা ফেরত দেয়। একটি HIDL পদ্ধতি যা একাধিক মান প্রদান করে (বা অ-আদি ধরনের একটি মান প্রদান করে) একটি কলব্যাক ফাংশনের মাধ্যমে তার ফলাফল প্রদান করে। যদি শুধুমাত্র একটি মান ফেরত দেওয়া হয় এবং এটি একটি আদিম প্রকার, একটি কলব্যাক ব্যবহার করা হয় না এবং মানটি পদ্ধতি থেকে ফেরত দেওয়া হয়। সার্ভার HIDL পদ্ধতি প্রয়োগ করে এবং ক্লায়েন্ট কলব্যাক প্রয়োগ করে।

অ্যাসিঙ্ক্রোনাস কলব্যাকগুলি HIDL ইন্টারফেসের সার্ভারকে কলগুলি শুরু করার অনুমতি দেয়। এটি প্রথম ইন্টারফেসের মাধ্যমে দ্বিতীয় ইন্টারফেসের একটি উদাহরণ পাস করে করা হয়। প্রথম ইন্টারফেসের ক্লায়েন্টকে অবশ্যই দ্বিতীয়টির সার্ভার হিসেবে কাজ করতে হবে। প্রথম ইন্টারফেসের সার্ভার দ্বিতীয় ইন্টারফেস অবজেক্টে পদ্ধতি কল করতে পারে। উদাহরণ স্বরূপ, একটি HAL বাস্তবায়ন তথ্য অসিঙ্ক্রোনাসভাবে সেই প্রক্রিয়ায় ফেরত পাঠাতে পারে যা এই প্রক্রিয়ার দ্বারা তৈরি এবং পরিবেশিত একটি ইন্টারফেস অবজেক্টে মেথড কল করে এটি ব্যবহার করছে। অ্যাসিঙ্ক্রোনাস কলব্যাকের জন্য ব্যবহৃত ইন্টারফেসের পদ্ধতিগুলি ব্লক করা হতে পারে (এবং কলারের কাছে মান ফেরত দিতে পারে) বা oneway । একটি উদাহরণের জন্য, HIDL C++ এ "অ্যাসিনক্রোনাস কলব্যাক" দেখুন।

মেমরির মালিকানাকে সহজ করার জন্য, পদ্ধতি কল এবং কলব্যাকগুলি শুধুমাত্র in নেওয়া হয় এবং inout out করে না।

প্রতি-লেনদেনের সীমা

HIDL পদ্ধতি এবং কলব্যাকগুলিতে পাঠানো ডেটার পরিমাণের উপর প্রতি-লেনদেনের সীমা আরোপ করা হয় না। যাইহোক, প্রতি লেনদেন 4KB-এর বেশি কলগুলিকে অতিরিক্ত হিসাবে বিবেচনা করা হয়। যদি এটি দেখা যায়, প্রদত্ত HIDL ইন্টারফেস পুনরায় আর্কিটেক্ট করার সুপারিশ করা হয়। আরেকটি সীমাবদ্ধতা হল একাধিক যুগপৎ লেনদেন পরিচালনা করার জন্য HIDL পরিকাঠামোতে উপলব্ধ সংস্থান। একাধিক লেনদেন একযোগে ফ্লাইটে হতে পারে একাধিক থ্রেড বা প্রসেস একটি প্রসেসে কল পাঠানোর কারণে বা একাধিক oneway কল যা গ্রহন প্রক্রিয়ার দ্বারা দ্রুত পরিচালনা করা হয় না। সমস্ত সমসাময়িক লেনদেনের জন্য উপলব্ধ সর্বোচ্চ মোট স্থান ডিফল্টরূপে 1MB।

একটি ভাল-পরিকল্পিত ইন্টারফেসে, এই সম্পদ সীমা অতিক্রম করা উচিত নয়; যদি এটি হয়, যে কলটি তাদের অতিক্রম করেছে তা হয় সম্পদ উপলব্ধ না হওয়া পর্যন্ত ব্লক করতে পারে বা পরিবহন ত্রুটির সংকেত দিতে পারে। প্রতি-লেনদেনের সীমা অতিক্রম করার প্রতিটি ঘটনা বা সমষ্টিগত ইন-ফ্লাইট লেনদেনের দ্বারা HIDL বাস্তবায়ন সংস্থানগুলিকে ডিবাগ করার সুবিধার্থে লগ করা হয়।

পদ্ধতি বাস্তবায়ন

এইচআইডিএল হেডার ফাইল তৈরি করে যা লক্ষ্য ভাষায় (সি++ বা জাভা) প্রয়োজনীয় প্রকার, পদ্ধতি এবং কলব্যাক ঘোষণা করে। HIDL-সংজ্ঞায়িত পদ্ধতি এবং কলব্যাকের প্রোটোটাইপ ক্লায়েন্ট এবং সার্ভার কোড উভয়ের জন্যই একই। এইচআইডিএল সিস্টেম কলকারীর দিকের পদ্ধতিগুলির প্রক্সি বাস্তবায়ন প্রদান করে যা IPC পরিবহনের জন্য ডেটা সংগঠিত করে এবং কলির দিকে স্টাব কোড যা পদ্ধতিগুলির বিকাশকারী বাস্তবায়নে ডেটা পাস করে।

একটি ফাংশনের কলারের (এইচআইডিএল পদ্ধতি বা কলব্যাক) ফাংশনে পাস করা ডেটা স্ট্রাকচারের মালিকানা থাকে এবং কল করার পরে মালিকানা ধরে রাখে; সব ক্ষেত্রেই ক্যালিকে স্টোরেজ খালি বা রিলিজ করতে হবে না।

  • C++-এ, ডেটা শুধুমাত্র পঠনযোগ্য হতে পারে (এতে লেখার প্রচেষ্টা একটি বিভাজন ত্রুটির কারণ হতে পারে) এবং কলের সময়কালের জন্য বৈধ। ক্লায়েন্ট কলের বাইরে এটি প্রচার করতে ডেটা গভীর-কপি করতে পারে।
  • জাভাতে, কোডটি ডেটার একটি স্থানীয় অনুলিপি পায় (একটি সাধারণ জাভা অবজেক্ট), যা এটি রাখতে এবং সংশোধন করতে পারে বা আবর্জনা-সংগ্রহ করার অনুমতি দিতে পারে।

অ-RPC ডেটা স্থানান্তর

HIDL-এর কাছে RPC কল ব্যবহার না করে ডেটা স্থানান্তর করার দুটি উপায় রয়েছে: শেয়ার্ড মেমরি এবং একটি ফাস্ট মেসেজ কিউ (FMQ), উভয়ই শুধুমাত্র C++ এ সমর্থিত।

  • শেয়ার করা মেমরি । অন্তর্নির্মিত HIDL টাইপ memory বরাদ্দ করা হয়েছে এমন ভাগ করা মেমরির প্রতিনিধিত্ব করে এমন একটি বস্তু পাস করতে ব্যবহৃত হয়। ভাগ করা মেমরি ম্যাপ করতে একটি গ্রহণ প্রক্রিয়া ব্যবহার করা যেতে পারে.
  • ফাস্ট মেসেজ কিউ (FMQ) । HIDL একটি টেমপ্লেটেড বার্তা সারি টাইপ প্রদান করে যা নো-ওয়েট মেসেজ-পাসিং প্রয়োগ করে। এটি পাসথ্রু বা বাইন্ডারাইজড মোডে কার্নেল বা সময়সূচী ব্যবহার করে না (আন্তঃ-ডিভাইস যোগাযোগে এই বৈশিষ্ট্যগুলি নেই)। সাধারণত, HAL তার সারির শেষ সেট আপ করে, এমন একটি বস্তু তৈরি করে যা বিল্ট-ইন HIDL টাইপ MQDescriptorSync বা MQDescriptorUnsync এর প্যারামিটারের মাধ্যমে RPC-এর মাধ্যমে পাস করা যেতে পারে। এই বস্তুটি সারির অন্য প্রান্ত সেট আপ করার জন্য গ্রহণ প্রক্রিয়া দ্বারা ব্যবহার করা যেতে পারে।
    • সিঙ্ক সারিগুলিকে ওভারফ্লো করার অনুমতি দেওয়া হয় না এবং শুধুমাত্র একজন পাঠক থাকতে পারে৷
    • আনসিঙ্ক সারিগুলিকে ওভারফ্লো করার অনুমতি দেওয়া হয়, এবং অনেক পাঠক থাকতে পারে, যার প্রত্যেককে অবশ্যই সময়মতো ডেটা পড়তে হবে বা এটি হারাতে হবে।
    কোন প্রকারকে আন্ডারফ্লো করার অনুমতি দেওয়া হয় না (একটি খালি সারি থেকে পড়া ব্যর্থ হয়), এবং প্রতিটি ধরণের শুধুমাত্র একজন লেখক থাকতে পারে।

FMQ সম্পর্কে আরও বিস্তারিত জানার জন্য, ফাস্ট মেসেজ কিউ (FMQ) দেখুন।