एचएएल के लिए एआईडीएल

Android 11 में, Android में एचएएल के लिए एआईडीएल का इस्तेमाल करने की सुविधा दी गई है. इससे, एचआईडीएल के बिना Android के कुछ हिस्सों को लागू किया जा सकता है. एचएएल को एआईडीएल का इस्तेमाल करने के लिए ट्रांज़िशन करें. हालांकि, ऐसा सिर्फ़ तब किया जा सकता है, जब अपस्ट्रीम एचएएल एचआईडीएल का इस्तेमाल करते हों.

फ़्रेमवर्क कॉम्पोनेंट (जैसे, system.img में मौजूद कॉम्पोनेंट) और हार्डवेयर कॉम्पोनेंट (जैसे, vendor.img में मौजूद कॉम्पोनेंट) के बीच कम्यूनिकेट करने के लिए, एआईडीएल का इस्तेमाल करने वाले एचएएल को स्टेबल एआईडीएल का इस्तेमाल करना होगा. हालांकि, किसी पार्टीशन में एक-दूसरे से कम्यूनिकेट करने के लिए, जैसे कि एक HAL से दूसरे HAL तक, आईपीसी मेकेनिज़्म के इस्तेमाल पर कोई पाबंदी नहीं है.

वजह

एआईडीएल, एचआईडीएल से ज़्यादा समय से इस्तेमाल किया जा रहा है. साथ ही, इसका इस्तेमाल कई अन्य जगहों पर भी किया जाता है. जैसे, Android फ़्रेमवर्क कॉम्पोनेंट के बीच या ऐप्लिकेशन में. अब AIDL में स्थिरता से जुड़ी सुविधा उपलब्ध है. इसलिए, एक ही आईपीसी रनटाइम के साथ पूरे स्टैक को लागू किया जा सकता है. AIDL में, HIDL की तुलना में बेहतर वर्शनिंग सिस्टम भी है. एआईडीएल के कुछ फ़ायदे यहां दिए गए हैं:

  • एक ही आईपीसी भाषा का इस्तेमाल करने का मतलब है कि आपको सिर्फ़ एक चीज़ सीखनी है, डीबग करनी है, ऑप्टिमाइज़ करनी है, और सुरक्षित करनी है.
  • एआईडीएल, इंटरफ़ेस के मालिकों के लिए इन-प्लेस वर्शनिंग की सुविधा देता है:
    • मालिक, इंटरफ़ेस के आखिर में तरीके जोड़ सकते हैं या पार्सल किए जा सकने वाले ऑब्जेक्ट में फ़ील्ड जोड़ सकते हैं. इसका मतलब है कि पिछले कुछ सालों में कोड को वर्शन करना आसान हो गया है. साथ ही, साल-दर-साल लागत भी कम हो गई है. टाइप में बदलाव किया जा सकता है और हर इंटरफ़ेस वर्शन के लिए अतिरिक्त लाइब्रेरी की ज़रूरत नहीं होती.
    • एक्सटेंशन इंटरफ़ेस को टाइप सिस्टम के बजाय रन टाइम में अटैच किया जा सकता है. इसलिए, डाउनस्ट्रीम एक्सटेंशन को इंटरफ़ेस के नए वर्शन पर रीबेस करने की ज़रूरत नहीं होती.
  • अगर किसी मौजूदा AIDL इंटरफ़ेस का मालिक उसे स्थिर करने का विकल्प चुनता है, तो उसका सीधे तौर पर इस्तेमाल किया जा सकता है. इससे पहले, इंटरफ़ेस की पूरी कॉपी HIDL में बनानी पड़ती थी.

AIDL रनटाइम के ख़िलाफ़ बनाना

AIDL के तीन अलग-अलग बैकएंड होते हैं: Java, NDK, और CPP. स्टेबल AIDL का इस्तेमाल करने के लिए, हमेशा system/lib*/libbinder.so पर libbinder की सिस्टम कॉपी का इस्तेमाल करें और /dev/binder पर बात करें. vendor इमेज पर मौजूद कोड के लिए, इसका मतलब है कि libbinder (VNDK से) का इस्तेमाल नहीं किया जा सकता: इस लाइब्रेरी में अस्थिर C++ API और अस्थिर इंटरनल हैं. इसके बजाय, नेटिव वेंडर कोड को AIDL के एनडीके बैकएंड का इस्तेमाल करना चाहिए. साथ ही, इसे libbinder_ndk (जिसे सिस्टम libbinder.so से मदद मिलती है) और aidl_interface एंट्री से बनाई गई एनडीके लाइब्रेरी से लिंक करना चाहिए. मॉड्यूल के सटीक नामों के लिए, मॉड्यूल के नाम रखने के नियम देखें.

