הערות ב-AIDL

באמצעות AIDL יש תמיכה בהערות שמספקות מידע נוסף למהדר AIDL על הרכיב עם ההערה. הפעולה הזו משפיעה גם על קוד ה-stub שנוצר.

התחביר דומה לתחביר של Java:

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

כאן, AnnotationName הוא שם ההערה, ו-AidlEntity הוא ישות AIDL כמו interface Foo, void method() או int arg. הערה מצורפת לישות שעוקבת אחריה.

עבור חלק מההערות אפשר להגדיר ארגומנטים בתוך הסוגריים, כפי שמוצג למעלה. בהערות שאין בהן ארגומנט אין צורך בסוגריים. לדוגמה:

@AnnotationName AidlEntity

ההערות האלו לא זהות להערות ב-Java, למרות שהן נראות דומות מאוד. המשתמשים לא יכולים להגדיר הערות מותאמות אישית ב-AIDL. כולן מוגדרות מראש. חלק מההערות משפיעות רק על קצה עורפי מסוים והן לא פועלות בקצוות עורפיים אחרים. יש להם הגבלות שונות שאליהן אפשר לצרף אותם.

רשימה של הערות 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

ערך null

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, @nullable T ממופה אל std::unique_ptr<T> ב-Android 11 ומטה, ול-std::optional<T> ב-Android 12 ואילך.

בקצה העורפי של NDK, @nullable T תמיד ממופה ל-std::optional<T>.

עבור סוג כמו L כמו T[] או List<T>, @nullable L ממופה ל-std::optional<std::vector<std::optional<T>>> (או std::unique_ptr<std::vector<std::unique_ptr<T>>> במקרה של קצה עורפי CPP ב-Android 11 ומטה).

יש חריג למיפוי הזה. כש-T הוא IBinder או ממשק AIDL, @nullable הוא ללא תפעול. במילים אחרות, גם @nullable IBinder וגם IBinder ממופים באופן שווה ל-android::sp<IBinder>, וזהו כבר ערך null כי הוא מצביע חזק (CPP קורא עדיין אפשרות null, אבל הסוג עדיין android::sp<IBinder>).

החל מ-Android 13, אפשר להשתמש ב-@nullable(heap=true) לשדות שניתן לשתף כדי ליצור מודלים רקורסיביים. אי אפשר להשתמש ב-@nullable(heap=true) עם פרמטרים של שיטות או סוגי החזרה. כשמוסיפים לו הערות, השדה ממופה לקובץ עזר של std::unique_ptr<T> שהוקצה בשביל הזיכרון, בקצוות העורפיים של CPP/NDK. השירות @nullable(heap=true) לא פעיל בקצה העורפי של Java.

utf8InCpp

utf8InCpp מצהיר ש-String מיוצג בפורמט UTF8 עבור הקצה העורפי של CPP. כפי שמציין ששמו מציין, ההערה מבוטלת בקצוות עורפיים אחרים. באופן ספציפי, הערך של String הוא תמיד UTF16 בקצה העורפי של Java ו-UTF8 בקצה העורפי NDK.

אפשר לצרף את ההערה הזו בכל מקום שבו אפשר להשתמש בסוג String, כולל ערכי החזרה, פרמטרים, הצהרות קבועות ושדות שניתנים להפרדה.

בקצה העורפי של CPP, @utf8InCpp String ב-AIDL ממופה אל std::string, ואילו String בלי ההערות ממופה ל-android::String16 שבו נעשה שימוש ב-UTF16.

שימו לב שעצם קיומו של ההערה utf8InCpp לא משנה את האופן שבו מחרוזות מועברות על החוט. המחרוזות תמיד נשלחות כ-UTF16 דרך החוט. מחרוזת עם הערות utf8InCpp מומרת ל-UTF16 לפני ההעברה. כשמתקבלת מחרוזת, היא מומרת מ-UTF16 ל-UTF8 אם מוסיפים לה הערות כ-utf8InCpp.

יציבות וינטג'

VintfStability מצהיר/ה שאפשר להשתמש בסוג שהוגדר על ידי המשתמש (ממשק, parcelable ו-enum) בכל הדומיינים של המערכת ושל הספקים. מידע נוסף על יכולת פעולה הדדית של ספק מערכת זמין במאמר AIDL ל-HALs.

ההערה לא משנה את החתימה של הסוג, אבל כשהיא מוגדרת, המכונה מהסוג הזה מסומנת כיציבה כדי לאפשר מעבר בתהליכי הספק והמערכת.

אפשר לצרף את ההערה רק להצהרות מסוג מוגדר על ידי המשתמש, כפי שמוצג כאן:

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

בנוסף, את קובצי ה-AIDL שמגדירים סוגים עם הערות עם VintfStability אפשר ליצור רק באמצעות סוג המודול aidl_interface Sung, כשהמאפיין stability מוגדר ל-"vintf".

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

שימוש באפליקציה לא נתמך

ההערה UnsupportedAppUsage מציינת שסוג AIDL עם הערות הוא חלק מהממשק שאינו SDK שניתן לגשת אליו באפליקציות מדור קודם. למידע נוסף על ממשקי ה-API המוסתרים, ראו הגבלות על ממשקים שאינם SDK.

ההערה UnsupportedAppUsage לא משפיעה על ההתנהגות של הקוד שנוצר. בהערה מוסיפים הערות רק למחלקה של Java שנוצרה עם ההערה של Java עם אותו השם.

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

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

