בהינתן קובץ ממשק HIDL, קצה העורפי של Java HIDL יוצר ממשקי Java, קוד Stub וקוד Proxy. הוא תומך בכל הסוגים הסקלריים של HIDL ([u
]int
{8,16,32,64}_t, float, double,
ו-enum
s), וגם במחרוזות, בממשקים, בסוגי safe_union, בסוגי struct, במערכים וב-vectors של סוגי HIDL נתמכים. ב-Java HIDL backend אין תמיכה בסוגי איחוד או בסוגי fmq. ב-Android 11 נוספה תמיכה בסוגים memory
ו-handle
.
מכיוון שסביבת זמן הריצה של Java לא תומכת באופן מובנה במושג של מספרים שלמים לא מסומנים, כל הסוגים הלא מסומנים (והספירות שמבוססות עליהם) מטופלים בשקט כשווי הערך המסומנים שלהם, כלומר uint32_t
הופך ל-int
בממשק Java. לא מתבצעת המרה של ערך. המטמיע בצד Java צריך להשתמש בערכים החתומים כאילו הם לא חתומים.
טיפוסים בני מנייה (enum)
Enums לא יוצרים מחלקות enum של Java, אלא מתורגמים למחלקות פנימיות שמכילות הגדרה של קבוע סטטי לכל מקרה enum. אם מחלקת ה-enum נגזרת ממחלקת enum אחרת, היא יורשת את סוג האחסון של המחלקה הזו. ספירות שמבוססות על סוג של מספר שלם לא חתום נכתבות מחדש כספירות שוות ערך חתומות. מכיוון שהסוג הבסיסי הוא פרימיטיבי, ערך ברירת המחדל של שדות או משתנים מסוג enum הוא אפס, גם אם אין ערך enum אפס.
לדוגמה, SomeBaseEnum
עם סוג של uint8_t
:
enum SomeBaseEnum : uint8_t { foo = 3 }; enum SomeEnum : SomeBaseEnum { quux = 33, goober = 127 };
… הופך ל:
public final class SomeBaseEnum { public static final byte foo = 3; } public final class SomeEnum { public static final byte foo = 3; public static final byte quux = 33; public static final byte goober = 127; }
וגם:
enum SomeEnum : uint8_t { FIRST_CASE = 10, SECOND_CASE = 192 };
… נכתב מחדש כך:
public final class SomeEnum { static public final byte FIRST_CASE = 10; // no change static public final byte SECOND_CASE = -64; }
מיתרים
String
ב-Java הוא utf-8 או utf-16, אבל הוא מומר ל-utf-8 כסוג HIDL נפוץ בזמן ההעברה. בנוסף, String
לא יכול להיות ריק (null) כשמעבירים אותו ל-HIDL.
כינוי וזיכרון
ב-Android 11 נוספה תמיכה ב-Java עבור הסוגים handle
ו-memory
. הם מתורגמים ל-android.os.NativeHandle
ול-android.os.HidlMemory
, בהתאמה. ידית null נחשבת לתקינה, אבל זיכרון null לא נחשב לתקין.
בקטע הקוד של השרת שנוצר, הארגומנטים של הזיכרון והטיפול שהתקבלו תקפים רק בהיקף של קריאת השיטה. אם רוצים להאריך את משך החיים של השרת, צריך לשכפל אותו באמצעות השיטות המתאימות של dup()
. אפשר להשתמש במופע שמוחזר אחרי הפעלת המתודה, וצריך לסגור אותו בצורה תקינה כשמסיימים להשתמש בו.
בקוד הלקוח שנוצר, אין צורך לשכפל או לשמור על תוקף של נקודות אחיזה ומופעי זיכרון שנשלחים כארגומנטים של קלט של השיטה שנקראה, אחרי שהשיטה מחזירה ערך. עם זאת, המערכת משכפלת אוטומטית את הידיות ואת מופעי הזיכרון שמתקבלים כארגומנטים של פלט באמצעות הקוד שנוצר אוטומטית, ולכן צריך לסגור אותם כמו שצריך כשמסיימים להשתמש בהם. זה נכון גם אם הארגומנטים האלה של ההחזרה מופיעים כערכי החזרה של השיטה (במקרה של ערך החזרה יחיד) או באמצעות סגנון הקריאה החוזרת הסינכרונית (במקרה של ערכי החזרה מרובים).
מידע נוסף על שכפול וסגירה זמין במסמכי התיעוד של מחלקות Java.
מערכים ווקטורים
מערכים מתורגמים למערכי Java, ווקטורים מתורגמים ל-ArrayList<T>
כאשר T הוא סוג האובייקט המתאים, ויכול להיות שהוא עוטף סוגים סקלריים כמו vec<int32_t> =>
ArrayList<Integer>
). לדוגמה:
takeAnArray(int32_t[3] array); returnAVector() generates (vec<int32_t> result);
… הופך ל:
void takeAnArray(int[] array); ArrayList<Integer> returnAVector();
מבנים
המבנים מתורגמים למחלקות Java עם פריסה דומה. לדוגמה:
struct Bar { vec<bool> someBools; }; struct Foo { int32_t a; int8_t b; float[10] c; Bar d; };
… הופך ל:
class Bar { public final ArrayList<Boolean> someBools = new ArrayList(); }; class Foo { public int a; public byte b; public final float[] c = new float[10]; public final Bar d = new Bar(); }
סוגים מוצהרים
כל סוג ברמה העליונה שמוצהר ב-types.hal
מקבל קובץ פלט משלו מסוג .java (כנדרש ב-Java). לדוגמה, הקובץ types.hal
הבא יוצר שני קבצים נוספים (Foo.java ו-Bar.java):
struct Foo { ... }; struct Bar { ... struct Baz { }; ... };
ההגדרה של Baz נמצאת במחלקה פנימית סטטית של Bar (ב-Bar.java
).