HIDL מחייב שימוש בגרסאות של כל ממשק שנכתב ב-HIDL. לאחר האלמנט HAL שהממשק שלה מתפרסם, הוא הוקפא וצריך לבצע שינויים נוספים היא גרסה חדשה של הממשק. אומנם לא ניתן להשתמש בממשק נתון שפורסם שונה, ניתן להרחיב אותו בממשק אחר.
מבנה קוד HIDL
קוד HIDL מאורגן בהגדרת משתמש סוגים, ממשקים וחבילות:
- סוגים בהגדרת המשתמש (UDT). HIDL מספק גישה לסדרה של סוגי נתונים פרימיטיביים שיכולים לשמש להרכבת סוגים מורכבים יותר באמצעות מבנים, איחודים וספירות. רכיבי ה-UDT מועברים לשיטות של ממשקים, וניתן להגדיר אותם ברמת החבילה (משותף לכולם ממשקים) או באופן מקומי לממשק.
- ממשקים. כאבן בניין בסיסית של HIDL, מורכב מהצהרות UDT ו-method. ממשקים יכולים גם לקבל בירושה ממשק אחר.
- חבילות. ארגון של ממשקי HIDL ונתונים קשורים
הסוגים שבהם הן פועלות. חבילה מזוהה לפי שם וגרסה
כולל:
- קובץ בשם
types.hal
להגדרת סוג נתונים. - אפס ממשקים או יותר, כל אחד בקובץ
.hal
משלו.
- קובץ בשם
קובץ ההגדרה של סוג הנתונים types.hal
מכיל רק פונקציות UDT (הכול
רכיבי UDT ברמת החבילה נשמרים בקובץ יחיד). ייצוגים ביעד
זמינים לכל הממשקים בחבילה.
פילוסופיה של גרסאות
חבילת HIDL (כמו android.hardware.nfc
), לאחר
פורסם עבור גרסה נתונה (כמו 1.0
), לא ניתן לשינוי. זה
ולא ניתן לשנות אותו. שינויים בממשקים שבחבילה או
ששינויים ב-UDT שלו יכולים להתרחש רק בחבילה אחרת.
ב-HIDL, ניהול הגרסאות חל ברמת החבילה, לא ברמת הממשק. וכל הממשקים ורכיבי ה-UDT בחבילה משתמשים באותה גרסה. Package (חבילה) גרסאות תואמות סמנטי ניהול גרסאות ללא רמת התיקון ורכיבי המטא-נתונים של ה-build. בטווח של חבילה נתונה, שינוי בגרסה משנית מרמז על הגרסה החדשה של החבילה תואמת לאחור עם החבילה הישנה וגדולה הפניה לגרסה מרמזת על כך שהגרסה החדשה של החבילה לא תואם לאחור עם החבילה הישנה.
מבחינה רעיונית, חבילה יכולה להיות קשורה לחבילה אחרת באחת מכמה דרכים:
- בכלל לא.
- תוספים תואמים לאחור ברמת החבילה הזה
מתרחשת שינויים חדשים בגרסה המשנית (הגרסה המשופרת הבאה) של החבילה.
לחבילה החדשה יש את אותו השם והגרסה הראשית כמו של החבילה הישנה, אבל
לגרסה המשנית הגבוהה יותר. מבחינה פונקציונלית, החבילה החדשה היא קבוצת-על של
[חבילה], כלומר:
- הממשקים ברמה העליונה של חבילת ההורה נמצאים בחבילה החדשה,
למרות שבממשקים עשויים להיות שיטות חדשות, פונקציות UDT מקומיות חדשות
תוסף ברמת הממשק מתואר למטה), ורכיבי UDT חדשים ב-
types.hal
- ניתן גם להוסיף ממשקים חדשים לחבילה החדשה.
- כל סוגי הנתונים של חבילת ההורה נמצאים בחבילה החדשה וגם יכול להיות מטופל באמצעות השיטות (שייתכן שהוטמעו מחדש) מהחבילה הישנה.
- ניתן גם להוסיף סוגי נתונים חדשים לשימוש באחת מהשיטות החדשות להעלאה או בממשקים חדשים.
- הממשקים ברמה העליונה של חבילת ההורה נמצאים בחבילה החדשה,
למרות שבממשקים עשויים להיות שיטות חדשות, פונקציות UDT מקומיות חדשות
תוסף ברמת הממשק מתואר למטה), ורכיבי UDT חדשים ב-
- תוספים תואמים לאחור ברמת הממשק. הגרסה החדשה
החבילה יכולה גם להרחיב את החבילה המקורית באמצעות רכיבים לוגיים נפרדים
ממשקים שמספקים פונקציונליות נוספת, ולא את הליבה.
למטרה הזו, רצוי:
- הממשקים בחבילה החדשה צריכים להפנות לסוגי הנתונים של החבילה הישנה חבילה.
- ממשקים בחבילה חדשה יכולים להרחיב ממשקים של גרסה ישנה אחת או יותר חבילות.
- להרחיב את חוסר התאימות המקורי לאחור. זהו עלייה לעומת הגרסה הראשית של החבילה ואין צורך בהתאמה בין בין שני המושגים. במידה שיש כזו, אפשר לבטא זאת באמצעות שילוב של מגרסה ישנה יותר של החבילה, וירושה של קבוצת משנה של וממשקים ישנים של חבילות.
מבנה הממשק
כדי ליצור ממשק בנוי היטב, הוספנו סוגים חדשים של פונקציונליות הן לא חלק מהעיצוב המקורי. צריך לשנות אותן ב-HIDL גרפי. לעומת זאת, אם אתם יכולים או מצפים לבצע שינוי בשני הצדדים הממשק שמציג פונקציונליות חדשה מבלי לשנות את הממשק אז הממשק לא מובנה.
טרבל תומך ברכיבי מערכת וספק שעברו הידור בנפרד, שבהם
vendor.img
במכשיר, וה-system.img
יכול להיות
עוברים הידור בנפרד. כל האינטראקציות בין vendor.img
לבין
צריך להגדיר את system.img
באופן מפורש וביסודיות כדי שניתן יהיה
ימשיכו לפעול במשך שנים רבות. זה כולל פלטפורמות רבות של API, אבל
הוא מנגנון ה-IPC שבו משתמש HIDL לתקשורת בין תהליכים
גבול system.img
/vendor.img
.
הדרישות
צריך להגדיר באופן מפורש את כל הנתונים שמועברים דרך HIDL. כדי להבטיח והלקוח יכולים להמשיך לעבוד יחד גם אחרי שהם הנתונים פותחו בנפרד או פועלים בהתאם להנחיות הבאות: דרישות:
- אפשר לתאר אותו ישירות ב-HIDL (באמצעות Builds enums וכו') עם שמות ומשמעות סמנטיים.
- אפשר לתאר אותו באמצעות תקן ציבורי כמו ISO/IEC 7816.
- אפשר לתאר זאת לפי תקן חומרה או פריסה פיזית של החומרה.
- הוא יכול להכיל נתונים אטומים (כמו מפתחות ציבוריים, מזהים וכו') במקרה הצורך.
אם נעשה שימוש בנתונים אטומים, יש לקרוא אותם רק בצד אחד של ה-HIDL
גרפי. לדוגמה, אם הקוד vendor.img
מספק רכיב
system.img
הודעת מחרוזת או vec<uint8_t>
נתונים, שאי אפשר לנתח את הנתונים האלה באמצעות system.img
עצמו, יכול
מועבר בחזרה אל vendor.img
כדי לפרש. מתי
העברת ערך מ-vendor.img
לקוד ספק
system.img
או למכשיר אחר, פורמט הנתונים והאופן שבו הם
חייב לקבל תיאור מדויק, והוא עדיין חלק
.
הנחיות
צריכה להיות לכם אפשרות לכתוב הטמעה או לקוח של HAL באמצעות קובצי ה- .hal (כלומר, אין צורך לחפש את המקור של Android או את הסטטוס הציבורי ). מומלץ לציין את ההתנהגות המדויקת הנדרשת. הצהרות כאלו כי "הטמעה יכולה לפעול עם מודל א' או ב'" לעודד הטמעות וישולבו עם הלקוחות שאיתם הם מפתחים.
פריסת קוד HIDL
HIDL כולל חבילות ליבה וחבילות של ספקים.
ממשקי הליבה של HIDL הם אלה שצוינו על ידי Google. החבילות שאליהן הם שייכים
שמתחילים ב-android.hardware.
והם מקבלים שמות על ידי מערכת משנה,
אולי עם רמות מקוננות של שמות. לדוגמה, השם של חבילת ה-NFC הוא
android.hardware.nfc
וחבילת המצלמה היא
android.hardware.camera
. באופן כללי, יש את השם של חבילת ליבה
android.hardware.
[name1
].[name2
]....
לחבילות HIDL יש גרסה בנוסף לשם שלהן. לדוגמה, החבילה
ייתכן ש-android.hardware.camera
הוא בגרסה 3.4
; זה
כי גרסת החבילה משפיעה על המיקום שלה בעץ המקור.
כל חבילות הליבה ממוקמות תחת hardware/interfaces/
בשדה
של מערכת ה-build. החבילה
android.hardware.
[name1
].[name2
]...
בגרסה $m.$n
זה פחות מ-
hardware/interfaces/name1/name2/
.../$m.$n/
; חבילה
גרסה 3.4
של android.hardware.camera
נמצאת בספרייה
hardware/interfaces/camera/3.4/.
קיים מיפוי בתוך הקוד
בין קידומת החבילה android.hardware.
לנתיב
hardware/interfaces/
.
חבילות שהן לא ליבה (ספק) הן חבילות שמופקות על ידי ספק ה-SoC או ODM.
התחילית לחבילות שאינן חבילות ליבה היא vendor.$(VENDOR).hardware.
, כאשר
$(VENDOR)
מתייחס לספק SoC או ל-OEM/ODM. פעולה זו ממופה לנתיב
vendor/$(VENDOR)/interfaces
בעץ (המיפוי הזה גם
כתובים בתוך הקוד).
שמות מסוג 'בהגדרת המשתמש' שעומדים בדרישות
ב-HIDL, לכל UDT יש שם מוגדר במלואו שמכיל את השם של ה-UDT,
שם החבילה שבו מוגדר ה-UDT, וגרסת החבילה.
נעשה שימוש בשם המוגדר במלואו רק כאשר מוצהר על מופעים מהסוג הזה
לא כשהסוג עצמו מוגדר. לדוגמה, נניח שהחבילה
android.hardware.nfc,
גרסה 1.0
מגדירה מבנה
בשם NfcData
. באתר ההצהרה (בין אם
types.hal
או בהצהרה של הממשק), ההצהרה
בפשטות:
struct NfcData { vec<uint8_t> data; };
בהצהרה על מופע מהסוג הזה (בין אם בתוך מבנה נתונים או כפרמטר method), יש להשתמש בשם הסוג המוגדר במלואו:
android.hardware.nfc@1.0::NfcData
התחביר הכללי הוא
PACKAGE@VERSION::UDT
, כאשר:
PACKAGE
הוא השם של חבילת HIDL, מופרדת באמצעות נקודות (למשלandroid.hardware.nfc
).VERSION
היא גרסת ה-Major.minor-version שמופרדת באמצעות נקודות פורמט החבילה (למשל,1.0
).UDT
הוא השם של HIDL UDT, שמופרד באמצעות נקודות. מכיוון ש-HIDL תומך ברכיבי UDT מקוננים ובממשקי HIDL יכולים להכיל רכיבי UDT (סוג הצהרה בתוך הצהרה), נקודות משמשות לגישה לשמות.
לדוגמה, אם ההצהרה הפנימית הבאה הוגדרה
קובץ סוגים בחבילה 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 לא מוגדר
), המהדר (compiler) 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;
).
segments.hal
כל חבילה של HIDL מכילה קובץ types.hal
שמכיל UDTs
שמשותפים בין כל הממשקים שמשתתפים בחבילה הזו. סוגי HIDL
הם תמיד ציבוריים. בין אם הוצהר על UDT
types.hal
או בתוך הצהרה בממשק, הסוגים האלה
נגישים מחוץ להיקף שבו הם מוגדרים. types.hal
לא מיועד לתאר את ה-API הציבורי של חבילה, אלא לארח רכיבי UDT
משמש את כל הממשקים בתוך החבילה. בשל האופי של HIDL, כל רכיבי ה-UDT
הן חלק מהממשק.
types.hal
מורכב מפונקציות UDT ו-import
הצהרות.
מכיוון ש-types.hal
זמין לכל הממשק של
חבילה (זהו ייבוא מרומז), הצהרות import
האלה
ברמת החבילה מעצם הגדרתן. גם רכיבי UDT ב-types.hal
יכולים לשלב
וממשקי ה-UDT והממשקים שיובאו.
לדוגמה, עבור 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 לא תומך במספר ירושה.
הדוגמאות הבאות לניהול גרסאות משתמשות בחבילה הבאה:
// 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
, א' או את כל B
חייב להיות True:
כלל א' | "זו גרסת התחלה משנית": כל הגרסאות המשניות הקודמות,
package@major.0 , package@major.1 , ...,
אין להגדיר package@major.(minor-1) .
|
---|
כלל ב' | כל התנאים הבאים נכונים:
|
---|
בגלל כלל א':
- החבילה יכולה להתחיל בכל מספר גרסה משני (לדוגמה,
android.hardware.biometrics.fingerprint
מתחיל ב-@2.1
). - הדרישה "
android.hardware.foo@1.0
לא מוגדרת" זה הספרייהhardware/interfaces/foo/1.0
לא אמורה להתקיים אפילו.
עם זאת, כלל א' לא משפיע על חבילה עם שם חבילה זהה, אבל
גרסה ראשית שונה (לדוגמה,
ב-android.hardware.camera.device
יש גם @1.0
וגם
הוגדר @3.2
; @3.2
לא צריך אינטראקציה עם
@1.0
.) לכן, @3.2::IExtFoo
יכול להאריך
@1.0::IFoo
.
אם שם החבילה שונה,
package@major.minor::IBar
יכול להרחיב מממשק עם
שם אחר (לדוגמה, android.hardware.bar@1.0::IBar
יכול
הרחבה של android.hardware.baz@2.2::IBaz
). אם הממשק לא מאפשר
להצהיר במפורש על סוג-על באמצעות מילת המפתח extend
, היא
נמשך לאורך android.hidl.base@1.0::IBase
(למעט IBase
עצמו).
ב.2 וגם ב.3 חייבים לפעול בו-זמנית. לדוגמה, גם אם
android.hardware.foo@1.1::IFoo
הרחבה
android.hardware.foo@1.0::IFoo
כדי להעביר את כלל ב'.2, אם
android.hardware.foo@1.1::IExtBar
הרחבה
android.hardware.foo@1.0::IBar
, זה עדיין לא סכום תקין.
ממשקי 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
של החבילה, הפניות ל-UDTs
יש עדיין צורך בגרסה 1.0
, ולכן הייבוא ברמת החבילה
ב-types.hal
. (ניתן היה לקבל את אותו אפקט באמצעות
ייבוא ברמת הממשק ב-IQuux.hal
).
ב-extends @1.0::IQuux
בהצהרה של
IQuux
, ציינת את הגרסה של IQuux
עברה בירושה (נדרשת הבחנה כי IQuux
משמש
להצהיר על ממשק ולקבל בירושה מממשק). מאחר שההצהרות
שמות שיורשים את כל מאפייני החבילות והגרסה באתר
אחרת, ההבחנה חייבת להיות בשם של ממשק הבסיס. אנחנו
היה צריך להשתמש גם ב-UDT מלא, אבל זה היה
מיותרת.
הממשק החדש IQuux
לא מצהיר מחדש על השיטה
fromFooToBar()
שהיא מקבלת בירושה מ@1.0::IQuux
; פשוט
מציין את השיטה החדשה ומוסיף אותה fromBarToFoo()
. ב-HIDL, מתבצעת בירושה
אי אפשר להצהיר שוב על methods בממשקי הצאצא, לכן
הממשק IQuux
לא יכול להצהיר על fromFooToBar()
במפורש.
מוסכמות בעלייה
לפעמים שמות ממשקים צריכים לשנות את השם של הממשק המורחב. ההמלצות שלנו שתוספים, מבני טיפוס ואיחודים של 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
אוכפת
כללי תאימות לאחור.