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

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

सिंटैक्स, 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 बताता है कि हो सकता है कि एनोटेट की गई इकाई की वैल्यू न दी गई हो.

इस जानकारी को सिर्फ़ तरीके लौटाने के तरीकों, तरीके के पैरामीटर, और पार्स किए जा सकने वाले फ़ील्ड में अटैच किया जा सकता है.

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> को मैप करता है.

एनडीके बैकएंड में, @nullable T हमेशा std::optional<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 इंटरफ़ेस हो, तो @nullable नो-ऑप होता है. दूसरे शब्दों में, @nullable IBinder और IBinder, दोनों android::sp<IBinder> से बराबर मैप होते हैं, जो पहले से शून्य हो सकता है, क्योंकि यह एक मज़बूत पॉइंटर है (सीपीपी से पता चलता है कि वैल्यू शून्य है, लेकिन टाइप अब भी android::sp<IBinder> है).

Android 13 और इसके बाद के वर्शन में, पार्स किए जा सकने वाले फ़ील्ड के लिए @nullable(heap=true) का इस्तेमाल किया जा सकता है. इससे, रिकर्सिव टाइप के मॉडल बनाए जा सकते हैं. @nullable(heap=true) का इस्तेमाल, तरीके के पैरामीटर या रिटर्न टाइप के साथ नहीं किया जा सकता. जब इसके साथ एनोटेट किया जाता है, तो फ़ील्ड को सीपीपी/एनडीके बैकएंड में, हीप-आवंटित रेफ़रंस std::unique_ptr<T> के साथ मैप किया जाता है. Java बैकएंड में, @nullable(heap=true) काम नहीं करता है.

utf8InCpp

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

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

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

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

विंटएफ़स्टेबिलिटी

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 सूंग मॉड्यूल टाइप का इस्तेमाल करके बनाई जा सकती हैं. इन फ़ाइलों में stability प्रॉपर्टी "vintf" पर सेट होती है.

aidl_interface {
    name: "my_interface",
    srcs: [...],
    stability: "vintf",
}

इस्तेमाल नहीं किया जा सकने वाला ऐप्लिकेशन

UnsupportedAppUsage व्याख्या से पता चलता है कि व्याख्या किया गया एआईडीएल टाइप, SDK टूल के अलावा किसी ऐसे इंटरफ़ेस का हिस्सा है जिसे लेगसी ऐप्लिकेशन से ऐक्सेस किया जा सकता है. छिपे हुए एपीआई के बारे में ज़्यादा जानकारी के लिए, बिना SDK टूल वाले इंटरफ़ेस पर पाबंदियां देखें.

UnsupportedAppUsage एनोटेशन से, जनरेट किए गए कोड के काम करने के तरीके पर कोई असर नहीं पड़ता. यह एनोटेशन, जनरेट की गई Java क्लास के साथ सिर्फ़ उसी नाम की Java एनोटेशन के बारे में बताता है.

// in AIDL
@UnsupportedAppUsage
interface IFoo {...}

// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}

यह गैर-Java बैकएंड के लिए काम नहीं करता.

बैकिंग

Backing एनोटेशन से यह पता चलता है कि एआईडीएल एनम टाइप का स्टोरेज टाइप क्या है.

@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_header तय करना होगा.
  • आपके पास पार्सल करने लायक जानकारी देने वाली एक NDK लाइब्रेरी होनी चाहिए. साथ ही, लाइब्रेरी को लाइब्रेरी में कंपाइल किया जाना चाहिए. उदाहरण के लिए, cc_* मॉड्यूल पर कोर बिल्ड सिस्टम में, static_libs या shared_libs का इस्तेमाल करें. aidl_interface के लिए, Android.bp में additional_shared_libraries से जुड़ी लाइब्रेरी जोड़ें.

JavaOnlyStableParcelable

JavaOnlyStableParcelable, पार्स किए जा सकने वाले डिक्लेरेशन (परिभाषा नहीं है) को स्टेबल के तौर पर मार्क करता है, ताकि उसे अन्य स्थायी 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
}

जब पार्स किया जा सकने वाला आपका रेफ़रंस, Android SDK के हिस्से के तौर पर पहले से ही सुरक्षित रूप से उपलब्ध हो, तो JavaOnlyStableParcelable की मदद से जांच को बदला जा सकता है.

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

Javaडिफ़ॉल्ट

Android 13 में जोड़ी गई JavaDefault से यह कंट्रोल किया जाता है कि setDefaultImpl के लिए, डिफ़ॉल्ट रूप से वर्शन लागू करने की सुविधा जनरेट होगी या नहीं. जगह बचाने के लिए, यह सहायता अब डिफ़ॉल्ट रूप से जनरेट नहीं होती.

Javaपासथ्रू

JavaPassthrough की मदद से, जनरेट किए गए Java API को आर्बिट्रेरी Java एनोटेशन के साथ एनोटेट करने की सुविधा मिलती है.

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

@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 पैरामीटर की वैल्यू सीधे तौर पर जनरेट होती है. एआईडीएल कंपाइलर पैरामीटर की वैल्यू पर ध्यान नहीं देता. अगर Java-लेवल पर सिंटैक्स की कोई गड़बड़ी होती है, तो उसे AIDL कंपाइलर नहीं देख पाएगा, बल्कि Java कंपाइलर उसे देख पाएगा.

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

तय साइज़

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

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

जानकारी

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

package android.foo;

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

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

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

@टिप्पणियों में छिपाएं

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

टिप्पणियों में @अब काम नहीं करेगा

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

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

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