এইচএএল-এর জন্য এআইডিএল

অ্যান্ড্রয়েড ১১ অ্যান্ড্রয়েডের HAL-এর জন্য AIDL ব্যবহারের সুবিধা চালু করেছে, যার ফলে HIDL ছাড়াই অ্যান্ড্রয়েডের কিছু অংশ বাস্তবায়ন করা সম্ভব হয়েছে। যেখানে সম্ভব, HAL-গুলোকে শুধুমাত্র AIDL ব্যবহারে রূপান্তরিত করুন (যখন আপস্ট্রিম HAL-গুলো HIDL ব্যবহার করে, তখন অবশ্যই HIDL ব্যবহার করতে হবে)।

system.img এর মতো ফ্রেমওয়ার্ক কম্পোনেন্ট এবং vendor.img এর মতো হার্ডওয়্যার কম্পোনেন্টের মধ্যে যোগাযোগের জন্য AIDL ব্যবহারকারী HAL-গুলোকে অবশ্যই স্টেবল AIDL ব্যবহার করতে হবে। তবে, একটি পার্টিশনের মধ্যে যোগাযোগের জন্য, যেমন—এক HAL থেকে অন্য HAL-এ, ব্যবহৃত IPC মেকানিজমের উপর কোনো বিধিনিষেধ নেই।

অনুপ্রেরণা

HIDL-এর চেয়ে AIDL অনেক আগে থেকে প্রচলিত এবং এটি অ্যান্ড্রয়েড ফ্রেমওয়ার্ক কম্পোনেন্টগুলোর মধ্যে বা অ্যাপের মতো আরও অনেক জায়গায় ব্যবহৃত হয়। এখন যেহেতু AIDL-এ স্ট্যাবিলিটি সাপোর্ট রয়েছে, তাই একটিমাত্র IPC রানটাইম দিয়ে একটি সম্পূর্ণ স্ট্যাক ইমপ্লিমেন্ট করা সম্ভব। AIDL-এর ভার্সনিং সিস্টেমও HIDL-এর চেয়ে উন্নত। AIDL-এর কিছু সুবিধা নিচে দেওয়া হলো:

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

AIDL রানটাইমের বিপরীতে বিল্ড করুন

AIDL-এর তিনটি ভিন্ন ব্যাকএন্ড রয়েছে: Java, NDK, এবং CPP। স্থিতিশীল AIDL ব্যবহার করার জন্য, সর্বদা system/lib*/libbinder.so তে থাকা libbinder এর সিস্টেম কপি ব্যবহার করুন এবং /dev/binder এ যোগাযোগ করুন। vendor ইমেজের কোডের জন্য, এর অর্থ হলো libbinder (VNDK থেকে) ব্যবহার করা যাবে না: এই লাইব্রেরির একটি অস্থিতিশীল C++ API এবং অস্থিতিশীল অভ্যন্তরীণ গঠন রয়েছে। পরিবর্তে, নেটিভ ভেন্ডর কোডকে অবশ্যই AIDL-এর NDK ব্যাকএন্ড ব্যবহার করতে হবে, libbinder_ndk সাথে লিঙ্ক করতে হবে (যা সিস্টেম libbinder.so দ্বারা সমর্থিত), এবং aidl_interface এন্ট্রি দ্বারা তৈরি NDK লাইব্রেরিগুলোর সাথে লিঙ্ক করতে হবে। সঠিক মডিউল নামগুলোর জন্য, মডিউল নামকরণের নিয়মাবলী দেখুন।

একটি AIDL HAL ইন্টারফেস লিখুন

সিস্টেম এবং ভেন্ডরের মধ্যে ব্যবহারযোগ্য একটি AIDL ইন্টারফেসের জন্য, ইন্টারফেসটিতে দুটি পরিবর্তন প্রয়োজন:

  • প্রতিটি টাইপ ডেফিনিশনকে অবশ্যই @VintfStability দিয়ে অ্যানোটেট করতে হবে।
  • aidl_interface ডিক্লারেশনে stability: "vintf", . অন্তর্ভুক্ত করা প্রয়োজন।

শুধুমাত্র একটি ইন্টারফেসের মালিকই এই পরিবর্তনগুলো করতে পারেন।

যখন আপনি এই পরিবর্তনগুলি করবেন, তখন ইন্টারফেসটি কাজ করার জন্য অবশ্যই VINTF ম্যানিফেস্টে থাকতে হবে। ভেন্ডর টেস্ট স্যুট (VTS) এর vts_treble_vintf_vendor_test টেস্টটি ব্যবহার করে এটি (এবং সম্পর্কিত প্রয়োজনীয়তা, যেমন রিলিজ করা ইন্টারফেসগুলি ফ্রোজেন আছে কিনা তা যাচাই করা) পরীক্ষা করুন। অন্য কোনো প্রসেসে পাঠানোর আগে একটি বাইন্ডার অবজেক্টের উপর NDK ব্যাকএন্ডে AIBinder_forceDowngradeToLocalStability , C++ ব্যাকএন্ডে android::Stability::forceDowngradeToLocalStability , অথবা Java ব্যাকএন্ডে android.os.Binder#forceDowngradeToSystemStability কল করে আপনি এই প্রয়োজনীয়তাগুলি ছাড়াই একটি @VintfStability ইন্টারফেস ব্যবহার করতে পারেন।

