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

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

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

वजह

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

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

AIDL रनटाइम के हिसाब से बनाना

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

AIDL HAL इंटरफ़ेस लिखना

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

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

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

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

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

ध्यान दें कि नीचे दिए गए कोड के उदाहरण में backends का इस्तेमाल सही है, क्योंकि इसमें तीन बैकएंड (Java, NDK, और CPP) हैं. नीचे दिए गए कोड में, सीपीपी बैकएंड को चुनने और उसे बंद करने का तरीका बताया गया है.

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

AIDL HAL इंटरफ़ेस ढूंढना

एचएएल के लिए AOSP के स्टेबल एआईडीएल इंटरफ़ेस, aidl फ़ोल्डर में मौजूद एचआईडीएल इंटरफ़ेस की ही बेस डायरेक्ट्री में होते हैं.

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

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

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

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

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

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

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

एक्सटेंशन के लिए पार्स किए जा सकने वाले आइटम: ParcelableHolder

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

पहले, ParcelableHolder के बिना, डिवाइस लागू करने वाले लोग, AOSP के तय किए गए स्थिर AIDL इंटरफ़ेस में बदलाव नहीं कर सकते थे, क्योंकि ज़्यादा फ़ील्ड जोड़ने पर गड़बड़ी होती थी:

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;
}

आखिर में, नए 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 VINTF मेनिफ़ेस्ट में, एआईडीएल सर्वर की जानकारी देना ज़रूरी है. उदाहरण के लिए, इस तरह:

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

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

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>

किसी मौजूदा एचएएल को HIDL से AIDL में बदलना

HIDL इंटरफ़ेस को AIDL में बदलने के लिए, hidl2aidl टूल का इस्तेमाल करें.

hidl2aidl की सुविधाएं:

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

.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. सिर्फ़ ज़रूरी टारगेट बनाएं.

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

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

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

वेंडर कोड को दिखने वाली AIDL सेवा टाइप में, hal_service_type एट्रिब्यूट होना चाहिए. अगर ऐसा नहीं है, तो sepolicy कॉन्फ़िगरेशन, किसी भी अन्य AIDL सेवा के जैसा ही होता है. हालांकि, एचएएल के लिए खास एट्रिब्यूट होते हैं. यहां 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_client_domain(system_server, hal_foo) के मुताबिक है. इसी तरह, HAL सर्वर में hal_server_domain(my_hal_domain, hal_foo) शामिल होता है. आम तौर पर, किसी दिए गए एचएएल एट्रिब्यूट के लिए, हम रेफ़रंस या उदाहरण के तौर पर एचएएल के लिए hal_foo_default जैसा डोमेन भी बनाते हैं. हालांकि, कुछ डिवाइस अपने सर्वर के लिए इन डोमेन का इस्तेमाल करते हैं. एक से ज़्यादा सर्वर के लिए डोमेन के बीच अंतर करना सिर्फ़ तब ज़रूरी होता है, जब हमारे पास एक ही इंटरफ़ेस देने वाले कई सर्वर हों और उन्हें लागू करने के लिए अलग-अलग अनुमति सेट की ज़रूरत हो. इन सभी मैक्रो में, 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_attribute_service(hal_foo, hal_foo2_service) दिख सकता है. आम तौर पर, इससे यह पता चलता है कि सेवाओं का इस्तेमाल हमेशा एक साथ किया जाता है. इसलिए, हम hal_foo2_service को हटाकर, अपनी सभी सेवाओं के लिए hal_foo_service का इस्तेमाल कर सकते हैं. ज़्यादातर एचएएल, एक से ज़्यादा hal_attribute_service सेट करते हैं, क्योंकि एचएएल के मूल एट्रिब्यूट का नाम सामान्य नहीं है और इसे बदला नहीं जा सकता.

इन सभी को मिलाकर, एचएएल का उदाहरण कुछ ऐसा दिखता है:

    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 और HIDL के बीच के मुख्य अंतर

AIDL HALs या AIDL HAL इंटरफ़ेस का इस्तेमाल करते समय, HIDL HALs लिखने के मुकाबले अंतरों के बारे में पता होना चाहिए.

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

एचएएल के लिए वेंडर टेस्ट सुइट (वीटीएस) टेस्ट

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

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

1. पुष्टि करें कि डिवाइस पर मौजूद एचएएल, Android के लिए सही और काम के हैं.

टेस्ट का यह सेट, test/vts-testcase/hal/treble/vintf में देखा जा सकता है. इनकी पुष्टि करना डेवलपर की ज़िम्मेदारी है:

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

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

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

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

इन टेस्ट में, सुविधाओं के काम करने की पुष्टि करना, गड़बड़ी को मैनेज करना, और सेवा से जुड़ा ऐसा कोई भी व्यवहार शामिल है जिसकी उम्मीद क्लाइंट को हो सकती है.

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

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

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

Cuttlefish पर VTS

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