זוהי פעולה ללא פעולה לקצוות עורפיים שאינם של Java.

גיבוי

ההערה Backing מציינת את סוג האחסון של סוג 'טיפוסים בני מנייה (enum)' מסוג AIDL.

@Backing(type="int")
enum Color { RED, BLUE, }

בקצה העורפי של CPP, נוצר סיווג C++ מסוג int32_t.

enum class Color : int32_t {
    RED = 0,
    BLUE = 1,
}

אם משמיטים את ההערה, ההנחה היא ש-type הוא byte, שממופה ל-int8_t עבור הקצה העורפי של CPP.

אפשר להגדיר את הארגומנט type רק לסוגי האינטגרל הבאים:

  • byte (ברוחב 8 ביט)
  • int (ברוחב 32 ביט)
  • long (רוחב 64 ביט)

NdkOnlyStableParcelable

NdkOnlyStableParcelable מסמן הצהרה מסוג parcelable (לא הגדרה) כיציבה, כך שאפשר להפנות אליה מסוגי AIDL יציבים אחרים. זה דומה ל-JavaOnlyStableParcelable, אבל NdkOnlyStableParcelable מסמן הצהרה מסוג Package כיציבה לקצה העורפי NDK במקום ל-Java.

כדי להשתמש בחבילה הזו:

  • צריך לציין ndk_header.
  • צריכה להיות לכם ספריית NDK שמציינת את החבילה, וצריך להדר אותה בספרייה. לדוגמה, במערכת build בסיסית של מודול cc_*, משתמשים ב-static_libs או ב-shared_libs. בשביל aidl_interface, מוסיפים את הספרייה בקטע additional_shared_libraries ב-Android.bp.

JavaOnlyStableParcelable

JavaOnlyStableParcelable מסמן הצהרה מסוג parcelable (לא הגדרה) כיציבה, כך שאפשר להפנות אליה מסוגי AIDL יציבים אחרים.

כדי להשתמש ב-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 יוצר באופן אוטומטי methods לסוגים של מגרשים בקצה העורפי של Java.

@JavaDerive(equals = true, toString = true)
parcelable Data {
  int number;
  String str;
}

ההערה דורשת פרמטרים נוספים כדי לקבוע מה ליצור. הפרמטרים הנתמכים הם:

  • הפונקציה equals=true יוצרת method equals ו-hashCode.
  • toString=true יוצרת method ל-toString שמדפיסה את שם הסוג והשדות. לדוגמה: Data{number: 42, str: foo}

ברירת מחדל של Java

JavaDefault, שנוסף ב-Android 13, קובע אם תיווצר תמיכה ברירת מחדל לניהול גרסאות של הטמעה (ל-setDefaultImpl). התמיכה הזו לא נוצרת יותר כברירת מחדל כדי לחסוך מקום.

JavaPassthrough

JavaPassthrough מאפשר להוסיף הערות ל-API של 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)

בקוד ה-Java שנוצר.

הערך של הפרמטר annotation נפלט ישירות. המהדר של AIDL לא בודק את הערך של הפרמטר. אם יש שגיאת תחביר ברמת Java, היא לא תזוהה על ידי מהדר AIDL אלא על ידי מהדר (compiler) Java.

אפשר לצרף את ההערה הזו לכל ישות AIDL. האנוטציה הזו היא ללא תפעול לקצוות עורפיים שאינם של Java.

גודל קבוע

המאפיין FixedSize מסמן חבילה מובנית כגודל קבוע. אחרי שמסמנים את החבילה, לא תהיה אפשרות להוסיף אליה שדות חדשים. גם כל השדות של המגרש צריכים להיות בגודל קבוע, כולל סוגים פרימיטיביים, טיפוסים בני מנייה (enums), מערכים בגודל קבוע ומגרשים אחרים שמסומנים ב-FixedSize.

הפעולה הזו לא מספקת אחריות לגבי ביטים שונים, ואין להסתמך עליה לתקשורת עם ביטים מעורבים.

מתאר

Descriptor מציין בכוח את מתאר הממשק של הממשק.

package android.foo;

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

התיאור של הממשק הזה הוא android.bar.IWorld. אם ההערה Descriptor חסרה, המתאר יהיה android.foo.IHello.

האפשרות הזו שימושית כשמשנים שם של ממשק שכבר פורסם. יצירת התיאור של הממשק עם השם החדש זהה לתיאור הממשק לפני שינוי השם מאפשרת לשני הממשקים לדבר זה עם זה.

@הסתרה בתגובות

המהדר של AIDL מזהה את @hide בתגובות ומעביר אותו לפלט של Java כדי ש- Metalava יגיע לאיסוף. ההערה הזו מבטיחה שמערכת ה-build של Android תדע שממשקי API של AIDL הם לא ממשקי API של SDK.

@הוצא משימוש בתגובות

המהדר של AIDL מזהה את @deprecated בתגובות כתג, כדי לזהות ישות AIDL שלא צריכה יותר להשתמש בה.

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

כל קצה עורפי מסמן ישויות שהוצאו משימוש עם הערה או מאפיין ספציפיים לקצה העורפי, כדי שקוד הלקוח יקבל אזהרה אם הוא מפנה לישויות שהוצאו משימוש. לדוגמה, ההערה @Deprecated והתג @deprecated מצורפים לקוד שנוצר ב-Java.