HIDL-এ লেখা প্রতিটি ইন্টারফেসের ভার্সন থাকতে হবে। কোনও HAL ইন্টারফেস প্রকাশ করার পরে, সেটি ফ্রিজ করা হয় এবং কোনও পরিবর্তন করতে হলে সেই ইন্টারফেসের নতুন ভার্সনে করতে হয়। প্রকাশিত ইন্টারফেস পরিবর্তন করা না গেলেও, অন্য ইন্টারফেসের মাধ্যমে এটি বাড়ানো যেতে পারে।
HIDL কোড স্ট্রাকচার
ব্যবহারকারীর সংজ্ঞায়িত টাইপ, ইন্টারফেস ও প্যাকেজে HIDL কোড সাজানো হয়:
- ব্যবহারকারী-নির্ধারিত ধরন (UDT)। HIDL, একগুচ্ছ প্রিমিটিভ ডেটা টাইপের অ্যাক্সেস প্রদান করে যা স্ট্রাকচার, ইউনিয়ন ও এনুমেরেশনের মাধ্যমে আরও জটিল ধরনের ডেটা কম্পোজ করতে ব্যবহার করা যেতে পারে। UDT-কে ইন্টারফেসের মেথডে পাস করা হয় এবং এটিকে প্যাকেজ (সব ইন্টারফেসের জন্য সাধারণ) বা ইন্টারফেসের লোকাল লেভেলে ডিফাইন করা যায়।
- ইন্টারফেস। HIDL-এর একটি মৌলিক বিল্ডিং ব্লক হিসেবে, ইন্টারফেসে UDT ও মেথড ঘোষণা থাকে। ইন্টারফেস অন্য ইন্টারফেস থেকেও ইনহেরিট করতে পারে।
- প্যাকেজ। সম্পর্কিত HIDL ইন্টারফেস এবং ডেটা
টাইপকে সংগঠিত করে যার উপর সেগুলি কাজ করে। একটি প্যাকেজ নাম এবং একটি সংস্করণ দ্বারা চিহ্নিত করা হয় এবং
নিম্নলিখিত অন্তর্ভুক্ত:
types.halনামের ডেটার ধরন সংক্রান্ত সংজ্ঞা ফাইল।- শূন্য বা একাধিক ইন্টারফেস, প্রতিটি নিজস্ব
.halফাইলে।
ডেটা-টাইপ ডেফিনিশন ফাইল types.hal-এ শুধু UDT (সব
প্যাকেজ-লেভেল UDT একটি ফাইলে রাখা হয়) থাকে। টার্গেট ভাষায় উপস্থাপনা প্যাকেজের সব ইন্টারফেসে উপলভ্য।
ভার্সনিং ফিলোজফি
কোনও HIDL প্যাকেজ (যেমন android.hardware.nfc) কোনও নির্দিষ্ট ভার্সনের (যেমন 1.0) জন্য প্রকাশ করার পরে
সেটি অপরিবর্তনীয় হয়ে যায়; সেটি
পরিবর্তন করা যায় না। প্যাকেজের ইন্টারফেসে পরিবর্তন বা এর UDT-তে কোনও
পরিবর্তন শুধুমাত্র অন্য প্যাকেজে করা যেতে পারে।
HIDL-এ, ভার্সনিং ইন্টারফেস লেভেলে নয়, প্যাকেজ লেভেলে প্রযোজ্য হয়, এবং প্যাকেজের মধ্যে থাকা সব ইন্টারফেস ও UDT একই ভার্সন শেয়ার করে। প্যাচ লেভেল ও বিল্ড-মেটাডেটা কম্পোনেন্ট ছাড়া প্যাকেজ ভার্সন সিমান্টিক ভার্সনিং মেনে চলে। কোনও নির্দিষ্ট প্যাকেজের ক্ষেত্রে, মাইনর ভার্সন বাম্পের অর্থ হল প্যাকেজের নতুন ভার্সনটি পুরনো প্যাকেজের সাথে ব্যাকওয়ার্ড-কম্প্যাটিবল এবং মেজর ভার্সন বাম্পের অর্থ হল প্যাকেজের নতুন ভার্সনটি পুরনো প্যাকেজের সাথে ব্যাকওয়ার্ড-কম্প্যাটিবল নয়।
ধারণাগতভাবে, একটি প্যাকেজ অন্য প্যাকেজের সাথে বিভিন্ন উপায়ে সম্পর্কিত হতে পারে:
- একদমই না।
- প্যাকেজ-লেভেল ব্যাকওয়ার্ড-কম্প্যাটিবল এক্সটেনসিবিলিটি। এটি
কোনও প্যাকেজের নতুন মাইনর-ভার্সন আপরেভের (পরবর্তী ইনক্রিমেন্ট করা রিভিশন) জন্য ঘটে;
নতুন প্যাকেজের নাম এবং মেজর ভার্সন পুরনো প্যাকেজের মতোই, তবে
মাইনর ভার্সনটি আরও উন্নত। কার্যকারিতার দিক থেকে, নতুন প্যাকেজটি পুরনো প্যাকেজের
সুপারসেট, অর্থাৎ:
- নতুন প্যাকেজে প্যারেন্ট প্যাকেজের টপ-লেভেল ইন্টারফেস থাকে,
যদিও ইন্টারফেসে নতুন পদ্ধতি, নতুন ইন্টারফেস-লোকাল UDT (নিচে বর্ণিত
ইন্টারফেস-লেভেল এক্সটেনশন) এবং
types.hal-এ নতুন UDT থাকতে পারে। - নতুন প্যাকেজে নতুন ইন্টারফেসও যোগ করা যেতে পারে।
- নতুন প্যাকেজে প্যারেন্ট প্যাকেজের সব ধরনের ডেটা উপস্থিত থাকে এবং পুরনো প্যাকেজের (সম্ভাব্য আবার প্রয়োগ করা) পদ্ধতির মাধ্যমে তা ম্যানেজ করা যায়।
- এছাড়াও, নতুন ডেটা টাইপ যোগ করা যেতে পারে যা নতুন পদ্ধতি বা আগে থেকে থাকা ইন্টারফেসের মাধ্যমে ব্যবহার করা যেতে পারে। অথবা নতুন ইন্টারফেসের মাধ্যমে।
- নতুন প্যাকেজে প্যারেন্ট প্যাকেজের টপ-লেভেল ইন্টারফেস থাকে,
যদিও ইন্টারফেসে নতুন পদ্ধতি, নতুন ইন্টারফেস-লোকাল UDT (নিচে বর্ণিত
ইন্টারফেস-লেভেল এক্সটেনশন) এবং
- ইন্টারফেস-লেভেল ব্যাকওয়ার্ড-কম্প্যাটিবল এক্সটেনসিবিলিটি। নতুন
প্যাকেজটি মূল প্যাকেজকে এক্সটেন্ড করতে পারে। এর মধ্যে এমন ইন্টারফেস থাকে যেগুলি যৌক্তিকভাবে আলাদা
এবং যেগুলি মূল কার্যকারিতা নয়, বরং অতিরিক্ত কার্যকারিতা প্রদান করে।
এই উদ্দেশ্যে, নিম্নলিখিত বিষয়গুলি কাঙ্ক্ষিত হতে পারে:
- নতুন প্যাকেজের ইন্টারফেসের জন্য পুরনো প্যাকেজের ডেটার ধরন ব্যবহার করতে হবে।
- নতুন প্যাকেজের ইন্টারফেস এক বা একাধিক পুরনো প্যাকেজের ইন্টারফেসকে এক্সটেন্ড করতে পারে।
- আসল ব্যাকওয়ার্ড ইনকমপ্যাটিবিলিটি বাড়ানো। এটি প্যাকেজের মেজর-ভার্সন আপরেভ এবং দুটির মধ্যে কোনও কোরিলেশন থাকার প্রয়োজন নেই। To the extent that there is, it can be expressed with a combination of types from the older version of the package, and inheritance of a subset of old-package interfaces.
ইন্টারফেস স্ট্রাকচার করা
একটি সুগঠিত ইন্টারফেসের জন্য, নতুন ধরনের কার্যকারিতা যোগ করা যা আসল ডিজাইনের অংশ নয়, HIDL-এ একটি পরিবর্তন প্রয়োজন ইন্টারফেস। অন্যদিকে, আপনি যদি ইন্টারফেসের দুই দিকেই পরিবর্তন করতে পারেন বা করার আশা করেন, যা ইন্টারফেসের কোনও পরিবর্তন না করেই নতুন কার্যকারিতা যোগ করে, তাহলে ইন্টারফেসটি স্ট্রাকচার্ড নয়।
Treble আলাদাভাবে কম্পাইল করা ভেন্ডর ও সিস্টেম কম্পোনেন্টকে সাপোর্ট করে, যেখানে
vendor.img কোনও ডিভাইসে এবং system.img আলাদাভাবে কম্পাইল করা
যায়। vendor.img ও
system.img-এর মধ্যে সমস্ত ইন্টার্যাকশনকে স্পষ্টভাবে ও পুঙ্খানুপুঙ্খভাবে সংজ্ঞায়িত করতে হবে যাতে সেগুলি
বহু বছর ধরে কাজ করা চালিয়ে যেতে পারে। এর মধ্যে অনেক API সারফেস অন্তর্ভুক্ত, তবে একটি প্রধান
সারফেস হল IPC মেকানিজম যা HIDL, ইন্টারপ্রসেস কমিউনিকেশনের জন্য
system.img/vendor.img বাউন্ডারিতে ব্যবহার করে।
প্রয়োজনীয়তা
HIDL-এর মাধ্যমে পাস করা সব ডেটা স্পষ্টভাবে সংজ্ঞায়িত করতে হবে। যাতে ইমপ্লিমেন্টেশন ও ক্লায়েন্ট একসাথে কাজ করা চালিয়ে যেতে পারে, এমনকি সেগুলি আলাদাভাবে কম্পাইল করা বা স্বতন্ত্রভাবে ডেভেলপ করা হলেও, ডেটাকে নিম্নলিখিত প্রয়োজনীয়তা মেনে চলতে হবে:
- সরাসরি HIDL-এ (structs enums ইত্যাদি ব্যবহার করে) বর্ণনা করা যেতে পারে, সাথে নাম ও অর্থ সহায়ক হতে হবে।
- ISO/IEC 7816-এর মতো কোনও পাবলিক স্ট্যান্ডার্ডের মাধ্যমে বর্ণনা করা যেতে পারে।
- হার্ডওয়্যার স্ট্যান্ডার্ড বা হার্ডওয়্যারের ফিজিক্যাল লেআউট দ্বারা বর্ণনা করা যেতে পারে।
- প্রয়োজন হলে, অস্বচ্ছ ডেটা (যেমন, পাবলিক কী, আইডি ইত্যাদি) হতে পারে।
অস্বচ্ছ ডেটা ব্যবহার করা হলে, HIDL
ইন্টারফেসের কোনও একটি দিক থেকে সেটি পড়তে হবে। যেমন, vendor.img কোড যদি system.img-এর কোনও কম্পোনেন্টকে
স্ট্রিং মেসেজ বা vec<uint8_t> ডেটা দেয়, তাহলে সেই ডেটা system.img নিজে পার্স করতে পারবে না;
এটি শুধুমাত্র vendor.img-এর কাছে ব্যাখ্যা করার জন্য ফেরত পাঠানো যেতে পারে। vendor.img থেকে system.img-এ
অথবা অন্য ডিভাইসে কোনও ভ্যালু পাস করার সময়
ডেটার ফর্ম্যাট এবং সেটি কীভাবে
ব্যাখ্যা করতে হবে তা অবশ্যই সঠিকভাবে বর্ণনা করতে হবে এবং এটি এখনও
ইন্টারফেসের অংশ।
নির্দেশিকা
আপনাকে শুধুমাত্র .hal ফাইল ব্যবহার করে HAL-এর কোনও ইমপ্লিমেন্টেশন বা ক্লায়েন্ট লিখতে পারতে হবে (অর্থাৎ, আপনাকে Android সোর্স বা পাবলিক স্ট্যান্ডার্ড দেখতে হবে না)। আমরা ঠিক কী ধরনের আচরণ প্রয়োজন তা নির্দিষ্ট করে দেওয়ার সাজেশন দিই। "কোনও প্রয়োগ A বা B করতে পারে" এই ধরনের বিবৃতি প্রয়োগকে যেসব ক্লায়েন্টের সাথে ডেভেলপ করা হয়েছে তাদের সাথে মিশে যেতে উৎসাহিত করে।
HIDL কোড লেআউট
HIDL-এ কোর ও ভেন্ডর প্যাকেজ অন্তর্ভুক্ত।
কোর HIDL ইন্টারফেস হল সেগুলি যা Google দ্বারা নির্দিষ্ট করা হয়েছে। android.hardware. দিয়ে শুরু হওয়া এবং সাবসিস্টেমের
নামে নামকরণ করা প্যাকেজ, সম্ভাব্যভাবে নেস্টেড লেভেলের
নামকরণ। যেমন, NFC প্যাকেজের নাম হল
android.hardware.nfc এবং ক্যামেরা প্যাকেজের নাম হল
android.hardware.camera. সাধারণত, একটি কোর প্যাকেজের নাম থাকে
android.hardware.[name1].[name2]….
HIDL প্যাকেজের নামে সাথে সাথে একটি ভার্সনও থাকে। যেমন, প্যাকেজ
android.hardware.camera 3.4 ভার্সনে থাকতে পারে; এটি
গুরুত্বপূর্ণ, কারণ প্যাকেজের ভার্সন সোর্স ট্রিতে এর প্লেসমেন্টকে প্রভাবিত করে।
বিল্ড সিস্টেমে
hardware/interfaces/-এর অধীনে সবকটি মূল প্যাকেজ রাখা হয়। $m.$n ভার্সনের প্যাকেজটিandroid.hardware.[name1][name2]
hardware/interfaces/name1/name2/…/$m.$n/-এর মধ্যে আছে;
android.hardware.camera ভার্সনের প্যাকেজটি 3.4
hardware/interfaces/camera/3.4/. ডিরেক্টরিতে আছে। প্যাকেজ প্রিফিক্স android.hardware. ও পাথ
hardware/interfaces/-এর মধ্যে
হার্ড-কোডেড ম্যাপিং আছে।
নন-কোর (ভেন্ডর) প্যাকেজ হল সেইসব প্যাকেজ যা SoC ভেন্ডর বা ODM তৈরি করে। নন-কোর প্যাকেজের
প্রিফিক্স হল vendor.$(VENDOR).hardware. যেখানে
$(VENDOR)SoC ভেন্ডর বা OEM/ODM-কে বোঝায়। এটি ট্রি-তে
vendor/$(VENDOR)/interfaces পাথের সাথে ম্যাপ করে (এই ম্যাপিংও
হার্ড-কোড করা)।
সম্পূর্ণরূপে উপযুক্ত ব্যবহারকারী-নির্ধারিত-ধরনের নাম
HIDL-এ, প্রতিটি UDT-র একটি সম্পূর্ণ কোয়ালিফায়েড নাম থাকে যার মধ্যে UDT-র নাম,
যে প্যাকেজে UDT ডিফাইন করা হয়েছে সেটির নাম এবং প্যাকেজ ভার্সন থাকে। টাইপের ইনস্ট্যান্স ঘোষণা করা হলে শুধুমাত্র তখনই
সম্পূর্ণ কোয়ালিফায়েড নাম ব্যবহার করা হয় এবং টাইপটি যেখানে
নির্ধারণ করা হয় সেখানে নয়। যেমন, ধরে নিন যে package
android.hardware.nfc, version 1.0 একটি struct
সংজ্ঞায়িত করে যার নাম NfcData। ঘোষণার সাইটে (types.hal-এ বা ইন্টারফেসের ঘোষণার মধ্যে), ঘোষণায় শুধু বলা হয়:
struct NfcData {
vec<uint8_t> data;
};এই ধরনের কোনও ইনস্ট্যান্স ঘোষণা করার সময় (ডেটা স্ট্রাকচারের মধ্যে বা মেথড প্যারামিটার হিসেবে), সম্পূর্ণ কোয়ালিফায়েড টাইপের নাম ব্যবহার করুন:
android.hardware.nfc@1.0::NfcData
সাধারণ সিনট্যাক্স হল
PACKAGE@VERSION::UDT, যেখানে:
PACKAGEহল HIDL প্যাকেজের ডট দিয়ে আলাদা করা নাম (যেমন,android.hardware.nfc)।VERSIONহল প্যাকেজের ডট-সেপারেটেড মেজর.মাইনর-ভার্সন ফর্ম্যাট (যেমন,1.0)।UDTহল HIDL UDT-র ডট-সেপারেটেড নাম। যেহেতু HIDL নেস্টেড UDT কাজ করে এবং HIDL ইন্টারফেসে UDT (এক ধরনের নেস্টেড ঘোষণা) থাকতে পারে, তাই নাম অ্যাক্সেস করার জন্য ডট ব্যবহার করা হয়।
যেমন, প্যাকেজ android.hardware.example ভার্সনের
1.0 সাধারণ
টাইপ ফাইলে নিম্নলিখিত নেস্টেড ঘোষণাটি যদি সংজ্ঞায়িত করা থাকে:
// types.hal package android.hardware.example@1.0; struct Foo { struct Bar { // … }; Bar cheers; };
Bar-এর সম্পূর্ণ উপযুক্ত নাম হল
android.hardware.example@1.0::Foo.Bar। উপরের প্যাকেজের মধ্যে থাকার পাশাপাশি, নেস্ট করা ডিক্লারেশন যদি
IQuux নামের কোনও ইন্টারফেসে থাকে:
// IQuux.hal package android.hardware.example@1.0; interface IQuux { struct Foo { struct Bar { // … }; Bar cheers; }; doSomething(Foo f) generates (Foo.Bar fb); };
Bar-এর সম্পূর্ণ উপযুক্ত নাম হল
android.hardware.example@1.0::IQuux.Foo.Bar।
দুটি ক্ষেত্রেই, Foo-এর ঘোষণা অনুযায়ী Bar-কে শুধুমাত্র Bar হিসেবে উল্লেখ করা যেতে পারে।
প্যাকেজ বা
ইন্টারফেস লেভেলে, আপনাকে অবশ্যই Foo-এর মাধ্যমে Bar উল্লেখ করতে হবে:
Foo.Bar, যেমন উপরে doSomething
মেথডের ঘোষণায় করা হয়েছে। অথবা, আপনি পদ্ধতিটি আরও বিস্তারিতভাবে এভাবে ঘোষণা করতে পারেন:
// IQuux.hal doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);
সম্পূর্ণভাবে উপযুক্ত এনুমেরেশন ভ্যালু
UDT যদি enum ধরনের হয়, তাহলে enum ধরনের প্রতিটি মানের একটি
সম্পূর্ণ কোয়ালিফায়েড নাম থাকে যা enum ধরনের সম্পূর্ণ কোয়ালিফায়েড নাম দিয়ে শুরু হয়,
তারপরে কোলন ও তারপরে enum মানের নাম থাকে। যেমন,
ধরে নিন যে প্যাকেজ android.hardware.nfc, ভার্সন 1.0
একটি এনুম টাইপ NfcStatus সংজ্ঞায়িত করে:
enum NfcStatus { STATUS_OK, STATUS_FAILED };
STATUS_OK-এর কথা উল্লেখ করার সময়, সম্পূর্ণভাবে উপযুক্ত নাম হল:
android.hardware.nfc@1.0::NfcStatus:STATUS_OK
সাধারণ সিনট্যাক্স হল
PACKAGE@VERSION::UDT:VALUE,
যেখানে:
PACKAGE@VERSION::UDTহল এনুম টাইপের একদম একই সম্পূর্ণ উপযুক্ত নাম।VALUEহল ভ্যালুর নাম।
অটোমেটিক অনুমান সংক্রান্ত নিয়ম
সম্পূর্ণভাবে উপযুক্ত UDT নাম উল্লেখ করার প্রয়োজন নেই। UDT নামের ক্ষেত্রে নিরাপদে নিম্নলিখিত বিষয়গুলি বাদ দেওয়া যেতে পারে:
- প্যাকেজ, যেমন
@1.0::IFoo.Type - প্যাকেজ ও ভার্সন, যেমন
IFoo.Type
HIDL, অটো-ইন্টারফারেন্স নিয়ম (কম নম্বর মানে বেশি অগ্রাধিকার) ব্যবহার করে নাম সম্পূর্ণ করার চেষ্টা করে।
নিয়ম ১
কোনও প্যাকেজ ও ভার্সন প্রদান করা না হলে, একটি স্থানীয় নাম লুক-আপ করার চেষ্টা করা হয়। উদাহরণ:
interface Nfc { typedef string NfcErrorMessage; send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m); };
NfcErrorMessage লোকাল ডিভাইসে খোঁজা হয় এবং typedef
এর উপরে সেটি পাওয়া যায়। NfcData স্থানীয়ভাবেও খোঁজা হয়, কিন্তু এটি স্থানীয়ভাবে
সংজ্ঞায়িত না হওয়ায়, নিয়ম ২ ও ৩ ব্যবহার করা হয়। @1.0::NfcStatus
একটি ভার্সন প্রদান করে, তাই ১ নম্বর নিয়ম প্রযোজ্য নয়।
নিয়ম ২
নিয়ম ১ কাজ না করলে এবং সম্পূর্ণরূপে উপযুক্ত নামের কোনও কম্পোনেন্ট না থাকলে
(প্যাকেজ, ভার্সন অথবা প্যাকেজ ও ভার্সন), বর্তমান প্যাকেজের তথ্য থেকে
কম্পোনেন্ট অটোফিল করা হয়। তারপরে HIDL কম্পাইলার
বর্তমান ফাইলে (এবং সমস্ত ইমপোর্ট করা ফাইলে) অটোফিল করা সম্পূর্ণ কোয়ালিফায়েড নাম খোঁজে।
উপরের উদাহরণ ব্যবহার করে, ধরে নিন যে ExtendedNfcData
-এর ঘোষণা NfcData-এর মতো একই প্যাকেজে (android.hardware.nfc) একই
ভার্সনে (1.0) করা হয়েছে, যেমনটি নিচে দেখানো হয়েছে:
struct ExtendedNfcData {
NfcData base;
// … additional members
};HIDL কম্পাইলার, সম্পূর্ণ কোয়ালিফায়েড UDT নাম
android.hardware.nfc@1.0::NfcData তৈরি করতে
বর্তমান প্যাকেজ থেকে প্যাকেজের নাম ও ভার্সনের নাম পূরণ করে। নামটি যেহেতু
বর্তমান প্যাকেজে আছে (ধরে নেওয়া হচ্ছে যে এটি সঠিকভাবে ইমপোর্ট করা হয়েছে), তাই এটি
ঘোষণার জন্য ব্যবহার করা হয়।
বর্তমান প্যাকেজের কোনও নাম তখনই ইমপোর্ট করা হয় যদি নিম্নলিখিতগুলির মধ্যে কোনও একটি সত্য হয়:
importবিবৃতি সহ এটি স্পষ্টভাবে ইমপোর্ট করা হয়েছে।- বর্তমান প্যাকেজে
types.hal-এ এটি সংজ্ঞায়িত করা আছে
NfcData শুধুমাত্র ভার্সন নম্বর
দ্বারা কোয়ালিফাই করলে একই প্রসেস অনুসরণ করা হয়:
struct ExtendedNfcData { // autofill the current package name (android.hardware.nfc) @1.0::NfcData base; // … additional members };
নিয়ম ৩
নিয়ম ২ কোনও ম্যাচ তৈরি করতে না পারলে (বর্তমান
প্যাকেজে UDT সংজ্ঞায়িত করা নেই), HIDL কম্পাইলার সব ইমপোর্ট করা প্যাকেজের মধ্যে ম্যাচ খোঁজে।
উপরের উদাহরণ ব্যবহার করে, ধরে নিন যে ExtendedNfcData-কে
android.hardware.nfc প্যাকেজের 1.1 ভার্সনে ঘোষণা করা হয়েছে,
1.1 1.0 ইমপোর্ট করা হয়েছে যেভাবে করা উচিত (দেখুন
প্যাকেজ-লেভেল এক্সটেনশন) এবং সংজ্ঞা
শুধুমাত্র UDT-র নাম নির্দিষ্ট করে:
struct ExtendedNfcData {
NfcData base;
// … additional members
};কম্পাইলার NfcData নামের যেকোনও UDT খোঁজে এবং 1.0 ভার্সনে
android.hardware.nfc-এ একটি খুঁজে পায়, যার ফলে android.hardware.nfc@1.0::NfcData-এর
সম্পূর্ণ কোয়ালিফায়েড UDT পাওয়া যায়। প্রদত্ত আংশিকভাবে উপযুক্ত UDT-এর জন্য একাধিক মিল পাওয়া গেলে, HIDL কম্পাইলার
সমস্যা দেখায়।
উদাহরণ
নিয়ম ২ ব্যবহার করে, বর্তমান প্যাকেজে সংজ্ঞায়িত ইমপোর্ট করা প্রকারকে অন্য প্যাকেজ থেকে ইমপোর্ট করা প্রকারের চেয়ে বেশি গুরুত্ব দেওয়া হয়:
// hardware/interfaces/foo/1.0/types.hal package android.hardware.foo@1.0; struct S {}; // hardware/interfaces/foo/1.0/IFooCallback.hal package android.hardware.foo@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/types.hal package android.hardware.bar@1.0; typedef string S; // hardware/interfaces/bar/1.0/IFooCallback.hal package android.hardware.bar@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/IBar.hal package android.hardware.bar@1.0; import android.hardware.foo@1.0; interface IBar { baz1(S s); // android.hardware.bar@1.0::S baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback };
S-কেandroid.hardware.bar@1.0::Sহিসেবে ইন্টারপোলেট করা হয়েছে এবং এটিbar/1.0/types.hal-এ পাওয়া গেছে (কারণtypes.halঅটোমেটিক ইমপোর্ট করা হয়েছে)।- নিয়ম ২ ব্যবহার করে
IFooCallback-কেandroid.hardware.bar@1.0::IFooCallbackহিসেবে ইন্টারপোলেট করা হয়েছে, কিন্তু এটি খুঁজে পাওয়া যায়নি কারণbar/1.0/IFooCallback.halঅটোমেটিক ইমপোর্ট করা হয়নি (যেমনtypes.halকরা হয়)। তাই, নিয়ম ৩ এটিকেandroid.hardware.foo@1.0::IFooCallbackহিসেবে সমাধান করে, যাimport android.hardware.foo@1.0;-এর মাধ্যমে ইমপোর্ট করা হয়)।
types.hal
প্রতিটি HIDL প্যাকেজে UDT সহ একটি types.hal ফাইল থাকে
যা সেই প্যাকেজে অংশগ্রহণকারী সমস্ত ইন্টারফেসের মধ্যে শেয়ার করা হয়। HIDL টাইপ
সবসময়ই পাবলিক হয়; UDT
types.hal-এ বা ইন্টারফেস ঘোষণার মধ্যে ঘোষণা করা হোক না কেন, এই টাইপগুলি
যে স্কোপে ডিফাইন করা হয়েছে তার বাইরে অ্যাক্সেস করা যায়। types.hal
কোনও প্যাকেজের পাবলিক API-এর বিবরণ দেওয়ার জন্য নয়, বরং প্যাকেজের মধ্যে থাকা সব ইন্টারফেসের
ব্যবহার করা UDT হোস্ট করার জন্য তৈরি করা হয়েছে। HIDL-এর প্রকৃতির কারণে, সব UDT
ই ইন্টারফেসের অংশ।
types.hal-এ UDT ও import স্টেটমেন্ট থাকে।
কারণ types.hal প্যাকেজের প্রতিটি ইন্টারফেসের জন্য উপলভ্য করা হয়েছে (এটি একটি ইমপ্লিসিট ইমপোর্ট), এইসব import স্টেটমেন্টকে
সংজ্ঞা অনুযায়ী প্যাকেজ-লেভেল বলা হয়। types.hal-এর UDT-তে ইমপোর্ট করা UDT ও ইন্টারফেসও
অন্তর্ভুক্ত থাকতে পারে।
যেমন, IFoo.hal-এর জন্য:
package android.hardware.foo@1.0; // whole package import import android.hardware.bar@1.0; // types only import import android.hardware.baz@1.0::types; // partial imports import android.hardware.qux@1.0::IQux.Quux; // partial imports import android.hardware.quuz@1.0::Quuz;
নিম্নলিখিতগুলি ইমপোর্ট করা হয়:
android.hidl.base@1.0::IBase(পরোক্ষভাবে)android.hardware.foo@1.0::types(পরোক্ষভাবে)android.hardware.bar@1.0-এর সবকিছু (এর মধ্যে সব ইন্টারফেস ও তারtypes.halঅন্তর্ভুক্ত)android.hardware.baz@1.0::typesথেকেtypes.hal(android.hardware.baz@1.0-এর ইন্টারফেস ইমপোর্ট করা হয়নি)IQux.halওtypes.halথেকেandroid.hardware.qux@1.0android.hardware.quuz@1.0থেকেQuuz(ধরে নেওয়া হচ্ছে যেQuuz,types.hal-এ সংজ্ঞায়িত করা আছে, সম্পূর্ণtypes.halফাইল পার্স করা হয়েছে, কিন্তুQuuzছাড়া অন্য কোনও ধরন ইমপোর্ট করা হয়নি)।
ইন্টারফেস-লেভেল ভার্সনিং
প্যাকেজের মধ্যে থাকা প্রতিটি ইন্টারফেস নিজস্ব ফাইলে থাকে। যে প্যাকেজের সাথে
ইন্টারফেসটি যুক্ত, সেটি ইন্টারফেসের সবচেয়ে উপরে
package স্টেটমেন্ট ব্যবহার করে ঘোষণা করা হয়। প্যাকেজ ঘোষণার পরে, শূন্য বা তার বেশি
ইন্টারফেস-লেভেল ইমপোর্ট (আংশিক বা সম্পূর্ণ-প্যাকেজ) তালিকাভুক্ত করা হতে পারে। যেমন:
package android.hardware.nfc@1.0;
HIDL-এ, ইন্টারফেস
extends কীওয়ার্ড ব্যবহার করে অন্যান্য ইন্টারফেস থেকে ইনহেরিট করতে পারে। কোনও ইন্টারফেসকে অন্য ইন্টারফেসের এক্সটেন্ড করতে হলে, import স্টেটমেন্টের মাধ্যমে
সেটির অ্যাক্সেস থাকতে হবে। এক্সটেন্ড করা হচ্ছে এমন
ইন্টারফেসের নাম (বেস ইন্টারফেস) উপরে ব্যাখ্যা করা টাইপ-নেম
কোয়ালিফিকেশন সংক্রান্ত নিয়ম মেনে চলে। কোনও ইন্টারফেস শুধুমাত্র একটি ইন্টারফেস থেকে ইনহেরিট করতে পারে;
HIDL একাধিক ইনহেরিটেন্স সমর্থন করে না।
নিচে দেওয়া আপরেভ ভার্সনিংয়ের উদাহরণে নিম্নলিখিত প্যাকেজ ব্যবহার করা হয়েছে:
// types.hal package android.hardware.example@1.0 struct Foo { struct Bar { vec<uint32_t> val; }; }; // IQuux.hal package android.hardware.example@1.0 interface IQuux { fromFooToBar(Foo f) generates (Foo.Bar b); }
Uprev সংক্রান্ত নিয়ম
প্যাকেজ package@major.minor নির্ধারণ করতে, A অথবা B-এর সবকটি
সত্য হতে হবে:
| নিয়ম ক | "Is a start minor version": আগের সব মাইনর ভার্সন,
package@major.0, package@major.1, …,
package@major.(minor-1) অবশ্যই সংজ্ঞায়িত করা যাবে না।
|
|---|
| নিয়ম 'খ' | নিম্নলিখিত সবকটি বিষয় সত্যি:
|
|---|
নিয়ম 'ক'-এর কারণে:
- প্যাকেজটি যেকোনও মাইনর ভার্সন নম্বর দিয়ে শুরু হতে পারে (যেমন,
android.hardware.biometrics.fingerprintথেকে শুরু হয়@2.1।) - "
android.hardware.foo@1.0সংজ্ঞায়িত করা নেই" এই প্রয়োজনীয়তার অর্থ হলhardware/interfaces/foo/1.0ডিরেক্টরি যেন না থাকে।
তবে, একই প্যাকেজের নাম কিন্তু আলাদা মেজর ভার্সন (যেমন,
android.hardware.camera.device-এ @1.0 ও
@3.2 দু'টিই আছে; @3.2-এর সাথে @1.0-এর
ইন্টার্যাক্ট করার প্রয়োজন নেই) থাকলে, নিয়ম 'ক' সেটির উপর প্রভাব ফেলে না। তাই, @3.2::IExtFoo, @1.0::IFoo-এর
এক্সটেনশন হতে পারে।
প্রদান করা প্যাকেজের নাম আলাদা হলে,
package@major.minor::IBar আলাদা নামের ইন্টারফেস থেকে
এক্সটেন্ড করতে পারে (যেমন, android.hardware.bar@1.0::IBar এক্সটেন্ড
করতে পারে android.hardware.baz@2.2::IBaz)। কোনও ইন্টারফেস extend কীওয়ার্ডের
মাধ্যমে স্পষ্টভাবে সুপার টাইপ ঘোষণা না করলে, এটি
android.hidl.base@1.0::IBase এক্সটেন্ড করে (IBase
নিজেকে বাদ দিয়ে)।
B.2 ও B.3 একই সময়ে অনুসরণ করতে হবে। যেমন, android.hardware.foo@1.1::IFoo যদি
android.hardware.foo@1.0::IFoo-কে এক্সটেন্ড করে B.2 নিয়ম পাস করে, তাহলেও
android.hardware.foo@1.1::IExtBar যদি
android.hardware.foo@1.0::IBar-কে এক্সটেন্ড করে, তাহলে এটি এখনও সঠিক uprev নয়।
Uprev ইন্টারফেস
android.hardware.example@1.0 (উপরে সংজ্ঞায়িত) থেকে
@1.1-এ আপগ্রেড করতে:
// types.hal package android.hardware.example@1.1; import android.hardware.example@1.0; // IQuux.hal package android.hardware.example@1.1 interface IQuux extends @1.0::IQuux { fromBarToFoo(Foo.Bar b) generates (Foo f); }
এটি types.hal-এ android.hardware.example-এর 1.0 ভার্সনের একটি প্যাকেজ-লেভেল import।
প্যাকেজের 1.1 ভার্সনে কোনও নতুন
UDT যোগ করা না হলেও, 1.0 ভার্সনে UDT-এর রেফারেন্স
এখনও প্রয়োজন, তাই types.hal-এ প্যাকেজ-লেভেল ইমপোর্ট
প্রয়োজন। (IQuux.hal-এ ইন্টারফেস লেভেল ইমপোর্ট করেও একই ফলাফল পাওয়া যেত।
)
extends @1.0::IQuux-এ
IQuux-এর ঘোষণায়, আমরা IQuux-এর সেই ভার্সন নির্দিষ্ট করেছি যা
ইনহেরিট করা হচ্ছে (দ্ব্যর্থতা নিরসন প্রয়োজন কারণ IQuux একটি ইন্টারফেস ঘোষণা করতে এবং
ইন্টারফেস থেকে ইনহেরিট করতে ব্যবহার করা হয়)। যেহেতু ঘোষণাগুলি
কেবলমাত্র নাম যা ঘোষণার সাইটে সমস্ত প্যাকেজ এবং ভার্সন অ্যাট্রিবিউটকে ইনহেরিট করে, তাই ডিসঅ্যাম্বিগুয়েশন অবশ্যই বেস ইন্টারফেসের নামে হতে হবে; আমরা
সম্পূর্ণ কোয়ালিফায়েড UDT-ও ব্যবহার করতে পারতাম, কিন্তু তা
অপ্রয়োজনীয় হত।
নতুন ইন্টারফেস IQuux @1.0::IQuux থেকে পাওয়া পদ্ধতিকে আবার ঘোষণা করে না
fromFooToBar(); এটি শুধু
যোগ করা নতুন পদ্ধতিকে তালিকাভুক্ত করে fromBarToFoo()। HIDL-এ, ইনহেরিট করা
মেথড চাইল্ড ইন্টারফেসে আবার ঘোষণা করা যাবে না, তাই
IQuux ইন্টারফেস fromFooToBar()
মেথড স্পষ্টভাবে ঘোষণা করতে পারবে না।
Uprev কনভেনশন
কখনও কখনও এক্সটেন্ড করা ইন্টারফেসের নাম পরিবর্তন করতে হয়। আমরা সাজেস্ট করি যে এনাম এক্সটেনশন, স্ট্রাকচার ও ইউনিয়নের নাম যেন সেগুলির এক্সটেনশনের নামের সাথে একই হয় যদি না সেগুলি এতটাই আলাদা হয় যে নতুন নাম দেওয়া প্রয়োজন। উদাহরণ:
// in parent hal file enum Brightness : uint32_t { NONE, WHITE }; // in child hal file extending the existing set with additional similar values enum Brightness : @1.0::Brightness { AUTOMATIC }; // extending the existing set with values that require a new, more descriptive name: enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };
কোনও পদ্ধতির নতুন সিমান্টিক নাম থাকলে (যেমন
fooWithLocation) সেটিই পছন্দ করা হয়। অন্যথায়, এটি যেটির এক্সটেনশন,
সেটির মতো একই নাম দিতে হবে। যেমন, @1.1::IFoo-এ foo_1_1 পদ্ধতিটি
@1.0::IFoo-এ foo পদ্ধতির কার্যকারিতা
প্রতিস্থাপন করতে পারে যদি আরও ভাল
বিকল্প নাম না থাকে।
প্যাকেজ-লেভেল ভার্সনিং
HIDL ভার্সনিং প্যাকেজ লেভেলে হয়; কোনও প্যাকেজ প্রকাশ করার পরে, এটি পরিবর্তন করা যায় না (এর ইন্টারফেস ও UDT-এর সেট পরিবর্তন করা যায় না)। প্যাকেজগুলি একে অপরের সাথে বিভিন্ন উপায়ে সম্পর্কিত হতে পারে, যার সবকটিই ইন্টারফেস-লেভেল ইনহেরিটেন্স এবং কম্পোজিশনের মাধ্যমে UDT তৈরির সংমিশ্রণের মাধ্যমে প্রকাশ করা যায়।
তবে, এক ধরনের সম্পর্ক কঠোরভাবে সংজ্ঞায়িত করা হয় এবং অবশ্যই প্রয়োগ করতে হবে: প্যাকেজ-লেভেল ব্যাকওয়ার্ড-কম্প্যাটিবল ইনহেরিটেন্স। এই পরিস্থিতিতে, পেরেন্ট প্যাকেজ হল সেই প্যাকেজ যা থেকে ইনহেরিট করা হচ্ছে এবং চাইল্ড প্যাকেজ হল সেই প্যাকেজ যা পেরেন্ট প্যাকেজকে এক্সটেন্ড করছে। প্যাকেজ-লেভেল পশ্চাৎমুখী-মানানসই ইনহেরিটেন্স সংক্রান্ত নিয়ম নিচে দেওয়া হল:
- চাইল্ড প্যাকেজের ইন্টারফেসগুলি পেরেন্ট প্যাকেজের সব টপ-লেভেল ইন্টারফেস থেকে ইনহেরিট করা হয়।
- নতুন প্যাকেজে নতুন ইন্টারফেসও যোগ করা যেতে পারে (অন্য প্যাকেজের অন্যান্য ইন্টারফেসের সাথে সম্পর্কিত কোনও বিধিনিষেধ নেই)।
- এছাড়াও, নতুন ডেটা টাইপ যোগ করা যেতে পারে যা নতুন ইন্টারফেসের মাধ্যমে বা আগে থেকে থাকা ইন্টারফেসের নতুন মেথড ব্যবহার করে করা যেতে পারে।
HIDL ইন্টারফেস-লেভেল ইনহেরিটেন্স ও UDT কম্পোজিশন ব্যবহার করে এইসব নিয়ম প্রয়োগ করা যেতে পারে, তবে এই সম্পর্কগুলি যে ব্যাকওয়ার্ড কম্প্যাটিবল প্যাকেজ এক্সটেনশন তৈরি করে তা জানতে মেটা-লেভেল জ্ঞান প্রয়োজন। এই জ্ঞান এইভাবে অনুমান করা হয়:
কোনও প্যাকেজ এই প্রয়োজনীয়তা পূরণ করলে, hidl-gen ব্যাকওয়ার্ড-কম্প্যাটিবিলিটি
সংক্রান্ত নিয়ম প্রয়োগ করে।