การกำหนดเวอร์ชันอินเทอร์เฟซ

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

โครงสร้างรหัส HIDL

มีการจัดระเบียบรหัส HIDL ตามที่ผู้ใช้กำหนด ประเภท อินเทอร์เฟซ และแพ็กเกจ

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

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

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

แพ็กเกจ HIDL (เช่น android.hardware.nfc) หลังจากถูก เผยแพร่สำหรับเวอร์ชันที่ระบุ (เช่น 1.0) จะเปลี่ยนแปลงไม่ได้ รายการดังกล่าว ไม่สามารถเปลี่ยนได้ การแก้ไขอินเทอร์เฟซในแพ็กเกจหรือ การเปลี่ยนแปลง UDT ทำได้เฉพาะในแพ็กเกจอื่นเท่านั้น

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

โดยหลักการแล้ว แพ็กเกจอาจเกี่ยวข้องกับแพ็กเกจอื่นได้หลายวิธี ดังนี้

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

การกำหนดโครงสร้างอินเทอร์เฟซ

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

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

ข้อกำหนด

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

  • สามารถอธิบายใน HIDL ได้โดยตรง (โดยใช้ Struct enum เป็นต้น) ชื่อและความหมาย
  • สามารถอธิบายตามมาตรฐานสาธารณะ เช่น ISO/IEC 7816
  • อธิบายได้โดยใช้มาตรฐานฮาร์ดแวร์หรือเลย์เอาต์ทางกายภาพของฮาร์ดแวร์
  • อาจเป็นข้อมูลที่ไม่ชัดเจน (เช่น คีย์สาธารณะ รหัส ฯลฯ) หากจำเป็น

หากใช้ข้อมูลแบบทึบ HIDL จะต้องอ่านค่าในด้านใดด้านหนึ่งเท่านั้น ของ Google ตัวอย่างเช่น หากโค้ด vendor.img ให้คอมโพเนนต์ใน system.imgข้อความสตริงหรือvec<uint8_t> ข้อมูลนั้นไม่สามารถแยกวิเคราะห์โดย system.img ได้ สามารถทำได้ จะส่งกลับไปยัง vendor.img เท่านั้นเพื่อตีความ เมื่อใด การส่งค่าจาก vendor.img ไปยังโค้ดของผู้ให้บริการเปิดอยู่ system.img หรืออุปกรณ์อื่น รูปแบบของข้อมูล และวิธีการที่ข้อมูล ในการตีความ ต้องมีการอธิบายอย่างละเอียดและยังคงเป็นส่วนหนึ่งของ ของ AdSense

หลักเกณฑ์

คุณควรจะสามารถเขียนการติดตั้งใช้งานหรือไคลเอ็นต์สำหรับ HAL ได้โดยใช้ ไฟล์ .hal (กล่าวคือ คุณไม่จำเป็นต้องดูซอร์สโค้ดของ Android หรือสาธารณะ มาตรฐาน) เราขอแนะนำให้ระบุลักษณะการทำงานที่จำเป็น ข้อความ เช่น "การใช้งานอาจทำ A หรือ B" ส่งเสริมให้มีการนำไปใช้งาน ได้สัมพันธ์กับลูกค้าที่พัฒนาด้วย

เลย์เอาต์รหัส HIDL

HIDL ประกอบด้วยแพ็กเกจหลักและแพ็กเกจผู้ให้บริการ

อินเทอร์เฟซ HIDL หลักคืออินเทอร์เฟซที่ Google ระบุไว้ พัสดุภัณฑ์ที่พวกเขาอยู่ จะเริ่มต้นด้วย android.hardware. และตั้งชื่อตามระบบย่อย ซึ่งมีโอกาสในระดับการตั้งชื่อที่ซ้อนอยู่ ตัวอย่างเช่น ชื่อแพ็กเกจ NFC android.hardware.nfc และแพ็กเกจกล้อง android.hardware.camera. โดยทั่วไป แพ็กเกจหลักจะมีชื่อ android.hardware.[name1][name2].... แพ็กเกจ HIDL จะมีเวอร์ชันอื่นนอกเหนือจากชื่อด้วย เช่น แพ็กเกจ android.hardware.camera อาจอยู่ที่เวอร์ชัน 3.4 นี่คือ สำคัญ เนื่องจากเวอร์ชันของแพ็กเกจมีผลต่อตำแหน่งของแพ็กเกจในโครงสร้างต้นทาง