एआईडीएल एचएएल इंटरफ़ेस लिखना

सिस्टम और वेंडर के बीच एआईडीएल इंटरफ़ेस का इस्तेमाल करने के लिए, इंटरफ़ेस में दो बदलाव करने होंगे:

  • हर टाइप की जानकारी को @VintfStability से एनोटेट किया जाना चाहिए.
  • aidl_interface के एलान में stability: "vintf", शामिल होना चाहिए.

सिर्फ़ इंटरफ़ेस का मालिक ही ये बदलाव कर सकता है.

ये बदलाव करने पर, इंटरफ़ेस को काम करने के लिए VINTF मेनिफ़ेस्ट में होना चाहिए. Vendor Test Suite (VTS) टेस्ट vts_treble_vintf_vendor_test का इस्तेमाल करके, इसकी जांच करें. साथ ही, इससे जुड़ी अन्य ज़रूरी शर्तों की भी जांच करें. जैसे, यह पुष्टि करना कि रिलीज़ किए गए इंटरफ़ेस फ़्रीज़ कर दिए गए हैं. इन ज़रूरी शर्तों के बिना @VintfStability इंटरफ़ेस का इस्तेमाल किया जा सकता है. इसके लिए, आपको NDK बैकएंड में AIBinder_forceDowngradeToLocalStability, C++ बैकएंड में android::Stability::forceDowngradeToLocalStability या Java बैकएंड में android.os.Binder#forceDowngradeToSystemStability को कॉल करना होगा. ऐसा बाइंडर ऑब्जेक्ट को किसी दूसरी प्रोसेस में भेजने से पहले करना होगा.

इसके अलावा, ज़्यादा से ज़्यादा कोड पोर्टेबिलिटी के लिए और संभावित समस्याओं से बचने के लिए, सीपीपी बैकएंड को बंद करें. जैसे, गैर-ज़रूरी अतिरिक्त लाइब्रेरी.

इस कोड में, सीपीपी बैकएंड को बंद करने का तरीका बताया गया है:

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

एआईडीएल एचएएल इंटरफ़ेस ढूंढना

एचएएल के लिए, एआईडीएल के स्टेबल इंटरफ़ेस, एचआईडीएल इंटरफ़ेस की तरह ही aidl फ़ोल्डर में होते हैं:

  • hardware/interfaces आम तौर पर, हार्डवेयर से मिले इंटरफ़ेस के लिए होता है.
  • frameworks/hardware/interfaces, हार्डवेयर को उपलब्ध कराए गए हाई-लेवल इंटरफ़ेस के लिए है.
  • system/hardware/interfaces, हार्डवेयर को उपलब्ध कराए गए लो-लेवल इंटरफ़ेस के लिए है.

एक्सटेंशन इंटरफ़ेस को vendor या hardware में मौजूद अन्य hardware/interfaces सबडाइरेक्ट्री में रखें.

एक्सटेंशन इंटरफ़ेस

Android के हर वर्शन में, आधिकारिक AOSP इंटरफ़ेस का एक सेट होता है. जब Android पार्टनर इन इंटरफ़ेस में सुविधाएं जोड़ना चाहते हैं, तो उन्हें सीधे तौर पर इनमें बदलाव नहीं करना चाहिए. ऐसा इसलिए, क्योंकि इससे उनका Android रनटाइम, AOSP Android रनटाइम के साथ काम नहीं करता. इन इंटरफ़ेस में बदलाव न करें, ताकि GSI इमेज काम करती रहे.

एक्सटेंशन को दो अलग-अलग तरीकों से रजिस्टर किया जा सकता है:

