HIDL C++

Android 8 יוצרת מחדש את הארכיטקטורה של Android OS כדי להגדיר ממשקים ברורים בין פלטפורמת Android שלא תלויה במכשיר וקוד ספציפי למכשיר ולספק. מערכת Android כבר מגדירה הרבה ממשקים כאלה בצורה של ממשקי HAL, מוגדרות ככותרות C ב-hardware/libhardware. HIDL מחליף את ממשקי HAL עם ממשקים יציבים בעלי גרסאות, שיכולים להיות מבוססי לקוח ממשקי HIDL בצד השרת ב-C++ (כמתואר בהמשך) או Java.

הדפים בקטע הזה מתארים הטמעות C++ של ממשקי HIDL, כולל פרטים על הקבצים שנוצרו באופן אוטומטי מה-HIDL .hal על ידי המהדר (compiler) hidl-gen, אופן האריזה של הקבצים האלה איך לשלב את הקבצים האלה עם קוד C++ שמשתמש בהם.

הטמעות של לקוחות ושרתים

לממשקי HIDL יש הטמעות לקוח ושרת:

  • לקוח של ממשק HIDL הוא הקוד שמשתמש באמצעות קריאה ל-methods.
  • שרת הוא הטמעה של ממשק HIDL מקבל שיחות מלקוחות ומחזיר תוצאות (במקרה הצורך).

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

איור 1. התקדמות הפיתוח של יישומי HAL מדור קודם.

יצירת לקוח HAL

בתור התחלה, צריך לכלול את ספריות ה-HAL בקובץ ה-makefile:

  • יצרן: LOCAL_SHARED_LIBRARIES += android.hardware.nfc@1.0
  • סונג: 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, וכבר יצרו קובצי makefile ל-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 תפעל במצב Passthrough, צריך הפונקציה 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 יכולים לשדרג את ההטמעה.

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

#include <hidl/LegacySupport.h>

int main(int /* argc */, char* /* argv */ []) {
    return defaultPassthroughServiceImplementation<INfc>("nfc");
}

defaultPassthroughServiceImplementation שיחות dlopen() עבור ספריית -impl שסופקה ומשמשת בתור שירות מקושר. דוגמה לקוד daemon (לשירות מקושר בלבד):

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), אבל הוא יכול להיות בכל מקום. המדיניות של מחלקה של HAL היא המאפיין hal_<module> (למשל, hal_nfc) צריך להחיל את המאפיין הזה על הדימון שמריץ HAL מסוים (אם אותו תהליך מטפל במספר תכונות HAL, יש כמה מאפיינים ניתן להחיל עליו).