แพ็กเกจหลักทั้งหมดอยู่ภายใต้ hardware/interfaces/ ในส่วน ระบบบิลด์ แพ็กเกจ android.hardware.[name1][name2]... ที่เวอร์ชัน $m.$n ต่ำกว่า hardware/interfaces/name1/name2/.../$m.$n/; พัสดุ android.hardware.camera เวอร์ชัน 3.4 อยู่ในไดเรกทอรี hardware/interfaces/camera/3.4/. มีการแมปแบบฮาร์ดโค้ดอยู่ ระหว่างคำนำหน้าแพ็กเกจ android.hardware. และเส้นทาง hardware/interfaces/

แพ็กเกจที่ไม่ใช่แพ็กเกจหลัก (ผู้ให้บริการ) คือแพ็กเกจที่ผลิตโดยผู้ให้บริการ SoC หรือ ODM คำนำหน้าสำหรับแพ็กเกจที่ไม่ใช่แพ็กเกจหลักคือ vendor.$(VENDOR).hardware. โดยที่ $(VENDOR)กล่าวถึงผู้ให้บริการ SoC หรือ OEM/ODM เส้นทางนี้จะจับคู่กับเส้นทาง vendor/$(VENDOR)/interfaces ในโครงสร้าง (การแมปนี้ยัง ฮาร์ดโค้ด)

ชื่อประเภทที่ผู้ใช้กำหนดซึ่งตรงตามเกณฑ์ทั้งหมด

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

struct NfcData {
    vec<uint8_t> data;
};

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

android.hardware.nfc@1.0::NfcData

ไวยากรณ์ทั่วไปคือ PACKAGE@VERSION::UDT โดยที่

  • PACKAGE คือชื่อที่คั่นด้วยจุดของแพ็กเกจ HIDL (เช่น android.hardware.nfc).
  • VERSION คือMajor.minor-version ที่คั่นด้วยจุด รูปแบบของแพ็กเกจ (เช่น 1.0).
  • UDT คือชื่อที่คั่นด้วยจุดของ HIDL UDT เนื่องจาก HIDL สนับสนุนอินเทอร์เฟซ UDT และ HIDL ที่ฝังอยู่อาจมี UDT (ประเภทของ การประกาศแบบซ้อน) จะใช้จุดเพื่อเข้าถึงชื่อ

ตัวอย่างเช่น ถ้าการกำหนดข้อความเชิงซ้อนต่อไปนี้มีการกำหนดไว้ใน ประเภทไฟล์ในแพ็กเกจ android.hardware.example เวอร์ชัน 1.0:

// types.hal
package android.hardware.example@1.0;
struct Foo {
    struct Bar {
        // …
    };
    Bar cheers;
};

ชื่อที่มีคุณสมบัติครบถ้วนของ Bar คือ android.hardware.example@1.0::Foo.Bar. นอกจากการอยู่ใน แพ็กเกจข้างต้น การประกาศที่ฝังอยู่ในอินเทอร์เฟซที่เรียกว่า IQuux:

// IQuux.hal
package android.hardware.example@1.0;
interface IQuux {
    struct Foo {
        struct Bar {
            // …
        };
        Bar cheers;
    };
    doSomething(Foo f) generates (Foo.Bar fb);
};

ชื่อที่มีคุณสมบัติครบถ้วนของ Bar คือ android.hardware.example@1.0::IQuux.Foo.Bar.

ในทั้ง 2 กรณี จะเรียก Bar ว่า Bar ได้เท่านั้น ภายในขอบเขตของการประกาศFoo ที่พัสดุหรือ ระดับอินเทอร์เฟซ คุณต้องอ้างถึง Bar ผ่าน Foo Foo.Bar ตามการประกาศเมธอด doSomething ที่ด้านบน หรือคุณจะประกาศเมธอดให้ชัดเจนมากขึ้นก็ได้ ดังนี้