हालांकि, जब वेंडर के हिसाब से (यानी कि अपस्ट्रीम एओएसपी का हिस्सा नहीं) कॉम्पोनेंट इंटरफ़ेस का इस्तेमाल करते हैं, तो मर्ज करने से जुड़ी समस्याएं नहीं होतीं. हालांकि, जब अपस्ट्रीम एओएसपी कॉम्पोनेंट में डाउनस्ट्रीम बदलाव किए जाते हैं, तो मर्ज करने से जुड़ी समस्याएं हो सकती हैं. इसलिए, इन रणनीतियों का सुझाव दिया जाता है:

  • अगली रिलीज़ में, इंटरफ़ेस में किए गए बदलावों को AOSP में अपस्ट्रीम करें.
  • अपस्ट्रीम इंटरफ़ेस में ऐसे बदलाव किए गए हैं जिनसे अगले रिलीज़ में ज़्यादा आसानी से बदलाव किए जा सकेंगे. साथ ही, मर्ज करने से जुड़ी समस्याएं भी नहीं होंगी.

एक्सटेंशन पार्सल किए जा सकने वाले ऑब्जेक्ट: ParcelableHolder

ParcelableHolder, Parcelable इंटरफ़ेस का एक इंस्टेंस है. इसमें Parcelable का दूसरा इंस्टेंस शामिल हो सकता है.

ParcelableHolder का मुख्य इस्तेमाल, Parcelable को एक्सटेंड करने लायक बनाना है. उदाहरण के लिए, डिवाइस बनाने वाली कंपनियां, AOSP में तय की गई Parcelable और AospDefinedParcelable को बढ़ाना चाहती हैं, ताकि वे वैल्यू-ऐड फ़ीचर शामिल कर सकें.

ParcelableHolder इंटरफ़ेस का इस्तेमाल करके, Parcelable को वैल्यू-ऐड सुविधाओं के साथ इंटिग्रेट करें. ParcelableHolder इंटरफ़ेस में Parcelable का उदाहरण शामिल है. अगर Parcelable में सीधे तौर पर फ़ील्ड जोड़ने की कोशिश की जाती है, तो गड़बड़ी होती है:

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

ऊपर दिए गए कोड में दिखाया गया है कि इस तरीके का इस्तेमाल नहीं किया जा सकता. ऐसा इसलिए, क्योंकि डिवाइस बनाने वाली कंपनी के जोड़े गए फ़ील्ड में, Android के अगले वर्शन में Parcelable में बदलाव होने पर टकराव हो सकता है.

ParcelableHolder का इस्तेमाल करके, पार्सल किए जा सकने वाले ऑब्जेक्ट का मालिक, Parcelable के इंस्टेंस में एक्सटेंशन पॉइंट तय कर सकता है:

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

इसके बाद, डिवाइस बनाने वाली कंपनियां अपने एक्सटेंशन के लिए, Parcelable का अपना इंस्टेंस तय कर सकती हैं:

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

ParcelableHolder फ़ील्ड का इस्तेमाल करके, नए Parcelable इंस्टेंस को ओरिजनल 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 सेवाओं के इंस्टेंस का नाम इस फ़ॉर्मैट में होता है: $package.$type/$instance. उदाहरण के लिए, वाइब्रेटर HAL का एक इंस्टेंस android.hardware.vibrator.IVibrator/default के तौर पर रजिस्टर किया जाता है.

एआईडीएल एचएएल सर्वर लिखना

@VintfStability एआईडीएल सर्वर को VINTF मेनिफ़ेस्ट में घोषित किया जाना चाहिए. उदाहरण के लिए:

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

ऐसा न होने पर, उन्हें सामान्य तरीके से AIDL सेवा रजिस्टर करनी चाहिए. वीटीएस टेस्ट चलाते समय, यह ज़रूरी है कि सभी घोषित एआईडीएल एचएएल उपलब्ध हों.

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 में बदलना

एचआईडीएल इंटरफ़ेस को एआईडीएल में बदलने के लिए, hidl2aidl टूल का इस्तेमाल करें.

