HIDL C++

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

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

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

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

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

การเปลี่ยนจาก HAL libhardware เป็น HIDL HAL, HAL กลายเป็นเซิร์ฟเวอร์ และกระบวนการที่เข้าสู่ HAL ไคลเอ็นต์ การใช้งานเริ่มต้นสามารถแสดงได้ทั้ง Passthrough และ Binderized 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 ของคุณและได้สร้างไฟล์ไฟล์สำหรับ 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 คือสตริงที่ระบุการส่งผ่าน การใช้งานของคุณ แอตทริบิวต์ของโหมดส่งผ่าน (Pass Through) จะมีการปฏิบัติตามโดยอัตโนมัติ เหนือคำสั่งอื่นๆ ซึ่งจะสร้าง 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 (ที่รองรับ Passthrough):

#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
}

Daemon นี้มักจะอาศัยอยู่ใน $PACKAGE + "-service-suffix" (สำหรับ เช่น android.hardware.nfc@1.0-service) แต่อาจเป็นที่ใดก็ได้ sepolicy สําหรับ คลาสของ HAL คือแอตทริบิวต์ hal_<module> (เช่น hal_nfc) แอตทริบิวต์นี้ต้องนำไปใช้กับ Daemon ที่เรียกใช้ HAL ที่เฉพาะเจาะจง (หากกระบวนการเดียวกันแสดง HAL หลายรายการ จะมีแอตทริบิวต์หลายรายการ ด้วย)