ממשקים & חבילות

HIDL בנוי סביב ממשקים, סוג מופשט המשמש בשפות מונחה עצמים להגדרת התנהגויות. כל ממשק הוא חלק מחבילה.

חבילות

שמות חבילות יכולים לכלול רמות משנה כגון package.subpackage . ספריית השורש של חבילות HIDL שפורסמו היא hardware/interfaces או vendor/vendorName (למשל vendor/google עבור מכשירי Pixel). שם החבילה יוצר ספריית משנה אחת או יותר תחת ספריית הבסיס; כל הקבצים המגדירים חבילה נמצאים באותה ספרייה. לדוגמה, ניתן למצוא package android.hardware.example.extension.light@2.0 תחת hardware/interfaces/example/extension/light/2.0 .

הטבלה הבאה מפרטת קידומות ומיקומים של חבילות:

קידומת חבילה מקום סוגי ממשקים
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* מסגרות/ קשורות
android.system.* system/hardware/interfaces/* מערכת/ קשור
android.hidl.* system/libhidl/transport/* הליבה

ספריית החבילה מכילה קבצים עם סיומת .hal . כל קובץ חייב להכיל הצהרת package עם שם החבילה והגרסה שהקובץ הוא חלק ממנה. הקובץ types.hal , אם קיים, אינו מגדיר ממשק אלא מגדיר סוגי נתונים הנגישים לכל ממשק בחבילה.

הגדרת ממשק

מלבד types.hal , כל קובץ .hal אחר מגדיר ממשק. ממשק מוגדר בדרך כלל באופן הבא:

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

ממשק ללא extends מפורשת משתרע באופן מרומז מ- android.hidl.base@1.0::IBase (בדומה ל- java.lang.Object ב-Java.) ממשק IBase, מיובא באופן מרומז, מצהיר על מספר שיטות שמורות שאסור ולא ניתן להצהרה מחדש בממשקים מוגדרי משתמש או בשימוש אחר. שיטות אלו כוללות:

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

מייבא

הצהרת import ​​היא מנגנון HIDL לגישה לממשקי חבילה וסוגים בחבילה אחרת. הצהרת import ​​מתייחסת לשתי ישויות:

  • ישות הייבוא , שיכולה להיות חבילה או ממשק; ו
  • ישות היבוא , שגם היא יכולה להיות חבילה או ממשק.

הישות המייבאת נקבעת לפי המיקום של הצהרת import . כאשר ההצהרה נמצאת בתוך types.hal של חבילה, מה שמיובא גלוי לכל החבילה; זהו ייבוא ​​ברמת החבילה . כאשר ההצהרה נמצאת בתוך קובץ ממשק, הישות המיובאת היא הממשק עצמו; זהו ייבוא ​​ברמת הממשק .

הישות המיובאת נקבעת לפי הערך שאחרי מילת המפתח import . הערך אינו חייב להיות שם מלא; אם רכיב מושמט, הוא מתמלא אוטומטית במידע מהחבילה הנוכחית. עבור ערכים מתאימים לחלוטין, מקרי הייבוא ​​הבאים נתמכים:

  • יבוא חבילה שלמה . אם הערך הוא שם חבילה וגרסה (תחביר המתואר להלן), אז החבילה כולה מיובאת לישות המייבאת.
  • יבוא חלקי . אם הערך הוא:
    • ממשק, ה- types.hal של החבילה והממשק הזה מיובאים לישות המייבאת.
    • UDT מוגדר ב- types.hal , אז רק אותו UDT מיובא לישות המייבאת (סוגים אחרים ב- types.hal אינם מיובאים).
  • יבוא מסוגים בלבד . אם הערך משתמש בתחביר של ייבוא ​​חלקי שתואר לעיל, אך עם types מילות המפתח במקום שם ממשק, רק ה-UDTs ב- types.hal של החבילה המיועדת מיובאים.

הישות המייבאת מקבלת גישה לשילוב של:

  • UDTs הנפוצים של החבילה המיובאת המוגדרים ב- types.hal ;
  • ממשקי החבילה המיובאת (ליבוא חבילה שלמה) או ממשק מוגדר (לייבוא ​​חלקי) לצורך הפקתם, העברת נקודות עזר אליהם ו/או ירושה מהם.

הצהרת הייבוא ​​משתמשת בתחביר-שם-סוג מלא כדי לספק את השם והגרסה של החבילה או הממשק המיובאים:

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

תורשת ממשק

ממשק יכול להיות הרחבה של ממשק שהוגדר קודם לכן. הרחבות יכולות להיות אחד משלושת הסוגים הבאים:

  • ממשק יכול להוסיף פונקציונליות לממשק אחר, תוך שילוב ה-API שלו ללא שינוי.
  • החבילה יכולה להוסיף פונקציונליות לאחת אחרת, לשלב את ה-API שלה ללא שינוי.
  • ממשק יכול לייבא סוגים מחבילה או מממשק ספציפי.

ממשק יכול להרחיב רק ממשק אחד אחר (ללא ירושה מרובה). כל ממשק בחבילה עם מספר גרסה מינור שאינו אפס חייב להרחיב ממשק בגרסה הקודמת של החבילה. לדוגמה, אם ממשק IBar בגרסה 4.0 של derivative החבילה מבוסס על (מרחיב) ממשק IFoo בגרסה 1.2 של החבילה original , ונוצרת גרסה 1.3 של החבילה original , גרסה 4.1 של IBar לא יכולה להרחיב את גרסה 1.3 של IFoo . במקום זאת, גרסה 4.1 IBar חייבת להרחיב את גרסה 4.0 IBar , הקשורה לגרסה 1.2 של IFoo . IBar גרסה 5.0 יכולה להרחיב את IFoo גרסה 1.3, אם תרצה בכך.

הרחבות ממשק אינן מרמזות על תלות בספרייה או הכללת HAL צולבת בקוד שנוצר - הן פשוט מייבאות את מבנה הנתונים והגדרות השיטה ברמת HIDL. כל שיטה ב-HAL חייבת להיות מיושמת באותו HAL.

הרחבות ספקים

במקרים מסוימים, הרחבות ספקים יוטמעו כתת-מחלקה של אובייקט הבסיס המייצג את ממשק הליבה שהם מרחיבים. אותו אובייקט יירשם תחת השם והגרסה הבסיסית HAL, ותחת השם והגרסת HAL (הספק) של התוסף.

גירסאות

לחבילות יש גרסאות, ולממשקים יש את הגרסה של החבילה שלהם. גרסאות מבוטאות בשני מספרים שלמים, עיקרי . קטין .

  • הגרסאות העיקריות אינן תואמות לאחור. הגדלת מספר הגרסה הראשית מאפסת את מספר הגרסה המשנית ל-0.
  • גרסאות מינוריות תואמות לאחור. הגדלת המספר הקטן מציינת שהגרסה החדשה יותר תואמת לחלוטין לאחור לגרסה הקודמת. ניתן להוסיף מבני נתונים ושיטות חדשות, אך לא ניתן לשנות מבני נתונים קיימים או חתימות שיטה.

מספר גרסאות עיקריות או משניות של HAL יכולות להיות נוכחות במכשיר בו-זמנית. עם זאת, יש להעדיף גרסה מינורית על פני גרסה עיקרית מכיוון שקוד לקוח שעובד עם ממשק גרסה מינורית קודמת יעבוד גם עם גרסאות מינוריות מאוחרות יותר של אותו ממשק. לפרטים נוספים על ניהול גרסאות והרחבות של ספקים, ראה גירסאות HIDL .

סיכום פריסת הממשק

סעיף זה מסכם כיצד לנהל חבילת ממשק HIDL (כגון hardware/interfaces ) ומאחד מידע המוצג לאורך סעיף HIDL. לפני הקריאה, ודא שאתה מכיר את גירסת HIDL , את מושגי הגיבוב ב-Hidl-gen , את פרטי העבודה עם HIDL באופן כללי ואת ההגדרות הבאות:

טווח הַגדָרָה
ממשק יישומים בינארי (ABI) ממשק תכנות יישומים + כל קישורים בינאריים הנדרשים.
שם מלא (fqName) שם כדי להבחין בין סוג hidl. דוגמה: android.hardware.foo@1.0::IFoo .
חֲבִילָה חבילה המכילה ממשק HIDL וסוגים. דוגמה: android.hardware.foo@1.0 .
שורש החבילה חבילת שורש המכילה את ממשקי HIDL. דוגמה: ממשק HIDL android.hardware נמצא בשורש החבילה android.hardware.foo@1.0 .
נתיב שורש החבילה מיקום בעץ המקור של אנדרואיד שאליו ממופה שורש חבילה.

להגדרות נוספות, ראה טרמינולוגיה של HIDL.

ניתן למצוא כל קובץ ממיפוי שורש החבילה והשם המלא שלו

שורשי החבילה מצוינים ל- hidl-gen בתור הארגומנט -r android.hardware:hardware/interfaces . לדוגמה, אם החבילה היא vendor.awesome.foo@1.0::IFoo וה- hidl-gen נשלח -r vendor.awesome:some/device/independent/path/interfaces , אז קובץ הממשק צריך להיות ממוקם ב- $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal .

בפועל, מומלץ לספק או OEM בשם awesome לשים את הממשקים הסטנדרטיים שלהם ב- vendor.awesome . לאחר בחירת נתיב חבילה, אסור לשנות אותו מכיוון שהוא אפוי ב-ABI של הממשק.

מיפוי נתיב חבילה צריך להיות ייחודי

לדוגמה, אם יש לך -rsome.package:$PATH_A ו- -rsome.package:$PATH_B , $PATH_A חייב להיות שווה ל- $PATH_B עבור ספריית ממשק עקבית (זה גם מקל בהרבה על ממשקי גרסאות ).

לשורש החבילה חייב להיות קובץ ניהול גרסאות

אם אתה יוצר נתיב חבילה כגון -r vendor.awesome:vendor/awesome/interfaces , עליך ליצור גם את הקובץ $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt , שאמור להכיל גיבוב של ממשקים שנעשו באמצעות -Lhash אפשרות ב- hidl-gen (על זה נדון בהרחבה ב- Hashing עם hidl-gen ).

ממשקים נכנסים למיקומים בלתי תלויים במכשיר

בפועל, מומלץ לשתף ממשקים בין סניפים. זה מאפשר שימוש מרבי בקוד ובדיקה מקסימלית של קוד במכשירים ובמקרי שימוש שונים.