এছাড়াও, কোডের সর্বোচ্চ বহনযোগ্যতা নিশ্চিত করতে এবং অপ্রয়োজনীয় অতিরিক্ত লাইব্রেরির মতো সম্ভাব্য সমস্যা এড়াতে, সিপিপি ব্যাকএন্ডটি নিষ্ক্রিয় করুন।

কোডটিতে দেখানো হয়েছে কীভাবে সিপিপি ব্যাকএন্ড নিষ্ক্রিয় করতে হয়:

    aidl_interface: {
        ...
        backend: {
            cpp: {
                enabled: false,
            },
        },
    }

AIDL HAL ইন্টারফেসগুলি খুঁজুন

HALS-এর জন্য AOSP স্থিতিশীল AIDL ইন্টারফেসগুলি HIDL ইন্টারফেসগুলির মতো একই বেস ডিরেক্টরিতে থাকা aidl ফোল্ডারগুলির মধ্যে থাকে:

  • hardware/interfaces বলতে সাধারণত হার্ডওয়্যার দ্বারা সরবরাহকৃত ইন্টারফেসগুলোকে বোঝানো হয়।
  • frameworks/hardware/interfaces হলো হার্ডওয়্যারকে প্রদত্ত উচ্চ-স্তরের ইন্টারফেসগুলোর জন্য।
  • system/hardware/interfaces হলো হার্ডওয়্যারকে প্রদত্ত নিম্ন-স্তরের ইন্টারফেসগুলোর জন্য।

এক্সটেনশন ইন্টারফেসগুলোকে vendor বা hardware অন্যান্য hardware/interfaces সাবডিরেক্টরিতে রাখুন।

এক্সটেনশন ইন্টারফেস

অ্যান্ড্রয়েডের প্রতিটি রিলিজের সাথে এক সেট অফিসিয়াল AOSP ইন্টারফেস থাকে। অ্যান্ড্রয়েড পার্টনাররা যখন এই ইন্টারফেসগুলিতে নতুন কোনো ফিচার যোগ করতে চান, তখন তাদের সরাসরি এগুলো পরিবর্তন করা উচিত নয়, কারণ এটি তাদের অ্যান্ড্রয়েড রানটাইমকে AOSP অ্যান্ড্রয়েড রানটাইমের সাথে বেমানান করে তোলে। এই ইন্টারফেসগুলো পরিবর্তন করা থেকে বিরত থাকুন, যাতে GSI ইমেজটি কাজ করা চালিয়ে যেতে পারে।

এক্সটেনশনগুলি দুটি ভিন্ন উপায়ে নিবন্ধন করতে পারে:

তবে, একটি এক্সটেনশন যেভাবে নিবন্ধিত হোক না কেন, যখন ভেন্ডর-নির্দিষ্ট (অর্থাৎ আপস্ট্রিম AOSP-এর অংশ নয়) কম্পোনেন্টগুলো ইন্টারফেসটি ব্যবহার করে, তখন মার্জ কনফ্লিক্ট হওয়ার সম্ভাবনা থাকে না। কিন্তু, যখন আপস্ট্রিম AOSP কম্পোনেন্টগুলোতে ডাউনস্ট্রিম পরিবর্তন করা হয়, তখন মার্জ কনফ্লিক্ট দেখা দিতে পারে, এবং সেক্ষেত্রে নিম্নলিখিত কৌশলগুলো সুপারিশ করা হয়:

  • পরবর্তী রিলিজে AOSP-তে ইন্টারফেস সংযোজনগুলো আপস্ট্রিম করুন।
  • পরবর্তী রিলিজে আপস্ট্রিম ইন্টারফেসে এমন কিছু সংযোজন করা হয়েছে যা আরও বেশি নমনীয়তা দেবে (মার্জ কনফ্লিক্ট ছাড়াই)।

বর্ধিত পার্সেলযোগ্য: পার্সেলযোগ্যধারক

ParcelableHolder হলো Parcelable ইন্টারফেসের একটি ইনস্ট্যান্স যা Parcelable এর আরেকটি ইনস্ট্যান্স ধারণ করতে পারে।

ParcelableHolder এর প্রধান ব্যবহার হলো Parcelable সম্প্রসারণযোগ্য করে তোলা। উদাহরণস্বরূপ, কল্পনা করুন যে ডিভাইস বাস্তবায়নকারীরা একটি AOSP-সংজ্ঞায়িত Parcelable , AospDefinedParcelable , তাদের নিজস্ব অতিরিক্ত বৈশিষ্ট্য যোগ করার জন্য সম্প্রসারণ করতে সক্ষম হবেন বলে আশা করেন।

