HIDL C++

Android 8 ปรับโครงสร้างระบบปฏิบัติการ Android ใหม่เพื่อกำหนดอินเทอร์เฟซที่ชัดเจนระหว่างแพลตฟอร์ม Android ที่ไม่ขึ้นอยู่กับอุปกรณ์กับโค้ดเฉพาะอุปกรณ์และผู้ให้บริการ Android ได้กำหนดอินเทอร์เฟซจำนวนมากในรูปแบบอินเทอร์เฟซ HAL แล้ว ซึ่งกำหนดเป็นส่วนหัว C ใน hardware/libhardware HIDL จะแทนที่อินเทอร์เฟซ HAL เหล่านี้ด้วยอินเทอร์เฟซเวอร์ชันที่เสถียร ซึ่งอาจเป็นอินเทอร์เฟซ HIDL ฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์ใน C++ (อธิบายไว้ด้านล่าง) หรือ Java

หน้าต่างๆ ในส่วนนี้จะอธิบายการใช้งาน C++ ของอินเทอร์เฟซ HIDL ซึ่งรวมถึงรายละเอียดเกี่ยวกับไฟล์ที่คอมไพเลอร์ hidl-gen สร้างขึ้นโดยอัตโนมัติจากไฟล์ .hal ของ HIDL, วิธีการแพ็กเกจไฟล์เหล่านี้ และวิธีผสานรวมไฟล์เหล่านี้กับโค้ด C++ ที่ใช้

การติดตั้งใช้งานไคลเอ็นต์และเซิร์ฟเวอร์

อินเทอร์เฟซ HIDL มีการใช้งานฝั่งไคลเอ็นต์และเซิร์ฟเวอร์ดังนี้

  • ไคลเอ็นต์ของอินเทอร์เฟซ HIDL คือโค้ดที่ใช้อินเทอร์เฟซโดยการเรียกใช้เมธอดในอินเทอร์เฟซ
  • เซิร์ฟเวอร์คือการใช้งานอินเทอร์เฟซ HIDL ที่ได้รับคําเรียกจากไคลเอ็นต์และแสดงผลลัพธ์ (หากจําเป็น)

ในการเปลี่ยนจาก libhardware HAL เป็น HIDL HAL การใช้งาน HAL จะกลายเป็นเซิร์ฟเวอร์ และกระบวนการเรียก HAL จะกลายเป็นไคลเอ็นต์ การใช้งานเริ่มต้นสามารถแสดงทั้ง HAL แบบส่งผ่านและแบบ Binderized และอาจเปลี่ยนแปลงได้เมื่อเวลาผ่านไป

รูปที่ 1 ความคืบหน้าในการพัฒนา HAL รุ่นเดิม

สร้างไคลเอ็นต์ HAL

เริ่มต้นด้วยการเพิ่มไลบรารี HAL ในไฟล์ make โดยทำดังนี้

  • ผู้ผลิต: 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 ภายในและเป็นข้อมูลอ้างอิงที่ดี) เมื่อโอน HAL จาก 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 จะอัปเกรดการใช้งานได้

ถัดไป ให้กรอกข้อมูลลงในสตั๊บด้วยฟังก์ชันการทำงานและตั้งค่าเดรัม ตัวอย่าง โค้ด daemon (รองรับการส่งผ่าน):

#include <hidl/LegacySupport.h>

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

defaultPassthroughServiceImplementation จะเรียกใช้dlopen()สำหรับไลบรารี -impl ที่ระบุและให้บริการเป็นบริการแบบ Binderized ตัวอย่างโค้ดเดรัม (สําหรับบริการแบบ 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 บางรายการ (หากกระบวนการเดียวกันแสดง HAL หลายรายการ ก็สามารถใช้แอตทริบิวต์หลายรายการกับกระบวนการนั้นได้)