AIDL תומך בהערות שנותנות לקומפיילר AIDL מידע נוסף על הרכיב שנוסף לו הערה, וזה משפיע גם על קוד ה-stub שנוצר.
התחביר דומה לזה של Java:
@AnnotationName(argument1=value, argument2=value) AidlEntity
כאן, AnnotationName הוא שם ההערה ו-AidlEntity הוא ישות AIDL כמו 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 מציין שהערך של הישות עם ההערה יכול להיות null.
אפשר לצרף את ההערה הזו רק לסוגי החזרה של שיטות, לפרמטרים של שיטות ולשדות שניתנים להעברה:
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 backend, @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 הוא פעולה שלא עושה כלום עבור קצה העורפי של Java, CPP ו-NDK. לדוגמה, ב-CPP backend, @nullable IBinder ו-IBinder ממופים באופן שווה ל-android::sp<IBinder>, שכבר ניתן להגדיר אותו כ-nullable כי הוא מצביע חזק (קריאות של CPP ו-NDK עדיין אוכפות את האפשרות להגדיר כ-nullable, אבל הסוג נשאר android::sp<IBinder> או ndk::SpAIBinder).
ב-Rust backend, סוגים שלא מיישמים Default (IBinder, ממשקי AIDL, ParcelFileDescriptor ו-parcelables לא מובנים) ממופים ל-Option<T> בהתאם להקשר שלהם:
- סוגי ההחזרה של השיטה, פרמטרים של
inופרמטרים שלinout: הסוגים האלה יכולים להיות בעלי ערך null רק אם הם מסומנים ב-@nullable, ומופנים אלOption<T>(או אלOption<&T>עבור פרמטרים שלinואל&mut Option<T>עבור פרמטרים שלinout). בלי@nullable, הן ממופות ישירות ל-T(או ל-&Tול-&mut T). - שדות שאפשר להעביר בחבילה ופרמטרים של
out: מכיוון שחבילות Rust שנוצרו נגזרות מ-Defaultופרמטרים שלoutמאותחלים כברירת מחדל, הסוגים האלה תמיד ממופים ל-Option<T>(ומערכים בגודל קבוע בהקשרים האלה ממופים ל-[Option<T>; N], בעוד שמערכים דינמיים בפרמטרים שלoutממופים ל-Vec<Option<T>>), גם בלי@nullable. גם אם לא מוסיפים את ההערה@nullable, עדיין מתבצעת אכיפה של אי-אפשרות להגדיר ערך null בזמן הריצה במהלך חלוקת החבילה (הפונקציה מחזירהStatusCode::UNEXPECTED_NULLאם הערך הואNone).
החל מ-Android 13, אפשר להשתמש ב-@nullable(heap=true) בשדות מסוג Parcelable כדי ליצור מודלים של סוגים רקורסיביים. אי אפשר להשתמש ב-@nullable(heap=true) עם פרמטרים של שיטות או עם סוגי החזרה. כשמוסיפים את ההערה הזו, השדה
ממופה להפניה שהוקצתה לערימה std::unique_ptr<T> ב-CPP וב-NDK. השיטה @nullable(heap=true) לא מבצעת פעולה בבק-אנד של Java.
utf8InCpp
utf8InCpp מכריז ש-String מיוצג בפורמט UTF8 עבור ה-CPP backend. כפי שהשם שלה מציין, ההערה היא no-op עבור קצה עורפי אחר.
באופן ספציפי, String הוא תמיד UTF16 בקצה העורפי של Java ו-UTF8 בקצה העורפי של NDK.
אפשר להוסיף את ההערה הזו בכל מקום שבו אפשר להשתמש בסוג String, כולל ערכי החזרה, פרמטרים, הצהרות קבועות ושדות שניתן להעביר בחבילה.
ב-CPP backend, @utf8InCpp String ב-AIDL ממופה ל-std::string, כאשר String ללא ההערה ממופה ל-android::String16 במקרה של שימוש ב-UTF16.
VintfStability
VintfStability מצהיר שאפשר להשתמש בסוג שהוגדר על ידי המשתמש (ממשק, parcelable ו-enum) בדומיינים של המערכת והספק. מידע נוסף על יכולת פעולה הדדית בין מערכות של ספקים זמין במאמר בנושא AIDL עבור HAL.
ההערה לא משנה את החתימה של הסוג, אבל כשהיא מוגדרת, המופע של הסוג מסומן כיציב כדי שאפשר יהיה להעביר אותו בין תהליכי הספק והמערכת.
אפשר לצרף את ההערה רק להצהרות על סוגים שהוגדרו על ידי המשתמש, כמו שמוצג כאן:
@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 {...}
זוהי פעולה שלא משפיעה על קצה העורפי שאינו Java.
הערה לגבי גיבוי
ההערה Backing מציינת את סוג האחסון של סוג enum של AIDL:
@Backing(type="int")
enum Color { RED, BLUE, }
בבק אנד של CPP, הפונקציה הזו יוצרת מחלקת enum של 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 מסמן הצהרה על אובייקט שניתן להעברה כהצהרה יציבה עבור קצה העורפי של NDK ולא עבור Java.
כדי להשתמש ב-parcelable הזה:
- חובה לציין את הערך
ndk_header. - צריכה להיות לכם ספריית NDK שבה מוגדר parcelable, והספרייה צריכה להיות מהודרת לספרייה. לדוגמה, במערכת build הליבה ב-
cc_*, משתמשים ב-static_libsאו ב-shared_libs. כדי להוסיף את הספרייה שלaidl_interface, עוברים אלadditional_shared_librariesבAndroid.bp.
JavaOnlyStableParcelable
JavaOnlyStableParcelable מציין הצהרה (לא הגדרה) של parcelable כהצהרה יציבה, כדי שאפשר יהיה להפנות אליה מסוגי AIDL יציבים אחרים.
ב-AIDL יציב, כל הסוגים שמוגדרים על ידי המשתמש צריכים להיות יציבים. במקרה של parcelables, כדי שהם יהיו יציבים, השדות שלהם צריכים להיות מתוארים במפורש בקובץ המקור של 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 מאפשרת לכם לבטל את הבדיקה כשחבילת הנתונים שאליה אתם מפנים זמינה בצורה בטוחה כחלק מ-Android SDK:
@JavaOnlyStableParcelable
parcelable Data;
parcelable AnotherData {
Data d; // OK
}
JavaDerive
JavaDerive יוצרת באופן אוטומטי שיטות לסוגים של parcelable ב-Java backend:
@JavaDerive(equals = true, toString = true)
parcelable Data {
int number;
String str;
}
ההערה דורשת פרמטרים נוספים כדי לשלוט במה שייווצר. הפרמטרים הנתמכים הם:
-
equals=trueיוצרת methods מסוגequalsו-hashCode. -
toString=trueיוצרת את השיטהtoStringשמדפיסה את השם של הסוג והשדות, למשלData{number: 42, str: foo}.
JavaDefault (הוצאה משימוש)
המאפיין JavaDefault, שנוסף ב-Android 13, קובע אם תיווצר תמיכה בניהול גרסאות של הטמעה שמוגדרת כברירת מחדל (עבור setDefaultImpl). התמיכה הזו לא נוצרת יותר כברירת מחדל כדי לחסוך במקום.
JavaPassthrough
JavaPassthrough מאפשר להוסיף הערה ל-Java API שנוצר עם הערה שרירותית של Java.
ההערות האלה ב-AIDL:
@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=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=true
הסברים על התכונות האלה מופיעים במאמרי העזרה של Rust.
FixedSize
FixedSize מסמן אובייקט Parcelable מובנה כגודל קבוע. אחרי שמסמנים אותו, אי אפשר להוסיף שדות חדשים ל-parcelable. כל השדות של האובייקט שניתן להעברה צריכים להיות מסוגים בגודל קבוע, כולל סוגים פרימיטיביים, סוגי enum, מערכים בגודל קבוע ואובייקטים אחרים שניתנים להעברה ומסומנים ב-FixedSize.
לאובייקטים מסוג FixedSize יש גדלים ויישור יציבים ב-ndk backend.
| סוג | גודל (בייטים) | התאמה (בייטים) |
|---|---|---|
boolean |
1 |
1 |
byte |
1 |
1 |
char |
2 |
2 |
int |
4 |
4 |
long |
8 |
8 |
float |
4 |
4 |
double |
8 |
8 |
parcelable |
הגודל הכולל של כל השדות | ההתאמה הגדולה ביותר של כל השדות |
union |
הגודל הכי גדול מבין כל השדות | ההתאמה הגדולה ביותר של כל השדות |
enum |
גודל סוג הגיבוי | התאמה של סוג הגיבוי |
T[N] (מערך בגודל קבוע) |
גודל של T * N |
התאמה של T |
String, IBinder, FileDescriptor, ParcelFileDescriptor |
N/A |
N/A |
תיאור
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 יאסוף אותו. ההערה הזו עוזרת לוודא שמערכת ה-Build של Android מזהה שממשקי AIDL API הם לא ממשקי SDK API.
@deprecated בתגובות
הקומפיילר של AIDL מזהה את התג @deprecated בתגובות כסימן לזיהוי ישות AIDL שכבר לא צריך להשתמש בה:
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
כל קצה עורפי מסמן ישויות שהוצאו משימוש בהערה או במאפיין ספציפיים לקצה העורפי, כדי שקוד הלקוח יקבל אזהרה אם הוא מתייחס לישויות שהוצאו משימוש. לדוגמה, ההערה @Deprecated והתג @deprecated
מצורפים לקוד Java שנוצר.