// IQuux.hal
doSomething(android.hardware.example@1.0::IQuux.Foo f) generates (android.hardware.example@1.0::IQuux.Foo.Bar fb);

ค่าการแจงนับที่มีคุณสมบัติครบถ้วน

หาก UDT เป็นประเภท enum แต่ละค่าของประเภท enum จะมีค่า ชื่อที่มีคุณสมบัติครบถ้วนที่ขึ้นต้นด้วยชื่อแบบเต็มของประเภท enum ตามด้วยเครื่องหมายทวิภาคแล้วตามด้วยชื่อของค่า enum ตัวอย่างเช่น สมมติว่าแพ็กเกจ android.hardware.nfc, เวอร์ชัน 1.0 กำหนดประเภท enum NfcStatus ดังนี้

enum NfcStatus {
    STATUS_OK,
    STATUS_FAILED
};

เมื่ออ้างถึง STATUS_OK ชื่อที่ตรงตามเกณฑ์ทั้งหมดคือ

android.hardware.nfc@1.0::NfcStatus:STATUS_OK

ไวยากรณ์ทั่วไปคือ PACKAGE@VERSION::UDT:VALUE, โดยมี

  • PACKAGE@VERSION::UDT คือ ชื่อที่ตรงกันทุกประการสำหรับประเภท enum
  • VALUE คือชื่อของค่า

กฎการอนุมานอัตโนมัติ

ไม่จำเป็นต้องระบุชื่อ UDT แบบเต็ม ชื่อ UDT สามารถ ละเว้นสิ่งต่อไปนี้อย่างปลอดภัย

  • แพ็กเกจ เช่น @1.0::IFoo.Type
  • ทั้งแพ็กเกจและเวอร์ชัน เช่น IFoo.Type

HIDL พยายามเติมชื่อให้สมบูรณ์โดยใช้กฎการแทรกแซงอัตโนมัติ (กฎที่ต่ำกว่า ตัวเลขหมายถึงลำดับความสำคัญที่สูงกว่า)

กฎข้อ 1

หากไม่ได้ระบุแพ็กเกจและเวอร์ชัน ระบบจะพยายามค้นหาชื่อในเครื่อง ตัวอย่าง

interface Nfc {
    typedef string NfcErrorMessage;
    send(NfcData d) generates (@1.0::NfcStatus s, NfcErrorMessage m);
};

ค้นหา NfcErrorMessage ในเครื่อง และ typedef เหนือแท็กดังกล่าว ค้นหา NfcData ในเครื่องเช่นกัน แต่ในความเป็นจริง ไม่ได้กำหนดไว้ภายในเครื่อง ระบบจะใช้กฎ 2 และ 3 @1.0::NfcStatus ระบุเวอร์ชัน ดังนั้นกฎ 1 จะไม่มีผล

กฎข้อ 2

หากกฎ 1 ล้มเหลวและคอมโพเนนต์ของชื่อที่สมบูรณ์ในตัวเองขาดหายไป (แพ็กเกจ เวอร์ชัน หรือแพ็กเกจและเวอร์ชัน) ระบบจะป้อนข้อความอัตโนมัติให้คอมโพเนนต์ จากแพ็กเกจปัจจุบัน จากนั้นคอมไพเลอร์ HIDL จะค้นหาใน ไฟล์ปัจจุบัน (และการนำเข้าทั้งหมด) เพื่อหาชื่อแบบเต็มที่ป้อนอัตโนมัติ ใช้ตัวอย่างด้านบน สมมติว่ามีการประกาศ ExtendedNfcData ดำเนินการในแพ็กเกจเดียวกัน (android.hardware.nfc) (1.0) เป็น NfcData ดังนี้

struct ExtendedNfcData {
    NfcData base;
    // … additional members
};

