Android 11 में, Android में एचएएल के लिए एआईडीएल का इस्तेमाल करने की सुविधा जोड़ी गई है. इससे, एचआईडीएल के बिना Android के कुछ हिस्सों को लागू करना संभव हो पाता है. जहां भी हो सके, एचएएल को सिर्फ़ एआईडीएल का इस्तेमाल करने के लिए ट्रांज़िशन करें. जब अपस्ट्रीम एचएएल, एचआईडीएल का इस्तेमाल करते हैं, तो एचआईडीएल का इस्तेमाल करना ज़रूरी है.
system.img
जैसे फ़्रेमवर्क कॉम्पोनेंट और vendor.img
जैसे हार्डवेयर कॉम्पोनेंट के बीच कम्यूनिकेट करने के लिए, AIDL का इस्तेमाल करने वाले एचएएल को स्थिर AIDL का इस्तेमाल करना चाहिए. हालांकि, किसी एक सेगमेंट में, जैसे कि एक HAL से दूसरे HAL में, सूचना भेजने के लिए IPC प्रोसेस का इस्तेमाल करने पर कोई पाबंदी नहीं है.
वजह
AIDL, HIDL से पहले से मौजूद है. इसका इस्तेमाल कई जगहों पर किया जाता है, जैसे कि Android फ़्रेमवर्क कॉम्पोनेंट के बीच या ऐप्लिकेशन में. अब AIDL में स्थिरता की सुविधा उपलब्ध है. इसलिए, एक ही आईपीसी रनटाइम की मदद से पूरे स्टैक को लागू किया जा सकता है. AIDL में, HIDL की तुलना में वर्शनिंग सिस्टम भी बेहतर है. यहां AIDL के कुछ फ़ायदे दिए गए हैं:
- एक ही IPC भाषा का इस्तेमाल करने का मतलब है कि आपको सिर्फ़ एक चीज़ को सीखना, डीबग करना, ऑप्टिमाइज़ करना, और सुरक्षित करना है.
- AIDL, इंटरफ़ेस के मालिकों के लिए, इन-प्लेस वर्शनिंग की सुविधा देता है:
- मालिक, इंटरफ़ेस के आखिर में तरीके या पार्सल करने लायक ऑब्जेक्ट में फ़ील्ड जोड़ सकते हैं. इसका मतलब है कि सालों के दौरान कोड का वर्शन बनाना आसान है. साथ ही, साल दर साल की लागत भी कम होती है. टाइप में बदलाव किया जा सकता है और हर इंटरफ़ेस वर्शन के लिए अतिरिक्त लाइब्रेरी की ज़रूरत नहीं होती.
- एक्सटेंशन इंटरफ़ेस, टाइप सिस्टम के बजाय रन टाइम पर अटैच किए जा सकते हैं. इसलिए, डाउनस्ट्रीम एक्सटेंशन को इंटरफ़ेस के नए वर्शन पर फिर से आधार बनाने की ज़रूरत नहीं है.
- जब कोई डेवलपर अपने मौजूदा AIDL इंटरफ़ेस को स्थिर करने का विकल्प चुनता है, तो उसका इस्तेमाल सीधे तौर पर किया जा सकता है. पहले, इंटरफ़ेस की पूरी कॉपी को HIDL में बनाना पड़ता था.
AIDL रनटाइम के हिसाब से बनाना
AIDL के तीन अलग-अलग बैकएंड हैं: Java, NDK, और CPP. स्थिर AIDL का इस्तेमाल करने के लिए, system/lib*/libbinder.so
पर libbinder
की सिस्टम कॉपी का हमेशा इस्तेमाल करें और /dev/binder
पर बातचीत करें. इसका मतलब है कि vendor
इमेज पर मौजूद कोड के लिए, VNDK की libbinder
का इस्तेमाल नहीं किया जा सकता: इस लाइब्रेरी में अस्थिर C++ API और अस्थिर इंटरनल हैं. इसके बजाय, नेटिव वेंडर कोड को AIDL के NDK बैकएंड का इस्तेमाल करना चाहिए. साथ ही, libbinder_ndk
(जो सिस्टम libbinder.so
के साथ काम करता है) और aidl_interface
एंट्री से बनाई गई NDK लाइब्रेरी के साथ लिंक करना चाहिए. मॉड्यूल के सटीक नामों के लिए, मॉड्यूल के नाम रखने के नियम देखें.
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
इंटरफ़ेस का इस्तेमाल किया जा सकता है.
इसके अलावा, ज़्यादा से ज़्यादा कोड को एक प्लैटफ़ॉर्म से दूसरे प्लैटफ़ॉर्म पर ले जाने के लिए और ग़ैर-ज़रूरी अतिरिक्त लाइब्रेरी जैसी संभावित समस्याओं से बचने के लिए, सीपीपी बैकएंड को बंद करें.
ध्यान दें कि नीचे दिए गए कोड के उदाहरण में backends
का इस्तेमाल सही है, क्योंकि इसमें तीन बैकएंड (Java, NDK, और CPP) हैं. इस कोड में, सीपीपी बैकएंड को बंद करने का तरीका बताया गया है:
aidl_interface: {
...
backends: {
cpp: {
enabled: false,
},
},
}
AIDL HAL इंटरफ़ेस ढूंढना
एचएएल के लिए AOSP के स्टेबल एआईडीएल इंटरफ़ेस, aidl
फ़ोल्डर में मौजूद होते हैं. ये फ़ोल्डर, HIDL इंटरफ़ेस वाली एक ही डायरेक्ट्री में होते हैं:
hardware/interfaces
, आम तौर पर हार्डवेयर से मिलने वाले इंटरफ़ेस के लिए होता है.frameworks/hardware/interfaces
, हार्डवेयर के लिए उपलब्ध कराए गए हाई-लेवल इंटरफ़ेस के लिए है.system/hardware/interfaces
, हार्डवेयर के लिए उपलब्ध कराए गए लो-लेवल इंटरफ़ेस के लिए है.
एक्सटेंशन इंटरफ़ेस को vendor
या hardware
में मौजूद अन्य hardware/interfaces
सबडायरेक्ट्री में डालें.
एक्सटेंशन इंटरफ़ेस
Android के हर रिलीज़ में, आधिकारिक AOSP इंटरफ़ेस का एक सेट होता है. जब Android पार्टनर इन इंटरफ़ेस में सुविधाएं जोड़ना चाहते हैं, तो उन्हें इनमें सीधे तौर पर बदलाव नहीं करना चाहिए. ऐसा करने से, उनका Android रनटाइम, AOSP Android रनटाइम के साथ काम नहीं करता. इन इंटरफ़ेस में बदलाव करने से बचें, ताकि जीएसआई इमेज काम करती रहे.
एक्सटेंशन दो अलग-अलग तरीकों से रजिस्टर किए जा सकते हैं:
- रनटाइम पर; अटैच किए गए एक्सटेंशन इंटरफ़ेस देखें
- स्टैंडअलोन के तौर पर, दुनिया भर में और VINTF में रजिस्टर किया गया हो
हालांकि, कोई भी एक्सटेंशन रजिस्टर किया जाता है, तो जब वेंडर-स्पेसिफ़िक (यानी कि अपस्ट्रीम AOSP का हिस्सा नहीं) कंपोनेंट इंटरफ़ेस का इस्तेमाल करते हैं, तो मर्ज करने से जुड़ी समस्याएं नहीं आ सकतीं. हालांकि, जब अपस्ट्रीम AOSP कंपोनेंट में डाउनस्ट्रीम बदलाव किए जाते हैं, तो मर्ज करने से जुड़ी समस्याएं आ सकती हैं. इसलिए, इन रणनीतियों का सुझाव दिया जाता है:
- अगली रिलीज़ में, इंटरफ़ेस में जोड़े गए बदलावों को AOSP में अपस्ट्रीम करें.
- अपस्ट्रीम इंटरफ़ेस में जोड़े गए ऐसे फ़ीचर जिनकी मदद से, अगले रिलीज़ में मर्ज करने से जुड़ी समस्याओं के बिना ज़्यादा आसानी से काम किया जा सकता है.
एक्सटेंशन के लिए पार्स किए जा सकने वाले आइटम: ParcelableHolder
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
}
जैसा कि पिछले कोड में देखा गया है, यह तरीका काम नहीं करता, क्योंकि डिवाइस लागू करने वाले व्यक्ति के जोड़े गए फ़ील्ड में, 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 (
.hal
) फ़ाइलों के आधार पर AIDL (.aidl
) फ़ाइलें बनाएं. - सभी बैकएंड चालू करके, बनाए गए नए AIDL पैकेज के लिए बिल्ड नियम बनाएं.
- HIDL टाइप से AIDL टाइप में अनुवाद करने के लिए, Java, CPP, और NDK बैकएंड में अनुवाद करने के तरीके बनाएं.
- ज़रूरी डिपेंडेंसी वाली Translate लाइब्रेरी के लिए, बिल्ड रूल बनाएं.
- स्टैटिक एसर्ट बनाएं, ताकि यह पक्का किया जा सके कि सीपीपी और एनडीके बैकएंड में, HIDL और एआईडीएल एनोमेरेटर की वैल्यू एक ही हों.
HAL फ़ाइलों के पैकेज को AIDL फ़ाइलों में बदलने के लिए, यह तरीका अपनाएं:
system/tools/hidl/hidl2aidl
में मौजूद टूल बनाएं.इस टूल को नए सोर्स से बनाने पर, आपको सबसे बेहतर अनुभव मिलता है. पिछले रिलीज़ की पुरानी शाखाओं पर मौजूद इंटरफ़ेस को बदलने के लिए, नए वर्शन का इस्तेमाल किया जा सकता है:
m hidl2aidl
टूल को आउटपुट डायरेक्ट्री के साथ चलाएं. इसके बाद, उस पैकेज का नाम डालें जिसे बदलना है.
इसके अलावा, जनरेट की गई सभी फ़ाइलों में सबसे ऊपर, लाइसेंस की नई फ़ाइल का कॉन्टेंट जोड़ने के लिए,
-l
आर्ग्युमेंट का इस्तेमाल करें. सही लाइसेंस और तारीख का इस्तेमाल करना न भूलें:hidl2aidl -o <output directory> -l <file with license> <package>
उदाहरण के लिए:
hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
जनरेट की गई फ़ाइलों को पढ़ें और कन्वर्ज़न से जुड़ी किसी भी समस्या को ठीक करें:
conversion.log
में ऐसी समस्याएं होती हैं जिन्हें पहले ठीक करना ज़रूरी है.- जनरेट की गई AIDL फ़ाइलों में ऐसी चेतावनियां और सुझाव हो सकते हैं जिन पर कार्रवाई की ज़रूरत हो. ये टिप्पणियां
//
से शुरू होती हैं. - पैकेज को साफ़ करें और उसमें सुधार करें.
- ज़रूरी सुविधाओं के लिए,
@JavaDerive
एनोटेशन देखें. जैसे,toString
याequals
.
सिर्फ़ अपनी ज़रूरत के मुताबिक टारगेट बनाएं:
- ऐसे बैकएंड बंद करें जिनका इस्तेमाल नहीं किया जाएगा. सीपीपी बैकएंड के बजाय, एनडीके बैकएंड का इस्तेमाल करें; एआईडीएल रनटाइम के हिसाब से बनाएं देखें.
- अनुवाद करने वाली लाइब्रेरी या उनसे जनरेट किया गया ऐसा कोड हटाएं जिसका इस्तेमाल नहीं किया जाएगा.
एआईडीएल और एचआईडीएल के बीच के मुख्य अंतर देखें:
- आम तौर पर, AIDL के पहले से मौजूद
Status
और अपवादों का इस्तेमाल करने से इंटरफ़ेस बेहतर होता है. साथ ही, इंटरफ़ेस के हिसाब से किसी दूसरे स्टेटस टाइप की ज़रूरत नहीं पड़ती. - मेथड में AIDL इंटरफ़ेस के आर्ग्युमेंट, डिफ़ॉल्ट रूप से
@nullable
नहीं होते, जैसे कि वे HIDL में होते थे.
- आम तौर पर, AIDL के पहले से मौजूद
एआईडीएल एचएएल के लिए SEPolicy
वेंडर कोड को दिखने वाली एआईडीएल सेवा के टाइप में,
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_service(hal_foo, hal_foo_service)
. एचआईडीएल एचएएल, hal_attribute_hwservice
मैक्रो का इस्तेमाल करते हैं. इसका मतलब है कि 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 इंटरफ़ेस में, गड़बड़ी की स्थिति पहले से मौजूद होती है. कस्टम स्थिति टाइप बनाने के बजाय, इंटरफ़ेस फ़ाइलों में कॉन्स्टेंट स्टेटस इंट बनाकर, सीपीपी और एनडीके बैकएंड में
EX_SERVICE_SPECIFIC
और Java बैकएंड मेंServiceSpecificException
का इस्तेमाल करें. गड़बड़ी को मैनेज करना देखें. - बाइंडर ऑब्जेक्ट भेजे जाने पर, AIDL अपने-आप थ्रेड पूल शुरू नहीं करता. आपको उन्हें मैन्युअल तरीके से शुरू करना होगा. इसके लिए, थ्रेड मैनेजमेंट देखें.
- AIDL, ट्रांसपोर्ट से जुड़ी ऐसी गड़बड़ियों पर प्रोसेस को बंद नहीं करता जिनकी पुष्टि नहीं की गई है. हालांकि, HIDL
Return
ऐसी गड़बड़ियों पर प्रोसेस को बंद कर देता है. - AIDL, हर फ़ाइल के लिए सिर्फ़ एक टाइप का एलान कर सकता है.
- आउटपुट पैरामीटर के अलावा, एआईडीएल आर्ग्युमेंट को
in
,out
याinout
के तौर पर तय किया जा सकता है. इसमें सिंक्रोनस कॉलबैक नहीं होते. - AIDL,
handle
के बजाय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 इंटरफ़ेस बनाते या उनमें बदलाव करते समय, यह ज़रूरी है कि वीटीएस टेस्ट अप-टू-डेट हों.
Android वेंडर एपीआई रिलीज़ के लिए फ़्रीज़ किए जाने से पहले, वीटीएस टेस्ट पूरे होने चाहिए और वेंडर के लागू किए गए वर्शन की पुष्टि के लिए तैयार होने चाहिए. इंटरफ़ेस फ़्रीज़ होने से पहले, ये तैयार होने चाहिए, ताकि डेवलपर अपने लागू किए गए वर्शन बना सकें, उनकी पुष्टि कर सकें, और HAL इंटरफ़ेस के डेवलपर को सुझाव/राय दे सकें.
Cuttlefish पर VTS
जब हार्डवेयर उपलब्ध नहीं होता, तब Android, एचएएल इंटरफ़ेस के लिए डेवलपमेंट वाहन के तौर पर Cuttlefish का इस्तेमाल करता है. इससे, स्केलेबल VTS और Android के इंटिग्रेशन टेस्टिंग की सुविधा मिलती है.
hal_implementation_test
यह जांच करता है कि Cuttlefish में, एचएएल इंटरफ़ेस के नए वर्शन लागू किए गए हैं या नहीं. इससे यह पक्का किया जा सकता है कि Android, नए इंटरफ़ेस को मैनेज करने के लिए तैयार है. साथ ही, नए हार्डवेयर और डिवाइस उपलब्ध होने पर, VTS टेस्ट, नए वेंडर के लागू किए गए वर्शन की जांच के लिए तैयार हैं.