อินเทอร์เฟซและแพ็กเกจ

HIDL สร้างขึ้นจากอินเทอร์เฟซ ซึ่งเป็นประเภทนามธรรมที่ใช้ในภาษาเชิงออบเจ็กต์เพื่อกำหนดลักษณะการทำงาน อินเทอร์เฟซแต่ละรายการเป็นส่วนหนึ่งของแพ็กเกจ

แพ็กเกจ

ชื่อแพ็กเกจอาจมีระดับย่อย เช่น package.subpackage ไดเรกทอรีรูทสำหรับแพ็กเกจ HIDL ที่เผยแพร่คือ hardware/interfaces หรือ vendor/vendorName (เช่น vendor/google สำหรับอุปกรณ์ Pixel) ชื่อแพ็กเกจจะสร้างไดเรกทอรีย่อยอย่างน้อย 1 ไดเรกทอรีในไดเรกทอรีรูท โดยไฟล์ทั้งหมดที่กําหนดแพ็กเกจจะอยู่ในไดเรกทอรีเดียวกัน เช่น package android.hardware.example.extension.light@2.0 จะอยู่ในhardware/interfaces/example/extension/light/2.0

ตารางต่อไปนี้แสดงรายการคำนำหน้าและตำแหน่งของแพ็กเกจ

คำนำหน้าแพ็กเกจ ตำแหน่ง ประเภทอินเทอร์เฟซ
android.hardware.* hardware/interfaces/* HAL
android.frameworks.* frameworks/hardware/interfaces/* เฟรมเวิร์ก/ ที่เกี่ยวข้อง
android.system.* system/hardware/interfaces/* system/ related
android.hidl.* system/libhidl/transport/* แกนกลาง

ไดเรกทอรีแพ็กเกจมีไฟล์ที่มีนามสกุล .hal ไฟล์ทุกไฟล์ต้องมีคำสั่ง package ที่ระบุชื่อแพ็กเกจและเวอร์ชันที่ไฟล์นั้นอยู่ ไฟล์ types.hal (หากมี) ไม่ได้กำหนดอินเทอร์เฟซ แต่กำหนดประเภทข้อมูลที่อินเทอร์เฟซทุกรายการในแพ็กเกจเข้าถึงได้

คําจํากัดความของอินเทอร์เฟซ

นอกเหนือจาก types.hal แล้ว ไฟล์ .hal อื่นๆ ทั้งหมดจะกำหนดอินเทอร์เฟซ โดยทั่วไปอินเทอร์เฟซจะกําหนดดังนี้

interface IBar extends IFoo { // IFoo is another interface
    // embedded types
    struct MyStruct {/*...*/};

    // interface methods
    create(int32_t id) generates (MyStruct s);
    close();
};

อินเทอร์เฟซที่ไม่มีประกาศ extends อย่างชัดแจ้งจะขยายมาจาก android.hidl.base@1.0::IBase โดยปริยาย (คล้ายกับ java.lang.Object ใน Java) อินเทอร์เฟซ IBase ที่นําเข้าโดยนัยจะประกาศเมธอดที่สงวนไว้หลายรายการที่ไม่ควรและไม่สามารถประกาศอีกครั้งในอินเทอร์เฟซที่ผู้ใช้กําหนดหรือใช้ในลักษณะอื่น ซึ่งได้แก่

  • ping
  • interfaceChain
  • interfaceDescriptor
  • notifySyspropsChanged
  • linkToDeath
  • unlinkToDeath
  • setHALInstrumentation
  • getDebugInfo
  • debug
  • getHashChain

กระบวนการนําเข้า

คำสั่ง import คือกลไก HIDL ในการเข้าถึงอินเทอร์เฟซและประเภทของแพ็กเกจในแพ็กเกจอื่น คำสั่ง import จะเกี่ยวข้องกับเอนทิตี 2 รายการ ได้แก่

  • เอนทิตีที่นําเข้า ซึ่งอาจเป็นแพ็กเกจหรืออินเทอร์เฟซก็ได้
  • เอนทิตีที่นําเข้า ซึ่งอาจเป็นแพ็กเกจหรืออินเทอร์เฟซ

