שפת ה-AIDL מבוססת באופן חלקי על שפת Java. הקבצים מציינים חוזה ממשק, סוגי נתונים שונים וקבועים שמשמשים בחוזה הזה.
חבילה
כל קובץ AIDL מתחיל בחבילה אופציונלית שתואמת לשמות החבילות במגוון קצוות עורפיים. הצהרת חבילה נראית כך:
package my.package;
בדומה ל-Java, קובצי AIDL צריכים להיות במבנה תיקיות שתואם לחבילה שלהם. קבצים עם חבילה my.package צריכים להיות בתיקייה my/package/.
סוגים
בקובצי AIDL, יש הרבה מקומות שבהם אפשר לציין סוגים. רשימה מדויקת של הסוגים שנתמכים בשפת AIDL מופיעה במאמר סוגי קצה עורפי של AIDL.
הערות
חלקים שונים בשפת AIDL תומכים בהערות. רשימה של הערות ומיקומים שאפשר להחיל אותן בהם זמינה במאמר הערות AIDL.
ייבוא
כדי להשתמש בסוגים שמוגדרים בממשקים אחרים, צריך קודם להוסיף תלות במערכת הבנייה. במודולים של cc_* ו-java_* Soong, שבהם נעשה שימוש בקובצי .aidl ישירות מתחת ל-srcs בגרסאות של פלטפורמת Android, אפשר להוסיף ספריות באמצעות השדה aidl: { include_dirs: ... }. לייבוא באמצעות
aidl_interface, אפשר לעיין במאמר הזה.
ייבוא נראה כך:
import some.package.Foo; // explicit import
כשמייבאים סוג באותה חבילה, אפשר להשמיט את החבילה. עם זאת, השמטה של החבילה עלולה להוביל לשגיאות ייבוא לא חד-משמעיות כשמציינים סוגים ללא חבילה ומכניסים אותם למרחב השמות הגלובלי (בדרך כלל כל הסוגים צריכים להיות במרחב שמות):
import Foo; // same as my.package.Foo
הגדרת סוגים
בדרך כלל, קובצי AIDL מגדירים סוגים שמשמשים כממשק.
ממשקים
זוהי דוגמה לממשק AIDL:
interface ITeleport {
// Location defined elsewhere
void teleport(Location baz, float speed);
String getName();
// ITeleportCallback defined elsewhere
void methodWithCallback(ITeleportCallback callback);
// ITeleportSession defined elsewhere
ITeleportSession getASubInterface();
}
ממשק מגדיר אובייקט עם סדרה של שיטות. השיטות יכולות להיות oneway (oneway void doFoo()) או סינכרוניות. אם הממשק מוגדר כ-oneway (oneway interface ITeleport {...}), כל השיטות בו הן oneway באופן מרומז. השיטות Oneway נשלחות באופן אסינכרוני ולא יכולות להחזיר תוצאה. שיטות חד-כיווניות מאותו השרשור לאותו קובץ binder מופעלות גם הן באופן סדרתי (אבל יכול להיות שהן מופעלות בשרשורים שונים). במאמר ניהול שרשורים בעורפי AIDL מוסבר איך להגדיר שרשורים.
Binder מאפשר שיתוף של הרבה ממשקים ואובייקטים של binder דרך ממשקי binder. ממשקי AIDL משתמשים לעיתים קרובות בקריאות חוזרות כחלק מקריאות לשיטות, כמו בדוגמה הקודמת עם ITeleportCallback. אפשר לעשות שימוש חוזר באובייקטים של קריאה חוזרת בין קריאות לאותה שיטה או לקריאות לשיטות שונות. שימוש נפוץ נוסף בסוגי ממשקים הוא להחזרת ממשקי משנה או אובייקטים של סשנים משיטות כמו ITeleportSession בדוגמה הקודמת. הקינון הזה מאפשר להצפין ממשקי API שונים ברמת ה-API או על סמך מצב זמן הריצה. לדוגמה, סשן יכול לייצג בעלות על משאב מסוים. כשממשקים מועברים כמה פעמים או מוחזרים ללקוח או לשרת שממנו הם הגיעו, הם תמיד שומרים על שוויון המצביעים של אובייקט ה-binder הבסיסי.
לשיטות יכולים להיות אפס או יותר ארגומנטים. הארגומנטים של השיטות יכולים להיות in, out או inout. במאמר AIDL backends directionality מוסבר איך זה משפיע על סוגי הארגומנטים.
Parcelables
במאמר AIDL backends custom parcelables מוסבר איך ליצור parcelables ספציפיים ל-backend.
Android מגרסה 10 ואילך תומך בהגדרות של parcelable ישירות ב-AIDL. סוג כזה של parcelable נקרא parcelable מובנה. מידע נוסף על הקשר בין AIDL מובנה ויציב בקומפיילר AIDL ובמערכת ה-build שלנו זמין במאמר AIDL מובנה לעומת AIDL יציב.
לדוגמה:
package my.package;
import my.package.Boo;
parcelable Baz {
@utf8InCpp String name = "baz";
Boo boo;
}
איגודים
Android מגרסה 12 ואילך תומך בהצהרות של איחודים מתויגים. לדוגמה:
package my.package;
import my.package.FooSettings;
import my.package.BarSettings;
union Settings {
FooSettings fooSettings;
BarSettings barSettings;
@utf8InCpp String str;
int number;
}
פרטים ספציפיים לגבי קצה העורפי זמינים במאמר איחודים של קצה עורפי של AIDL.
טיפוסים בני מנייה (enum)
Android מגרסה 11 ואילך תומך בהצהרות enum. לדוגמה:
package my.package;
enum Boo {
A = 1 * 4,
B = 3,
}
הצהרות מקוננות על סוגים
Android מגרסה 13 ואילך תומך בהצהרות על סוגים מקוננים. לדוגמה:
package my.package;
import my.package.Baz;
interface IFoo {
void doFoo(Baz.Nested nested); // defined in my/package/Baz.aidl
void doBar(Bar bar); // defined below
parcelable Bar { ... } // nested type definition
}
ערכים קבועים
ממשקי AIDL מותאמים אישית, אובייקטים מסוג Parcelable ואיגודים יכולים להכיל גם קבועים מסוג integer ומחרוזת, כמו:
const @utf8InCpp String HAPPY = ":)";
const String SAD = ":(";
const byte BYTE_ME = 1;
const int ANSWER = 6 * 7;
ביטויים קבועים
אפשר לציין קבועים של AIDL, גדלים של מערכים וספירות באמצעות ביטויי קבועים. אפשר להשתמש בסוגריים כדי להציב פעולות בתוך פעולות אחרות. אפשר להשתמש בערכי ביטוי קבועים עם ערכים שלמים או ערכים מסוג float.
הערכים המילוליים true ו-false מייצגים ערכים בוליאניים. ערכים עם . אבל בלי סיומת, כמו 3.8, נחשבים לערכים מסוג double. ערכי Float מסתיימים בסיומת f, למשל 2.4f. ערך שלם עם הסיומת l או L מציין ערך ארוך של 64 ביט. אחרת, ערכי האינטגרלים מקבלים את הסוג הקטן ביותר ששומר על הערך בין 8 ביט (בייט), 32 ביט (int) ו-64 ביט (long). לכן 256 נחשב לint, אבל 255 + 1 גולש להיות byte .0 ערכים הקסדצימליים, כמו 0x3, מפורשים קודם כסוג הלא חתום הקטן ביותר ששומר על הערך בין 32 ל-64 ביט, ואז מפורשים מחדש כערכים לא חתומים. לכן, 0xffffffff מקבל את הערך int
-1. החל מ-Android 13, אפשר להוסיף את הסיומת u8 לקבועים, כמו 3u8, כדי לייצג ערך byte. הסיומת הזו חשובה כדי שחישוב כמו 0xffu8 * 3 יפורש כ--3 עם סוג byte, בעוד ש-0xff * 3 יפורש כ-765 עם סוג int.
לאופרטורים הנתמכים יש סמנטיקה של C++ ו-Java. אלה האופרטורים הבינאריים, לפי סדר עדיפות מהנמוך לגבוה: || && | ^ & == != < > <= >= << >> + - * / %. אופרטורים אונריים הם + - ! ~.