एआईडीएल में एनोटेशन

एआईडीएल ऐसे एनोटेशन के साथ काम करता है जो एआईडीएल कंपाइलर को एनोटेट किए गए एलिमेंट के बारे में ज़्यादा जानकारी देते हैं. इससे जनरेट किए गए स्टब कोड पर भी असर पड़ता है.

सिंटैक्स, 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

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 हो सकता है.

सीपीपी बैकएंड में, @nullable T, Android 11 या उससे पहले के वर्शन में std::unique_ptr<T> पर मैप होता है. साथ ही, Android 12 या उसके बाद के वर्शन में std::optional<T> पर मैप होता है.

NDK बैकएंड में, @nullable T हमेशा std::optional<T> पर मैप होता है.

Rust बैकएंड में, @nullable T हमेशा Option<T> पर मैप होता है.

T[] या List<T> जैसी सूची जैसे टाइप L के लिए, @nullable L को std::optional<std::vector<std::optional<T>>> पर मैप करें (या Android 11 या इससे पहले के वर्शन के लिए, सीपीपी बैकएंड के मामले में std::unique_ptr<std::vector<std::unique_ptr<T>>>).

हालांकि, इस मैपिंग में एक अपवाद है. जब T IBinder या AIDL इंटरफ़ेस है, तो 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> से मैप किया जाता है. @nullable(heap=true), Java बैकएंड में काम नहीं करता.

utf8InCpp

utf8InCpp से पता चलता है कि String को सीपीपी के बैकएंड के लिए, UTF8 फ़ॉर्मैट में दिखाया गया है. जैसा कि इसके नाम से पता चलता है कि यह एनोटेशन अन्य बैकएंड के लिए काम नहीं करता. खास तौर पर, String हमेशा Java बैकएंड में UTF16 और NDK बैकएंड में UTF8 होता है.

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

सीपीपी बैकएंड के लिए, एआईडीएल में @utf8InCpp String, std::string पर मैप होता है. वहीं, एनोटेशन के बिना String, android::String16 पर मैप होता है, जहां UTF16 का इस्तेमाल किया जाता है.

ध्यान दें कि utf8InCpp एनोटेशन की मौजूदगी से, तार पर स्ट्रिंग भेजने के तरीके में कोई बदलाव नहीं होता. स्ट्रिंग को हमेशा UTF16 के तौर पर ट्रांसफ़र किया जाता है. utf8InCpp एनोटेट की गई स्ट्रिंग को ट्रांसमिट करने से पहले, उसे UTF16 में बदल दिया जाता है. जब कोई स्ट्रिंग मिलती है, तो अगर उसे utf8InCpp के तौर पर एनोटेट किया गया है, तो उसे UTF16 से UTF8 में बदल दिया जाता है.

VintfStability

VintfStability से पता चलता है कि उपयोगकर्ता के तय किए गए टाइप (इंटरफ़ेस, पार्सल करने लायक, और सूची) का इस्तेमाल, सिस्टम और वेंडर डोमेन में किया जा सकता है. सिस्टम-वेंडर इंटरऑपरेबिलिटी के बारे में ज़्यादा जानने के लिए, एचएएल के लिए एआईडीएल देखें.

एनोटेशन से टाइप के हस्ताक्षर में बदलाव नहीं होता. हालांकि, इसे सेट करने पर, टाइप के इंस्टेंस को स्थिर के तौर पर मार्क किया जाता है, ताकि वह वेंडर और सिस्टम की सभी प्रोसेस में इस्तेमाल किया जा सके.

एनोटेशन को सिर्फ़ उपयोगकर्ता के बताए गए टाइप की जानकारी के साथ अटैच किया जा सकता है, जैसा कि यहां दिखाया गया है:

@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 टाइप, SDK टूल के अलावा किसी अन्य इंटरफ़ेस का हिस्सा है. इस इंटरफ़ेस को लेगसी ऐप्लिकेशन से ऐक्सेस किया जा सकता है. छिपे हुए एपीआई के बारे में ज़्यादा जानकारी के लिए, SDK के अलावा अन्य इंटरफ़ेस पर पाबंदियां देखें.

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 की मदद से, उस Parcelable के लिए जांच को बदला जा सकता है जिसका रेफ़रंस दिया जा रहा है. ऐसा तब किया जा सकता है, जब वह 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 एनोटेशन के साथ एनोटेट किया जा सकता है.

AIDL में ये एनोटेशन

@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")

बनना

@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)

कोड में दिखेगा.

annotation पैरामीटर की वैल्यू सीधे तौर पर जनरेट होती है. AIDL कंपाइलर, पैरामीटर की वैल्यू की जांच नहीं करता. अगर Java-लेवल पर सिंटैक्स की कोई गड़बड़ी होती है, तो उसे AIDL कंपाइलर नहीं देख पाएगा, बल्कि Java कंपाइलर उसे देख पाएगा.

यह जानकारी किसी भी एआईडीएल इकाई के साथ अटैच की जा सकती है. यह एनोटेशन, Java बैकएंड के लिए काम नहीं करता.

FixedSize

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

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

डिस्क्रिप्टर

Descriptor ज़बरदस्ती किसी इंटरफ़ेस का इंटरफ़ेस डिस्क्रिप्टर तय करता है.

package android.foo;

@Descriptor(value="android.bar.IWorld")
interface IHello {...}

इस इंटरफ़ेस का डिस्क्रिप्टर android.bar.IWorld है. अगर Descriptor एनोटेशन मौजूद नहीं है, तो डिस्क्रिप्टर के तौर पर android.foo.IHello का इस्तेमाल किया जाएगा.

यह पहले से पब्लिश किए गए इंटरफ़ेस का नाम बदलने के लिए काम आता है. नाम बदले गए इंटरफ़ेस के डिस्क्रिप्टर को, नाम बदलने से पहले के इंटरफ़ेस के डिस्क्रिप्टर के जैसा बनाने से, दोनों इंटरफ़ेस एक-दूसरे से बातचीत कर पाते हैं.

@hide in comments

एआईडीएल कंपाइलर, टिप्पणियों में @hide की पहचान करता है और इसे मेटलवा को पिकअप करने के लिए, Java आउटपुट के ज़रिए पास करता है. इस टिप्पणी से यह पक्का होता है कि Android के बिल्ड सिस्टम को पता है कि AIDL एपीआई, SDK टूल के एपीआई नहीं हैं.

टिप्पणियों में @deprecated

AIDL कंपाइलर, टिप्पणियों में @deprecated को टैग के तौर पर पहचानता है. इससे, उस एआईडीएल इकाई की पहचान की जाती है जिसका अब इस्तेमाल नहीं किया जाना चाहिए.

interface IFoo {
  /** @deprecated use bar() instead */
  void foo();
  void bar();
}

हर बैकएंड, बंद की गई इकाइयों को बैकएंड के हिसाब से एनोटेशन या एट्रिब्यूट से मार्क करता है, ताकि क्लाइंट को बंद की गई इकाइयों का रेफ़रंस देने पर चेतावनी दी जा सके. उदाहरण के लिए, @Deprecated एनोटेशन और @deprecated टैग, Java से जनरेट किए गए कोड से अटैच होते हैं.