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

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

इसका सिंटैक्स, Java के सिंटैक्स जैसा ही होता है:

@AnnotationName(argument1=value, argument2=value) AidlEntity

यहां, AnnotationName एनोटेशन का नाम है और AidlEntity, interface Foo, void method() या int arg जैसी कोई एआईडीएल इकाई है. एनोटेशन, उसके बाद आने वाली इकाई से जुड़ा होता है.

कुछ एनोटेशन में, ब्रैकेट के अंदर आर्ग्युमेंट सेट किए जा सकते हैं. जैसा कि पिछले उदाहरण में दिखाया गया है. जिन एनोटेशन में कोई तर्क नहीं होता उनके लिए कोष्ठक की ज़रूरत नहीं होती. उदाहरण के लिए:

@AnnotationName AidlEntity

ये एनोटेशन, Java एनोटेशन से अलग होते हैं. हालांकि, ये एक जैसे दिखते हैं. सभी एनोटेशन पहले से तय होते हैं. साथ ही, इन्हें अटैच करने के लिए कुछ पाबंदियां होती हैं. कुछ एनोटेशन सिर्फ़ किसी खास बैकएंड पर असर डालते हैं और अन्य बैकएंड में काम नहीं करते.

यहां AIDL के पहले से तय एनोटेशन की सूची दी गई है:

एनोटेशनAndroid वर्शन में जोड़ा गया
nullable7
utf8InCpp7
VintfStability11
UnsupportedAppUsage10
Hide11
Backing11
NdkOnlyStableParcelable14
JavaOnlyStableParcelable11
JavaDerive12
JavaPassthrough12
FixedSize12
Descriptor12

शून्य हो सकता है

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

CPP बैकएंड में, 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> के तौर पर मैप किया जाता है. यह पहले से ही नल हो सकता है, क्योंकि यह एक स्ट्रॉन्ग पॉइंटर है. सीपीपी में अब भी नल होने की स्थिति लागू होती है, लेकिन टाइप अब भी 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, }

सीपीपी बैकएंड में, यह 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=true
  • Clone=true
  • Ord=true
  • PartialOrd=true
  • Eq=true
  • PartialEq=true
  • Hash=true

इन विशेषताओं के बारे में जानने के लिए, Rust का दस्तावेज़ देखें.

FixedSize

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

ब्यौरा

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

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

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

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