צריך להשתמש ב-HIDL כדי לתאר את כל דגלי ה-build שמשמשים להדרה מותנית של המסגרת. צריך לקבץ את דגלים הרלוונטיים ל-build ולכלול אותם בקובץ .hal
אחד. השימוש ב-HIDL לציון פריטי תצורה כולל את היתרונות הבאים:
- עם גרסאות (כדי להוסיף פריטים חדשים להגדרה, ספקים או יצרני ציוד מקורי צריכים להרחיב את ה-HAL באופן מפורש)
- מתועדים היטב
- בקרת גישה באמצעות SELinux
- בדיקת תקינות של פריטי ההגדרה באמצעות Vendor Test Suite (בדיקת טווח, בדיקת יחסי תלות בין פריטים וכו')
- ממשקי 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_
כבר לא נחוצות. - הוספת תגובות עוזרים למפתחים להבין את המטרה של פריט התצורה, איך הוא משנה את התנהגות המסגרת, ערכים חוקיים ומידע רלוונטי אחר.
סוגי ההחזרות של פונקציות יכולים להיות Optional[Bool|String|Int32|UInt32|Int64|UInt64]
. הסוגים מוגדרים ב-types.hal
באותה ספרייה, והערכים הפרימיטיביים עטופים בשדה שמציין אם הערך צוין על ידי ה-HAL. אם לא, המערכת משתמשת בערך ברירת המחדל.
struct OptionalString { bool specified; string value; };
במקרים הרלוונטיים, מגדירים את המאפיין enum שמייצג בצורה הטובה ביותר את סוג פריט התצורה, ומשתמשים במאפיין enum הזה כסוג ההחזרה. בדוגמה שלמעלה, המאפיין NumBuffers
מוגדר כדי להגביל את מספר הערכים התקפים. כשמגדירים סוגי נתונים מותאמים אישית כאלה, מוסיפים שדה או ערך enum (למשל, USE_DEFAULT
) כדי לציין אם הערך צוין על ידי ה-HAL או לא.
לא חובה שדגל build יחיד יהפוך לפונקציה יחידה ב-HIDL. לחלופין, בעלי המודולים יכולים לצבור דגלים קשורים של build לתוך struct, וליצור פונקציה שמחזירה את ה-struct הזה (כך אפשר לצמצם את מספר הקריאות לפונקציות).
לדוגמה, אפשרות לאסוף שני דגלים של build ל-struct יחיד ב-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
ו-IBluetoothConfigs
לפריטי תצורה שקשורים ל-Bluetooth.