คอมไพเลอร์ HIDL จะกรอกข้อมูลชื่อแพ็กเกจและชื่อเวอร์ชันจาก แพ็กเกจปัจจุบันเพื่อสร้างชื่อ UDT ที่สมบูรณ์ในตัวเอง android.hardware.nfc@1.0::NfcData. ตามชื่อมีอยู่ใน แพ็กเกจปัจจุบัน (สมมติว่านำเข้าอย่างถูกต้อง) ใช้สำหรับ ของคุณ

ระบบจะนำเข้าชื่อในแพ็กเกจปัจจุบัน ก็ต่อเมื่อหนึ่งในรายการต่อไปนี้คือ true:

  • มีการนำเข้าอย่างชัดเจนด้วยคำสั่ง import
  • มีการกำหนดไว้ในภาษาtypes.halในแพ็กเกจปัจจุบัน

ก็จะเป็นไปตามกระบวนการเดียวกันนี้ หาก NfcData ผ่านการรับรอง หมายเลขเวอร์ชัน

struct ExtendedNfcData {
    // autofill the current package name (android.hardware.nfc)
    @1.0::NfcData base;
    // … additional members
};

กฎข้อ 3

หากกฎ 2 สร้างการจับคู่ไม่สำเร็จ (ไม่ได้กำหนด UDT ไว้ในฟิลด์ ) คอมไพเลอร์ HIDL จะสแกนหารายการที่ตรงกันภายในแพ็กเกจที่นำเข้าทั้งหมด จากตัวอย่างด้านบน สมมติว่ามีการประกาศ ExtendedNfcData ใน เวอร์ชัน 1.1 ของแพ็กเกจ android.hardware.nfc 1.1 นำเข้า 1.0 ตามที่ควรจะเป็น (ดู ส่วนขยายระดับแพ็กเกจ) และคำจำกัดความ ระบุเฉพาะชื่อ UDT เท่านั้น

struct ExtendedNfcData {
    NfcData base;
    // … additional members
};

คอมไพเลอร์จะค้นหา UDT ที่ชื่อ NfcData และพบ UDT ใน android.hardware.nfc ในเวอร์ชัน 1.0 ส่งผลให้ UDT ที่สมบูรณ์ของ android.hardware.nfc@1.0::NfcData หากมีมากกว่านั้น พบผลการค้นหาที่ตรงกันมากกว่า 1 รายการสำหรับ UDT ที่มีคุณสมบัติบางส่วน นั่นคือคอมไพเลอร์ HIDL เกิดข้อผิดพลาด

ตัวอย่าง

เมื่อใช้กฎ 2 ประเภทที่นำเข้าที่กำหนดไว้ในแพ็กเกจปัจจุบันจะชอบมากกว่า ประเภทที่นำเข้าจากแพ็กเกจอื่น:

// hardware/interfaces/foo/1.0/types.hal
package android.hardware.foo@1.0;
struct S {};

// hardware/interfaces/foo/1.0/IFooCallback.hal
package android.hardware.foo@1.0;
interface IFooCallback {};

// hardware/interfaces/bar/1.0/types.hal
package android.hardware.bar@1.0;
typedef string S;

// hardware/interfaces/bar/1.0/IFooCallback.hal
package android.hardware.bar@1.0;
interface IFooCallback {};

// hardware/interfaces/bar/1.0/IBar.hal
package android.hardware.bar@1.0;
import android.hardware.foo@1.0;
interface IBar {
    baz1(S s); // android.hardware.bar@1.0::S
    baz2(IFooCallback s); // android.hardware.foo@1.0::IFooCallback
};
  • S จะได้รับการประมาณค่าเป็น android.hardware.bar@1.0::S และพบใน bar/1.0/types.hal (เนื่องจาก types.hal ทำงานอัตโนมัติ นำเข้าแล้ว)
  • IFooCallback จะได้รับการประมาณค่าเป็น android.hardware.bar@1.0::IFooCallback โดยใช้กฎ 2 แต่ ไม่พบ เนื่องจากไม่ได้นำเข้า bar/1.0/IFooCallback.hal โดยอัตโนมัติ (เนื่องจาก types.hal) ดังนั้น กฎ 3 จะแปลค่าเป็น android.hardware.foo@1.0::IFooCallback แทน ซึ่งมีการนำเข้า ผ่าน import android.hardware.foo@1.0;)

