ב-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
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, הפונקציה הזו פולטת סוג של 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
מסמנת הצהרה על תכונה שניתנת להעברה (לא הגדרה) כיציבה, כדי שניתן יהיה להפנות אליה מסוגים יציבים אחרים של 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 יציבה, כל הסוגים שהוגדרו על ידי המשתמש צריכים להיות יציבים. כדי ש-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
מאפשר לבטל את הבדיקה כשה-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.
RustDerive
RustDerive
מטמיע באופן אוטומטי מאפיינים לסוגים שנוצרו ב-Rust.
כדי לשלוט במה שייווצר, צריך להוסיף פרמטרים להערה. הפרמטרים הנתמכים הם:
Copy=true
Clone=true
Ord=true
PartialOrd=true
Eq=true
PartialEq=true
Hash=true
הסברים על המאפיינים האלה זמינים בכתובת https://doc.rust-lang.org.
FixedSize
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.