בקטע הזה מתוארים סוגי הנתונים HIDL. פרטים על ההטמעה זמינים במאמר HIDL C++ (ל-C++ הטמעות) או HIDL Java (להטמעות Java).
קווי דמיון ל-C++ כוללים:
structs
צריך להשתמש בתחביר C++ ; הפלטפורמהunions
תומכת בתחביר C++ כברירת מחדל. יש לתת שמות לשניהם; מבנים ואיחודים אנונימיים אינם נתמכים.- מותר להשתמש ב-Typedefs ב-HIDL (כפי שהן ב-C++ ).
- תגובות בסגנון C++ מותרות ומועתקות לקובץ הכותרת שנוצר.
דוגמאות ל-Java:
- לכל קובץ, HIDL מגדיר מרחב שמות בסגנון Java שחייב להתחיל ב-
android.hardware.
מרחב השמות שנוצר על ידי C++::android::hardware::…
- כל הגדרות הקובץ נכללות בסגנון Java
wrapper של
interface
. - הצהרות מערך HIDL מותאמות לסגנון Java ולא בסגנון C++. דוגמה:
struct Point { int32_t x; int32_t y; }; Point[3] triangle; // sized array
- ההערות דומות לפורמט Javadoc.
ייצוג נתונים
struct
או union
שמורכבים מ-
פריסה רגילה
(תת-תחום מהדרישה של סוגי נתונים ישנים) יש זיכרון עקבי
פריסה בקוד C++ שנוצר, שנאכף באמצעות מאפייני התאמה מפורשים
struct
ו-union
חברים.
סוגים ראשוניים של HIDL, וגם enum
ו-bitfield
(שתמיד נגזרים מסוגים פרימיטיביים), ממפים לסוגים סטנדרטיים של C++
כמו std::uint32_t
cstdint.
מכיוון ש-Java לא תומכת בסוגים לא חתומים, סוגי HIDL לא חתומים ממופים סוג ה-Java החתום התואם. מבנים למפות למחלקות Java; מערכים ממופים למערכי Java; בשלב הזה אין תמיכה ב-unions ב-Java. מחרוזות נשמרות באופן פנימי כ-UTF8. מכיוון ש-Java תומכת רק מחרוזות UTF16, ערכי מחרוזות שנשלחו להטמעה של Java או ממנה וייתכן שלא יהיו זהים בתרגום מחדש, כי מערכות התווים למפות תמיד בצורה חלקה.
נתונים שהתקבלו דרך IPC ב-C++ מסומנים כ-const
ונמצאים
זיכרון לקריאה בלבד שנשאר רק במהלך הבקשה להפעלת הפונקציה. נתונים
שהתקבלו דרך IPC ב-Java כבר הועתקו לאובייקטי Java, כך שניתן
יישמרו ללא העתקה נוספת (וניתן לשנותה).
הערות
ניתן להוסיף הערות בסגנון Java להצהרות. ההערות הן בוצע ניתוח על ידי הקצה העורפי של ספק הבדיקה (VTS) של המהדר (compiler) ל-HIDL, אבל אף אחד אנוטציות מנותחות שכאלו למעשה מובנות על ידי המהדר של HIDL. במקום זאת, אנוטציות VTS שנותחו מטופלות על ידי VTS Compiler (VTSC).
ההערות משתמשות בתחביר Java: @annotation
או
@annotation(value)
או @annotation(id=value, id=value…)
כאשר הערך יכול להיות ביטוי קבוע, מחרוזת או רשימת ערכים
בתוך {}
, בדיוק כמו ב-Java. מספר הערות עם אותו שם
יכולים להיות מצורפים לאותו פריט.
העברת הצהרות
ב-HIDL, ייתכן שלא תהיה הצהרה קדימה על מבנים, מה שעלול לגרום למוגדר על ידי המשתמש סוגים שונים של נתונים עם הפניה עצמית (לדוגמה, לא ניתן לתאר רשימה מקושרת) או עץ ב-HIDL). רוב תוכניות HAL הקיימות (לפני מערכת Android 8.x) כוללות שימוש מוגבל את ההצהרות הבאות, ואפשר להסיר אותן על ידי סידור מחדש של מבנה הנתונים. וההצהרות שלו.
ההגבלה הזאת מאפשרת להעתיק מבני נתונים לפי ערך באמצעות מודל פשוט
בהעתקה עמוקה, במקום לעקוב אחרי ערכי המצביע שעשויים להתרחש
במבנה נתונים עם התייחסות עצמית. אם אותם נתונים מועברים פעמיים,
למשל באמצעות שני פרמטרים של method או vec<T>
שמצביעים אל
אותם נתונים, שני עותקים נפרדים נוצרים ונשלחים.
הצהרות מקוננות
HIDL תומך בהצהרות מקננות בכמה רמות שרוצים (באמצעות הצהרה אחת חריג שמצוין בהמשך). לדוגמה:
interface IFoo { uint32_t[3][4][5][6] multidimArray; vec<vec<vec<int8_t>>> multidimVector; vec<bool[4]> arrayVec; struct foo { struct bar { uint32_t val; }; bar b; } struct baz { foo f; foo.bar fb; // HIDL uses dots to access nested type names } …
היוצא מן הכלל הוא שניתן להטמיע סוגי ממשק רק
vec<T>
ורק רמה אחת בקישורי עומק (לא
vec<vec<IFoo>>
).
תחביר של מצביע גולמי
שפת HIDL לא משתמשת ב-* ולא תומכת את הגמישות המלאה של מצביעי C/C++ גולמיים. לפרטים על האופן שבו היטל HIDL מצביעים ומערכים/וקטורים, ראו vec<T> תבנית.
ממשקים
למילת המפתח interface
יש שני שימושים.
- תיפתח ההגדרה של ממשק בקובץ .hal
- אפשר להשתמש בו כסוג מיוחד בשדות struct/union, פרמטרים של method,
והחזרות. הוא נתפס כממשק כללי ומילה נרדפת
android.hidl.base@1.0::IBase
לדוגמה, הפונקציה IServiceManager
פועלת באופן הבא:
get(string fqName, string name) generates (interface service);
בשיטה הזו מבטיחים לחפש ממשק מסוים לפי שם. כמו כן
זהה להחלפת הממשק ב-android.hidl.base@1.0::IBase
.
ניתן להעביר ממשקים רק בשתי דרכים: כפרמטרים ברמה עליונה, או
חברים של vec<IMyInterface>
. הם לא יכולים להיות חברים ב-
vecs, מבניים, מערכים או איחודים מקוננים.
MQDescriptorSync ו-MQDescriptorUnsync
הסוגים MQDescriptorSync
וMQDescriptorUnsync
העברה של מתארים מסונכרנים או לא מסונכרנים בתור 'תור הודעות מהירות' (FMQ)
דרך ממשק HIDL. פרטים נוספים זמינים במאמר
HIDL C++ (אין מתגי FMQ
שנתמכות ב-Java).
סוג הזיכרון
הסוג memory
משמש לייצוג זיכרון משותף לא ממופה
HIDL. המדיניות הזו נתמכת רק ב-C++. ניתן להשתמש בערך מהסוג הזה ב
המקבל לאתחול אובייקט IMemory
, מיפוי הזיכרון
והופך אותו לשימושי. פרטים נוספים זמינים במאמר
HIDL C++.
אזהרה: נתונים מובְנים ששמורים בתיקיות 'משותפים'
זיכרון חייב להיות סוג שהפורמט שלו אף פעם לא משתנה כל עוד
לגרסת הממשק שעברה את memory
. אחרת, מוצרי HAL עלולים לסבול
בעיות תאימות חמורות.
סוג מצביע העכבר
הסוג pointer
מיועד לשימוש פנימי בלבד מסוג HIDL.
Bitfield<T> סוג תבנית
bitfield<T>
שבו T
הוא
user-defined enum מרמז על כך שהערך הוא ערך OR-או ב-bit
ערכי enum שמוגדרים ב-T
. בקוד שנוצר,
bitfield<T>
מופיע בתור הסוג הבסיסי של T. עבור
דוגמה:
enum Flag : uint8_t { HAS_FOO = 1 << 0, HAS_BAR = 1 << 1, HAS_BAZ = 1 << 2 }; typedef bitfield<Flag> Flags; setFlags(Flags flags) generates (bool success);
המהדר מטפל בסוג הדגלים בדיוק כמו ב-uint8_t
.
למה לא להשתמש
(u)int8_t
/(u)int16_t
/(u)int32_t
/(u)int64_t
?
השימוש ב-bitfield
מספק לקורא מידע נוסף בנוגע ל-HAL,
שיודע עכשיו ש-setFlags
מקבל ערך OR של דגל (כלומר
יודע שקריאה ל-setFlags
עם 16 אינה חוקית). ללא
bitfield
, המידע הזה מועבר רק באמצעות מסמכים. לחשבון
הפונקציה VTS יכולה למעשה לבדוק אם ערך הדגלים הוא ערך OR של דגל (או ביטי).
כינויים מסוג ראשוני
אזהרה: כתובות מכל סוג (גם כתובות פיזיות) כתובות מכשיר) אף פעם לא יכולות להיות חלק מכינוי מקורי. העברתי המידע בין התהליכים מסוכן וחשוף לתקיפות. צריך לאמת את כל הערכים שמועברים בין תהליכים לפני שנעשה בהם שימוש לחפש זיכרון מוקצה בתוך תהליך. אחרת, כינויים שגויים עלולים לגרום גישה לזיכרון או פגיעה בזיכרון.
הסמנטיקה של HIDL היא העתקה לפי ערך, שמרמזת שהפרמטרים מועתקים.
פיסות נתונים גדולות או נתונים שצריך לשתף בין תהליכים
(כמו גדר סנכרון), מתבצעות על ידי העברת מתארי קבצים שמצביעים על
לאובייקטים קבועים: ashmem
לזיכרון משותף, לקבצים בפועל, או
כל דבר אחר שיכול להסתתר מאחורי מתאר קובץ. מנהל ההתקן של הקישור
מעתיקה את מתאר הקובץ לתהליך השני.
custom_handle_t
ב-Android יש תמיכה ב-native_handle_t
, רעיון כללי של כינוי
הוגדרה ב-libcutils
.
typedef struct native_handle { int version; /* sizeof(native_handle_t) */ int numFds; /* number of file-descriptors at &data[0] */ int numInts; /* number of ints at &data[numFds] */ int data[0]; /* numFds + numInts ints */ } native_handle_t;
כינוי מקורי הוא אוסף של רכיבי int ומתארי קבצים שמועברים
לפי ערך. ניתן לאחסן מתאר קובץ יחיד בנקודת אחיזה מקומית עם
ללא ints ומתאר קובץ יחיד. העברת כינויים באמצעות כינויים מקומיים
שעבר אנונימיזציה באמצעות הסוג של רכיב handle
, מבטיח
הכינויים נכללים ישירות ב-HIDL.
ל-native_handle_t
יש גודל משתנה, לכן אי אפשר לכלול אותו
ישירות בתוך מבנה. שדה כינוי יוצר מצביע אל
הוקצה native_handle_t
.
בגרסאות הקודמות של Android, הכינויים המקוריים נוצרו באמצעות אותם
הפונקציות הקיימות
libcutils.
ב-Android מגרסה 8.0 ואילך, הפונקציות האלה מועתקות אל
מרחב השמות android::hardware::hidl
או הועבר ל-NDK. hiDL
שנוצר אוטומטית, מחזיר את הפונקציות מהפונקציות האלה ומבצע אותן סריאליזציה שלהן באופן אוטומטי,
ללא מעורבות של קוד שנכתב על ידי המשתמש.
הבעלות על הכינוי ועל מתאר הקובץ
כשמבצעים קריאה ל-method של ממשק HIDL שמעבירה (או מחזירה)
אובייקט hidl_handle
(ברמה העליונה או חלק מסוג מורכב),
הבעלות על תיאורי הקבצים שכלולה בו היא:
- המבצע הקריאה שמעביר אובייקט
hidl_handle
בתור הארגומנט שומר את הבעלות על מתארי הקבצים שנכלליםnative_handle_t
זה כולל. המתקשר צריך לסגור את הקבצים האלה כשמגדירים הרבה מילים. - התהליך של החזרת
hidl_handle
אובייקט (על ידי העברתו לפונקציה_cb
) שומר על הבעלות על תיאורי קבצים שנכללים בתוךnative_handle_t
שמוקף ברכיב אובייקט; התהליך חייב לסגור את מתארי הקבצים האלה כשהוא מסתיים איתם. - לתחבורה שמקבלת
hidl_handle
הבעלות על מתארי הקבצים בתוךnative_handle_t
עטוף על ידי האובייקט; המקבל יכול להשתמש בתיאורי הקבצים האלה כפי שהוא הקריאה החוזרת של העסקה, אבל צריכה לשכפל את נקודת האחיזה המקורית כדי להשתמש בקובץ שמעבר לקריאה החוזרת (callback). ההעברה מתקשרת באופן אוטומטיclose()
לתיאורי הקבצים כשהעסקה תסתיים.
HIDL לא תומך בכינויים ב-Java (כיוון ש-Java לא תומכת בכינויים ב- הכול).
מערכים בגודל
למערכים בגודל מבני HIDL, הרכיבים שלהם יכולים להיות מכל סוג שהוא מבנה יכול להכיל:
struct foo { uint32_t[3] x; // array is contained in foo };
מיתרים
מחרוזות נראות שונה ב-C++ וב-Java, אבל התעבורה הבסיסית סוג האחסון הוא מבנה של C++. פרטים נוספים זמינים במאמר HIDL C++ סוגי נתונים או סוגי נתונים של HIDL Java.
הערה: העברת מחרוזת אל Java או ממנה דרך ממשק HIDL (כולל Java ל-Java) גורם להמרות מסוג מערכת תווים שעשויים לא לשמור על הקידוד המקורי.
ו<T> סוג תבנית
התבנית vec<T>
מייצגת מאגר נתונים זמני בגודל משתנה
שמכיל מופעים של T
.
T
יכול להיות אחת מהאפשרויות הבאות:
- סוגים ראשוניים (למשל uint32_t)
- מיתרים
- טיפוסים בני מנייה שהוגדרו על ידי המשתמש
- מבנים שהוגדרו על ידי המשתמש
- ממשקים, או מילת המפתח
interface
(יש תמיכה ב-vec<IFoo>
, ב-vec<interface>
רק כפרמטר ברמה עליונה) - כינויים
- Bitfield<U>
- vec<U>, כאשר U נמצא ברשימה הזו חוץ מהממשק (למשל
אין תמיכה ב-
vec<vec<IFoo>>
) - U[] (מערך בגודל U), כאשר U נמצא ברשימה הזו חוץ מהממשק
סוגים בהגדרת המשתמש
בקטע הזה מתוארים סוגים שהוגדרו על ידי המשתמש.
Enum
HIDL לא תומך בטיפוסים אנונימיים של טיפוסים בני מנייה (enum). אחרת, טיפוסים בני מנייה (enum) ב-HIDL דומים אל C++11:
enum name : type { enumerator , enumerator = constexpr , … }
טיפוס enum בסיסי מוגדר במונחים של אחד מסוגי המספרים השלמים ב-HIDL. אם לא מצוין עבור המונה הראשון של טיפוסים בני מנייה (enum) המבוסס על מספר שלם 0. אם לא צוין ערך למונה מאוחר יותר, ערך ברירת המחדל של הערך הקודם הוא 1+. לדוגמה:
// RED == 0 // BLUE == 4 (GREEN + 1) enum Color : uint32_t { RED, GREEN = 3, BLUE }
טיפוסים בני מנייה (enum) יכולים גם לרשת מטיפוס טיפוסים (enum) שהוגדר קודם לכן. אם לא קיים ערך
מצוין עבור המונה הראשון של 'טיפוסים בני מנייה (enum)' (במקרה הזה
FullSpectrumColor
), ברירת המחדל היא הערך
מונה של מספר ההורה +1. לדוגמה:
// ULTRAVIOLET == 5 (Color:BLUE + 1) enum FullSpectrumColor : Color { ULTRAVIOLET }
אזהרה: הירושה של Enum פועלת לאחור מרוב סוגי הירושה האחרים. לא ניתן להשתמש בערך 'טיפוסים בני מנייה (enum)' בתור ערך כערך הורה מסוג 'טיפוסים בני מנייה (enum)'. הסיבה לכך היא ש-enum של צאצא כולל יותר ערכים מ- הורה. עם זאת, אפשר להשתמש באופן בטוח בערך 'טיפוסים בני מנייה (enum)' בתור ערך של 'טיפוסים בני מנייה (enum)' כי ערכי 'טיפוסים בני מנייה (enum)' הם מעצם הגדרתם קבוצת-על של ערכי 'טיפוסים בני מנייה (enum)'. חשוב לזכור את זה כשמעצבים ממשקים, כי 'טיפוסים בני מנייה (enum)' לא יכולים להתייחס ל-'טיפוסים בני מנייה (enum)' באיטרציות מאוחרות יותר גרפי.
לערכי enum יש תחביר נקודתיים (ולא תחביר נקודה כ-
סוגים מקוננים). התחביר הוא Type:VALUE_NAME
. אין צורך לציין
אם יש הפניה לערך מאותו סוג enum או מאותו סוג צאצא. דוגמה:
enum Grayscale : uint32_t { BLACK = 0, WHITE = BLACK + 1 }; enum Color : Grayscale { RED = WHITE + 1 }; enum Unrelated : uint32_t { FOO = Color:RED + 1 };
החל מ-Android 10, ל-enum יש
אפשר להשתמש במאפיין len
בביטויים קבועים.
MyEnum::len
הוא המספר הכולל של הרשומות בספירה הזו.
הוא שונה ממספר הערכים הכולל, שעשוי להיות קטן יותר כאשר
יש כפילות.
מבנה
HIDL לא תומך במבנים אנונימיים. אחרת, מבני HIDL דומה ל-C.
HIDL לא תומך במבני נתונים באורך משתנה שנכללים במלואם
בנייה. זה כולל את המערך באורך בלתי מוגבל שמשמש לפעמים
השדה האחרון של מבנה ב-C/C++ (לפעמים נראה בגודל של
[0]
). HIDL vec<T>
מייצג גודל דינמי
מערכים שהנתונים שלהם מאוחסנים במאגר נתונים זמני נפרד. של מופעים כאלה מיוצגים
עם מופע של vec<T>
ב-struct
.
באופן דומה, string
יכול להיות בתוך struct
(מאגרי הנתונים הזמניים המשויכים הם נפרדים). ב-C++ שנוצר, מופעים של HIDL
הסוג של הכינוי מיוצג באמצעות מצביע על נקודת האחיזה המותאמת בפועל
מופעים של סוג נתוני הבסיס הם באורך משתנה.
Union
HIDL לא תומך באיחודים אנונימיים. אחרת, איחודים דומים ל-C.
איחודים לא יכולים להכיל סוגי תיקון (כמו מצביעים, תיאורי קבצים, binder)
). הם לא צריכים שדות מיוחדים או סוגים משויכים,
פשוט הועתקה באמצעות memcpy()
או באמצעות שימוש מקביל. איחוד עשוי לא באופן ישיר
יכללו (או יכללו באמצעות מבני נתונים אחרים) כל דבר שדורש הגדרה
היסטוגים של binder (כלומר, הפניות או הפניות לממשק קלסר). לדוגמה:
union UnionType { uint32_t a; // vec<uint32_t> r; // Error: can't contain a vec<T> uint8_t b;1 }; fun8(UnionType info); // Legal
אפשר להצהיר על איחודים גם בתוך מבני נתונים. לדוגמה:
struct MyStruct { union MyUnion { uint32_t a; uint8_t b; }; // declares type but not member union MyUnion2 { uint32_t a; uint8_t b; } data; // declares type but not member }