আপনার নিজস্ব অতিরিক্ত বৈশিষ্ট্য যোগ করে Parcelable প্রসারিত করতে ParcelableHolder ইন্টারফেসটি ব্যবহার করুন। ParcelableHolder ইন্টারফেসটিতে Parcelable এর একটি ইনস্ট্যান্স থাকে। আপনি যদি সরাসরি Parcelable এ ফিল্ড যোগ করার চেষ্টা করেন, তাহলে একটি ত্রুটি দেখা দেবে:

parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}

পূর্ববর্তী কোডে যেমন দেখা গেছে, এই পদ্ধতিটি ত্রুটিপূর্ণ, কারণ অ্যান্ড্রয়েডের পরবর্তী সংস্করণগুলিতে Parcelable সংশোধিত হলে ডিভাইস ইমপ্লিমেন্টারের যোগ করা ফিল্ডগুলির মধ্যে সংঘাত দেখা দিতে পারে।

ParcelableHolder ব্যবহার করে, একটি Parcelable-এর মালিক Parcelable এর একটি ইনস্ট্যান্সে একটি এক্সটেনশন পয়েন্ট সংজ্ঞায়িত করতে পারেন:

parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}

তারপর ডিভাইস বাস্তবায়নকারীরা তাদের এক্সটেনশনের জন্য নিজস্ব Parcelable ইনস্ট্যান্স সংজ্ঞায়িত করতে পারেন:

parcelable OemDefinedParcelable {
  String x;
  int[] y;
}

নতুন Parcelable ইনস্ট্যান্সটিকে ParcelableHolder ফিল্ডের মাধ্যমে মূল Parcelable সাথে সংযুক্ত করা যেতে পারে:


// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;

ap.extension.setParcelable(op);

...

OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);

// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();

ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);

...

std::shared_ptr<OemDefinedParcelable> op_ptr;

ap.extension.getParcelable(&op_ptr);

// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);

...

std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);

// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });

ap.extension.set_parcelable(Rc::clone(&op));

...

let op = ap.extension.get_parcelable::<OemDefinedParcelable>();

AIDL HAL সার্ভার ইনস্ট্যান্সের নাম

প্রচলিত রীতি অনুযায়ী, AIDL HAL সার্ভিসগুলোর ইনস্ট্যান্স নেম $package.$type/$instance ফরম্যাটের হয়ে থাকে। উদাহরণস্বরূপ, ভাইব্রেটর HAL-এর একটি ইনস্ট্যান্স android.hardware.vibrator.IVibrator/default হিসেবে রেজিস্টার করা হয়।

একটি AIDL HAL সার্ভার লিখুন

@VintfStability AIDL সার্ভারগুলিকে অবশ্যই VINTF ম্যানিফেস্টে ঘোষণা করতে হবে, উদাহরণস্বরূপ:

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>

অন্যথায়, তাদের স্বাভাবিকভাবে একটি AIDL পরিষেবা নিবন্ধন করতে হবে। VTS পরীক্ষা চালানোর সময়, আশা করা হয় যে সমস্ত ঘোষিত AIDL HAL উপলব্ধ থাকবে।

একটি AIDL ক্লায়েন্ট লিখুন

AIDL ক্লায়েন্টদের অবশ্যই সামঞ্জস্য ম্যাট্রিক্সে নিজেদের ঘোষণা করতে হবে, উদাহরণস্বরূপ:

    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>

বিদ্যমান একটি HAL-কে HIDL থেকে AIDL-এ রূপান্তর করুন

HIDL ইন্টারফেসকে AIDL-এ রূপান্তর করতে hidl2aidl টুলটি ব্যবহার করুন।

hidl2aidl বৈশিষ্ট্যসমূহ:

  • প্রদত্ত প্যাকেজের জন্য HAL ( .hal ) ফাইলের উপর ভিত্তি করে AIDL ( .aidl ) ফাইল তৈরি করুন।
  • নতুন তৈরি করা AIDL প্যাকেজের জন্য সমস্ত ব্যাকএন্ড সক্রিয় রেখে বিল্ড নিয়ম তৈরি করুন।
  • HIDL টাইপ থেকে AIDL টাইপে অনুবাদ করার জন্য Java, CPP, এবং NDK ব্যাকএন্ডে translate মেথড তৈরি করুন।
  • প্রয়োজনীয় নির্ভরতাসহ অনুবাদ লাইব্রেরিগুলোর জন্য বিল্ড নিয়ম তৈরি করুন।
  • CPP এবং NDK ব্যাকএন্ডে HIDL ও AIDL এনুমেটরগুলোর মান একই আছে কিনা, তা নিশ্চিত করতে স্ট্যাটিক অ্যাসার্ট তৈরি করুন।

