שפת הגדרת ממשק HAL או HIDL היא שפת תיאור ממשק (IDL) שיש לציין לבין הממשק בין HAL המשתמשים שלו. HIDL מאפשר לציין סוגים וקריאות שיטה, שנאספו כדי וממשקים וחבילות. באופן כללי, HIDL היא מערכת לתקשורת בין מסדי קוד שעשויים לעבור הידור בנפרד.
HIDL מיועדת לשימוש לתקשורת בין תהליכים (IPC). קבצים מסוג HAL שנוצרו באמצעות HDL הם שנקראים HALs מקושרים, כי הם יכולים לתקשר עם שכבות ארכיטקטורה אחרות באמצעות קלסר שיחות לתקשורת בין תהליכים (IPC). תהליכי HAL מנוהלים מופעלים בתהליך נפרד מהלקוח שמשתמש בהם. עבור ספריות שחייבות להיות מקושרות לתהליך, מעבר זמין גם הוא (לא נתמך ב-Java).
HIDL מציין מבני נתונים וחתימות שיטה המסודרים בממשקים (בדומה למחלקה) שנאספות לחבילות. התחביר של HIDL נראה מוכר ל-C++ וגם מתכנתים אחרים, אבל במילות מפתח. HIDL גם משתמש בהערות בסגנון Java.
טרמינולוגיה
הקטע הזה משתמש במונחים הבאים שקשורים ל-HIDL:
מקושר | מציין שנעשה שימוש ב-HIDL עבור הפעלות לשירות מרחוק בין תהליכים הוטמעו באמצעות מנגנון דמוי Binder. כדאי לעיין גם במעבר חיצוני. |
---|---|
קריאה חוזרת, אסינכרונית | ממשק שמופעל על ידי משתמש HAL, שמועבר ל-HAL (באמצעות שיטת HIDL), וגם שנקראה על ידי HAL כדי להחזיר נתונים בכל שלב. |
קריאה חוזרת, סינכרונית | מחזירה נתונים מהטמעה של שיטת HIDL של שרת ללקוח. לא משתמשים בו ל-methods שמחזירות ערך מבוטל או ערך ראשוני יחיד. |
לקוח | תהליך שקורא ל-methods של ממשק מסוים. מסגרת HAL או Android יכול להיות לקוח של ממשק אחד ושרת של ממשק אחר. עוד באותו הקשר העברת מידע. |
נמשך | מציין ממשק שמוסיף שיטות ו/או סוגים לממשק אחר. ממשק יכול להרחיב רק ממשק אחד נוסף. מתאים לקטינים מספר גרסאות באותו שם חבילה או עבור חבילה חדשה (למשל, ספק ) כדי להתבסס על חבילה ישנה יותר. |
יוצרת | מציינת שיטת ממשק שמחזירה ערכים ללקוח. כדי לחזור ערך לא פרימיטיבי אחד, או יותר מערך אחד, פונקציית קריאה חוזרת סינכרונית נוצרת. |
ממשק | אוסף של שיטות וסוגים. תורגם לכיתה ב-C++ או ב-Java. הכול ה-methods בממשק נקראים באותו כיוון: תהליך לקוח מפעיל שיטות שהוטמעו על ידי תהליך בשרת. |
כיוון אחד | כשמחילים את השיטה HIDL, היא מציינת שהשיטה לא מחזירה ערכים לא חוסם. |
חבילה | איסוף של ממשקים וסוגי נתונים שחולקים גרסה. |
העברת סיגנל ללא שינוי | מצב HIDL שבו השרת הוא ספרייה משותפת, dlopen ed
על ידי הלקוח. במצב מעבר, הלקוח והשרת הם אותו תהליך, אבל
באמצעות Codebases נפרדים. משמש רק להעברת מסדי קוד מדור קודם למודל HIDL.
ראו גם Binderized. |
שרת | תהליך שמטמיע שיטות בממשק. עוד באותו הקשר העברת מידע. |
תחבורה | תשתית HIDL שמעבירה נתונים בין השרת ללקוח. |
גרסה | גרסת החבילה. מורכב משני מספרים שלמים: ראשי וקטין. עריכות קלות שדרוגי גרסאות עשויים להוסיף (אבל לא לשנות) סוגים ושיטות. |
עיצוב HIDL
המטרה של HIDL היא מצב שבו ניתן להחליף את ה-framework של Android בלי
לבנות מחדש נכסי HAL. יעדי HAL נוצרים על ידי ספקים או יצרני SOC
המחיצה /vendor
במכשיר, שמאפשרת את מסגרת Android
להחלפה ב-OTA מבלי להרכיב מחדש את ה-HAL.
תכנון HIDL מאזן את החששות הבאים:
- יכולת פעולה הדדית. יצירת ממשקים מהימנים שמאפשרים פעולה הדדית בין תהליכים שעשויים להיות מורכבים מארכיטקטורות שונות, שרשראות כלים, וליצור תצורות אישיות. לממשקי HIDL יש גרסאות ואי אפשר לשנות אותם אחרי שהן מתפרסמות.
- יעילות. HIDL מנסה למזער את מספר ההעתקה ב-AI. נתונים בהגדרת HIDL נשלחים לקוד C++ בפריסה רגילה של C++ מבני נתונים שאפשר להשתמש בהם בלי לפתוח את החבילות. HIDL גם מספק שיתוף ממשקי זיכרון, ומאחר שקריאות RPC הן איטיות במידה מסוימת, HIDL תומך דרכים להעברת נתונים בלי להשתמש בקריאה ל-RPC: זיכרון משותף וקריאה מהירה תור הודעות (FMQ).
- אינטואיטיבי. HIDL נמנע מבעיות מורכבות של בעלות על זיכרון על ידי
באמצעות פרמטרים של
in
בלבד ל-RPC (מידע נוסף זמין במאמר Android ממשק Definition Language (AIDL)); והערכים שהם לא יכולים להיות שמוחזרים מ-methods מוחזרים באמצעות פונקציות קריאה חוזרת. אין לי נתונים מועברים ל-HIDL לצורך העברה או קבלת נתונים מ-HIDL נתונים - הבעלות נשארת תמיד בפונקציה הקריאה. הנתונים צריכים קיימים רק לכל משך הפונקציה שנקראה והם עלולים להרוס אותם מיד אחרי שהפונקציה נקראת חזרה.
שימוש במצב העברת נתונים
כדי לעדכן מכשירים עם גרסאות קודמות של Android ל-Android O, אתם יכולים: כוללים HALs קונבנציונליים (וגם דור קודם) בממשק HIDL חדש שמשרת את HAL במצב קישור (binderized) ובמצב זהה (pass-through). האריזה הזאת שקופים גם ל-HAL וגם ל-framework של Android.
מצב העברת נתונים זמין רק ללקוחות ולהטמעות של C++. במכשירים שמותקנות בהם גרסאות קודמות של Android לא כתוב HAL ב-Java, לכן שאילתות Java HAL מקושרות מטבען.
קובצי כותרות של הרשאות העברה
כשקובץ .hal
עובר הידור, hidl-gen
יוצר
קובץ כותרת עליונה נוסף BsFoo.h
בנוסף לכותרות
משמש לתקשורת בין binders. הכותרת הזאת מגדירה פונקציות
dlopen
. בדיקות HAL של צדדים שלישיים פועלות באותו תהליך שבו
הם נקראים, ברוב המקרים שיטות העברה מופעלות על ידי
בקשה להפעלת פונקציה (אותו שרשור). oneway
methods פועלות בשרשור משלהן
כי הם לא אמורים להמתין למעבדת HAL כדי לעבד אותם (כלומר, כל
שנעשה בהן שימוש ב-methods oneway
במצב מעבר, חייבות להיות בטוחות לשרשור.
בהינתן IFoo.hal
, הפרמטר BsFoo.h
כולל את ערך ה-HIDL שנוצר
שיטות שבאמצעותן אפשר לספק תכונות נוספות (כמו oneway
שהטרנזקציות פועלות בשרשור אחר). הקובץ דומה ל-
BpFoo.h
, עם זאת, במקום להעביר שיחות IPC באמצעות binder,
הפונקציות הרצויות מופעלות ישירות. הטמעות עתידיות של מוצרי HAL
עשוי לספק יישומים מרובים, כמו FooFast HAL ו
Foo Document HAL. במקרים כאלה, קובץ לכל הטמעה נוספת
(למשל, PTFooFast.cpp
והקבוצה
PTFooAccurate.cpp
).
HAL של העברה מסוג העברת נתונים
אפשר לקשר בין הטמעות HAL שתומכות במצב העברה. בהינתן
בממשק HAL a.b.c.d@M.N::IFoo
, נוצרות שתי חבילות:
a.b.c.d@M.N::IFoo-impl
כולל הטמעה של HAL וחושף את הפונקציהIFoo* HIDL_FETCH_IFoo(const char* name)
. במצב מופעל במכשירים מדור קודם, החבילה הזוdlopen
וההטמעה מתבצעת נוצר באמצעותHIDL_FETCH_IFoo
. אפשר ליצור את קוד הבסיס באמצעותhidl-gen
ו--Lc++-impl
ו-Landroidbp-impl
.a.b.c.d@M.N::IFoo-service
פתיחת HAL של העברה רושם את עצמו כשירות מקושר ומאפשר את אותה הטמעת HAL לשמש גם כמודל אלטרנטיבי וגם כקישור.
בסוג IFoo
, אפשר לקרוא ל-sp<IFoo>
IFoo::getService(string name, bool getStub)
כדי לקבל גישה למופע מסוים
מתוך IFoo
. אם הערך של getStub
נכון, getService
מנסה לפתוח HAL רק במצב העברה. אם getStub
הוא
False, getService
מנסה למצוא שירות מקושר. אם זה
נכשל, לאחר מכן הוא מנסה למצוא את שירות ההעברה. getStub
אסור להשתמש בפרמטר,
defaultPassthroughServiceImplementation
. (מכשירים שמופעלים עם
Android O הוא מכשירים מקושרים לחלוטין, כך שפתיחת שירות במצב העברה
אסורה).
דקדוק HIDL
השפה HIDL דומה ל-C (אבל לא משתמשת ב-C)
לעיבוד מראש). כל סימני הפיסוק לא מתוארים בהמשך (מלבד השימוש הברור
של =
ו-|
) הוא חלק מהדקדוק.
הערה: כדי לקבל פרטים על סגנון הקוד של HIDL, אתם יכולים לעיין ב מדריך לסגנון קוד.
/** */
מציינת הערה במסמך. אפשר להחיל את האפשרויות האלה רק להצהרות מסוג 'סוג', 'שיטה', 'שדה' ו'ערך טיפוסים בני מנייה (enum)'./* */
מציין תגובה לכמה שורות.//
מציין תגובה לסוף השורה. מלבד//
, שורות חדשות זהות לכל רווח אחר.- בדקדוק לדוגמה שבהמשך, טקסט מ-
//
עד לסוף שורה זו אינה חלק מהדקדוק, אלא תגובה על הדקדוק. - המשמעות של
[empty]
היא שיכול להיות שהמונח ריק. - השימוש ב
?
אחרי שימוש בליטרל או במונח הוא אופציונלי. ...
מציין רצף שמכיל אפס פריטים או יותר עם מפרידה את סימני הפיסוק כפי שצוין. אין ארגומנטים שונים ב-HIDL.- פסיקים נפרדים לרכיבי רצף.
- נקודה ופסיק מסיימים כל רכיב, כולל הרכיב האחרון.
- כל המילים באותיות גדולות הן גדולות.
italics
היא משפחת אסימונים כמוinteger
אוidentifier
(C רגיל) כללי הניתוח).constexpr
הוא ביטוי קבוע בסגנון C (כמו1 + 1
וגם1L << 3
).import_name
הוא שם חבילה או ממשק, שעומד בדרישות כפי שמתואר ב- HIDL ניהול גרסאות.- אותיות קטנות
words
הן אסימונים מילוליים.
דוגמה:
ROOT = PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... } // not for types.hal | PACKAGE IMPORTS ITEM ITEM... // only for types.hal; no method definitions ITEM = ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?; | safe_union identifier { UFIELD; UFIELD; ...}; | struct identifier { SFIELD; SFIELD; ...}; // Note - no forward declarations | union identifier { UFIELD; UFIELD; ...}; | enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar | typedef TYPE identifier; VERSION = integer.integer; PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION; PREAMBLE = interface identifier EXTENDS EXTENDS = <empty> | extends import_name // must be interface, not package GENERATES = generates (FIELD, FIELD ...) // allows the Binder interface to be used as a type // (similar to typedef'ing the final identifier) IMPORTS = [empty] | IMPORTS import import_name; TYPE = uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t | float | double | bool | string | identifier // must be defined as a typedef, struct, union, enum or import // including those defined later in the file | memory | pointer | vec<TYPE> | bitfield<TYPE> // TYPE is user-defined enum | fmq_sync<TYPE> | fmq_unsync<TYPE> | TYPE[SIZE] FIELD = TYPE identifier UFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SFIELD = TYPE identifier | safe_union identifier { FIELD; FIELD; ...}; | struct identifier { FIELD; FIELD; ...}; | union identifier { FIELD; FIELD; ...}; | safe_union identifier { FIELD; FIELD; ...} identifier; | struct identifier { FIELD; FIELD; ...} identifier; | union identifier { FIELD; FIELD; ...} identifier; SIZE = // Must be greater than zero constexpr ANNOTATIONS = [empty] | ANNOTATIONS ANNOTATION ANNOTATION = | @identifier | @identifier(VALUE) | @identifier(ANNO_ENTRY, ANNO_ENTRY ...) ANNO_ENTRY = identifier=VALUE VALUE = "any text including \" and other escapes" | constexpr | {VALUE, VALUE ...} // only in annotations ENUM_ENTRY = identifier | identifier = constexpr