Android O สร้างสถาปัตยกรรมใหม่ให้กับระบบปฏิบัติการ Android เพื่อกำหนดอินเทอร์เฟซที่ชัดเจนระหว่างแพลตฟอร์ม Android ที่ไม่ขึ้นกับอุปกรณ์และรหัสเฉพาะของอุปกรณ์และผู้ขาย Android ได้กำหนดอินเทอร์เฟซดังกล่าวไว้มากมายในรูปแบบของอินเทอร์เฟซ HAL ซึ่งกำหนดเป็นส่วนหัว C ใน hardware/libhardware
HIDL แทนที่อินเทอร์เฟซ HAL เหล่านี้ด้วยอินเทอร์เฟซเวอร์ชันเสถียร ซึ่งสามารถเป็นอินเทอร์เฟซ HIDL ฝั่งไคลเอ็นต์และเซิร์ฟเวอร์ใน C++ (อธิบายด้านล่าง) หรือ Java
หน้าในส่วนนี้จะอธิบายการใช้งาน C++ ของอินเทอร์เฟซ HIDL รวมถึงรายละเอียดเกี่ยวกับไฟล์ที่สร้างโดยอัตโนมัติจากไฟล์ .hal
โดยคอมไพเลอร์ hidl-gen
วิธีจัดแพ็คเกจไฟล์เหล่านี้ และวิธีรวมไฟล์เหล่านี้กับโค้ด C++ ที่ ใช้พวกเขา
การใช้งานไคลเอนต์และเซิร์ฟเวอร์
อินเทอร์เฟซ HIDL มีการใช้งานไคลเอนต์และเซิร์ฟเวอร์:
- ไคลเอ็นต์ ของอินเทอร์เฟซ HIDL คือโค้ดที่ใช้อินเทอร์เฟซโดยเรียกใช้เมธอด
- เซิร์ฟเวอร์ คือการใช้งานอินเทอร์เฟซ HIDL ที่รับสายจากลูกค้าและส่งคืนผลลัพธ์ (หากจำเป็น)
ในการเปลี่ยนจาก libhardware
HAL เป็น HIDL HAL การใช้งาน HAL จะกลายเป็นเซิร์ฟเวอร์ และกระบวนการที่เรียกเข้าสู่ HAL จะกลายเป็นไคลเอ็นต์ การใช้งานเริ่มต้นสามารถให้บริการทั้ง HAL ที่ส่งผ่านและผูกมัด และสามารถเปลี่ยนแปลงได้ตลอดเวลา:
รูปที่ 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 ของคุณ และสร้าง makefiles สำหรับ 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 เป็นสตริงที่ระบุการใช้งาน passthrough คำสั่งด้านบนเป็นไปตามข้อกำหนดของโหมดส่งผ่านโดยอัตโนมัติ ซึ่งจะสร้างเป้าหมาย 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 (รองรับ 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 will never exceed // 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 หลายรายการ สามารถใช้แอ็ตทริบิวต์ได้หลายรายการ)