HAL ফাইলের একটি প্যাকেজকে AIDL ফাইলে রূপান্তর করতে এই ধাপগুলো অনুসরণ করুন:

  1. system/tools/hidl/hidl2aidl এ অবস্থিত টুলটি বিল্ড করুন।

    সর্বশেষ সোর্স থেকে এই টুলটি বিল্ড করলে সবচেয়ে পরিপূর্ণ অভিজ্ঞতা পাওয়া যায়। পূর্ববর্তী রিলিজের পুরোনো ব্রাঞ্চগুলোর ইন্টারফেস রূপান্তর করতে আপনি সর্বশেষ সংস্করণটি ব্যবহার করতে পারেন:

    m hidl2aidl
  2. আউটপুট ডিরেক্টরির পরে রূপান্তর করার প্যাকেজটি দিয়ে টুলটি চালান।

    ঐচ্ছিকভাবে, তৈরি হওয়া সমস্ত ফাইলের শীর্ষে একটি নতুন লাইসেন্স ফাইলের বিষয়বস্তু যোগ করতে -l আর্গুমেন্টটি ব্যবহার করুন। সঠিক লাইসেন্স এবং তারিখ ব্যবহার করতে ভুলবেন না:

    hidl2aidl -o <output directory> -l <file with license> <package>

    উদাহরণস্বরূপ:

    hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
  3. তৈরি হওয়া ফাইলগুলো ভালোভাবে পড়ুন এবং রূপান্তরের ক্ষেত্রে কোনো সমস্যা থাকলে তা সমাধান করুন:

    • conversion.log এ এমন যেকোনো অমীমাংসিত সমস্যা থাকে যা প্রথমে সমাধান করতে হবে।
    • তৈরি হওয়া AIDL ফাইলগুলোতে এমন কিছু সতর্কবার্তা ও পরামর্শ থাকতে পারে যেগুলোর ওপর ব্যবস্থা নেওয়া প্রয়োজন। এই মন্তব্যগুলো // দিয়ে শুরু হয়।
    • প্যাকেজটি পরিমার্জন ও উন্নত করুন।
    • প্রয়োজনীয় ফিচার, যেমন toString বা equals এর জন্য @JavaDerive অ্যানোটেশনটি দেখুন।
  4. শুধু আপনার প্রয়োজনীয় লক্ষ্যগুলোই তৈরি করুন:

    • যে ব্যাকএন্ডগুলো ব্যবহার করা হবে না, সেগুলো নিষ্ক্রিয় করুন। CPP ব্যাকএন্ডের চেয়ে NDK ব্যাকএন্ডকে অগ্রাধিকার দিন; AIDL রানটাইমের বিপরীতে বিল্ড দেখুন।
    • অনুবাদ লাইব্রেরিগুলো অথবা সেগুলোর দ্বারা তৈরি হওয়া অব্যবহৃত কোড মুছে ফেলুন।
  5. AIDL এবং HIDL-এর প্রধান পার্থক্যগুলো দেখুন :

    • AIDL-এর অন্তর্নির্মিত Status এবং exception ব্যবহার করলে সাধারণত ইন্টারফেসের উন্নতি ঘটে এবং আরেকটি ইন্টারফেস-নির্দিষ্ট স্ট্যাটাস টাইপের প্রয়োজনীয়তা দূর হয়।
    • HIDL-এর মতো AIDL ইন্টারফেসের মেথডের আর্গুমেন্টগুলো ডিফল্টভাবে @nullable হয় না।

AIDL HAL-এর জন্য SEPolicy

ভেন্ডর কোডের কাছে দৃশ্যমান একটি AIDL সার্ভিস টাইপের অবশ্যই hal_service_type অ্যাট্রিবিউটটি থাকতে হবে। অন্যথায়, sepolicy কনফিগারেশনটি অন্য যেকোনো AIDL সার্ভিসের মতোই হয় (যদিও HAL-এর জন্য বিশেষ অ্যাট্রিবিউট রয়েছে)। এখানে একটি HAL সার্ভিস কনটেক্সটের সংজ্ঞার উদাহরণ দেওয়া হলো:

    type hal_foo_service, service_manager_type, hal_service_type;

প্ল্যাটফর্ম দ্বারা সংজ্ঞায়িত বেশিরভাগ পরিষেবার জন্য, সঠিক টাইপের একটি পরিষেবা প্রসঙ্গ ইতিমধ্যেই যুক্ত করা থাকে (উদাহরণস্বরূপ, android.hardware.foo.IFoo/default ইতিমধ্যেই hal_foo_service হিসাবে চিহ্নিত করা আছে)। তবে, যদি কোনো ফ্রেমওয়ার্ক ক্লায়েন্ট একাধিক ইনস্ট্যান্স নাম সমর্থন করে, তাহলে ডিভাইস-নির্দিষ্ট service_contexts ফাইলগুলিতে অতিরিক্ত ইনস্ট্যান্স নাম যোগ করতে হবে:

    android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0