Type.hal

แพ็กเกจ HIDL ทุกรายการจะมีไฟล์ types.hal ที่มี UDT ซึ่งจะใช้ร่วมกันระหว่างอินเทอร์เฟซทั้งหมดที่เข้าร่วมแพ็กเกจนั้น ประเภท HIDL เป็นแบบสาธารณะเสมอ ไม่ว่าจะมีการประกาศ UDT ใน types.hal หรือภายในการประกาศอินเทอร์เฟซ ประเภท เข้าถึงได้นอกขอบเขตที่ระบุไว้ types.hal ไม่ได้มีไว้เพื่ออธิบาย API สาธารณะของแพ็กเกจ แต่ใช้เพื่อโฮสต์ UDT อินเทอร์เฟซทั้งหมดภายในแพ็กเกจจะใช้ เนื่องด้วยธรรมชาติของ HIDL, UDT ทั้งหมด เป็นส่วนหนึ่งของอินเทอร์เฟซ

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

ตัวอย่างเช่น สำหรับ IFoo.hal

package android.hardware.foo@1.0;
// whole package import
import android.hardware.bar@1.0;
// types only import
import android.hardware.baz@1.0::types;
// partial imports
import android.hardware.qux@1.0::IQux.Quux;
// partial imports
import android.hardware.quuz@1.0::Quuz;

ระบบนําเข้ารายการต่อไปนี้

  • android.hidl.base@1.0::IBase (โดยนัย)
  • android.hardware.foo@1.0::types (โดยนัย)
  • ทุกอย่างใน android.hardware.bar@1.0 (รวมทั้งหมด อินเทอร์เฟซและtypes.hal)
  • types.hal จาก android.hardware.baz@1.0::types (ระบบจะไม่นำเข้าอินเทอร์เฟซใน android.hardware.baz@1.0)
  • IQux.hal และ types.hal จาก android.hardware.qux@1.0
  • Quuz จาก android.hardware.quuz@1.0 (สมมติว่า Quuz กำหนดไว้ใน types.hal ทั้ง ไฟล์ types.hal ได้รับการแยกวิเคราะห์ แต่ประเภทอื่นที่ไม่ใช่ Quuz ไม่ได้นำเข้า)

การกำหนดเวอร์ชันระดับอินเทอร์เฟซ

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

package android.hardware.nfc@1.0;

ใน HIDL อินเทอร์เฟซสามารถรับค่าจากอินเทอร์เฟซอื่นๆ โดยใช้ คีย์เวิร์ด extends รายการ หากต้องการให้อินเทอร์เฟซขยายอีกอินเทอร์เฟซหนึ่ง ต้องมีสิทธิ์เข้าถึงคีย์ดังกล่าวผ่านคำสั่ง import ชื่อของ อินเทอร์เฟซที่กำลังขยาย (อินเทอร์เฟซพื้นฐาน) เป็นไปตามกฎสำหรับชื่อประเภท คุณสมบัติที่อธิบายข้างต้น อินเทอร์เฟซหนึ่งรับค่าจากอินเทอร์เฟซได้เพียง 1 รายการเท่านั้น HIDL ไม่รองรับการสืบทอดหลายรายการ

ตัวอย่างการกำหนดเวอร์ชัน Uprev ด้านล่างใช้แพ็กเกจต่อไปนี้

// types.hal
package android.hardware.example@1.0
struct Foo {
    struct Bar {
        vec<uint32_t> val;
    };
};

// IQuux.hal
package android.hardware.example@1.0
interface IQuux {
    fromFooToBar(Foo f) generates (Foo.Bar b);
}

กฎ Uprev

หากต้องการกำหนดแพ็กเกจ package@major.minor ให้เลือก A หรือ B ทั้งหมด ต้องเป็นจริง

กฎ A "เป็นเวอร์ชันย่อยที่เริ่มใหม่": เวอร์ชันย่อยก่อนหน้าทั้งหมด package@major.0, package@major.1, ... ต้องไม่กำหนด package@major.(minor-1)
หรือ
กฎ ข

