AIDL, एनोटेशन के साथ काम करता है. ये एनोटेशन, AIDL कंपाइलर को एनोटेट किए गए एलिमेंट के बारे में अतिरिक्त जानकारी देते हैं. इससे जनरेट किए गए स्टब कोड पर भी असर पड़ता है.
इसका सिंटैक्स, Java के सिंटैक्स जैसा ही होता है:
@AnnotationName(argument1=value, argument2=value) AidlEntity
यहां, AnnotationName एनोटेशन का नाम है और AidlEntity, interface Foo, void method() या int arg जैसी एआईडीएल इकाई है. एनोटेशन, उसके बाद आने वाली इकाई से जुड़ा होता है.
कुछ एनोटेशन में, कोष्ठक के अंदर आर्ग्युमेंट सेट किए जा सकते हैं. जैसा कि पिछले उदाहरण में दिखाया गया है. जिन एनोटेशन में कोई तर्क नहीं होता उनके लिए कोष्ठक की ज़रूरत नहीं होती. उदाहरण के लिए:
@AnnotationName AidlEntity
ये एनोटेशन, Java एनोटेशन से अलग होते हैं. हालांकि, ये एक जैसे दिखते हैं. सभी एनोटेशन पहले से तय होते हैं. साथ ही, इन्हें अटैच करने के लिए कुछ पाबंदियां होती हैं. कुछ एनोटेशन सिर्फ़ किसी खास बैकएंड पर असर डालते हैं और अन्य बैकएंड में काम नहीं करते.
यहां AIDL के पहले से तय एनोटेशन की सूची दी गई है:
| एनोटेशन | 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 यह एलान करता है कि एनोटेट की गई इकाई की वैल्यू शून्य हो सकती है.
इस एनोटेशन को सिर्फ़ इन चीज़ों से अटैच किया जा सकता है: मेथड के रिटर्न टाइप, मेथड के पैरामीटर, और पार्सल किए जा सकने वाले फ़ील्ड:
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 या इसके बाद के वर्शन में @nullable T को 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 या AIDL इंटरफ़ेस होता है, तब @nullable, Rust को छोड़कर सभी बैकएंड के लिए नो-ऑप होता है. दूसरे शब्दों में कहें, तो @nullable IBinder और IBinder, दोनों को android::sp<IBinder> के तौर पर मैप किया जाता है. यह पहले से ही नल हो सकता है, क्योंकि यह एक स्ट्रॉन्ग पॉइंटर है. CPP में, अब भी नल होने की स्थिति लागू होती है, लेकिन टाइप अब भी android::sp<IBinder> है. Rust में, ये टाइप nullable सिर्फ़ तब होते हैं, जब इन्हें @nullable के साथ एनोटेट किया जाता है. अगर एनोटेट किया गया है, तो ये Option<T> पर मैप होते हैं.
Android 13 से, @nullable(heap=true) का इस्तेमाल पार्सल किए जा सकने वाले फ़ील्ड के लिए किया जा सकता है, ताकि रिकर्सिव टाइप को मॉडल किया जा सके. @nullable(heap=true) का इस्तेमाल, मेथड पैरामीटर या रिटर्न टाइप के साथ नहीं किया जा सकता. इस एनोटेशन का इस्तेमाल करने पर, फ़ील्ड को CPP और NDK बैकएंड में हीप-एलॉकेट किए गए रेफ़रंस std::unique_ptr<T> पर मैप किया जाता है. @nullable(heap=true), Java बैकएंड में कोई कार्रवाई नहीं करता है.
utf8InCpp
utf8InCpp यह एलान करता है कि CPP बैकएंड के लिए, String को UTF8 फ़ॉर्मैट में दिखाया गया है. जैसा कि इसके नाम से पता चलता है, यह एनोटेशन अन्य बैकएंड के लिए कोई कार्रवाई नहीं करता है.
खास तौर पर, Java बैकएंड में String हमेशा UTF16 होता है और NDK बैकएंड में UTF8 होता है.
इस एनोटेशन को किसी भी ऐसी जगह पर जोड़ा जा सकता है जहां String टाइप का इस्तेमाल किया जा सकता है. जैसे, रिटर्न वैल्यू, पैरामीटर, कॉन्सटेंट के एलान, और पार्सल किए जा सकने वाले फ़ील्ड.
CPP बैकएंड के लिए, AIDL में @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 फ़ाइलों को सिर्फ़ aidl_interface Soong मॉड्यूल टाइप का इस्तेमाल करके बनाया जा सकता है. साथ ही, stability प्रॉपर्टी को vintf पर सेट किया जा सकता है:
aidl_interface {
name: "my_interface",
srcs: [...],
stability: "vintf",
}
UnsupportedAppUsage
UnsupportedAppUsage एनोटेशन से पता चलता है कि एनोटेट किया गया AIDL टाइप, गैर-एसडीके इंटरफ़ेस का हिस्सा है. यह इंटरफ़ेस, लेगसी ऐप्लिकेशन के लिए उपलब्ध है.
छुपे हुए एपीआई के बारे में ज़्यादा जानने के लिए, नॉन-एसडीके इंटरफ़ेस पर पाबंदियां देखें.
UnsupportedAppUsage एनोटेशन से, जनरेट किए गए कोड के व्यवहार पर कोई असर नहीं पड़ता. यह एनोटेशन, जनरेट की गई Java क्लास को सिर्फ़ उसी नाम के Java एनोटेशन के साथ एनोटेट करता है:
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
यह Java के अलावा अन्य बैकएंड के लिए कोई कार्रवाई नहीं करता है.
बैकअप एनोटेशन
Backing एनोटेशन, AIDL enum टाइप के स्टोरेज टाइप के बारे में बताता है:
@Backing(type="int")
enum Color { RED, BLUE, }
CPP बैकएंड में, यह 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 पार्सल किए जा सकने वाले किसी एलान (डेफ़िनिशन नहीं) को स्टेबल के तौर पर मार्क करता है, ताकि इसे अन्य स्टेबल AIDL टाइप से रेफ़रंस किया जा सके. यह JavaOnlyStableParcelable की तरह है, लेकिन NdkOnlyStableParcelable, पार्सल किए जा सकने वाले एलान को Java के बजाय NDK बैकएंड के लिए स्टेबल के तौर पर मार्क करता है.
इस पार्सल का इस्तेमाल करने के लिए:
- आपको
ndk_headerएट्रिब्यूट की वैल्यू देनी होगी. - आपके पास एक NDK लाइब्रेरी होनी चाहिए, जिसमें पार्सल किए जा सकने वाले ऑब्जेक्ट के बारे में जानकारी दी गई हो. साथ ही, लाइब्रेरी को लाइब्रेरी में कंपाइल किया जाना चाहिए. उदाहरण के लिए,
cc_*मॉड्यूल पर कोर बिल्ड सिस्टम में,static_libsयाshared_libsका इस्तेमाल करें.aidl_interfaceके लिए,Android.bpमेंadditional_shared_librariesके नीचे मौजूद लाइब्रेरी जोड़ें.
JavaOnlyStableParcelable
JavaOnlyStableParcelable पार्सल किए जा सकने वाले किसी एलान (डेफ़िनिशन नहीं) को स्टेबल के तौर पर मार्क करता है, ताकि इसे अन्य स्टेबल AIDL टाइप से रेफ़रंस किया जा सके.
स्टेबल AIDL के लिए, यह ज़रूरी है कि उपयोगकर्ता की ओर से तय किए गए सभी टाइप स्टेबल हों. पार्सल किए जा सकने वाले ऑब्जेक्ट के लिए, यह ज़रूरी है कि उसके फ़ील्ड के बारे में एआईडीएल सोर्स फ़ाइल में साफ़ तौर पर बताया गया हो:
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 (अब सेवा में नहीं है)
JavaDefault को Android 13 में जोड़ा गया था. इससे यह कंट्रोल किया जाता है कि setDefaultImpl के लिए, डिफ़ॉल्ट तौर पर लागू किए गए वर्शन के साथ काम करने की सुविधा जनरेट की जाए या नहीं. जगह बचाने के लिए, अब यह सुविधा डिफ़ॉल्ट रूप से जनरेट नहीं होती.
JavaPassthrough
JavaPassthrough की मदद से, जनरेट किए गए Java API को किसी भी 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 पैरामीटर की वैल्यू सीधे तौर पर भेजी जाती है. AIDL कंपाइलर, पैरामीटर की वैल्यू की जांच नहीं करता. अगर Java-लेवल पर सिंटैक्स से जुड़ी कोई गड़बड़ी होती है, तो उसे AIDL कंपाइलर नहीं, बल्कि Java कंपाइलर पकड़ लेगा.
इस एनोटेशन को किसी भी AIDL इकाई से जोड़ा जा सकता है. यह एनोटेशन, Java के अलावा अन्य बैकएंड के लिए कोई कार्रवाई नहीं करता.
RustDerive
RustDerive, जनरेट किए गए Rust टाइप के लिए, अपने-आप ट्रेट लागू करता है.
एनोटेशन को यह कंट्रोल करने के लिए अतिरिक्त पैरामीटर की ज़रूरत होती है कि क्या जनरेट करना है. इन पैरामीटर का इस्तेमाल किया जा सकता है:
Copy=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=true
इन विशेषताओं के बारे में जानने के लिए, Rust का दस्तावेज़ देखें.
FixedSize
FixedSize, स्ट्रक्चर्ड पार्सलेबल को तय साइज़ के तौर पर मार्क करता है. मार्क किए जाने के बाद, पार्सल किए जा सकने वाले ऑब्जेक्ट में नए फ़ील्ड नहीं जोड़े जा सकते. पार्सल किए जा सकने वाले ऑब्जेक्ट के सभी फ़ील्ड का साइज़ तय होना चाहिए. इनमें प्रिमिटिव टाइप, एनम, तय साइज़ वाले ऐरे, और FixedSize के तौर पर मार्क किए गए अन्य पार्सल किए जा सकने वाले ऑब्जेक्ट शामिल हैं.
FixedSize ऑब्जेक्ट के साइज़ और अलाइनमेंट, ndk बैकएंड में स्थिर होते हैं.
| टाइप | साइज़ (बाइट में) | अलाइनमेंट (बाइट में) |
|---|---|---|
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, किसी इंटरफ़ेस के इंटरफ़ेस डिस्क्रिप्टर को ज़बरदस्ती तय करता है:
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
इस इंटरफ़ेस का डिस्क्रिप्टर android.bar.IWorld है. अगर Descriptor एनोटेशन मौजूद नहीं है, तो डिस्क्रिप्टर android.foo.IHello होगा.
यह पहले से पब्लिश किए गए इंटरफ़ेस का नाम बदलने के लिए काम आता है. नाम बदले गए इंटरफ़ेस के डिस्क्रिप्टर को, नाम बदलने से पहले इंटरफ़ेस के डिस्क्रिप्टर के जैसा ही बनाने से, दोनों इंटरफ़ेस एक-दूसरे से कम्यूनिकेट कर पाते हैं.
@hide in comments
AIDL कंपाइलर, टिप्पणियों में मौजूद @hide को पहचानता है और इसे Java आउटपुट में पास करता है, ताकि metalava इसे पिकअप कर सके. इस टिप्पणी से यह पक्का करने में मदद मिलती है कि Android बिल्ड सिस्टम यह पहचान ले कि AIDL एपीआई, एसडीके एपीआई नहीं हैं.
@deprecated in comments
एआईडीएल कंपाइलर, टिप्पणियों में @deprecated को ऐसे टैग के तौर पर पहचानता है जिसका इस्तेमाल अब नहीं किया जाना चाहिए:
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
हर बैकएंड, बंद की गई इकाइयों को बैकएंड के हिसाब से एनोटेशन या एट्रिब्यूट के साथ मार्क करता है, ताकि क्लाइंट कोड को यह सूचना मिल सके कि वह बंद की गई इकाइयों को रेफ़र कर रहा है. उदाहरण के लिए, @Deprecated एनोटेशन और @deprecated टैग, Java से जनरेट किए गए कोड से जुड़े होते हैं.