ב-Android 8 בוצעה ארכיטקטורה מחדש של מערכת ההפעלה Android כדי להגדיר ממשקים ברורים בין פלטפורמת Android שאינה תלויה במכשיר לבין קוד ספציפי למכשיר ולספק.
כבר מוגדרים ב-Android ממשקים רבים כאלה בצורת ממשקי HAL, שמוגדרים ככותרות C ב-hardware/libhardware
. HIDL מחליף את ממשקי ה-HAL האלה בממשקים יציבים עם גרסאות, שיכולים להיות ממשקי HIDL בצד הלקוח ובצד השרת ב-C++ (כפי שמתואר בהמשך) או ב-Java.
בדפים שבקטע הזה מתוארות הטמעות של ממשקי HIDL ב-C++, כולל פרטים על הקבצים שנוצרים באופן אוטומטי מקובצי ה-.hal
של HIDL על ידי המהדר hidl-gen
, על האופן שבו הקבצים האלה נארזים ועל האופן שבו משלבים את הקבצים האלה עם קוד ה-C++ שמשתמש בהם.
הטמעות בצד הלקוח ובצד השרת
לממשקי HIDL יש הטמעות של לקוח ושל שרת:
- לקוח של ממשק HIDL הוא הקוד שמשתמש בממשק באמצעות קריאה לשיטות שלו.
- שרת הוא הטמעה של ממשק HIDL שמקבל קריאות מלקוחות ומחזיר תוצאות (אם צריך).
במעבר מ-HAL של libhardware
ל-HAL של HIDL, הטמעת ה-HAL הופכת לשרת והתהליך שמפעיל את ה-HAL הופך ללקוח. הטמעות ברירת המחדל יכולות לשרת גם HALs של העברה וגם HALs מצורפים, והן יכולות להשתנות עם הזמן:
איור 1. התקדמות הפיתוח של ממשקי HAL מדור קודם.
יצירת לקוח HAL
מתחילים בהכללת ספריות ה-HAL בקובץ ה-makefile:
- יצרן:
LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
- Soong:
shared_libs: [ …, android.hardware.nfc@1.0 ]
בשלב הבא, צריך לכלול את קובצי הכותרות של HAL:
#include <android/hardware/nfc/1.0/IFoo.h> … // in code: sp<IFoo> client = IFoo::getService(); client->doThing();
יצירת שרת HAL
כדי ליצור את הטמעת ה-HAL, צריך את קובצי ה-.hal
שמייצגים את ה-HAL, וכבר יצרתם קובצי make ל-HAL באמצעות -Lmakefile
או -Landroidbp
ב-hidl-gen
(./hardware/interfaces/update-makefiles.sh
עושה זאת לקובצי HAL פנימיים והוא מקור טוב למידע). כשמעבירים HALs מ-libhardware
, אפשר לבצע הרבה מהעבודה הזו בקלות באמצעות c2hal.
כדי ליצור את הקבצים הנדרשים להטמעת ה-HAL:
PACKAGE=android.hardware.nfc@1.0 LOC=hardware/interfaces/nfc/1.0/default/ m -j hidl-gen hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport $PACKAGE hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport $PACKAGE
כדי שה-HAL יפעל במצב העברה, הפונקציה HIDL_FETCH_IModuleName
צריכה להיות ב-/(system|vendor|...)/lib(64)?/hw/android.hardware.package@3.0-impl(OPTIONAL_IDENTIFIER).so
, כאשר OPTIONAL_IDENTIFIER היא מחרוזת שמזהה את הטמעת העברה. הפקודות שלמעלה עומדות בדרישות של מצב העברה אוטומטית, ויוצרות גם את היעד android.hardware.nfc@1.0-impl
, אבל אפשר להשתמש בכל תוסף. לדוגמה, android.hardware.nfc@1.0-impl-foo
משתמש ב--foo
כדי להבדיל את עצמו.
אם HAL הוא גרסה משנית או תוסף של HAL אחר, צריך להשתמש ב-HAL הבסיסי כדי לתת שם לקובץ הבינארי הזה. לדוגמה, הטמעות של android.hardware.graphics.mapper@2.1
עדיין צריכות להיות בקובץ בינארי שנקרא android.hardware.graphics.mapper@2.0-impl(OPTIONAL_IDENTIFIER)
.
בדרך כלל, הערך של OPTIONAL_IDENTIFIER יכלול את גרסת ה-HAL בפועל. כך, לקוחות 2.0 יכולים לאחזר את הקובץ הבינארי ישירות, ולקוחות 2.1 יכולים לבצע שדרוג של ההטמעה.
בשלב הבא, ממלאים את ה-stubs בפונקציונליות ומגדירים דימון (daemon). קוד לדוגמה של דימון (עם תמיכה בהעברה (passthrough)):
#include <hidl/LegacySupport.h> int main(int /* argc */, char* /* argv */ []) { return defaultPassthroughServiceImplementation<INfc>("nfc"); }
defaultPassthroughServiceImplementation
קורא ל-dlopen()
עבור ספריית -impl
שסופקה ומספק אותה כשירות ב-binder. קוד דימון לדוגמה (לשירות ב-binder בלבד):
int main(int /* argc */, char* /* argv */ []) { // This function must be called before you join to ensure the proper // number of threads are created. The threadpool never exceeds // size one because of this call. ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); sp<INfc> nfc = new Nfc(); const status_t status = nfc->registerAsService(); if (status != ::android::OK) { return 1; // or handle error } // Adds this thread to the threadpool, resulting in one total // thread in the threadpool. We could also do other things, but // would have to specify 'false' to willJoin in configureRpcThreadpool. ::android::hardware::joinRpcThreadpool(); return 1; // joinRpcThreadpool should never return }
הדימון הזה נמצא בדרך כלל ב-$PACKAGE + "-service-suffix"
(לדוגמה, android.hardware.nfc@1.0-service
), אבל הוא יכול להיות בכל מקום.
sepolicy של סוג ספציפי של HAL הוא המאפיין hal_<module>
(לדוגמה, hal_nfc)
. צריך להחיל את המאפיין הזה על הדימון שמפעיל HAL מסוים (אם אותו תהליך משרת כמה HALs, אפשר להחיל עליו כמה מאפיינים).