ב-AIDL יש תמיכה בהערות שמספקות למהדר AIDL מידע נוסף על הרכיב עם ההערה, שמשפיע גם על קוד הסטאב שנוצר.
התחביר דומה לזה של 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 |
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
.
בקצה העורפי של ה-CPP, הערך @nullable T
ממופה לערך std::unique_ptr<T>
ב-Android 11 ומטה, ולערך std::optional<T>
ב-Android 12 ואילך.
בקצה העורפי של NDK, @nullable T
תמיד ממופה ל-std::optional<T>
.
בקצה העורפי של Rust, @nullable T
תמיד ממופה ל-Option<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
לא מבצעת פעולה כלשהי בכל הקצוות העורפיים, מלבד Rust. במילים אחרות, גם @nullable IBinder
וגם IBinder
ממפים באופן שווה ל-android::sp<IBinder>
, שכבר יכול להכיל ערך null כי הוא הצבעה חזקה (קריאות ב-CPP עדיין אוכפות את היכולת להכיל ערך null, אבל הסוג עדיין android::sp<IBinder>
). ב-Rust, הסוגים האלה הם nullable
רק אם מסמנים אותם ב-@nullable
. אם נוספו להן הערות, הן ממופות לערך Option<T>
.
החל מ-Android 13, אפשר להשתמש ב-@nullable(heap=true)
בשדות שניתן לחלק כדי ליצור מודלים של סוגים רפלקסיביים. אי אפשר להשתמש ב-@nullable(heap=true)
עם פרמטרים של שיטות או עם סוגי החזרים. כשמציינים את ההערה הזו, השדה ממופה להפניה std::unique_ptr<T>
שמוקצה ב-heap בקצוות העורפי של CPP/NDK. @nullable(heap=true)
הוא פעולה ללא תוצאה בקצה העורפי של Java.
utf8InCpp
utf8InCpp
מצהיר ש-String
מיוצג בפורמט UTF8 לקצה העורפי של ה-CPP. כפי שרואים מהשם, ההערה לא מבוצעת בקצוות עורפיים אחרים.
באופן ספציפי, String
הוא תמיד UTF16 בקצה העורפי של Java ו-UTF8 בקצה העורפי של NDK.
אפשר לצרף את ההערה הזו בכל מקום שבו אפשר להשתמש בסוג String
, כולל ערכי החזרה, פרמטרים, הצהרות על קבועים ושדות שניתנים להעברה (Parcelable).
לקצה העורפי של CPP, הערך @utf8InCpp String
ב-AIDL ממופה לערך std::string
, ואילו הערך String
ללא ההערה ממופה לערך android::String16
שבו נעשה שימוש ב-UTF16.
חשוב לזכור שההערה utf8InCpp
לא משנה את האופן שבו מחרוזות מועברות דרך החיבור. מחרוזות מועברות תמיד כ-UTF16 באינטרנט. מחרוזת עם הערות utf8InCpp
מומרת ל-UTF16 לפני ההעברה. כשמתקבלת מחרוזת, היא מומרת מ-UTF16 ל-UTF8 אם היא סומנה בתווית utf8InCpp
.
יציבות וינטג'
VintfStability
מצהיר שאפשר להשתמש בסוג שהוגדר על ידי משתמש (interface, parcelable ו-enum) בכל הדומיינים של המערכת והספק. מידע נוסף על יכולת פעולה הדדית של ספק מערכת זמין במאמר AIDL ל-HALs.
ההערה לא משנה את החתימה של הסוג, אבל כשמגדירים אותה, המכונה של הסוג מסומנת כיציבה כדי שתוכל לעבור בין תהליכי הספק והמערכת.
אפשר לצרף את ההערה רק להצהרות על סוגים שהוגדרו על ידי משתמשים, כפי שמוצג כאן:
@VintfStability
interface IFoo {
....
}
@VintfStability
parcelable Data {
....
}
@VintfStability
enum Type {
....
}
כשסוג מסוים מסומן ב-VintfStability
, צריך לסמן גם כל סוג אחר שמוזכר בסוג הזה. בדוגמה הבאה, צריך להוסיף הערה VintfStability
גם ל-Data
וגם ל-IBar
.
@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
של Soong, כשהמאפיין stability
מוגדר ל-"vintf"
.
aidl_interface {
name: "my_interface",
srcs: [...],
stability: "vintf",
}
UnsupportedAppUsage
ההערה UnsupportedAppUsage
מציינת שסוג AIDL עם הערות הוא חלק מהממשק שאינו SDK שניתן לגשת אליו באפליקציות מדור קודם.
מידע נוסף על ממשקי ה-API המוסתרים זמין במאמר הגבלות על ממשקים שאינם SDK.
ההערה UnsupportedAppUsage
לא משפיעה על ההתנהגות של הקוד שנוצר. האנוטציה מוסיפה את האנוטציה של Java עם אותו שם רק לכיתה ב-Java שנוצרה.
// in AIDL
@UnsupportedAppUsage
interface IFoo {...}
// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}
זוהי פעולה ללא תוצאה (no-op) לקצוות עורפיים שאינם Java.
גיבוי
ההערה Backing
מציינת את סוג האחסון של סוג 'טיפוסים בני מנייה (enum)' מסוג AIDL.
@Backing(type="int")
enum Color { RED, BLUE, }
בקצה העורפי של ה-CPP, הפונקציה הזו פולטת סוג של Enumeration Class ב-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
מסמנת הצהרה על תכונה שניתנת להעברה (לא הגדרה) כיציבה, כדי שניתן יהיה להפנות אליה מסוגים יציבים אחרים של AIDL. זה דומה ל-JavaOnlyStableParcelable
, אבל הערך NdkOnlyStableParcelable
מסמן הצהרה על תכונה שניתנת לחלוקה כיציבה לקצה העורפי של NDK במקום לג'אווה.
כדי להשתמש ב-Parcelable הזה:
- חובה לציין את
ndk_header
. - צריכה להיות לכם ספריית NDK שמציינת את ה-Parcelable, והספרייה צריכה להיות מתומצתת בספרייה. לדוגמה, במערכת הליבה ליצירת גרסאות build במודול
cc_*
, משתמשים ב-static_libs
או ב-shared_libs
. עבורaidl_interface
, מוסיפים את הספרייה בקטעadditional_shared_libraries
ב-Android.bp
.
JavaOnlyStableParcelable
JavaOnlyStableParcelable
מסמנת הצהרה על תכונה שניתנת להעברה (לא הגדרה) כיציבה, כדי שניתן יהיה להפנות אליה מסוגים יציבים אחרים של AIDL.
כדי ליצור גרסת AIDL יציבה, כל הסוגים שהוגדרו על ידי המשתמש צריכים להיות יציבים. כדי ש-Parcelable יהיה יציב, צריך לתאר את השדות שלו באופן מפורש בקובץ המקור של 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 לא היה מובנה (או רק הוצהר), אי אפשר להפנות אליו.
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
יוצר באופן אוטומטי שיטות לסוגים של parcelable בקצה העורפי של 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 שנוצר.
ההערות הבאות ב-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 אלא על ידי המהדר של Java.
אפשר לצרף את ההערה הזו לכל ישות AIDL. האנוטציה הזו היא ללא תפעול לקצוות עורפיים שאינם של Java.
גודל קבוע
FixedSize
מסמנת רכיב parcelable מובנה כרכיב בגודל קבוע. אחרי הסימון, לא תהיה אפשרות להוסיף שדות חדשים ל-Parcelable. כל השדות של ה-Parcelable חייבים להיות גם מסוגים בגודל קבוע, כולל סוגים פרימיטיביים, מערכים בגודל קבוע ו-Parcelables אחרים שמסומנים ב-FixedSize
.
הדבר לא מבטיח תאימות בין ערכים שונים של ביטים, ואין להסתמך עליו בתקשורת עם ערכים שונים של ביטים.
מתאר
Descriptor
מציין בכפייה את מתאר הממשק של ממשק.
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
התיאור של הממשק הזה הוא android.bar.IWorld
. אם ההערה Descriptor
חסרה, התיאור יהיה android.foo.IHello
.
אפשר להשתמש באפשרות הזו כדי לשנות את השם של ממשק שכבר פורסם. יצירת התיאור של הממשק עם השם החדש זהה לתיאור הממשק לפני שינוי השם מאפשרת לשני הממשקים לדבר זה עם זה.
@hide בתגובות
המהדר של AIDL מזהה את @hide
בתגובות ומעביר אותו לפלט של Java כדי ש- Metalava יאסוף. התגובה הזו מוודאת שמערכת ה-build של Android יודעת שממשקי AIDL API הם לא ממשקי SDK API.
@deprecated בתגובות
המהדר של AIDL מזהה את @deprecated
בתגובות כתג כדי לזהות ישות AIDL שלא צריכה יותר להשתמש בה.
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
כל קצה עורפי מסומן ישויות שהוצאו משימוש באמצעות הערה או מאפיין ספציפיים לקצה העורפי, כדי שיופיע אזהרה בקוד הלקוח אם הוא מפנה לישויות שהוצאו משימוש. לדוגמה, ההערה @Deprecated
והתג @deprecated
מצורפים לקוד שנוצר ב-Java.