เอนทิตีที่นำเข้าจะกำหนดโดยตำแหน่งของคำสั่ง import เมื่อคำสั่งอยู่ภายในtypes.halของแพ็กเกจ แพ็กเกจทั้งหมดจะเห็นสิ่งที่นำเข้า ซึ่งถือเป็นการนำเข้าระดับแพ็กเกจ เมื่อคำสั่งอยู่ภายในไฟล์อินเทอร์เฟซ อินเทอร์เฟซนั้นเองจะเป็นเอนทิตีที่นําเข้า นั่นคือการนําเข้าระดับอินเทอร์เฟซ

เอนทิตีที่นําเข้าจะกําหนดโดยค่าหลังคีย์เวิร์ด import ค่าไม่จำเป็นต้องเป็นชื่อที่สมบูรณ์ หากละเว้นคอมโพเนนต์ ระบบจะป้อนข้อมูลจากแพ็กเกจปัจจุบันโดยอัตโนมัติ สําหรับค่าที่ผ่านการกําหนดค่าอย่างเต็มรูปแบบ ระบบจะรองรับกรณีการนําเข้าต่อไปนี้

  • การนําเข้าทั้งแพ็กเกจ หากค่าเป็นชื่อแพ็กเกจและเวอร์ชัน (ไวยากรณ์ที่อธิบายไว้ด้านล่าง) ระบบจะนำเข้าทั้งแพ็กเกจไปยังเอนทิตีที่นำเข้า
  • การนําเข้าบางส่วน หากค่ามีรูปแบบดังนี้
    • ระบบจะนําเข้าอินเทอร์เฟซ, types.hal ของแพ็กเกจ และอินเทอร์เฟซนั้นไปยังเอนทิตีที่นําเข้า
    • UDT ที่กําหนดใน types.hal ระบบจะนําเข้าเฉพาะ UDT นั้นไปยังเอนทิตีที่นําเข้า (จะไม่นําเข้าประเภทอื่นๆ ใน types.hal)
  • การนําเข้าประเภทเท่านั้น หากค่าใช้ไวยากรณ์ของการนําเข้าบางส่วนที่อธิบายไว้ข้างต้น แต่มีคีย์เวิร์ด types แทนชื่ออินเทอร์เฟซ ระบบจะนําเข้าเฉพาะ UDT ใน types.hal ของแพ็กเกจที่กําหนด

บุคคลที่นําเข้าจะได้รับสิทธิ์เข้าถึงรายการต่อไปนี้

  • UDT ทั่วไปของแพ็กเกจที่นําเข้าซึ่งกําหนดไว้ใน types.hal
  • อินเทอร์เฟซของแพ็กเกจที่นําเข้า (สําหรับการนําเข้าทั้งแพ็กเกจ) หรืออินเทอร์เฟซที่ระบุ (สําหรับการนําเข้าบางส่วน) เพื่อวัตถุประสงค์ในการเรียกใช้ การส่งแฮนเดิลให้ และ/หรือการรับช่วงมาจากอินเทอร์เฟซดังกล่าว

คำสั่งการนําเข้าใช้ไวยากรณ์ชื่อประเภทที่สมบูรณ์เพื่อระบุชื่อและเวอร์ชันของแพ็กเกจหรืออินเทอร์เฟซที่นําเข้า

import android.hardware.nfc@1.0;            // import a whole package
import android.hardware.example@1.0::IQuux; // import an interface and types.hal
import android.hardware.example@1.0::types; // import just types.hal

การรับช่วงอินเทอร์เฟซต่อ