hidl2aidl सुविधाएं:

  • दिए गए पैकेज के लिए, एचएएल (.hal) फ़ाइलों के आधार पर एआईडीएल (.aidl) फ़ाइलें बनाएं.
  • सभी बैकएंड चालू करके, नए बनाए गए AIDL पैकेज के लिए बिल्ड के नियम बनाएं.
  • HIDL टाइप से AIDL टाइप में अनुवाद करने के लिए, Java, CPP, और NDK बैकएंड में अनुवाद करने के तरीके बनाएं.
  • ज़रूरी डिपेंडेंसी के साथ, अनुवाद करने वाली लाइब्रेरी के लिए बिल्ड नियम बनाएं.
  • स्टैटिक असर्ट बनाएं, ताकि यह पक्का किया जा सके कि HIDL और AIDL एन्यूमरेटर की वैल्यू, CPP और NDK बैकएंड में एक जैसी हों.

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 फ़ाइलों में चेतावनियां और सुझाव हो सकते हैं. इन पर कार्रवाई करना ज़रूरी है. ये टिप्पणियां // से शुरू होती हैं.
    • पैकेज को साफ़ करना और उसमें सुधार करना.
    • जिन सुविधाओं की ज़रूरत हो सकती है उनके लिए @JavaDerive एनोटेशन देखें. जैसे, toString या equals.
  4. सिर्फ़ उन टारगेट को बनाएं जिनकी आपको ज़रूरत है:

    • उन बैकएंड को बंद करें जिनका इस्तेमाल नहीं किया जाएगा. सीपीपी बैकएंड के बजाय, NDK बैकएंड का इस्तेमाल करें; AIDL रनटाइम के ख़िलाफ़ बनाएं लेख पढ़ें.
    • अनुवाद करने वाली लाइब्रेरी या उनके जनरेट किए गए ऐसे कोड को हटाएं जिनका इस्तेमाल नहीं किया जाएगा.
  5. एआईडीएल और एचआईडीएल के बीच मुख्य अंतर देखें:

    • AIDL में पहले से मौजूद Status और अपवादों का इस्तेमाल करने से, आम तौर पर इंटरफ़ेस बेहतर होता है. साथ ही, इंटरफ़ेस के हिसाब से स्टेटस टाइप की ज़रूरत नहीं पड़ती.
    • एचआईडीएल में, एआईडीएल इंटरफ़ेस के तरीके के आर्ग्युमेंट डिफ़ॉल्ट रूप से @nullable होते थे. हालांकि, अब ऐसा नहीं है.

एआईडीएल एचएएल के लिए 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

जब कोई नया एचएएल बनाया जाता है, तो एचएएल एट्रिब्यूट जोड़ने ज़रूरी होते हैं. कोई खास एचएएल एट्रिब्यूट, कई तरह की सेवाओं से जुड़ा हो सकता है. इनमें से हर सेवा के कई इंस्टेंस हो सकते हैं, जैसा कि अभी बताया गया है. किसी एचएएल, foo के लिए, hal_attribute(foo) है. यह मैक्रो, hal_foo_client और hal_foo_server एट्रिब्यूट को तय करता है. किसी डोमेन के लिए, hal_client_domain और hal_server_domain मैक्रो, किसी डोमेन को दिए गए एचएएल एट्रिब्यूट से जोड़ते हैं. उदाहरण के लिए, इस HAL का क्लाइंट होने वाला सिस्टम सर्वर, नीति hal_client_domain(system_server, hal_foo) के मुताबिक काम करता है. इसी तरह, HAL सर्वर में hal_server_domain(my_hal_domain, hal_foo) शामिल होता है.

आम तौर पर, किसी HAL एट्रिब्यूट के लिए, hal_foo_default जैसे डोमेन भी बनाएं, ताकि HAL के उदाहरण या रेफ़रंस दिए जा सकें. हालांकि, कुछ डिवाइस अपने सर्वर के लिए इन डोमेन का इस्तेमाल करते हैं. एक से ज़्यादा सर्वर के लिए डोमेन के बीच अंतर करना सिर्फ़ तब ज़रूरी होता है, जब एक ही इंटरफ़ेस को सेवा देने वाले एक से ज़्यादा सर्वर हों और उन्हें लागू करने के लिए अलग-अलग अनुमतियों के सेट की ज़रूरत हो. इन सभी मैक्रो में, hal_foo कोई sepolicy ऑब्जेक्ट नहीं है. इसके बजाय, इस टोकन का इस्तेमाल ये मैक्रो, क्लाइंट सर्वर पेयर से जुड़े एट्रिब्यूट के ग्रुप को रेफ़र करने के लिए करते हैं.

हालांकि, अब तक hal_foo_service और hal_foo (hal_attribute(foo) से एट्रिब्यूट पेयर) को नहीं जोड़ा गया है. एचएएल एट्रिब्यूट, hal_attribute_service मैक्रो का इस्तेमाल करके एआईडीएल एचएएल सेवाओं से जुड़ा होता है. एचआईडीएल एचएएल, 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)

अटैच किए गए एक्सटेंशन इंटरफ़ेस