যখন আপনি একটি নতুন ধরনের HAL তৈরি করেন, তখন আপনাকে অবশ্যই HAL অ্যাট্রিবিউট যোগ করতে হবে। একটি নির্দিষ্ট HAL অ্যাট্রিবিউট একাধিক সার্ভিস টাইপের সাথে যুক্ত থাকতে পারে (যার প্রত্যেকটির একাধিক ইনস্ট্যান্স থাকতে পারে, যেমনটি এইমাত্র আলোচনা করা হয়েছে)। foo নামক একটি HAL-এর জন্য hal_attribute(foo) রয়েছে। এই ম্যাক্রোটি hal_foo_client এবং hal_foo_server অ্যাট্রিবিউটগুলো সংজ্ঞায়িত করে। একটি নির্দিষ্ট ডোমেইনের জন্য, hal_client_domain এবং hal_server_domain ম্যাক্রোগুলো একটি ডোমেইনকে একটি নির্দিষ্ট HAL অ্যাট্রিবিউটের সাথে যুক্ত করে। উদাহরণস্বরূপ, এই HAL-এর ক্লায়েন্ট হিসেবে system server-এর জন্য hal_client_domain(system_server, hal_foo) পলিসিটি প্রযোজ্য। একইভাবে, একটি HAL server-এর জন্য hal_server_domain(my_hal_domain, hal_foo) অন্তর্ভুক্ত থাকে।

সাধারণত, একটি নির্দিষ্ট HAL অ্যাট্রিবিউটের জন্য, রেফারেন্স বা উদাহরণ HAL-এর জন্য hal_foo_default মতো একটি ডোমেইনও তৈরি করা হয়। তবে, কিছু ডিভাইস এই ডোমেইনগুলো তাদের নিজস্ব সার্ভারের জন্য ব্যবহার করে। একাধিক সার্ভারের জন্য ডোমেইনের মধ্যে পার্থক্য করা তখনই গুরুত্বপূর্ণ, যখন একই ইন্টারফেস পরিচালনা করার জন্য একাধিক সার্ভার থাকে এবং তাদের বাস্তবায়নে ভিন্ন পারমিশন সেটের প্রয়োজন হয়। এই সমস্ত ম্যাক্রোতে, hal_foo কোনো sepolicy অবজেক্ট নয়। বরং, এই টোকেনটি একটি ক্লায়েন্ট-সার্ভার জোড়ার সাথে যুক্ত অ্যাট্রিবিউটের সমষ্টিকে বোঝাতে ব্যবহৃত হয়।

তবে, এখন পর্যন্ত, hal_foo_service এবং hal_foo ( hal_attribute(foo) থেকে প্রাপ্ত অ্যাট্রিবিউট জোড়া) একে অপরের সাথে যুক্ত নয়। একটি HAL অ্যাট্রিবিউট AIDL HAL সার্ভিসের সাথে hal_attribute_service ম্যাক্রো ব্যবহার করে যুক্ত করা হয় (HIDL HAL-এর জন্য hal_attribute_hwservice ম্যাক্রো ব্যবহৃত হয়), উদাহরণস্বরূপ, hal_attribute_service(hal_foo, hal_foo_service) । এর মানে হলো, hal_foo_client প্রসেসগুলো HAL-এর অ্যাক্সেস পেতে পারে এবং hal_foo_server প্রসেসগুলো HAL রেজিস্টার করতে পারে। এই রেজিস্ট্রেশন নিয়মগুলো প্রয়োগ করে থাকে কনটেক্সট ম্যানেজার ( servicemanager )।

সার্ভিসের নামগুলো সবসময় HAL অ্যাট্রিবিউটের সাথে নাও মিলতে পারে, যেমন, hal_attribute_service(hal_foo, hal_foo2_service) । সাধারণত, যেহেতু এটি বোঝায় যে সার্ভিসগুলো সবসময় একসাথে ব্যবহৃত হয়, তাই আপনি hal_foo2_service টি সরিয়ে দিয়ে সমস্ত সার্ভিস কনটেক্সটের জন্য hal_foo_service ব্যবহার করতে পারেন। যখন HAL একাধিক hal_attribute_service ইনস্ট্যান্স সেট করে, তার কারণ হলো মূল HAL অ্যাট্রিবিউটের নামটি যথেষ্ট সাধারণ নয় এবং তা পরিবর্তন করা যায় না।

এই সবকিছু মিলিয়ে, একটি উদাহরণ HAL দেখতে এইরকম:

    public/attributes:
    // define hal_foo, hal_foo_client, hal_foo_server
    hal_attribute(foo)

    public/service.te
    // define hal_foo_service
    type hal_foo_service, hal_service_type, protected_service, service_manager_type

    public/hal_foo.te:
    // allow binder connection from client to server
    binder_call(hal_foo_client, hal_foo_server)
    // allow client to find the service, allow server to register the service
    hal_attribute_service(hal_foo, hal_foo_service)
    // allow binder communication from server to service_manager
    binder_use(hal_foo_server)

    private/service_contexts:
    // bind an AIDL service name to the selinux type
    android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0

    private/<some_domain>.te:
    // let this domain use the hal service
    binder_use(some_domain)
    hal_client_domain(some_domain, hal_foo)

    vendor/<some_hal_server_domain>.te
    // let this domain serve the hal service
    hal_server_domain(some_hal_server_domain, hal_foo)

