HIDL דורש גרסה של כל ממשק שנכתב ב- HIDL. לאחר פרסום ממשק HAL, הוא קפוא וכל שינוי נוסף חייב להתבצע בגרסה חדשה של ממשק זה. אמנם לא ניתן לשנות ממשק נתון מסוים, אך ניתן להרחיב אותו באמצעות ממשק אחר.
מבנה קוד HIDL
קוד HIDL מאורגן בסוגים, ממשקים וחבילות המוגדרים על ידי המשתמש:
- סוגים מוגדרים על ידי המשתמש (UDT) . HIDL מספק גישה לקבוצת סוגי נתונים פרימיטיביים שבהם ניתן להשתמש כדי לחבר סוגים מורכבים יותר באמצעות מבנים, איגודים וספירות. UDT מועברים לשיטות ממשק, וניתן להגדירם ברמת חבילה (המשותפת לכל הממשקים) או באופן מקומי לממשק.
- ממשקים . כאבן בניין בסיסית של HIDL, ממשק מורכב מהצהרות UDT ושיטות. ממשקים יכולים גם לרשת מממשק אחר.
- חבילות . מארגן ממשקי HIDL קשורים וסוגי הנתונים עליהם הם פועלים. חבילה מזוהה על ידי שם וגרסה וכוללת את הדברים הבאים:
- קובץ הגדרת סוג נתונים הנקרא
types.hal
. - אפס ממשקים או יותר, כל אחד בקובץ ה-
.hal
שלו.
- קובץ הגדרת סוג נתונים הנקרא
סוגי הקבצים מסוג הגדרת סוג types.hal
מכילים types.hal
בלבד (כל ה- UDT ברמת החבילה נשמרים בקובץ יחיד). ייצוגים בשפת היעד זמינים לכל הממשקים בחבילה.
פילוסופיית גרסאות
חבילת HIDL (כגון android.hardware.nfc
), לאחר שפורסמה עבור גרסה נתונה (כגון 1.0
), אינה ניתנת לשינוי; אי אפשר לשנות את זה. שינויים בממשקים שבחבילה או כל שינוי ב- UDT שלה יכולים להתרחש רק בחבילה אחרת .
ב- HIDL, גרסאות חלות ברמת החבילה, לא ברמת הממשק, וכל הממשקים וה- UDT בחבילה חולקים את אותה גרסה. גרסאות החבילה עוקבות אחר גרסאות סמנטיות ללא רמת התיקון ורכיבי metadata build. בתוך חבילה נתונה, בליטה בגרסת מינור מרמזת על כך שהגרסה החדשה של החבילה אינה תואמת לאחור עם החבילה הישנה וחבילה בגרסה הראשית מרמזת כי הגרסה החדשה של החבילה אינה תואמת לאחור עם החבילה הישנה.
מבחינה רעיונית, חבילה יכולה להתייחס לחבילה אחרת באחת מכמה דרכים:
- בכלל לא .
- הרחבה תואמת לאחור ברמת החבילה . זה קורה בשינוי מהדורות חדשות של גרסה משנית (תיקון מצטבר הבא) של חבילה; לחבילה החדשה יש שם וגרסה ראשית זהה לחבילה הישנה, אך גרסה מינורית גבוהה יותר. מבחינה פונקציונלית, החבילה החדשה היא קבוצת על של החבילה הישנה, כלומר:
- ממשקים ברמה העליונה של חבילת האב קיימים בחבילה החדשה, אם כי בממשקים עשויים להיות שיטות חדשות, ממשקי ממשק חדשים מקומיים (הרחבה ברמת הממשק המתוארת להלן) ו- UDT חדשים ב-
types.hal
. - ניתן להוסיף לחבילה החדשה גם ממשקים חדשים.
- כל סוגי הנתונים של חבילת האב נמצאים בחבילה החדשה וניתן לטפל בהם בשיטות (שאולי מיושמות מחדש) מהחבילה הישנה.
- ניתן להוסיף גם סוגי נתונים חדשים לשימוש בשיטות חדשות של ממשקים קיימים שקדמו להם, או באמצעות ממשקים חדשים.
- ממשקים ברמה העליונה של חבילת האב קיימים בחבילה החדשה, אם כי בממשקים עשויים להיות שיטות חדשות, ממשקי ממשק חדשים מקומיים (הרחבה ברמת הממשק המתוארת להלן) ו- UDT חדשים ב-
- הרחבה תואמת לאחור ברמת הממשק . החבילה החדשה יכולה גם להרחיב את החבילה המקורית על ידי מורכבת מממשקים נפרדים מבחינה לוגית שמספקים פונקציונליות נוספת ולא הליבה. לצורך זה עשוי להיות רצוי להלן:
- ממשקים בחבילה החדשה צריכים להשתמש בסוגי הנתונים של החבילה הישנה.
- ממשקים בחבילה חדשה עשויים להאריך ממשקים של חבילה ישנה אחת או יותר.
- הרחב את חוסר התאימות המקורי לאחור . זהו גרסה עיקרית של החבילה ולא צריך להיות שום מתאם בין השניים. במידה שיש, זה יכול לבוא לידי ביטוי עם שילוב של סוגים מהגרסה הישנה של החבילה, וירושה של תת קבוצה של ממשקי חבילה ישנה.
בניית ממשקים
עבור ממשק מובנה היטב, הוספת סוגים חדשים של פונקציונליות שאינם חלק מהעיצוב המקורי צריכה לדרוש שינוי בממשק HIDL. לעומת זאת, אם אתה יכול או מצפה לבצע שינוי משני צידי הממשק שמציג פונקציונליות חדשה מבלי לשנות את הממשק עצמו, הרי שהממשק אינו מובנה.
טרבל תומך ברכיב ספקים ורכיבי מערכת בהם ניתן vendor.img
את vendor.img
במכשיר ואת system.img
. יש להגדיר באופן מפורש ויסודי את כל האינטראקציות בין vendor.img
ו- system.img
כדי שיוכלו להמשיך לעבוד במשך שנים רבות. זה כולל משטחי API רבים, אך משטח עיקרי הוא מנגנון ה- IPC ש- HIDL משתמש בו לתקשורת בין- vendor.img
בגבול system.img
/ vendor.img
.
דרישות
יש להגדיר את כל הנתונים המועברים דרך HIDL. על מנת להבטיח שהיישום והלקוח יוכלו להמשיך לעבוד גם כאשר הם נערכים בנפרד או מפותחים באופן עצמאי, הנתונים חייבים לעמוד בדרישות הבאות:
- ניתן לתאר ב- HIDL ישירות (באמצעות enums structts וכו ') עם שמות ומשמעות סמנטיים.
- ניתן לתאר על ידי תקן ציבורי כגון ISO / IEC 7816.
- ניתן לתאר על ידי תקן חומרה או פריסה פיזית של חומרה.
- יכול להיות נתונים אטומים (כגון מפתחות ציבוריים, מזהים וכו ') במידת הצורך.
אם משתמשים בנתונים אטומים, יש לקרוא אותם רק על ידי צד אחד של ממשק HIDL. לדוגמה, אם vendor.img
קוד נותן מרכיב על system.img
הודעה מחרוזת או vec<uint8_t>
נתונים, נתונים שלא ניתן לנתחו ידי system.img
עצמה; ניתן להחזיר אותו רק ל- vendor.img
לפרשנות. כאשר מעבירים ערך מ- vendor.img
לקוד ספק ב- system.img
או למכשיר אחר, יש לתאר במדויק את פורמט הנתונים ואופן פירושם והם עדיין חלק מהממשק .
הנחיות
אתה אמור להיות מסוגל לכתוב יישום או לקוח של HAL תוך שימוש בקבצי ה- hal בלבד (כלומר, לא תצטרך להסתכל על מקור האנדרואיד או על הסטנדרטים הציבוריים). אנו ממליצים לציין את ההתנהגות המדויקת. אמירות כגון "יישום יכול לעשות א 'או ב" לעודד מימושים השתזרו עם הלקוחות שהם מפותחים עם.
פריסת קוד HIDL
HIDL כולל חבילות ליבה וספקים.
ממשקי ליבת HIDL הם אלה שצוינו על ידי גוגל. החבילות שאליהן שייכות מתחילות עם android.hardware.
ונקראים לפי תת-מערכת, פוטנציאלית עם רמות שמות מקוננות. לדוגמא, חבילת ה- NFC נקראת android.hardware.nfc
וחבילת המצלמה היא android.hardware.camera
. באופן כללי, לחבילת ליבה יש את השם android.hardware.
[ name1
]. [ name2
] .... לחבילות HIDL יש גרסה בנוסף לשמם. לדוגמה, החבילה android.hardware.camera
עשויה להיות בגרסה 3.4
; זה חשוב מכיוון שגרסת החבילה משפיעה על מיקומה בעץ המקור.
כל חבילות הליבה ממוקמות תחת hardware/interfaces/
במערכת הבנייה. החבילה android.hardware.
[ name1
]. [ name2
] ... בגרסה $m.$n
נמצאת תחת hardware/interfaces/name1/name2/
… /$m.$n/
; חבילה android.hardware.camera
גרסה 3.4
נמצאת hardware/interfaces/camera/3.4/.
הספריה hardware/interfaces/camera/3.4/.
מיפוי מקודד קיים בין קידומת החבילה android.hardware.
hardware/interfaces/
הנתיב hardware/interfaces/
.
חבילות שאינן ליבות (ספקיות) הן אלה המיוצרות על ידי ספק SoC או ODM. הקידומת לחבילות שאינן ליבות היא vendor.$(VENDOR).hardware.
כאשר $(VENDOR)
מתייחס לספק SoC או OEM / ODM. זה ממפה vendor/$(VENDOR)/interfaces
הנתיבים vendor/$(VENDOR)/interfaces
העץ (מיפוי זה מקודד גם הוא קשה).
שמות מסוגים מוגדרים על ידי המשתמש המלאים
ב- HIDL, לכל UDT יש שם מוסמך לחלוטין המורכב משם UDT, שם החבילה שבו מוגדר ה- UDT וגרסת החבילה. השם המלא מלא משמש רק כאשר מוצהרים מופעים מהסוג ולא במקום בו מוגדר הסוג עצמו. לדוגמא, נניח לחבילה android.hardware.nfc,
גרסה 1.0
מגדירה מבנה בשם NfcData
. באתר ההצהרה (בין אם ב- types.hal
ובין אם במסגרת הצהרת ממשק), ההצהרה פשוט קובעת:
struct NfcData { vec<uint8_t> data; };
בעת הכרזה על מופע מסוג זה (בין אם במבנה נתונים ובין אם כפרמטר מתודה), השתמש בשם הסוג המלא:
android.hardware.nfc@1.0::NfcData
התחביר הכללי הוא PACKAGE @ VERSION :: UDT
, שם:
-
PACKAGE
היא שם מופרדת נקודה של חבילה HIDL (למשל,android.hardware.nfc
). -
VERSION
הוא הפורמט המופרד בין הנקודות העיקריות.מינור של החבילה (למשל,1.0
). -
UDT
הוא השם המופרד באמצעות נקודה של HIDL UDT. מכיוון ש- HIDL תומך ב- UDT מקונן וממשקי HIDL יכולים להכיל UDTs (סוג של הצהרה מקוננת), נקודות משמשות לגישה לשמות.
לדוגמא, אם ההצהרה המקוננת הבאה הוגדרה בקובץ הסוגים הנפוצים בחבילה android.hardware.example
גרסה 1.0
:
// types.hal package android.hardware.example@1.0; struct Foo { struct Bar { // … }; Bar cheers; };
השם המלא של Bar
הוא android.hardware.example@1.0::Foo.Bar
. אם, בנוסף להיותם בחבילה הנ"ל, ההצהרה המקוננת הייתה בממשק בשם IQuux
:
// IQuux.hal package android.hardware.example@1.0; interface IQuux { struct Foo { struct Bar { // … }; Bar cheers; }; doSomething(Foo f) generates (Foo.Bar fb); };
השם המלא של Bar
הוא android.hardware.example@1.0::IQuux.Foo.Bar
.
בשני המקרים, Bar
יכול להיות המכונה Bar
רק במסגרת ההכרזה של Foo
. ברמת החבילה או הממשק, עליכם להתייחס Bar
דרך Foo
: Foo.Bar
, כמו בהצהרת השיטה doSomething
לעיל. לחלופין, תוכל להכריז על השיטה בצורה יותר מילולית כ:
// IQuux.hal doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);
ערכי ספירה מלאים
אם UDT הוא סוג enum, אז לכל ערך מסוג enum יש שם מוסמך לחלוטין שמתחיל בשם המוסמך במלואו של סוג enum, ואחריו נקודתיים, ואז אחריו שם ערך enum. לדוגמא, נניח שחבילה android.hardware.nfc,
גרסה 1.0
מגדירה סוג enum NfcStatus
:
enum NfcStatus { STATUS_OK, STATUS_FAILED };
כאשר מתייחסים ל- STATUS_OK
, השם המוסמך הוא:
android.hardware.nfc@1.0::NfcStatus:STATUS_OK
התחביר הכללי הוא PACKAGE @ VERSION :: UDT : VALUE
, שם:
-
PACKAGE @ VERSION :: UDT
הוא אותו שם מוסמך לחלוטין עבור סוג enum. -
VALUE
הוא שם הערך.
כללי הסקה אוטומטית
אין צורך לציין שם UDT מלא. שם UDT יכול להשמיט בבטחה את הדברים הבאים:
- החבילה, למשל
@1.0::IFoo.Type
- גם חבילה וגם גרסה, למשל
IFoo.Type
HIDL מנסה להשלים את השם באמצעות כללי הפרעה אוטומטית (מספר כלל נמוך יותר פירושו עדיפות גבוהה יותר).
חוק מספר 1
אם לא מסופקים חבילה וגרסה, מנסים לחפש שם מקומי. דוגמא:
interface Nfc { typedef string NfcErrorMessage; send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m); };
NfcErrorMessage
למעלה באופן מקומי, typedef
שמעליו נמצא. NfcData
היא הרימה גם מקומית, אבל כפי שהוא אינו מוגדר באופן מקומי, שלטון 2 ו 3 משמשים. @1.0::NfcStatus
מספק גרסה, ולכן כלל 1 אינו חל.
כלל 2
אם כלל 1 נכשל ורכיב מהשם המוסמך במלואו חסר (חבילה, גרסה או חבילה וגרסה), הרכיב ממולא אוטומטית במידע מהחבילה הנוכחית. מהדר ה- HIDL מחפש בקובץ הנוכחי (ובכל הייבוא) למצוא את השם המלא במלואו. בעזרת הדוגמה לעיל, נניח שההצהרה על ExtendedNfcData
נעשתה באותה חבילה ( android.hardware.nfc
) באותה גרסה ( 1.0
) כמו NfcData
, כדלקמן:
struct ExtendedNfcData { NfcData base; // … additional members };
מהדר HIDL ממלא את שם החבילה ואת שם הגרסה מהחבילה הנוכחית כדי לייצר את שם ה- UDT המוסמך במלואו android.hardware.nfc@1.0::NfcData
. מכיוון שהשם קיים בחבילה הנוכחית (בהנחה שהיא מיובאת כהלכה), הוא משמש לצורך ההצהרה.
שם בחבילה הנוכחית מיובא רק אם אחד מהדברים הבאים נכון:
- הוא מיובא במפורש עם הצהרת
import
. - זה מוגדר ב-
types.hal
בחבילה הנוכחית
מתבצע אותו תהליך אם NfcData
הוסמך על ידי מספר הגרסה בלבד:
struct ExtendedNfcData { // autofill the current package name (android.hardware.nfc) @1.0::NfcData base; // … additional members };
כלל 3
אם כלל 2 לא מצליח לייצר התאמה (ה- UDT אינו מוגדר בחבילה הנוכחית), מהדר ה- HIDL מחפש התאמה בכל החבילות המיובאות. בעזרת הדוגמה שלעיל, נניח ש- ExtendedNfcData
מוכרז בגרסה 1.1
של חבילה android.hardware.nfc
, 1.1
מייבא 1.0
כפי שצריך (ראה הרחבות ברמת חבילה ), וההגדרה מציינת רק את שם ה- UDT:
struct ExtendedNfcData { NfcData base; // … additional members };
המהדר מחפש כל UDT בשם NfcData
ומוצא אחד כזה ב- android.hardware.nfc
בגרסה 1.0
, וכתוצאה מכך UDT מוסמך לחלוטין של android.hardware.nfc@1.0::NfcData
. אם נמצא יותר מתאמה אחת עבור UDT מוסמך חלקי, מהדר HIDL משליך.
דוגמא
באמצעות כלל 2, סוג מיובא המוגדר בחבילה הנוכחית מועדף על פני סוג מיובא מחבילה אחרת:
// hardware/interfaces/foo/1.0/types.hal package android.hardware.foo@1.0; struct S {}; // hardware/interfaces/foo/1.0/IFooCallback.hal package android.hardware.foo@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/types.hal package android.hardware.bar@1.0; typedef string S; // hardware/interfaces/bar/1.0/IFooCallback.hal package android.hardware.bar@1.0; interface IFooCallback {}; // hardware/interfaces/bar/1.0/IBar.hal package android.hardware.bar@1.0; import android.hardware.foo@1.0; interface IBar { baz1(S s); // android.hardware.bar@1.0::S baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback };
-
S
משולב כ-android.hardware.bar@1.0::S
ונמצאbar/1.0/types.hal
(מכיווןtypes.hal
מיובא אוטומטית). -
IFooCallback
כ-android.hardware.bar@1.0::IFooCallback
באמצעות כלל 2, אך לא ניתן למצוא אותו מכיווןbar/1.0/IFooCallback.hal
אינו מיובא אוטומטית (כפיtypes.hal
הוא). לפיכך, כלל 3 פותר אותו ל-android.hardware.foo@1.0::IFooCallback
במקום זאת, המיובא באמצעותimport android.hardware.foo@1.0;
).
types.hal
כל חבילת HIDL מכילה קובץ types.hal
המכיל UDT המשותף בין כל הממשקים המשתתפים בחבילה זו. סוגי HIDL הם תמיד ציבוריים; בין אם UDT מוכרזת types.hal
או בתוך הצהרת ממשק, סוגים אלה הם לנגיש מחוץ לתחום שבו הם מוגדרים. types.hal
לא נועד לתאר את ה- API הציבורי של חבילה, אלא לארח UDT שמשמש את כל הממשקים בתוך החבילה. בשל אופיו של HIDL, כל ה- UDTs הם חלק מהממשק.
types.hal
מורכב מ- UDT והצהרות import
. מכיוון ש- types.hal
זמין לכל ממשק של החבילה (זהו ייבוא משתמע), הצהרות import
אלה הן ברמת החבילה בהגדרה. UDTs ב- types.hal
עשויים לכלול גם UDTs וממשקים שיובאו כך.
לדוגמה, עבור IFoo.hal
:
package android.hardware.foo@1.0; // whole package import import android.hardware.bar@1.0; // types only import import android.hardware.baz@1.0::types; // partial imports import android.hardware.qux@1.0::IQux.Quux; // partial imports import android.hardware.quuz@1.0::Quuz;
הבאים מיובאים:
-
android.hidl.base@1.0::IBase
(במשתמע) -
android.hardware.foo@1.0::types
(מרומז) - הכל ב-
android.hardware.bar@1.0
(כולל כל הממשקיםtypes.hal
) -
types.hal
מ-android.hardware.baz@1.0::types
(ממשקים ב-android.hardware.baz@1.0
אינם מיובאים) -
IQux.hal
ו-types.hal
מ-android.hardware.qux@1.0
-
Quuz
מ-android.hardware.quuz@1.0
(בהנחהQuuz
מוגדר ב-types.hal
, כל הקובץtypes.hal
מנותח, אך סוגים אחרים מלבדQuuz
אינם מיובאים).
גרסאות ברמת ממשק
כל ממשק בתוך חבילה שוכן בקובץ משלו. החבילה אליה משתייך הממשק מוכרזת בראש הממשק באמצעות הצהרת package
. בעקבות הצהרת החבילה, ניתן לרשום יבוא ברמת ממשק אפס או יותר (חלקי או חבילה מלאה). לדוגמה:
package android.hardware.nfc@1.0;
בשנת HIDL, ממשקים יכולים לרשת מ ממשקים אחרים באמצעות extends
מילות מפתח. כדי שממשק יאריך ממשק אחר, עליו להיות בעל גישה אליו באמצעות הצהרת import
. שם הממשק המורחב (ממשק הבסיס) עוקב אחר הכללים להסמכת שם סוג שהוסברו לעיל. ממשק עשוי לרשת רק מממשק אחד; HIDL אינו תומך בירושה מרובה.
הדוגמאות של גרסאות uprev להלן משתמשות בחבילה הבאה:
// types.hal package android.hardware.example@1.0 struct Foo { struct Bar { vec<uint32_t> val; }; }; // IQuux.hal package android.hardware.example@1.0 interface IQuux { fromFooToBar(Foo f) generates (Foo.Bar b); }
חוקי Uprev
כדי להגדיר חבילה חבילה package@major.minor
, A או כל B חייבים להיות נכונים:
כלל א | "האם מדובר בגרסת מינור התחלה": אין package@major.0 כל הגרסאות המשניות הקודמות, package@major.0 , package@major.(minor-1) package@major.1 ,…, package@major.(minor-1) . |
---|
כלל ב ' | כל הדברים הבאים נכונים:
|
---|
בגלל כלל א ':
- החבילה יכולה להתחיל עם כל מספר גרסה מינורי (לדוגמה,
android.hardware.biometrics.fingerprint
מתחיל ב-@2.1
). - הדרישה "
android.hardware.foo@1.0
אינה מוגדרת" פירושהhardware/interfaces/foo/1.0
הספריהhardware/interfaces/foo/1.0
אפילו לא צריכה להתקיים.
עם זאת, כלל A אינו משפיע על חבילה בעלת שם חבילה זהה אלא על גרסה עיקרית שונה (לדוגמה, ל- android.hardware.camera.device
מוגדרים גם @1.0
וגם @3.2
; @3.2
לא צריך לקיים אינטראקציה עם @1.0
מכאן, @3.2::IExtFoo
יכול להאריך @1.0::IFoo
.
בתנאי package@major.minor::IBar
החבילה שונה, package@major.minor::IBar
עשוי להתרחב מממשק עם שם אחר (לדוגמה, android.hardware.bar@1.0::IBar
יכול להרחיב את android.hardware.baz@2.2::IBaz
). אם ממשק אינו מצהיר במפורש על סוג סופר עם מילת המפתח extend
, הוא יאריך את android.hidl.base@1.0::IBase
(למעט IBase
עצמו).
יש לעקוב אחר B.2 ו- B.3 במקביל. לדוגמא, גם אם android.hardware.foo@1.1::IFoo
מרחיב את android.hardware.foo@1.0::IFoo
כדי להעביר את כלל B.2, אם android.hardware.foo@1.1::IExtBar
מרחיב את android.hardware.foo@1.0::IBar
, זה עדיין לא uprev חוקי.
ממשקים מקדימים
כדי uprev android.hardware.example@1.0
(מוגדר לעיל) ל- @1.1
:
// types.hal package android.hardware.example@1.1; import android.hardware.example@1.0; // IQuux.hal package android.hardware.example@1.1 interface IQuux extends @1.0::IQuux { fromBarToFoo(Foo.Bar b) generates (Foo f); }
זהו import
ברמת חבילה של גרסה 1.0
של android.hardware.example
ב- types.hal
. אמנם לא מוסיפים שום UDT חדשים בגירסה 1.1
של החבילה, אך עדיין יש צורך בהפניות ל- UDT בגרסה 1.0
, ומכאן ייבוא ברמת החבילה ב- types.hal
. (ניתן היה להשיג את אותו אפקט עם ייבוא ברמת הממשק ב- IQuux.hal
.)
extends @1.0::IQuux
בהצהרה על IQuux
, ציינו את גרסת ה- IQuux
בירושה (נדרשת IQuux
משום IQuux
משמש IQuux
ממשק IQuux
מממשק). מכיוון שהצהרות הן פשוט שמות שעוברות בירושה את כל מאפייני החבילה והגרסה באתר ההצהרה, על ההבהרה להיות על שם ממשק הבסיס; יכולנו להשתמש גם ב- UDT המלא, אבל זה היה מיותר.
הממשק החדש IQuux
אינו IQuux
מחדש על שיטה מ- fromFooToBar()
שהוא יורש מ- @1.0::IQuux
; זה פשוט מפרט את השיטה החדשה שהיא מוסיפה מ- fromBarToFoo()
. ב- HIDL, לא ניתן להכריז שוב על שיטות שעוברות בתורשה בממשקי הילד, ולכן ממשק IQuux
אינו יכול להכריז במפורש על שיטת fromFooToBar()
.
מוסכמות Uprev
לפעמים שמות ממשק חייבים לשנות את שם הממשק המרחיב. אנו ממליצים כי הרחבות, תחומים ואיגודים של enum יקבלו את אותו השם כמו שהם משתרעים אלא אם כן הם שונים דיו כדי להצדיק שם חדש. דוגמאות:
// in parent hal file enum Brightness : uint32_t { NONE, WHITE }; // in child hal file extending the existing set with additional similar values enum Brightness : @1.0::Brightness { AUTOMATIC }; // extending the existing set with values that require a new, more descriptive name: enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };
אם לשיטה יכולה להיות שם סמנטי חדש (למשל fooWithLocation
) אז עדיף. אחרת, יש לקרוא לזה באופן דומה למה שהוא מרחיב. לדוגמא, השיטה foo_1_1
ב- @1.1::IFoo
עשויה להחליף את הפונקציונליות של שיטת foo
ב- @1.0::IFoo
אם אין שם חלופי טוב יותר.
גרסאות ברמת החבילה
גרסת HIDL מתרחשת ברמת החבילה; לאחר פרסום החבילה היא לא ניתנת לשינוי (לא ניתן לשנות את מערך הממשקים וה- UDT שלה). חבילות יכולות להתייחס זו לזו בכמה דרכים, שכולן ניתנות לביטוי באמצעות שילוב של ירושה ברמת הממשק ובניית UDT לפי קומפוזיציה.
עם זאת, סוג אחד של יחסים מוגדר בקפידה ויש לאכוף אותו: ירושה תואמת לאחור ברמת החבילה . בתרחיש זה, חבילת ההורה היא החבילה להיות בירושה ואת חבילת הילד היא אחד הארכת ההורה. כללי הירושה התואמים לאחור ברמת החבילה הם כדלקמן:
- כל הממשקים ברמה העליונה של חבילת האב עוברים בירושה מממשקים בחבילת הצאצא.
- ניתן להוסיף ממשקים חדשים גם את החבילה החדשה (אין הגבלות על קשרי גומלין לממשקים אחרים בחבילות אחרות).
- ניתן להוסיף גם סוגי נתונים חדשים לשימוש בשיטות חדשות של ממשקים קיימים שקדמו להם, או באמצעות ממשקים חדשים.
ניתן ליישם כללים אלה באמצעות תורשה ברמת ממשק HIDL והרכב UDT, אך דורשים ידע ברמת מטא בכדי לדעת שקשרים אלה מהווים סיומת חבילה תואמת לאחור. ידע זה מוסכם באופן הבא:
אם חבילה עומדת בדרישה זו, hidl-gen
אוכף כללי תאימות לאחור.