एक्सटेंशन को किसी भी बाइंडर इंटरफ़ेस से जोड़ा जा सकता है. भले ही, वह टॉप-लेवल का इंटरफ़ेस हो, जो सीधे तौर पर सर्विस मैनेजर के साथ रजिस्टर किया गया हो या वह सबइंटरफ़ेस हो. एक्सटेंशन पाने के दौरान, आपको पुष्टि करनी होगी कि एक्सटेंशन का टाइप आपकी उम्मीद के मुताबिक है. एक्सटेंशन सिर्फ़ उस प्रोसेस से सेट किए जा सकते हैं जो बाइंडर को दिखा रही है.

जब भी कोई एक्सटेंशन, मौजूदा एचएएल की सुविधा में बदलाव करता है, तब अटैच किए गए एक्सटेंशन का इस्तेमाल करें. जब पूरी तरह से नई सुविधा की ज़रूरत हो, तो इस तरीके का इस्तेमाल करना ज़रूरी नहीं है. इसके बजाय, सीधे तौर पर सेवा मैनेजर के साथ एक्सटेंशन इंटरफ़ेस रजिस्टर किया जा सकता है. अटैच किए गए एक्सटेंशन इंटरफ़ेस, सबइंटरफ़ेस से अटैच होने पर सबसे ज़्यादा काम के होते हैं. ऐसा इसलिए, क्योंकि ये क्रम कई लेवल के हो सकते हैं या इनके कई इंस्टेंस हो सकते हैं. किसी अन्य सेवा की बाइंडर इंटरफ़ेस हैरारकी को मिरर करने के लिए, ग्लोबल एक्सटेंशन का इस्तेमाल करने पर, सीधे तौर पर अटैच किए गए एक्सटेंशन के बराबर सुविधाएं देने के लिए, बहुत ज़्यादा बुककीपिंग की ज़रूरत होती है.

किसी बाइंडर पर एक्सटेंशन सेट करने के लिए, इन एपीआई का इस्तेमाल करें:

  • NDK बैकएंड: AIBinder_setExtension
  • Java बैकएंड: android.os.Binder.setExtension
  • सीपीपी बैकएंड: android::Binder::setExtension
  • Rust बैकएंड: binder::Binder::set_extension

किसी बाइंडर के लिए एक्सटेंशन पाने के लिए, इन एपीआई का इस्तेमाल करें:

  • NDK बैकएंड: AIBinder_getExtension
  • Java बैकएंड: android.os.IBinder.getExtension
  • सीपीपी बैकएंड: android::IBinder::getExtension
  • Rust बैकएंड: binder::Binder::get_extension

इन एपीआई के बारे में ज़्यादा जानकारी पाने के लिए, इससे जुड़े बैकएंड में getExtension फ़ंक्शन का दस्तावेज़ देखें. एक्सटेंशन इस्तेमाल करने का एक उदाहरण hardware/interfaces/tests/extension/vibrator में दिया गया है.

एआईडीएल और एचआईडीएल के बीच मुख्य अंतर