เงื่อนไขต่อไปนี้เป็นจริงทั้งหมด

  1. "เวอร์ชันย่อยก่อนหน้าถูกต้อง": package@major.(minor-1) ต้องได้รับการกำหนดและเป็นไปตามกฎ A เดียวกัน (ไม่มี package@major.0 จนถึง package@major.(minor-2) ได้รับการกำหนดไว้) หรือกฎ ข (หากเป็นการปรับค่าใช้จ่ายจาก @major.(minor-2))

    และ

  2. "รับค่าอินเทอร์เฟซที่มีชื่อเดียวกันอย่างน้อย 1 รายการ": มี อินเทอร์เฟซ package@major.minor::IFoo ที่ขยาย package@major.(minor-1)::IFoo (หากแพ็กเกจก่อนหน้านี้มีอินเทอร์เฟซ)

    และ

  3. "ไม่มีอินเทอร์เฟซที่รับช่วงมาโดยใช้ชื่ออื่น": ต้องไม่มีอินเทอร์เฟซ package@major.minor::IBar ที่ขยาย package@major.(minor-1)::IBaz โดยที่ IBar และ IBaz เป็น 2 ชื่อที่แตกต่างกัน หากมีอินเทอร์เฟซที่มีตัวเลือก ชื่อเดียวกัน package@major.minor::IBar ต้องขยาย package@major.(minor-k)::IBar ที่ไม่มี IBar ที่มี k เล็ก

เนื่องจากกฎ A:

  • แพ็กเกจอาจเริ่มต้นด้วยหมายเลขเวอร์ชันย่อย (เช่น android.hardware.biometrics.fingerprint เริ่มต้นที่ @2.1)
  • ข้อกำหนด "ไม่ได้กำหนด android.hardware.foo@1.0" หมายความว่า ไดเรกทอรี hardware/interfaces/foo/1.0 ก็ไม่ควรอยู่

อย่างไรก็ตาม กฎ ก จะไม่มีผลกับแพ็กเกจที่มีชื่อแพ็กเกจเดียวกัน แต่มี เวอร์ชันหลักที่แตกต่างกัน (เช่น android.hardware.camera.device มีทั้ง @1.0 และ คำจำกัดความของ @3.2 @3.2 ไม่จำเป็นต้องโต้ตอบกับ @1.0) ดังนั้น @3.2::IExtFoo จึงสามารถขยาย @1.0::IFoo

หากชื่อแพ็กเกจระบุไว้เป็นอย่างอื่น package@major.minor::IBar สามารถขยายจากอินเทอร์เฟซที่มี ชื่ออื่น (เช่น android.hardware.bar@1.0::IBar สามารถ ขยาย android.hardware.baz@2.2::IBaz) หากอินเทอร์เฟซไม่ ประกาศประเภทขั้นสูงด้วยคีย์เวิร์ด extend อย่างชัดเจน ขยาย android.hidl.base@1.0::IBase (ยกเว้น IBase เอง)

ข.2 และ ข.3 ต้องปฏิบัติตามพร้อมกัน ตัวอย่างเช่น แม้ว่า android.hardware.foo@1.1::IFoo ต่อเวลา android.hardware.foo@1.0::IFooเพื่อให้ผ่านกฎ ข.2 หาก android.hardware.foo@1.1::IExtBar ขยาย android.hardware.foo@1.0::IBar ยังไม่ใช่จำนวนเงินที่ถูกต้อง

อินเทอร์เฟซ Uprev

เพื่อเพิ่ม android.hardware.example@1.0 (ตามคำจำกัดความด้านบน) เป็น @1.1:

// types.hal
package android.hardware.example@1.1;
import android.hardware.example@1.0;

// IQuux.hal
package android.hardware.example@1.1
interface IQuux extends @1.0::IQuux {
    fromBarToFoo(Foo.Bar b) generates (Foo f);
}