อินเทอร์เฟซอาจเป็นส่วนขยายของอินเทอร์เฟซที่กําหนดไว้ก่อนหน้านี้ ส่วนขยายอาจเป็นอย่างใดอย่างหนึ่งต่อไปนี้

  • อินเทอร์เฟซสามารถเพิ่มฟังก์ชันการทำงานให้กับอินเทอร์เฟซอื่นได้ โดยที่ API ของอินเทอร์เฟซนั้นไม่เปลี่ยนแปลง
  • แพ็กเกจสามารถเพิ่มฟังก์ชันการทำงานให้กับอีกแพ็กเกจหนึ่งได้ โดยรวม API ของแพ็กเกจนั้นไว้
  • อินเทอร์เฟซสามารถนําเข้าประเภทจากแพ็กเกจหรือจากอินเทอร์เฟซที่เฉพาะเจาะจง

อินเทอร์เฟซจะขยายอินเทอร์เฟซอื่นได้เพียงอินเทอร์เฟซเดียวเท่านั้น (ไม่มีการรับช่วงหลายรายการ) อินเทอร์เฟซแต่ละรายการในแพ็กเกจที่มีหมายเลขเวอร์ชันย่อยที่ไม่ใช่ 0 จะต้องขยายอินเทอร์เฟซในแพ็กเกจเวอร์ชันก่อนหน้า ตัวอย่างเช่น หากอินเทอร์เฟซ IBar ในแพ็กเกจ derivative เวอร์ชัน 4.0 อิงตาม (ขยาย) อินเทอร์เฟซ IFoo ในแพ็กเกจ original เวอร์ชัน 1.2 และมีการสร้างแพ็กเกจ original เวอร์ชัน 1.3 IBar เวอร์ชัน 4.1 จะขยาย IFoo เวอร์ชัน 1.3 ไม่ได้ แต่ IBar เวอร์ชัน 4.1 ต้องขยายจากIBar เวอร์ชัน 4.0 ซึ่งเชื่อมโยงกับ IFoo เวอร์ชัน 1.2 IBar เวอร์ชัน 5.0 อาจขยาย IFoo เวอร์ชัน 1.3 ได้ หากต้องการ

ส่วนขยายอินเทอร์เฟซไม่ได้บ่งบอกถึงการพึ่งพาไลบรารีหรือการรวม HAL หลายรายการในโค้ดที่สร้างขึ้น เพียงแต่นําเข้าโครงสร้างข้อมูลและคําจํากัดความของเมธอดที่ระดับ HIDL วิธีการทุกรายการใน HAL ต้องติดตั้งใช้งานใน HAL นั้น

ส่วนขยายของผู้ให้บริการ

ในบางกรณี ระบบจะใช้ส่วนขยายของผู้ให้บริการเป็นคลาสย่อยของออบเจ็กต์พื้นฐานที่แสดงอินเทอร์เฟซหลักที่ขยาย ออบเจ็กต์เดียวกันจะลงทะเบียนภายใต้ชื่อและเวอร์ชัน HAL ของฐาน และภายใต้ชื่อและเวอร์ชัน HAL ของส่วนขยาย (ผู้ให้บริการ)

การกำหนดเวอร์ชัน

แพ็กเกจมีเวอร์ชัน และอินเทอร์เฟซจะมีเวอร์ชันของแพ็กเกจ เวอร์ชันจะแสดงเป็นจำนวนเต็มที่แบ่งออกเป็น 2 ส่วน ได้แก่ หลักรอง

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

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

สรุปเลย์เอาต์อินเทอร์เฟซ

ส่วนนี้จะสรุปวิธีจัดการแพ็กเกจอินเทอร์เฟซ HIDL (เช่น hardware/interfaces) และรวบรวมข้อมูลที่แสดงในส่วน HIDL ก่อนอ่าน โปรดทําความคุ้นเคยกับแนวคิดการกำหนดเวอร์ชัน HIDL, การแฮชด้วย hild-gen, รายละเอียดของการทํางานกับ HIDL โดยทั่วไป และคำจำกัดความต่อไปนี้