एआईडीएल एचएएल या एआईडीएल एचएएल इंटरफ़ेस का इस्तेमाल करते समय, एचआईडीएल एचएएल लिखने की तुलना में होने वाले अंतरों के बारे में जानें.

  • AIDL भाषा का सिंटैक्स, Java के ज़्यादा करीब है. HIDL का सिंटैक्स, C++ के जैसा होता है.
  • सभी एआईडीएल इंटरफ़ेस में, गड़बड़ी की स्थिति पहले से मौजूद होती है. कस्टम स्टेटस टाइप बनाने के बजाय, इंटरफ़ेस फ़ाइलों में कॉन्स्टेंट स्टेटस इंट बनाएं. साथ ही, CPP और NDK बैकएंड में EX_SERVICE_SPECIFIC और Java बैकएंड में ServiceSpecificException का इस्तेमाल करें. गड़बड़ी ठीक करना लेख पढ़ें.
  • AIDL, बाइंडर ऑब्जेक्ट भेजे जाने पर थ्रेड पूल अपने-आप शुरू नहीं करता. आपको उन्हें मैन्युअल तरीके से शुरू करना होगा. इसके लिए, थ्रेड मैनेजमेंट देखें.
  • ट्रांसपोर्ट से जुड़ी ऐसी गड़बड़ियों के लिए AIDL प्रोसेस बंद नहीं करता जिनकी जांच नहीं की गई है. हालांकि, HIDL Return ऐसी गड़बड़ियों के लिए प्रोसेस बंद कर देता है.
  • AIDL, हर फ़ाइल के लिए सिर्फ़ एक टाइप का एलान कर सकता है.
  • आउटपुट पैरामीटर के अलावा, AIDL के आर्ग्युमेंट को in, out या inout के तौर पर तय किया जा सकता है. इसमें कोई सिंक्रोनस कॉलबैक नहीं होता.
  • AIDL, handle के बजाय fd को प्रिमिटिव टाइप के तौर पर इस्तेमाल करता है.
  • HIDL, पुराने सिस्टम के साथ काम न करने वाले बदलावों के लिए मुख्य वर्शन और पुराने सिस्टम के साथ काम करने वाले बदलावों के लिए माइनर वर्शन का इस्तेमाल करता है. AIDL में, पुराने सिस्टम के साथ काम करने वाले बदलावों को लागू किया जाता है. AIDL में, मुख्य वर्शन का कोई कॉन्सेप्ट नहीं है. इसके बजाय, इसे पैकेज के नामों में शामिल किया जाता है. उदाहरण के लिए, AIDL, पैकेज के नाम bluetooth2 का इस्तेमाल कर सकता है.
  • AIDL, डिफ़ॉल्ट रूप से रीयलटाइम प्राथमिकता को इनहेरिट नहीं करता है. रीयलटाइम प्राथमिकता इनहेरिटेंस की सुविधा चालू करने के लिए, हर बाइंडर के लिए setInheritRt फ़ंक्शन का इस्तेमाल करना ज़रूरी है.

एचएएल के लिए टेस्ट

इस सेक्शन में, एचएएल की टेस्टिंग के सबसे सही तरीकों के बारे में बताया गया है. ये तरीके तब भी मान्य होते हैं, जब आपके एचएएल के लिए इंटिग्रेशन टेस्ट वीटीएस में न हो.

Android, HAL को लागू करने के तरीके की पुष्टि करने के लिए वीटीएस पर निर्भर करता है. वीटीएस से यह पक्का करने में मदद मिलती है कि Android, वेंडर के पुराने वर्शन के साथ काम कर सकता है. VTS की जांच में फ़ेल होने वाले वर्शन में, साथ काम करने से जुड़ी समस्याएं हो सकती हैं. इनकी वजह से, ओएस के आने वाले वर्शन के साथ काम करने में समस्याएं आ सकती हैं.

HAL के लिए वीटीएस के दो मुख्य हिस्से होते हैं.

1. पुष्टि करें कि डिवाइस पर मौजूद HAL, Android को पता हैं और Android के मुताबिक हैं

Android, इंस्टॉल किए गए सभी HAL की सटीक और स्टैटिक सूची पर निर्भर करता है. इस सूची को VINTF मेनिफ़ेस्ट में दिखाया गया है. खास तौर पर, पूरे प्लैटफ़ॉर्म पर की जाने वाली जांचों से, पूरे सिस्टम में एचएएल लेयर की इंटिग्रिटी की पुष्टि की जाती है. एचएएल से जुड़े किसी भी टेस्ट को लिखने से पहले, आपको इन टेस्ट को भी चलाना चाहिए. इनसे यह पता चल सकता है कि किसी एचएएल में वीआईएनटीएफ़ कॉन्फ़िगरेशन अलग-अलग हैं या नहीं.

जांच के इस सेट को test/vts-testcase/hal/treble/vintf में देखा जा सकता है. अगर आपको वेंडर HAL लागू करने पर काम करना है, तो इसकी पुष्टि करने के लिए vts_treble_vintf_vendor_test का इस्तेमाल करें. atest vts_treble_vintf_vendor_test कमांड का इस्तेमाल करके, यह टेस्ट चलाया जा सकता है.