সংযুক্ত এক্সটেনশন ইন্টারফেস

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

যখন কোনো এক্সটেনশন বিদ্যমান HAL-এর কার্যকারিতা পরিবর্তন করে, তখন সংযুক্ত এক্সটেনশন ব্যবহার করুন। যখন সম্পূর্ণ নতুন সক্ষমতার প্রয়োজন হয়, তখন এই পদ্ধতির প্রয়োজন হয় না এবং আপনি সরাসরি সার্ভিস ম্যানেজারের কাছে একটি এক্সটেনশন ইন্টারফেস রেজিস্টার করতে পারেন। সংযুক্ত এক্সটেনশন ইন্টারফেসগুলো সাব-ইন্টারফেসের সাথে সংযুক্ত থাকলেই সবচেয়ে বেশি কার্যকর হয়, কারণ এই হায়ারার্কিগুলো গভীর বা মাল্টি-ইনস্ট্যান্সড হতে পারে। অন্য কোনো সার্ভিসের বাইন্ডার ইন্টারফেস হায়ারার্কি অনুকরণ করতে একটি গ্লোবাল এক্সটেনশন ব্যবহার করলে, সরাসরি সংযুক্ত এক্সটেনশনগুলোর সমতুল্য সক্ষমতা প্রদানের জন্য ব্যাপক হিসাবরক্ষণের প্রয়োজন হয়।

বাইন্ডারে এক্সটেনশন সেট করতে, নিম্নলিখিত API-গুলি ব্যবহার করুন:

  • NDK ব্যাকএন্ড: AIBinder_setExtension
  • জাভা ব্যাকএন্ড: android.os.Binder.setExtension
  • CPP ব্যাকএন্ড: android::Binder::setExtension
  • রাস্ট ব্যাকএন্ড: binder::Binder::set_extension

বাইন্ডারের মেয়াদ বাড়াতে, নিম্নলিখিত API-গুলো ব্যবহার করুন:

  • NDK ব্যাকএন্ড: AIBinder_getExtension
  • জাভা ব্যাকএন্ড: android.os.IBinder.getExtension
  • CPP ব্যাকএন্ড: android::IBinder::getExtension
  • রাস্ট ব্যাকএন্ড: binder::Binder::get_extension

এই API-গুলো সম্পর্কে আরও তথ্য আপনি সংশ্লিষ্ট ব্যাকএন্ডের getExtension ফাংশনের ডকুমেন্টেশনে খুঁজে পেতে পারেন। এক্সটেনশন কীভাবে ব্যবহার করতে হয় তার একটি উদাহরণ hardware/interfaces/tests/extension/vibrator এ রয়েছে।

AIDL এবং HIDL এর প্রধান পার্থক্যগুলি

AIDL HAL বা AIDL HAL ইন্টারফেস ব্যবহার করার সময়, HIDL HAL লেখার তুলনায় এর পার্থক্যগুলো সম্পর্কে সচেতন থাকুন।

  • AIDL ভাষার সিনট্যাক্স জাভার কাছাকাছি। HIDL-এর সিনট্যাক্স C++-এর অনুরূপ।
  • সমস্ত AIDL ইন্টারফেসে অন্তর্নির্মিত ত্রুটির স্ট্যাটাস রয়েছে। কাস্টম স্ট্যাটাস টাইপ তৈরি করার পরিবর্তে, ইন্টারফেস ফাইলগুলিতে ধ্রুবক স্ট্যাটাস ইন্ট তৈরি করুন এবং CPP ও NDK ব্যাকএন্ডে EX_SERVICE_SPECIFIC এবং Java ব্যাকএন্ডে ServiceSpecificException ব্যবহার করুন। ত্রুটি পরিচালনা (Error handling ) দেখুন।
  • বাইন্ডার অবজেক্ট পাঠানোর সময় AIDL স্বয়ংক্রিয়ভাবে থ্রেড পুল চালু করে না। আপনাকে সেগুলি ম্যানুয়ালি চালু করতে হবে ( থ্রেড ম্যানেজমেন্ট দেখুন)।
  • AIDL আনচেকড ট্রান্সপোর্ট এররের ক্ষেত্রে অ্যাবোর্ট করে না (HIDL Return আনচেকড এররের ক্ষেত্রে অ্যাবোর্ট করে)।
  • AIDL প্রতি ফাইলে কেবল একটি প্রকার ঘোষণা করতে পারে।
  • আউটপুট প্যারামিটার ছাড়াও AIDL আর্গুমেন্টগুলো in , out , বা inout হিসেবে নির্দিষ্ট করা যায় (কোনো সিনক্রোনাস কলব্যাক নেই)।
  • AIDL প্রিমিটিভ টাইপ হিসেবে handle এর পরিবর্তে fd ব্যবহার করে।
  • HIDL অসঙ্গত পরিবর্তনের জন্য মেজর ভার্সন এবং সঙ্গত পরিবর্তনের জন্য মাইনর ভার্সন ব্যবহার করে। AIDL-এ, পশ্চাৎ-সঙ্গতিপূর্ণ পরিবর্তনগুলো ইন-প্লেস করা হয়। AIDL-এ মেজর ভার্সনের কোনো সুস্পষ্ট ধারণা নেই; এর পরিবর্তে, এটি প্যাকেজের নামের মধ্যেই অন্তর্ভুক্ত থাকে। উদাহরণস্বরূপ, AIDL bluetooth2 ’ প্যাকেজটির নাম ব্যবহার করতে পারে।
  • AIDL ডিফল্টরূপে রিয়েলটাইম প্রায়োরিটি উত্তরাধিকার সূত্রে পায় না। রিয়েলটাইম প্রায়োরিটি উত্তরাধিকার সক্রিয় করতে প্রতিটি বাইন্ডারের জন্য setInheritRt ফাংশনটি ব্যবহার করতে হবে।