นี่คือ import ระดับแพ็กเกจของเวอร์ชัน 1.0 ของ android.hardware.example ใน types.hal ในขณะที่ไม่มี เพิ่ม UDT ไว้ในแพ็กเกจเวอร์ชัน 1.1 การอ้างอิงถึง UDT ใน ยังต้องใช้เวอร์ชัน 1.0 อยู่ ดังนั้น การนำเข้าระดับแพ็กเกจ ใน types.hal (ผลลัพธ์เดียวกันนี้อาจได้รับจาก การนำเข้าระดับอินเทอร์เฟซใน IQuux.hal)

ในextends @1.0::IQuux ในการประกาศ IQuux เราได้ระบุเวอร์ชันของ IQuux ที่ รับค่าเดิม (ต้องมีคำอธิบาย เนื่องจาก IQuux ใช้เพื่อ ประกาศอินเทอร์เฟซและรับค่าจากอินเทอร์เฟซ) ตามที่ประกาศไว้ เพียงชื่อที่รับช่วงแอตทริบิวต์แพ็กเกจและเวอร์ชันทั้งหมดในเว็บไซต์ของ ข้อความชี้แจงต้องเป็นชื่อของอินเทอร์เฟซพื้นฐาน เรา ที่จะใช้ UDT ที่มีคุณสมบัติครบถ้วนเช่นกัน แต่นั่นจะเป็น ซ้ำซ้อน

อินเทอร์เฟซใหม่ IQuux ไม่ประกาศเมธอดอีกครั้ง fromFooToBar() พร็อพเพอร์ตี้จะรับค่ามาจาก @1.0::IQuux ง่ายๆ แสดงวิธีการใหม่ที่เพิ่ม fromBarToFoo() ใน HIDL จะรับค่าเดิม ไม่อาจประกาศอีกครั้งในอินเทอร์เฟซย่อยได้ อินเทอร์เฟซ IQuux จะไม่สามารถประกาศ fromFooToBar() อย่างชัดเจน

การประชุมสุดยอด

บางครั้งชื่ออินเทอร์เฟซต้องเปลี่ยนชื่ออินเทอร์เฟซส่วนขยาย คำแนะนำจากเรา ว่าส่วนขยาย โครงสร้าง และสหภาพของ enum มีชื่อเหมือนกับสิ่งที่ขยาย เว้นแต่จะแตกต่างกันมากพอที่จะรับประกันชื่อใหม่ ตัวอย่าง

// in parent hal file
enum Brightness : uint32_t { NONE, WHITE };

// in child hal file extending the existing set with additional similar values
enum Brightness : @1.0::Brightness { AUTOMATIC };

// extending the existing set with values that require a new, more descriptive name:
enum Color : @1.0::Brightness { HW_GREEN, RAINBOW };

หากเมธอดมีชื่อความหมายใหม่ (ตัวอย่างเช่น fooWithLocation) ก็ควรเป็นเช่นนั้น มิเช่นนั้นระบบควรทำดังนี้ ตั้งชื่อที่คล้ายกับสิ่งที่ส่วนขยายนั้นอยู่ ตัวอย่างเช่น เมธอด foo_1_1 ใน @1.1::IFoo สามารถแทนที่ฟังก์ชันการทำงานได้ ของเมธอด foo ใน @1.0::IFoo ถ้าไม่มีวิธีที่ดีกว่า ชื่อสำรอง

การกำหนดเวอร์ชันระดับแพ็กเกจ

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

อย่างไรก็ตาม มีการกำหนดความสัมพันธ์ประเภทหนึ่งไว้อย่างเคร่งครัดและต้องมีการบังคับใช้ ดังนี้ การรับช่วงค่าที่เข้ากันได้แบบย้อนหลังในระดับแพ็กเกจ ในสถานการณ์นี้ พารามิเตอร์ แพ็กเกจ parent คือแพ็กเกจที่รับช่วงมาจาก และ แพ็กเกจย่อยคือแพ็กเกจที่ขยายหน่วยโฆษณาหลัก ระดับแพ็กเกจ กฎการรับค่าที่เข้ากันได้แบบย้อนหลังมีดังนี้

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

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

หากแพ็กเกจเป็นไปตามข้อกำหนดนี้ hidl-gen จะบังคับใช้ ความเข้ากันได้แบบย้อนหลัง