इन टेस्ट से यह पुष्टि की जाती है कि:

  • VINTF मेनिफ़ेस्ट में बताए गए हर @VintfStability इंटरफ़ेस को, रिलीज़ किए गए किसी वर्शन पर फ़्रीज़ कर दिया जाता है. इससे यह पुष्टि होती है कि इंटरफ़ेस के दोनों पक्ष, इंटरफ़ेस के उस वर्शन की सटीक परिभाषा से सहमत हैं. यह कुकी, बुनियादी ऑपरेशन के लिए ज़रूरी है.
  • VINTF मेनिफ़ेस्ट में बताए गए सभी एचएएल, उस डिवाइस पर उपलब्ध होते हैं. जिस क्लाइंट के पास, एलान की गई HAL सेवा को इस्तेमाल करने की ज़रूरी अनुमतियां हैं वह किसी भी समय उन सेवाओं को पा सकता है और उनका इस्तेमाल कर सकता है.
  • VINTF मेनिफ़ेस्ट में बताए गए सभी HAL, इंटरफ़ेस के उस वर्शन को इस्तेमाल कर रहे हैं जिसके बारे में उन्होंने मेनिफ़ेस्ट में बताया है.
  • किसी डिवाइस पर, बंद किए गए HAL इस्तेमाल नहीं किए जा रहे हैं. Android, एचएएल इंटरफ़ेस के पुराने वर्शन के लिए सहायता बंद कर देता है. इसके बारे में FCM के लाइफ़साइकल में बताया गया है.
  • डिवाइस पर ज़रूरी HAL मौजूद हैं. Android को ठीक से काम करने के लिए, कुछ HAL ज़रूरी होते हैं.

2. हर एचएएल के अनुमानित व्यवहार की पुष्टि करें

हर एचएएल इंटरफ़ेस के अपने वीटीएस टेस्ट होते हैं. इनसे यह पुष्टि की जाती है कि क्लाइंट से उम्मीद के मुताबिक काम हो रहा है या नहीं. टेस्ट केस, एलान किए गए हर एचएएल इंटरफ़ेस के इंस्टेंस के ख़िलाफ़ चलाए जाते हैं. साथ ही, लागू किए गए इंटरफ़ेस के वर्शन के आधार पर, खास व्यवहार लागू करते हैं.

C++ में, सिस्टम पर इंस्टॉल किए गए हर HAL की सूची पाने के लिए, libaidlvintf_gtest_helper में मौजूद android::getAidlHalInstanceNames फ़ंक्शन का इस्तेमाल किया जा सकता है. Rust में, binder::get_declared_instances का इस्तेमाल करें.

इन टेस्ट में, HAL को लागू करने के हर पहलू को शामिल करने की कोशिश की जाती है. Android फ़्रेमवर्क, HAL पर निर्भर करता है या आने वाले समय में निर्भर कर सकता है.

इन टेस्ट में, सुविधाओं के काम करने की पुष्टि करना, गड़बड़ी ठीक करना, और क्लाइंट को सेवा से मिलने वाली अन्य सुविधाएं शामिल हैं.

एचएएल डेवलपमेंट के लिए वीटीएस माइलस्टोन

Android के HAL इंटरफ़ेस बनाते या उनमें बदलाव करते समय, VTS टेस्ट (या कोई भी टेस्ट) को अप-टू-डेट रखना ज़रूरी है.

Android Vendor API रिलीज़ के लिए फ़्रीज़ किए जाने से पहले, VTS टेस्ट पूरे होने चाहिए. साथ ही, वेंडर के लागू किए गए बदलावों की पुष्टि करने के लिए तैयार होने चाहिए. इंटरफ़ेस फ़्रीज़ होने से पहले, उन्हें तैयार होना चाहिए, ताकि डेवलपर उन्हें लागू कर सकें, उनकी पुष्टि कर सकें, और एचएएल इंटरफ़ेस डेवलपर को सुझाव/राय दे सकें या शिकायत कर सकें.

Cuttlefish पर टेस्ट करना

हार्डवेयर उपलब्ध न होने पर, Android, HAL इंटरफ़ेस के लिए Cuttlefish का इस्तेमाल डेवलपमेंट व्हीकल के तौर पर करता है. इससे Android के इंटिग्रेशन की जांच को बड़े पैमाने पर किया जा सकता है.

hal_implementation_test ऐसे टेस्ट जिनसे यह पता चलता है कि Cuttlefish में एचएएल इंटरफ़ेस के नए वर्शन लागू किए गए हैं. इससे यह पक्का किया जा सकता है कि Android, नए इंटरफ़ेस को हैंडल करने के लिए तैयार है. साथ ही, वीटीएस टेस्ट, नए हार्डवेयर और डिवाइसों के उपलब्ध होते ही, वेंडर के नए वर्शन को लागू करने की जांच करने के लिए तैयार हैं.