एआईडीएल, एनोटेशन के साथ काम करता है. इनकी मदद से, एआईडीएल कंपाइलर को एनोटेट किए गए एलिमेंट के बारे में अतिरिक्त जानकारी मिलती है. इसका असर, जनरेट किए गए स्टब कोड पर भी पड़ता है.
इसका सिंटैक्स, Java के सिंटैक्स जैसा होता है:
@AnnotationName(argument1=value, argument2=value) AidlEntity
यहां, AnnotationName एनोटेशन का नाम है. वहीं, AidlEntity एक एआईडीएल इकाई है. जैसे, interface Foo, void method() या int arg. एनोटेशन, उसके बाद आने वाली इकाई से अटैच होता है.
कुछ एनोटेशन में, ब्रैकेट के अंदर आर्ग्युमेंट सेट किए जा सकते हैं. जैसा कि पिछले उदाहरण में दिखाया गया है. जिन एनोटेशन में आर्ग्युमेंट नहीं होता उनके लिए ब्रैकेट की ज़रूरत नहीं होती. उदाहरण के लिए:
@AnnotationName AidlEntity
ये एनोटेशन, Java के एनोटेशन से अलग होते हैं. हालांकि, ये दिखने में एक जैसे होते हैं. सभी एनोटेशन पहले से तय होते हैं. साथ ही, इन पर पाबंदियां होती हैं कि इन्हें कहां अटैच किया जा सकता है. कुछ एनोटेशन का असर सिर्फ़ किसी खास बैकएंड पर पड़ता है. वहीं, अन्य बैकएंड में ये काम नहीं करते.
यहां, पहले से तय एआईडीएल एनोटेशन की सूची दी गई है:
| एनोटेशन | Android के इस वर्शन में जोड़ा गया |
|---|---|
nullable | 7 |
utf8InCpp | 7 |
VintfStability | 11 |
UnsupportedAppUsage | 10 |
Hide | 11 |
Backing | 11 |
NdkOnlyStableParcelable | 14 |
JavaOnlyStableParcelable | 11 |
JavaDerive | 12 |
JavaPassthrough | 12 |
FixedSize | 12 |
Descriptor | 12 |
nullable
nullable से यह तय होता है कि एनोटेट की गई इकाई की वैल्यू, शून्य हो सकती है.
इस एनोटेशन को सिर्फ़ मेथड के रिटर्न टाइप, मेथड के पैरामीटर, और पार्सल किए जा सकने वाले फ़ील्ड से अटैच किया जा सकता है:
interface IFoo {
// method return types
@nullable Data method();
// method parameters
void method2(in @nullable Data d);
}
parcelable Data {
// parcelable fields
@nullable Data d;
}
एनोटेशन को प्रिमिटिव टाइप से अटैच नहीं किया जा सकता. यहां एक गड़बड़ी दिखाई गई है:
void method(in @nullable int a); // int is a primitive type
Java बैकएंड के लिए, यह एनोटेशन काम नहीं करता. Java में, सभी नॉनप्रिमिटिव टाइप को रेफ़रंस के ज़रिए पास किया जाता है. इनकी वैल्यू null हो सकती है.
सीपीपी बैकएंड में, Android
11 या इससे पुराने वर्शन में @nullable T, std::unique_ptr<T> पर मैप होता है. वहीं, Android 12 या इसके बाद के वर्शन में यह std::optional<T> पर मैप होता है.
एनडीके बैकएंड में, @nullable T, std::optional<T> पर मैप होता है.
Rust बैकएंड में, @nullable T, Option<T> पर मैप होता है.
सूची जैसे टाइप L के लिए, जैसे कि T[] या List<T>, @nullable L पर मैप होता है
std::optional<std::vector<std::optional<T>>>. वहीं, Android 11 या इससे पुराने वर्शन के लिए, सीपीपी बैकएंड में यह
std::unique_ptr<std::vector<std::unique_ptr<T>>> पर मैप होता है.
इस मैपिंग में एक अपवाद है. जब T, IBinder या कोई एआईडीएल इंटरफ़ेस होता है, तो Rust को छोड़कर अन्य सभी बैकएंड के लिए @nullable काम नहीं करता. दूसरे शब्दों में, दोनों
@nullable IBinder और IBinder समान रूप से android::sp<IBinder> पर मैप होते हैं, जो
पहले से ही शून्य हो सकता है क्योंकि यह एक मज़बूत पॉइंटर है (सीपीपी रीड अभी भी
शून्य वैल्यू लागू करते हैं, लेकिन टाइप अभी भी android::sp<IBinder> है). Rust में,
ये टाइप केवल तभी nullable होते हैं जब उन्हें @nullable से एनोटेट किया गया हो. एनोटेट किए जाने पर, ये
Option<T> पर मैप होते हैं.
Android 13 से, पार्सल किए जा सकने वाले फ़ील्ड के लिए @nullable(heap=true) का इस्तेमाल करके, रिकर्सिव टाइप मॉडल किए जा सकते हैं. मेथड के पैरामीटर या रिटर्न टाइप के साथ @nullable(heap=true) का इस्तेमाल नहीं किया जा सकता. इससे एनोटेट किए जाने पर, फ़ील्ड को
सीपीपी और एनडीके
बैकएंड में, हीप-एलोकेट किए गए रेफ़रंस std::unique_ptr<T> पर मैप किया जाता है. Java बैकएंड में, @nullable(heap=true) काम नहीं करता.
utf8InCpp
utf8InCpp से यह तय होता है कि सीपीपी बैकएंड के लिए, String को UTF8 फ़ॉर्मैट में दिखाया जाता है. जैसा कि इसके नाम से पता चलता है, अन्य बैकएंड के लिए यह एनोटेशन काम नहीं करता.
खास तौर पर, Java बैकएंड में String हमेशा UTF16 में होता है. वहीं, एनडीके बैकएंड में यह UTF8 में होता है.
इस एनोटेशन को कहीं भी अटैच किया जा सकता है, जहां String टाइप का इस्तेमाल किया जा सकता है. इनमें रिटर्न वैल्यू, पैरामीटर, कॉन्स्टेंट के एलान, और पार्सल किए जा सकने वाले फ़ील्ड शामिल हैं.
सीपीपी बैकएंड के लिए, एआईडीएल में @utf8InCpp String, std::string पर मैप होता है. वहीं,
String एनोटेशन के बिना, android::String16 पर मैप होता है. इसमें UTF16 का इस्तेमाल किया जाता है.
VintfStability
VintfStability से यह तय होता है कि उपयोगकर्ता के तय किए गए टाइप (इंटरफ़ेस, पार्सल किए जा सकने वाले, और enum) का इस्तेमाल, सिस्टम और वेंडर डोमेन, दोनों में किया जा सकता है. सिस्टम और वेंडर के बीच इंटरऑपरेबिलिटी के बारे में ज़्यादा जानने के लिए, एचएएल के लिए
एआईडीएल देखें.
इस एनोटेशन से टाइप के सिग्नेचर में कोई बदलाव नहीं होता. हालांकि, इसे सेट करने पर, टाइप के इंस्टेंस को स्टेबल के तौर पर मार्क किया जाता है, ताकि इसे वेंडर और सिस्टम प्रोसेस के बीच ट्रांसफ़र किया जा सके.
इस एनोटेशन को सिर्फ़ उपयोगकर्ता के तय किए गए टाइप के एलान से अटैच किया जा सकता है. जैसा कि यहां दिखाया गया है:
@VintfStability
interface IFoo {
....
}
@VintfStability
parcelable Data {
....
}
@VintfStability
enum Type {
....
}
जब किसी टाइप को VintfStability से एनोटेट किया जाता है, तो उस टाइप में रेफ़रंस किए गए किसी भी अन्य टाइप को भी इसी तरह एनोटेट किया जाना चाहिए. यहां दिए गए उदाहरण में, Data और IBar, दोनों को VintfStability से एनोटेट किया जाना चाहिए:
@VintfStability
interface IFoo {
void doSomething(in IBar b); // references IBar
void doAnother(in Data d); // references Data
}
@VintfStability // required
interface IBar {...}
@VintfStability // required
parcelable Data {...}
इसके अलावा, VintfStability से एनोटेट किए गए टाइप तय करने वाली एआईडीएल फ़ाइलों को सिर्फ़ aidl_interface Soong मॉड्यूल टाइप का इस्तेमाल करके बनाया जा सकता है. इसके लिए, stability प्रॉपर्टी को vintf पर सेट करना होगा:
aidl_interface {
name: "my_interface",
srcs: [...],
stability: "vintf",
}
UnsupportedAppUsage
UnsupportedAppUsage एनोटेशन से यह पता चलता है कि एनोटेट किया गया एआईडीएल टाइप, गैर-एसडीके इंटरफ़ेस का हिस्सा है. इसे लेगसी ऐप्लिकेशन के लिए ऐक्सेस किया जा सकता है.
छिपे हुए एपीआई के बारे में ज़्यादा जानकारी के लिए, गैर-एसडीके
इंटरफ़ेस
पर पाबंदियां देखें.
UnsupportedAppUsage एनोटेशन से, जनरेट किए गए कोड के व्यवहार पर कोई असर नहीं पड़ता. यह एनोटेशन, जनरेट की गई Java क्लास को सिर्फ़ उसी नाम के Java एनोटेशन से एनोटेट करता है:
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
नॉन-Java बैकएंड के लिए, यह एनोटेशन काम नहीं करता.
Backing एनोटेशन
Backing एनोटेशन से, एआईडीएल enum टाइप का स्टोरेज टाइप तय होता है:
@Backing(type="int")
enum Color { RED, BLUE, }
सीपीपी बैकएंड में, इससे int32_t टाइप की C++ enum क्लास जनरेट होती है:
enum class Color : int32_t {
RED = 0,
BLUE = 1,
}
अगर एनोटेशन मौजूद नहीं है, तो type को byte माना जाता है. यह सीपीपी बैकएंड के लिए int8_t पर मैप होता है.
type आर्ग्युमेंट को सिर्फ़ इन इंटिग्रल टाइप पर सेट किया जा सकता है:
byte(8-बिट)int(32-बिट)long(64-बिट)
NdkOnlyStableParcelable
NdkOnlyStableParcelable से, पार्सल किए जा सकने वाले एलान (डेफ़िनिशन नहीं) को स्टेबल के तौर पर मार्क किया जाता है, ताकि इसे अन्य स्टेबल एआईडीएल टाइप से रेफ़रंस किया जा सके. यह
JavaOnlyStableParcelable की तरह है. हालांकि,
NdkOnlyStableParcelable से, पार्सल किए जा सकने वाले एलान को Java के बजाय एनडीके
बैकएंड के लिए स्टेबल के तौर पर मार्क किया जाता है.
इस पार्सल किए जा सकने वाले का इस्तेमाल करने के लिए:
- आपको
ndk_headerतय करना होगा. - आपके पास एक एनडीके लाइब्रेरी होनी चाहिए. इसमें पार्सल किए जा सकने वाले की जानकारी दी गई हो. साथ ही, लाइब्रेरी को लाइब्रेरी में कंपाइल किया जाना चाहिए. उदाहरण के लिए,
cc_*मॉड्यूल पर कोर बिल्ड सिस्टम में,static_libsयाshared_libsका इस्तेमाल करें.aidl_interfaceके लिए,Android.bpमेंadditional_shared_librariesके तहत लाइब्रेरी जोड़ें.
JavaOnlyStableParcelable
JavaOnlyStableParcelable से, पार्सल किए जा सकने वाले एलान (डेफ़िनिशन नहीं) को स्टेबल के तौर पर मार्क किया जाता है, ताकि इसे अन्य स्टेबल एआईडीएल टाइप से रेफ़रंस किया जा सके.
स्टेबल एआईडीएल के लिए, उपयोगकर्ता के तय किए गए सभी टाइप स्टेबल होने चाहिए. पार्सल किए जा सकने वाले को स्टेबल बनाने के लिए, उसके फ़ील्ड को एआईडीएल सोर्स फ़ाइल में साफ़ तौर पर बताया जाना चाहिए:
parcelable Data { // Data is a structured parcelable.
int x;
int y;
}
parcelable AnotherData { // AnotherData is also a structured parcelable
Data d; // OK, because Data is a structured parcelable
}
अगर पार्सल किए जा सकने वाले का स्ट्रक्चर नहीं है (या सिर्फ़ एलान किया गया है), तो उसे रेफ़रंस नहीं किया जा सकता:
parcelable Data; // Data is NOT a structured parcelable
parcelable AnotherData {
Data d; // Error
}
JavaOnlyStableParcelable की मदद से, उस पार्सल किए जा सकने वाले को रेफ़रंस करते समय, जांच को बदला जा सकता है जो Android SDK के हिस्से के तौर पर सुरक्षित तरीके से उपलब्ध है:
@JavaOnlyStableParcelable
parcelable Data;
parcelable AnotherData {
Data d; // OK
}
JavaDerive
JavaDerive से, Java बैकएंड में पार्सल किए जा सकने वाले टाइप के लिए, मेथड अपने-आप जनरेट होते हैं:
@JavaDerive(equals = true, toString = true)
parcelable Data {
int number;
String str;
}
एनोटेशन के लिए, यह कंट्रोल करने के लिए अतिरिक्त पैरामीटर की ज़रूरत होती है कि क्या जनरेट करना है. काम करने वाले पैरामीटर ये हैं:
equals=trueसे,equalsऔरhashCodeमेथड जनरेट होते हैं.toString=trueसे,toStringमेथड जनरेट होता है. इससे टाइप और फ़ील्ड के नाम प्रिंट होते हैं. उदाहरण के लिए,Data{number: 42, str: foo}.
JavaDefault (अब इस्तेमाल में नहीं है)
Android 13 में जोड़ा गया JavaDefault, यह कंट्रोल करता है कि डिफ़ॉल्ट तौर पर लागू करने के वर्शनिंग की सुविधा जनरेट की गई है या नहीं. यह सुविधा setDefaultImpl के लिए है. जगह बचाने के लिए, यह सुविधा अब डिफ़ॉल्ट रूप से जनरेट नहीं होती.
JavaPassthrough
JavaPassthrough की मदद से, जनरेट किए गए Java एपीआई को किसी भी Java एनोटेशन से एनोटेट किया जा सकता है.
एआईडीएल में मौजूद ये एनोटेशन:
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")
जनरेट किए गए Java कोड में इस तरह दिखते हैं:
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
annotation पैरामीटर की वैल्यू सीधे तौर पर एमिट होती है. एआईडीएल कंपाइलर, पैरामीटर की वैल्यू की जांच नहीं करता. अगर Java-लेवल के सिंटैक्स में कोई गड़बड़ी होती है, तो उसे एआईडीएल कंपाइलर नहीं, बल्कि Java कंपाइलर पकड़ता है.
इस एनोटेशन को किसी भी एआईडीएल इकाई से अटैच किया जा सकता है. नॉन-Java बैकएंड के लिए, यह एनोटेशन काम नहीं करता.
RustDerive
RustDerive से, जनरेट किए गए Rust टाइप के लिए, ट्रेट अपने-आप लागू होते हैं.
एनोटेशन के लिए, यह कंट्रोल करने के लिए अतिरिक्त पैरामीटर की ज़रूरत होती है कि क्या जनरेट करना है. काम करने वाले पैरामीटर ये हैं:
Copy=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=true
इन ट्रेट के बारे में जानने के लिए, Rust का दस्तावेज़ देखें.
FixedSize
FixedSize से, स्ट्रक्चर्ड पार्सल किए जा सकने वाले को तय साइज़ के तौर पर मार्क किया जाता है. मार्क करने के बाद, पार्सल किए जा सकने वाले में नए फ़ील्ड नहीं जोड़े जा सकते. पार्सल किए जा सकने वाले के सभी फ़ील्ड, तय साइज़ वाले टाइप होने चाहिए. इनमें प्रिमिटिव टाइप, enum, तय साइज़ वाले कलेक्शन, और FixedSize से मार्क किए गए अन्य पार्सल किए जा सकने वाले शामिल हैं.
ndk बैकएंड में, FixedSize ऑब्जेक्ट के साइज़ और अलाइनमेंट स्टेबल होते हैं.
| टाइप | साइज़ (बाइट में) | अलाइनमेंट (बाइट में) |
|---|---|---|
boolean |
1 |
1 |
byte |
1 |
1 |
char |
2 |
2 |
int |
4 |
4 |
long |
8 |
8 |
float |
4 |
4 |
double |
8 |
8 |
parcelable |
सभी फ़ील्ड का कुल साइज़ | सभी फ़ील्ड का सबसे बड़ा अलाइनमेंट |
union |
सभी फ़ील्ड का सबसे बड़ा साइज़ | सभी फ़ील्ड का सबसे बड़ा अलाइनमेंट |
enum |
बैकअप टाइप का साइज़ | बैकअप टाइप का अलाइनमेंट |
T[N] (तय साइज़ वाला कलेक्शन) |
T * N का साइज़ |
T का अलाइनमेंट |
String, IBinder, FileDescriptor, ParcelFileDescriptor |
N/A |
N/A |
Descriptor
Descriptor से, किसी इंटरफ़ेस के इंटरफ़ेस डिस्क्रिप्टर को ज़बरदस्ती तय किया जाता है:
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
इस इंटरफ़ेस का डिस्क्रिप्टर android.bar.IWorld है. अगर Descriptor एनोटेशन मौजूद नहीं है, तो डिस्क्रिप्टर android.foo.IHello होगा.
यह पहले से पब्लिश किए गए इंटरफ़ेस का नाम बदलने के लिए काम का है. नाम बदले गए इंटरफ़ेस के डिस्क्रिप्टर को, नाम बदलने से पहले वाले इंटरफ़ेस के डिस्क्रिप्टर के जैसा बनाने से, दोनों इंटरफ़ेस एक-दूसरे से बात कर पाते हैं.
टिप्पणियों में @hide
एआईडीएल कंपाइलर, टिप्पणियों में मौजूद @hide को पहचानता है और इसे Java आउटपुट में पास करता है, ताकि metalava इसे पिकअप कर सके. इस टिप्पणी से यह पक्का करने में मदद मिलती है कि Android बिल्ड सिस्टम यह पहचानता है कि एआईडीएल एपीआई, एसडीके एपीआई नहीं हैं.
टिप्पणियों में @deprecated
एआईडीएल कंपाइलर, टिप्पणियों में मौजूद @deprecated को एक टैग के तौर पर पहचानता है. इससे, ऐसी एआईडीएल इकाई की पहचान की जाती है जिसका इस्तेमाल अब नहीं किया जाना चाहिए:
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
हर बैकएंड, अब इस्तेमाल में नहीं आने वाली इकाइयों को बैकएंड के हिसाब से एनोटेशन या एट्रिब्यूट से मार्क करता है, ताकि क्लाइंट कोड को चेतावनी मिले. ऐसा तब होता है, जब वह अब इस्तेमाल में नहीं आने वाली इकाइयों को रेफ़रंस करता है. उदाहरण के लिए, @Deprecated एनोटेशन और @deprecated टैग, Java के जनरेट किए गए कोड से अटैच होते हैं.