HAL-দের জন্য পরীক্ষা

এই বিভাগে HAL পরীক্ষার সর্বোত্তম পদ্ধতিগুলো বর্ণনা করা হয়েছে। আপনার HAL-এর ইন্টিগ্রেশন টেস্ট VTS- এ না থাকলেও এই পদ্ধতিগুলো প্রযোজ্য।

অ্যান্ড্রয়েড প্রত্যাশিত HAL ইমপ্লিমেন্টেশনগুলো যাচাই করার জন্য VTS-এর উপর নির্ভর করে। VTS নিশ্চিত করতে সাহায্য করে যে অ্যান্ড্রয়েড যেন পুরোনো ভেন্ডর ইমপ্লিমেন্টেশনগুলোর সাথে ব্যাকওয়ার্ড কম্প্যাটিবল থাকতে পারে। যে ইমপ্লিমেন্টেশনগুলো VTS পরীক্ষায় উত্তীর্ণ হতে পারে না, সেগুলোতে পরিচিত কম্প্যাটিবিলিটি সমস্যা থাকে, যা সেগুলোকে OS-এর ভবিষ্যৎ সংস্করণগুলোর সাথে কাজ করতে বাধা দিতে পারে।

HAL-দের জন্য VTS-এর দুটি প্রধান অংশ রয়েছে।

১. যাচাই করুন যে ডিভাইসে থাকা HAL-গুলো Android-এর কাছে পরিচিত এবং প্রত্যাশিত।

অ্যান্ড্রয়েড ইনস্টল করা সমস্ত HAL-এর একটি স্থির ও নির্ভুল তালিকার উপর নির্ভর করে। এই তালিকাটি VINTF ম্যানিফেস্ট- এ প্রকাশ করা হয়। বিশেষ, প্ল্যাটফর্ম-ব্যাপী পরীক্ষাগুলো পুরো সিস্টেমের HAL স্তরগুলোর অখণ্ডতা একত্রে যাচাই করে। কোনো HAL-নির্দিষ্ট পরীক্ষা লেখার আগে, আপনার এই পরীক্ষাগুলোও চালানো উচিত, কারণ এগুলো বলে দিতে পারে যে কোনো HAL-এর VINTF কনফিগারেশন অসামঞ্জস্যপূর্ণ কিনা।

এই টেস্ট সেটটি test/vts-testcase/hal/treble/vintf এ পাওয়া যাবে। আপনি যদি কোনো ভেন্ডর HAL ইমপ্লিমেন্টেশন নিয়ে কাজ করেন, তবে তা যাচাই করার জন্য vts_treble_vintf_vendor_test ব্যবহার করুন। আপনি atest vts_treble_vintf_vendor_test কমান্ডটি দিয়ে এই টেস্টটি চালাতে পারেন।