คำศัพท์ คำจำกัดความ
อินเทอร์เฟซแบบไบนารีของแอปพลิเคชัน (ABI) Application Programming Interface รวมถึงการลิงก์แบบไบนารีที่จำเป็น
ชื่อที่สมบูรณ์ในตัวเอง (fqName) ชื่อเพื่อแยกแยะประเภท HIDL ตัวอย่าง: android.hardware.foo@1.0::IFoo
พัสดุ แพ็กเกจที่มีอินเทอร์เฟซและประเภท HIDL ตัวอย่าง: android.hardware.foo@1.0
รูทของแพ็กเกจ แพ็กเกจรูทที่มีอินเทอร์เฟซ HIDL ตัวอย่างเช่น อินเทอร์เฟซ HIDL android.hardware อยู่ในรูทของแพ็กเกจ android.hardware.foo@1.0
เส้นทางรูทของแพ็กเกจ ตําแหน่งในลําดับชั้นซอร์สโค้ด Android ที่รูทของแพ็กเกจแมปถึง

ดูคำจำกัดความเพิ่มเติมได้ในคำศัพท์ HIDL

คุณดูไฟล์ทุกไฟล์ได้จากการแมปรูทของแพ็กเกจและชื่อที่สมบูรณ์ในตัวเอง

ระบุรูทของแพ็กเกจเป็น hidl-gen เป็นอาร์กิวเมนต์ -r android.hardware:hardware/interfaces ตัวอย่างเช่น หากแพ็กเกจคือ vendor.awesome.foo@1.0::IFoo และ hidl-gen ได้รับการส่ง -r vendor.awesome:some/device/independent/path/interfaces ไฟล์อินเทอร์เฟซควรอยู่ใน $ANDROID_BUILD_TOP/some/device/independent/path/interfaces/foo/1.0/IFoo.hal

ในทางปฏิบัติ เราขอแนะนำให้ผู้ให้บริการหรือ OEM ชื่อ awesome ใส่อินเทอร์เฟซมาตรฐานใน vendor.awesome หลังจากเลือกเส้นทางแพ็กเกจแล้ว คุณจะเปลี่ยนแปลงเส้นทางดังกล่าวไม่ได้เนื่องจากเส้นทางนี้ฝังอยู่ใน ABI ของอินเทอร์เฟซ

การแมปเส้นทางแพ็กเกจควรไม่ซ้ำกัน

เช่น หากคุณมี -rsome.package:$PATH_A และ -rsome.package:$PATH_B $PATH_A ต้องเท่ากับ $PATH_B เพื่อให้ไดเรกทอรีอินเทอร์เฟซสอดคล้องกัน (วิธีนี้ยังทำให้การกำหนดเวอร์ชันอินเทอร์เฟซง่ายขึ้นมากด้วย)

รูทของแพ็กเกจต้องมีไฟล์การกำหนดเวอร์ชัน

หากคุณสร้างเส้นทางแพ็กเกจ เช่น -r vendor.awesome:vendor/awesome/interfaces คุณควรสร้างไฟล์ $ANDROID_BUILD_TOP/vendor/awesome/interfaces/current.txt ด้วย ซึ่งควรมีแฮชของอินเทอร์เฟซที่สร้างโดยใช้ตัวเลือก -Lhash ใน hidl-gen (เรื่องนี้มีการอธิบายอย่างละเอียดในหัวข้อการแฮชด้วย hidl-gen)

อินเทอร์เฟซจะอยู่ในที่ที่ไม่ขึ้นอยู่กับอุปกรณ์

ในทางปฏิบัติ เราขอแนะนำให้แชร์อินเทอร์เฟซระหว่างสาขา วิธีนี้ช่วยให้ใช้โค้ดซ้ำได้มากที่สุดและทดสอบโค้ดในอุปกรณ์และกรณีการใช้งานต่างๆ ได้มากที่สุด