יצירת ממשק HAL

צריך להשתמש ב-HIDL כדי לתאר את כל דגלי ה-build שמשמשים באופן מותנה את ה-framework. דגלי build רלוונטיים חייבים להיות מקובצים ולכלול קובץ .hal יחיד. שימוש ב-HIDL לציון פריטי תצורה כוללת את היתרונות הבאים:

  • גרסאות (כדי להוסיף פריטי הגדרה חדשים, ספקים/יצרני ציוד מקורי חייבים להרחיב באופן מפורש את HAL)
  • מתועד היטב
  • בקרת גישה באמצעות SELinux
  • בדיקת רמת השפיות לפריטי תצורה באמצעות בדיקת ספק חבילה (בדיקת טווח, בדיקת תלות בין פריטים וכו')
  • ממשקי API שנוצרים באופן אוטומטי ב-C++ וב-Java

זיהוי הדגלים של build שמשמשים את ה-framework

מתחילים בזיהוי הגדרות ה-build שמשמשות להדר באופן מותנה framework, ואז נוטשים הגדרות מיושנות כדי להקטין את הקבוצה. לדוגמה, הקבוצה הבאה של דגלי build זוהתה עבור surfaceflinger:

  • TARGET_USES_HWC2
  • TARGET_BOARD_PLATFORM
  • TARGET_DISABLE_TRIPLE_BUFFERING
  • TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS
  • NUM_FRAMEBUFFER_SURFACE_BUFFERS
  • TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK
  • VSYNC_EVENT_PHASE_OFFSET_NS
  • SF_VSYNC_EVENT_PHASE_OFFSET_NS
  • PRESENT_TIME_OFFSET_FROM_VSYNC_NS
  • MAX_VIRTUAL_DISPLAY_DIMENSION

יצירת ממשק HAL

הגישה להגדרות build של מערכת משנה מתבצעת דרך ממשק HAL, הממשקים למתן ערכי תצורה מקובצים בחבילת ה-HAL android.hardware.configstore (כרגע בגרסה 1.0). לדוגמה, כדי ליצור קובץ ממשק HAL עבור surfaceflinger, hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal:

package android.hardware.configstore@1.0;

interface ISurfaceFlingerConfigs {
    // TO-BE-FILLED-BELOW
};

אחרי יצירת הקובץ .hal, מריצים את הפקודה hardware/interfaces/update-makefiles.sh כדי להוסיף את הרכיב החדש קובץ .hal אל Android.bp ו Android.mk קבצים.

הוספת פונקציות ל-build דגלים

לכל דגל build, מוסיפים פונקציה חדשה לממשק. לדוגמה, ב- hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal:

interface ISurfaceFlingerConfigs {
    disableTripleBuffering() generates(OptionalBool ret);
    forceHwcForVirtualDisplays() generates(OptionalBool ret);
    enum NumBuffers: uint8_t {
        USE_DEFAULT = 0,
        TWO = 2,
        THREE = 3,
    };
    numFramebufferSurfaceBuffers() generates(NumBuffers ret);
    runWithoutSyncFramework() generates(OptionalBool ret);
    vsyncEventPhaseOffsetNs generates (OptionalUInt64 ret);
    presentTimeOffsetFromSyncNs generates (OptionalUInt64 ret);
    maxVirtualDisplayDimension() generates(OptionalInt32 ret);
};

כשמוסיפים פונקציה:

  • שמות תמציתיים. הימנעות מהמרת משתנה makefile בשמות של פונקציות, וחשוב לזכור ש-TARGET_ הקידומות BOARD_ לא נחוצות יותר.
  • הוספת תגובות. לעזור למפתחים להבין את המטרה של config, האופן שבו הוא משנה את ההתנהגות של מסגרת, ערכים חוקיים ופרטים רלוונטיים אחרים מידע.

סוגי ההחזרה של הפונקציות יכולים להיות Optional[Bool|String|Int32|UInt32|Int64|UInt64] הסוגים מוגדרים ב-types.hal באותה ספרייה ועוטפים ערכים ראשוניים עם שדה שמציין אם הערך מצוין על ידי HAL. אם לא, ברירת המחדל נעשה שימוש בערך שלו.

struct OptionalString {
    bool specified;
    string value;
};

במקרים המתאימים, הגדירו את טיפוס הטיפוסים שמייצג בצורה הטובה ביותר את סוג ומשתמשים ב-enum הזה כסוג ההחזרה. בדוגמה שלמעלה, NumBuffers טיפוסים בני מנייה (enum) מוגדר כדי להגביל את מספר הערכים התקינים ערכים. כשמגדירים סוגי נתונים מותאמים אישית כאלה, צריך להוסיף שדה או ערך enum (ל לדוגמה, USE_DEFAULT) לציון אם הערך לא צוין או לא צוין. מאת HAL.

לא חובה שדגל אחד של build יהפוך לפונקציה אחת HIDL. בעלי מודולים יכולים במקום זאת לקבץ דגלי build בעלי קשר הדוק לתוך של מבנה יש פונקציה שמחזירה את המבנה (פעולה זו יכולה להפחית מספר הקריאות לפונקציה).

לדוגמה, אפשרות לצבירת שני דגלי build במבנה אחד באזור hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal היא:

 interface ISurfaceFlingerConfigs {
    // other functions here
    struct SyncConfigs {
        OptionalInt64 vsyncEventPhaseoffsetNs;
        OptionalInt64 presentTimeoffsetFromSyncNs;
    };
    getSyncConfigs() generates (SyncConfigs ret);
    // other functions here
};

חלופות לפונקציית HAL יחידה

כחלופה לשימוש בפונקציית HAL יחידה לכל דגלי ה-build, HAL הממשק מספק גם פונקציות פשוטות כמו getBoolean(string key) ו-getInteger(string key). בפועל key=value זוגות מאוחסנים בקבצים נפרדים ובשירות HAL שמספק ערכים על ידי קריאה/ניתוח של הקבצים האלה.

אמנם קל להגדיר את הגישה הזו, אבל היא לא כוללת את היתרונות מסופק על ידי HIDL (אכיפה של ניהול גרסאות, קלות תיעוד, בקרת גישה) ולכן היא לא מומלצת.

ממשק יחיד וממשקים מרובים

העיצוב של ממשק HAL לפריטי תצורה מציג בחירות:

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

קל יותר להשתמש בממשק אחד, אבל קשה יותר לתחזק אותו כי פריטי התצורה יתווספו לקובץ היחיד. נוסף על כך, בקרת גישה לא פרטנית, כך שתהליך שמקבלים גישה לממשק יכול לקרוא כל פריטי התצורה (לא ניתן לקבל גישה לקבוצה חלקית של פריטי תצורה ). לחלופין, אם לא ניתנה גישה, לא ניתן לקבל את פריטי ההגדרה נקראו.

עקב הבעיות האלה, מערכת Android משתמשת בממשקים מרובים עם ממשק HAL אחד של קבוצת פריטי תצורה קשורים. לדוגמה, ISurfaceflingerConfigs עבור surfaceflinger-related ו-IBluetoothConfigs להגדרות שקשורות ל-Bluetooth של הגדרות אישיות.