এই পরীক্ষাগুলো যাচাই করার জন্য দায়ী:

  • একটি VINTF ম্যানিফেস্টে ঘোষিত প্রতিটি @VintfStability ইন্টারফেস একটি পরিচিত প্রকাশিত সংস্করণে স্থির (frozen) করা হয়। এর মাধ্যমে যাচাই করা হয় যে, ইন্টারফেসের উভয় পক্ষই সেই সংস্করণের সঠিক সংজ্ঞার বিষয়ে একমত। মৌলিক কার্যক্রমের জন্য এটি প্রয়োজনীয়।
  • একটি VINTF ম্যানিফেস্টে ঘোষিত সমস্ত HAL সেই ডিভাইসে উপলব্ধ থাকে। ঘোষিত HAL পরিষেবা ব্যবহার করার জন্য পর্যাপ্ত অনুমতিসম্পন্ন যেকোনো ক্লায়েন্টকে অবশ্যই যেকোনো সময়ে সেই পরিষেবাগুলি পেতে এবং ব্যবহার করতে সক্ষম হতে হবে।
  • একটি VINTF ম্যানিফেস্টে ঘোষিত সমস্ত HAL, ম্যানিফেস্টে ঘোষিত ইন্টারফেসের সংস্করণটিই পরিবেশন করে।
  • ডিভাইসে কোনো অপ্রচলিত HAL পরিবেশন করা হচ্ছে না। FCM লাইফসাইকেলে বর্ণিত অনুযায়ী অ্যান্ড্রয়েড HAL ইন্টারফেসের নিম্ন সংস্করণগুলির জন্য সমর্থন বন্ধ করে দেয়।
  • ডিভাইসটিতে প্রয়োজনীয় HAL গুলো উপস্থিত আছে। অ্যান্ড্রয়েড সঠিকভাবে কাজ করার জন্য কিছু HAL প্রয়োজন।

২. প্রতিটি HAL-এর প্রত্যাশিত আচরণ যাচাই করুন।

প্রতিটি HAL ইন্টারফেসের ক্লায়েন্টদের কাছ থেকে প্রত্যাশিত আচরণ যাচাই করার জন্য নিজস্ব VTS টেস্ট থাকে। এই টেস্ট কেসগুলো একটি ঘোষিত HAL ইন্টারফেসের প্রতিটি ইনস্ট্যান্সের উপর চলে এবং ইন্টারফেসটির বাস্তবায়িত সংস্করণের উপর ভিত্তি করে নির্দিষ্ট আচরণ প্রয়োগ করে।

C++ এ, আপনি libaidlvintf_gtest_helper এর android::getAidlHalInstanceNames ফাংশনটি ব্যবহার করে সিস্টেমে ইনস্টল করা প্রতিটি HAL এর একটি তালিকা পেতে পারেন। Rust এ, binder::get_declared_instances ব্যবহার করুন।

এই পরীক্ষাগুলি HAL বাস্তবায়নের প্রতিটি দিককে অন্তর্ভুক্ত করার চেষ্টা করে, যার উপর অ্যান্ড্রয়েড ফ্রেমওয়ার্ক নির্ভর করে বা ভবিষ্যতে নির্ভর করতে পারে।

এই পরীক্ষাগুলোর মধ্যে রয়েছে ফিচারের সমর্থন যাচাই করা, ত্রুটি ব্যবস্থাপনা, এবং পরিষেবাটির কাছ থেকে একজন গ্রাহক প্রত্যাশিত অন্য যেকোনো আচরণ।

HAL উন্নয়নের জন্য VTS মাইলফলক

অ্যান্ড্রয়েডের HAL ইন্টারফেস তৈরি বা পরিবর্তন করার সময় VTS টেস্ট (বা যেকোনো টেস্ট) হালনাগাদ রাখা আবশ্যক।

অ্যান্ড্রয়েড ভেন্ডর এপিআই রিলিজের জন্য ভেন্ডর ইমপ্লিমেন্টেশনগুলো চূড়ান্ত করার আগে, সেগুলো যাচাই করার জন্য ভিটিএস টেস্টগুলো অবশ্যই শেষ করে প্রস্তুত রাখতে হবে। ইন্টারফেসগুলো চূড়ান্ত হওয়ার আগেই এগুলো প্রস্তুত থাকতে হবে, যাতে ডেভেলপাররা তাদের ইমপ্লিমেন্টেশন তৈরি করতে, সেগুলো যাচাই করতে এবং এইচএএল ইন্টারফেস ডেভেলপারদের মতামত জানাতে পারেন।

কাটলফিশের উপর পরীক্ষা

যখন হার্ডওয়্যার উপলব্ধ থাকে না, তখন অ্যান্ড্রয়েড HAL ইন্টারফেসের উন্নয়নের মাধ্যম হিসেবে কাটলফিশ ব্যবহার করে। এর ফলে অ্যান্ড্রয়েডের পরিবর্ধনযোগ্য ইন্টিগ্রেশন টেস্টিং করা সম্ভব হয়।

hal_implementation_test পরীক্ষা করে দেখে যে Cuttlefish-এ সর্বশেষ HAL ইন্টারফেস সংস্করণগুলোর ইমপ্লিমেন্টেশন আছে কিনা, যাতে Android নতুন ইন্টারফেসগুলো পরিচালনা করার জন্য প্রস্তুত থাকে এবং নতুন হার্ডওয়্যার ও ডিভাইস উপলব্ধ হওয়ার সাথে সাথেই VTS টেস্টগুলো নতুন ভেন্ডর ইমপ্লিমেন্টেশনগুলো পরীক্ষা করার জন্য প্রস্তুত থাকে।