AIDL สำหรับ HAL

Android 11 เปิดตัวความสามารถในการใช้ AIDL สำหรับ HAL ใน Android ซึ่งทำให้สามารถติดตั้งใช้งานบางส่วนของ Android โดยไม่ต้องใช้ HIDL ได้ เปลี่ยน HAL ให้ใช้ AIDL เพียงอย่างเดียวเมื่อเป็นไปได้ (เมื่อ HAL ต้นทางใช้ HIDL จะต้องใช้ HIDL)

HAL ที่ใช้ AIDL เพื่อสื่อสารระหว่างคอมโพเนนต์เฟรมเวิร์ก เช่น คอมโพเนนต์ใน system.img กับคอมโพเนนต์ฮาร์ดแวร์ เช่น คอมโพเนนต์ใน vendor.img ต้องใช้ AIDL ที่เสถียร อย่างไรก็ตาม หากต้องการสื่อสารภายในพาร์ติชัน เช่น จาก HAL หนึ่งไปยังอีก HAL หนึ่ง จะไม่มีข้อจำกัดเกี่ยวกับกลไก IPC ที่จะใช้ได้

แรงจูงใจ

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

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

บิลด์กับรันไทม์ AIDL

AIDL มีแบ็กเอนด์ 3 แบบ ได้แก่ Java, NDK และ CPP หากต้องการใช้ AIDL ที่เสถียร ให้ใช้สำเนาระบบของ libbinder ที่ system/lib*/libbinder.so เสมอ และพูดคุยใน /dev/binder สําหรับโค้ดในภาพ vendor หมายความว่าจะใช้ libbinder (จาก VNDK) ไม่ได้ เนื่องจากไลบรารีนี้มี C++ API ที่ไม่เสถียรและอินเทอร์เนลที่ไม่เสถียร แทนที่จะใช้แบ็กเอนด์ NDK ของ AIDL, ลิงก์กับ libbinder_ndk (ซึ่งระบบ libbinder.so รองรับ) และลิงก์กับไลบรารี NDK ที่สร้างขึ้นโดยรายการ aidl_interface ดูชื่อโมดูลที่แน่นอนได้ที่กฎการตั้งชื่อโมดูล

เขียนอินเทอร์เฟซ AIDL HAL

หากต้องการให้ระบบและผู้ให้บริการใช้อินเทอร์เฟซ AIDL ได้ อินเทอร์เฟซดังกล่าวต้องเปลี่ยนแปลง 2 อย่าง ดังนี้

  • คำจำกัดความประเภททุกรายการต้องมีการกำกับเนื้อหาด้วย @VintfStability
  • ประกาศ aidl_interface ต้องมี stability: "vintf",

มีเพียงเจ้าของอินเทอร์เฟซเท่านั้นที่ทําการเปลี่ยนแปลงเหล่านี้ได้

เมื่อทําการเปลี่ยนแปลงเหล่านี้ อินเทอร์เฟซต้องอยู่ในไฟล์ Manifest ของ VINTF จึงจะทํางานได้ ทดสอบข้อกำหนดนี้ (และข้อกำหนดที่เกี่ยวข้อง เช่น ยืนยันว่าอินเทอร์เฟซที่เผยแพร่แล้วถูกหยุดไว้) โดยใช้การทดสอบ VTS vts_treble_vintf_vendor_test คุณสามารถใช้อินเทอร์เฟซ @VintfStability โดยไม่ต้องมีข้อกำหนดเหล่านี้ได้โดยเรียกใช้ AIBinder_forceDowngradeToLocalStability ในแบ็กเอนด์ NDK, android::Stability::forceDowngradeToLocalStability ในแบ็กเอนด์ C++, หรือ android.os.Binder#forceDowngradeToSystemStability ในแบ็กเอนด์ Java บนออบเจ็กต์ Binder ก่อนที่จะส่งไปยังกระบวนการอื่น

นอกจากนี้ ให้ปิดใช้แบ็กเอนด์ CPP เพื่อให้โค้ดย้ายได้มากที่สุดและหลีกเลี่ยงปัญหาที่อาจเกิดขึ้น เช่น ไลบรารีเพิ่มเติมที่ไม่จำเป็น

โปรดทราบว่าการใช้ backends ในตัวอย่างโค้ดต่อไปนี้ถูกต้อง เนื่องจากมีแบ็กเอนด์ 3 รายการ (Java, NDK และ CPP) โค้ดแสดงวิธีปิดใช้แบ็กเอนด์ CPP

    aidl_interface: {
        ...
        backends: {
            cpp: {
                enabled: false,
            },
        },
    }

ค้นหาอินเทอร์เฟซ AIDL HAL

อินเทอร์เฟซ AIDL ที่เสถียรของ AOSP สำหรับ HAL จะอยู่ในโฟลเดอร์ aidl ในไดเรกทอรีฐานเดียวกันกับอินเทอร์เฟซ HIDL

  • hardware/interfaces สำหรับอินเทอร์เฟซที่ฮาร์ดแวร์มักจะให้
  • frameworks/hardware/interfaces สำหรับอินเทอร์เฟซระดับสูงที่ให้กับฮาร์ดแวร์
  • system/hardware/interfaces สำหรับอินเทอร์เฟซระดับต่ำที่ให้บริการแก่ฮาร์ดแวร์

ใส่อินเทอร์เฟซส่วนขยายในhardware/interfaces ไดเรกทอรีย่อยอื่นๆ ใน vendor หรือ hardware

อินเทอร์เฟซส่วนขยาย

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

คุณสามารถลงทะเบียนส่วนขยายได้ 2 วิธีดังนี้

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

  • ส่งต่อการเพิ่มอินเทอร์เฟซไปยัง AOSP ในรุ่นถัดไป
  • การเพิ่มอินเทอร์เฟซสำหรับอัปสตรีมที่ช่วยเพิ่มความยืดหยุ่น (โดยไม่เกิดข้อขัดแย้งในการผสาน) ในรุ่นถัดไป

รายการที่แยกส่วนได้ของส่วนขยาย: ParcelableHolder

ParcelableHolder คืออินสแตนซ์ของอินเทอร์เฟซ Parcelable ที่อาจมีอินสแตนซ์อื่นของ Parcelable

กรณีการใช้งานหลักของ ParcelableHolder คือทำให้ Parcelable ขยายได้ เช่น รูปภาพที่ผู้ติดตั้งใช้งานอุปกรณ์คาดหวังว่าจะขยาย Parcelable, AospDefinedParcelable ที่ AOSP กำหนดให้มีฟีเจอร์ที่เพิ่มมูลค่า

ใช้อินเทอร์เฟซ ParcelableHolder เพื่อขยาย Parcelable ด้วยฟีเจอร์ที่เพิ่มมูลค่า อินเทอร์เฟซ ParcelableHolder มีอินสแตนซ์ของ Parcelable หากคุณพยายามเพิ่มช่องใน Parcelable โดยตรง ระบบจะแสดงข้อผิดพลาด

parcelable AospDefinedParcelable {
  int a;
  String b;
  String x; // ERROR: added by a device implementer
  int[] y; // added by a device implementer
}

ดังที่เห็นในโค้ดก่อนหน้า แนวทางปฏิบัตินี้ใช้ไม่ได้เนื่องจากช่องที่เพิ่มโดยผู้ติดตั้งใช้งานอุปกรณ์อาจขัดแย้งกันเมื่อมีการแก้ไข Parcelable ใน Android เวอร์ชันถัดไป

การใช้ ParcelableHolder ช่วยให้เจ้าของรายการที่แบ่งออกเป็นส่วนๆ สามารถกำหนดจุดขยายในอินสแตนซ์ของ Parcelable ดังนี้

parcelable AospDefinedParcelable {
  int a;
  String b;
  ParcelableHolder extension;
}

จากนั้นผู้ติดตั้งใช้งานอุปกรณ์จะกําหนดอินสแตนซ์ Parcelable ของตนเองสําหรับส่วนขยายได้ ดังนี้

parcelable OemDefinedParcelable {
  String x;
  int[] y;
}

คุณสามารถแนบอินสแตนซ์ Parcelable ใหม่ไปกับParcelable เดิมได้โดยใช้ช่อง ParcelableHolder ดังนี้


// Java
AospDefinedParcelable ap = ...;
OemDefinedParcelable op = new OemDefinedParcelable();
op.x = ...;
op.y = ...;

ap.extension.setParcelable(op);

...

OemDefinedParcelable op = ap.extension.getParcelable(OemDefinedParcelable.class);

// C++
AospDefinedParcelable ap;
OemDefinedParcelable op;
std::shared_ptr<OemDefinedParcelable> op_ptr = make_shared<OemDefinedParcelable>();

ap.extension.setParcelable(op);
ap.extension.setParcelable(op_ptr);

...

std::shared_ptr<OemDefinedParcelable> op_ptr;

ap.extension.getParcelable(&op_ptr);

// NDK
AospDefinedParcelable ap;
OemDefinedParcelable op;
ap.extension.setParcelable(op);

...

std::optional<OemDefinedParcelable> op;
ap.extension.getParcelable(&op);

// Rust
let mut ap = AospDefinedParcelable { .. };
let op = Rc::new(OemDefinedParcelable { .. });

ap.extension.set_parcelable(Rc::clone(&op));

...

let op = ap.extension.get_parcelable::<OemDefinedParcelable>();

ชื่ออินสแตนซ์เซิร์ฟเวอร์ AIDL HAL

ตามธรรมเนียมแล้ว บริการ AIDL HAL จะมีชื่ออินสแตนซ์ในรูปแบบ $package.$type/$instance เช่น อินสแตนซ์ของ HAL ของไวเบรเตอร์ได้รับการลงทะเบียนเป็น android.hardware.vibrator.IVibrator/default

เขียนเซิร์ฟเวอร์ AIDL HAL

@VintfStability คุณต้องประกาศเซิร์ฟเวอร์ AIDL ในไฟล์ Manifest ของ VINTF ดังนี้

    <hal format="aidl">
        <name>android.hardware.vibrator</name>
        <version>1</version>
        <fqname>IVibrator/default</fqname>
    </hal>

มิฉะนั้น ควรลงทะเบียนบริการ AIDL ตามปกติ เมื่อทำการทดสอบ VTS คาดว่า HAL ของ AIDL ที่ประกาศไว้ทั้งหมดจะพร้อมใช้งาน

เขียนไคลเอ็นต์ AIDL

ไคลเอ็นต์ AIDL ต้องประกาศตัวเองในตารางความเข้ากันได้ เช่น

    <hal format="aidl" optional="true">
        <name>android.hardware.vibrator</name>
        <version>1-2</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>

แปลง HAL ที่มีอยู่จาก HIDL เป็น AIDL

ใช้เครื่องมือ hidl2aidl เพื่อแปลงอินเทอร์เฟซ HIDL เป็น AIDL

ฟีเจอร์ของ hidl2aidl

  • สร้างไฟล์ AIDL (.aidl) ตามไฟล์ HAL (.hal) สําหรับแพ็กเกจที่ระบุ
  • สร้างกฎการสร้างสำหรับแพ็กเกจ AIDL ที่สร้างขึ้นใหม่โดยเปิดใช้แบ็กเอนด์ทั้งหมด
  • สร้างเมธอดการแปลในแบ็กเอนด์ Java, CPP และ NDK สำหรับการแปลจากประเภท HIDL เป็นประเภท AIDL
  • สร้างกฎการสร้างสำหรับไลบรารีการแปลที่มีข้อกำหนดที่จำเป็น
  • สร้างการยืนยันแบบคงที่เพื่อให้แน่ใจว่าตัวระบุรายการ HIDL และ AIDL มีค่าเดียวกันในแบ็กเอนด์ CPP และ NDK

ทําตามขั้นตอนต่อไปนี้เพื่อแปลงแพ็กเกจไฟล์ HAL เป็นไฟล์ AIDL

  1. สร้างเครื่องมือที่อยู่ใน system/tools/hidl/hidl2aidl

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

    m hidl2aidl
  2. เรียกใช้เครื่องมือด้วยไดเรกทอรีเอาต์พุตตามด้วยแพ็กเกจที่จะแปลง

    (ไม่บังคับ) ใช้อาร์กิวเมนต์ -l เพื่อเพิ่มเนื้อหาของไฟล์ใบอนุญาตใหม่ไว้ที่ด้านบนของไฟล์ที่สร้างขึ้นทั้งหมด ตรวจสอบว่าคุณใช้ใบอนุญาตและวันที่ที่ถูกต้อง

    hidl2aidl -o <output directory> -l <file with license> <package>

    เช่น

    hidl2aidl -o . -l my_license.txt android.hardware.nfc@1.2
  3. อ่านไฟล์ที่สร้างขึ้นและแก้ไขปัญหาเกี่ยวกับการแปลง

    • conversion.log มีปัญหาที่ยังไม่ได้จัดการซึ่งต้องแก้ไขก่อน
    • ไฟล์ AIDL ที่สร้างขึ้นอาจมีคำเตือนและคำแนะนำที่จำเป็นต้องดำเนินการ ความคิดเห็นเหล่านี้ขึ้นต้นด้วย //
    • ล้างข้อมูลและปรับปรุงแพ็กเกจ
    • ตรวจสอบคำอธิบายประกอบ @JavaDerive เพื่อดูฟีเจอร์ที่อาจต้องใช้ เช่น toString หรือ equals
  4. สร้างเฉพาะเป้าหมายที่ต้องการ

    • ปิดใช้แบ็กเอนด์ที่จะไม่ใช้งาน ใช้แบ็กเอนด์ NDK แทนแบ็กเอนด์ CPP ดูการสร้างกับรันไทม์ AIDL
    • นำไลบรารีการแปลหรือโค้ดที่สร้างขึ้นซึ่งจะไม่ได้ใช้ออก
  5. ดูความแตกต่างที่สำคัญระหว่าง AIDL กับ HIDL

    • โดยทั่วไปแล้ว การใช้ Status และข้อยกเว้นในตัวของ AIDL จะปรับปรุงอินเทอร์เฟซและทำให้ไม่จำเป็นต้องมีสถานะประเภทอื่นสำหรับอินเทอร์เฟซ
    • อาร์กิวเมนต์อินเทอร์เฟซ AIDL ในเมธอดจะไม่เป็น @nullable โดยค่าเริ่มต้นเหมือนใน HIDL

SEPolicy สำหรับ AIDL HAL

ประเภทบริการ AIDL ที่แสดงต่อรหัสผู้ให้บริการต้องมีแอตทริบิวต์ hal_service_type มิเช่นนั้น การกําหนดค่า sepolicy จะเหมือนกับบริการ AIDL อื่นๆ (แม้ว่าจะมีแอตทริบิวต์พิเศษสําหรับ HAL) ตัวอย่างคำจำกัดความของบริบทบริการ HAL มีดังนี้

    type hal_foo_service, service_manager_type, hal_service_type;

สําหรับบริการส่วนใหญ่ที่แพลตฟอร์มกําหนดไว้ ระบบจะเพิ่มบริบทบริการที่มีประเภทที่ถูกต้องอยู่แล้ว (เช่น android.hardware.foo.IFoo/default มีการทำเครื่องหมายเป็น hal_foo_service อยู่แล้ว) อย่างไรก็ตาม หากไคลเอ็นต์เฟรมเวิร์กรองรับชื่ออินสแตนซ์หลายรายการ คุณต้องเพิ่มชื่ออินสแตนซ์เพิ่มเติมในไฟล์ service_contexts สำหรับอุปกรณ์แต่ละเครื่อง ดังนี้

    android.hardware.foo.IFoo/custom_instance u:object_r:hal_foo_service:s0

เมื่อสร้าง HAL ประเภทใหม่ คุณต้องเพิ่มแอตทริบิวต์ HAL แอตทริบิวต์ HAL ที่เฉพาะเจาะจงอาจเชื่อมโยงกับบริการหลายประเภท (แต่ละประเภทอาจมีอินสแตนซ์หลายรายการตามที่ได้กล่าวไปก่อนหน้านี้) สำหรับ HAL foo จะมี hal_attribute(foo) มาโครนี้กําหนดแอตทริบิวต์ hal_foo_client และ hal_foo_server สำหรับโดเมนหนึ่งๆ มาโคร hal_client_domain และ hal_server_domain จะเชื่อมโยงโดเมนกับแอตทริบิวต์ HAL ที่ระบุ ตัวอย่างเช่น เซิร์ฟเวอร์ระบบที่เป็นไคลเอ็นต์ของ HAL นี้สอดคล้องกับนโยบาย hal_client_domain(system_server, hal_foo) เซิร์ฟเวอร์ HAL ก็มี hal_server_domain(my_hal_domain, hal_foo) เช่นเดียวกัน

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

อย่างไรก็ตาม จนถึงตอนนี้ hal_foo_service และ hal_foo (คู่แอตทริบิวต์จาก hal_attribute(foo)) ยังไม่ได้เชื่อมโยงกัน แอตทริบิวต์ HAL จะเชื่อมโยงกับบริการ AIDL HAL โดยใช้มาโคร hal_attribute_service (HIDL HAL ใช้มาโคร hal_attribute_hwservice) เช่น hal_attribute_service(hal_foo, hal_foo_service) ซึ่งหมายความว่าhal_foo_clientกระบวนการจะเข้าถึง HAL ได้ และhal_foo_serverกระบวนการจะลงทะเบียน HAL ได้ ผู้จัดการบริบท (servicemanager) จะเป็นผู้บังคับใช้กฎการจดทะเบียนเหล่านี้

ชื่อบริการอาจไม่ตรงกับแอตทริบิวต์ HAL เสมอไป เช่น hal_attribute_service(hal_foo, hal_foo2_service) โดยทั่วไปแล้ว คุณสามารถนำ hal_foo2_service ออกและใช้ hal_foo_service กับบริบทบริการทั้งหมดได้ เนื่องจากประโยคนี้บอกเป็นนัยว่าบริการดังกล่าวใช้ร่วมกันเสมอ เมื่อ HAL ตั้งค่าอินสแตนซ์ hal_attribute_service หลายรายการ แสดงว่าชื่อแอตทริบิวต์ HAL เดิมไม่ทั่วไปพอและเปลี่ยนไม่ได้

เมื่อรวมทั้งหมดเข้าด้วยกัน ตัวอย่าง HAL จะมีลักษณะดังนี้

    public/attributes:
    // define hal_foo, hal_foo_client, hal_foo_server
    hal_attribute(foo)

    public/service.te
    // define hal_foo_service
    type hal_foo_service, hal_service_type, protected_service, service_manager_type

    public/hal_foo.te:
    // allow binder connection from client to server
    binder_call(hal_foo_client, hal_foo_server)
    // allow client to find the service, allow server to register the service
    hal_attribute_service(hal_foo, hal_foo_service)
    // allow binder communication from server to service_manager
    binder_use(hal_foo_server)

    private/service_contexts:
    // bind an AIDL service name to the selinux type
    android.hardware.foo.IFooXxxx/default u:object_r:hal_foo_service:s0

    private/<some_domain>.te:
    // let this domain use the hal service
    binder_use(some_domain)
    hal_client_domain(some_domain, hal_foo)

    vendor/<some_hal_server_domain>.te
    // let this domain serve the hal service
    hal_server_domain(some_hal_server_domain, hal_foo)

อินเทอร์เฟซส่วนขยายที่แนบมา

ส่วนขยายจะแนบไปกับอินเทอร์เฟซ Binder ใดก็ได้ ไม่ว่าจะเป็นอินเทอร์เฟซระดับบนสุดที่ลงทะเบียนกับ Service Manager โดยตรงหรืออินเทอร์เฟซย่อย เมื่อได้รับส่วนขยาย คุณต้องยืนยันว่าประเภทส่วนขยายเป็นไปตามที่คาดไว้ คุณตั้งค่าส่วนขยายได้เฉพาะจากกระบวนการที่แสดง Binder เท่านั้น

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

หากต้องการตั้งค่าส่วนขยายใน Binder ให้ใช้ API ต่อไปนี้

  • แบ็กเอนด์ NDK: AIBinder_setExtension
  • แบ็กเอนด์ Java: android.os.Binder.setExtension
  • แบ็กเอนด์ CPP: android::Binder::setExtension
  • แบ็กเอนด์ Rust: binder::Binder::set_extension

หากต้องการรับส่วนขยายใน Binder ให้ใช้ API ต่อไปนี้

  • แบ็กเอนด์ NDK: AIBinder_getExtension
  • แบ็กเอนด์ Java: android.os.IBinder.getExtension
  • แบ็กเอนด์ CPP: android::IBinder::getExtension
  • แบ็กเอนด์ Rust: binder::Binder::get_extension

ดูข้อมูลเพิ่มเติมสำหรับ API เหล่านี้ได้ในเอกสารประกอบของฟังก์ชัน getExtension ในแบ็กเอนด์ที่เกี่ยวข้อง ตัวอย่างวิธีใช้ส่วนขยายมีอยู่ในhardware/interfaces/tests/extension/vibrator

ความแตกต่างที่สำคัญระหว่าง AIDL กับ HIDL

เมื่อใช้ AIDL HAL หรือใช้อินเทอร์เฟซ AIDL HAL โปรดทราบว่ามีความแตกต่างเมื่อเทียบกับการเขียน HIDL HAL

  • ไวยากรณ์ของภาษา AIDL ใกล้เคียงกับ Java มากกว่า ไวยากรณ์ HIDL คล้ายกับ C++
  • อินเทอร์เฟซ AIDL ทั้งหมดมีสถานะข้อผิดพลาดในตัว แทนที่จะสร้างประเภทสถานะที่กำหนดเอง ให้สร้าง int สถานะคงที่ในไฟล์อินเทอร์เฟซ และใช้ EX_SERVICE_SPECIFIC ในแบ็กเอนด์ CPP และ NDK และ ServiceSpecificException ในแบ็กเอนด์ Java ดูการจัดการข้อผิดพลาด
  • AIDL จะไม่เริ่มต้นพูลเธรดโดยอัตโนมัติเมื่อส่งออบเจ็กต์ Binder โดยคุณต้องเริ่มชุดข้อความด้วยตนเอง (ดูการจัดการชุดข้อความ)
  • AIDL จะไม่หยุดทำงานเมื่อมีข้อผิดพลาดในการขนส่งที่ไม่ได้ตรวจสอบ (HIDL Return จะหยุดทำงานเมื่อมีข้อผิดพลาดที่ไม่ได้ตรวจสอบ)
  • AIDL ประกาศได้เพียง 1 ประเภทต่อไฟล์
  • อาร์กิวเมนต์ AIDL สามารถระบุเป็น in, out หรือ inout นอกเหนือจากพารามิเตอร์เอาต์พุต (ไม่มีการเรียกกลับแบบซิงค์)
  • AIDL ใช้ fd เป็นประเภทพื้นฐานแทน handle
  • HIDL ใช้เวอร์ชันหลักสำหรับการเปลี่ยนแปลงที่เข้ากันไม่ได้และเวอร์ชันย่อยสำหรับการเปลี่ยนแปลงที่เข้ากันได้ ใน AIDL จะมีการเปลี่ยนแปลงที่เข้ากันได้แบบย้อนหลัง AIDL ไม่มีแนวคิดที่ชัดเจนเกี่ยวกับเวอร์ชันหลัก แต่รวมไว้ในชื่อแพ็กเกจแทน เช่น AIDL อาจใช้ชื่อแพ็กเกจ bluetooth2
  • AIDL จะไม่รับค่าลำดับความสำคัญแบบเรียลไทม์โดยค่าเริ่มต้น ต้องใช้ฟังก์ชัน setInheritRt ต่อ Binder เพื่อเปิดใช้การสืบทอดลําดับความสําคัญแบบเรียลไทม์

การทดสอบชุดทดสอบของผู้ให้บริการ (VTS) สําหรับ HAL

Android อาศัยชุดทดสอบของผู้ให้บริการ (VTS) เพื่อยืนยันการติดตั้งใช้งาน HAL ที่คาดไว้ VTS ช่วยให้มั่นใจได้ว่า Android จะใช้งานร่วมกับการใช้งานเดิมของผู้ให้บริการได้ การติดตั้งใช้งานที่ไม่ผ่าน VTS มีปัญหาความเข้ากันได้ที่ทราบกันดี ซึ่งอาจทำให้ใช้งานกับระบบปฏิบัติการเวอร์ชันในอนาคตไม่ได้

VTS สำหรับ HAL ประกอบด้วย 2 ส่วนหลักๆ ดังนี้

1. ยืนยันว่า Android รู้จักและคาดหวัง HAL ในอุปกรณ์

ชุดการทดสอบนี้อยู่ใน test/vts-testcase/hal/treble/vintf การทดสอบเหล่านี้มีหน้าที่รับผิดชอบในการยืนยันสิ่งต่อไปนี้

  • อินเทอร์เฟซ @VintfStability ทั้งหมดที่ประกาศในไฟล์ Manifest ของ VINTF จะหยุดอยู่ที่เวอร์ชันที่เผยแพร่แล้วซึ่งทราบ วิธีนี้ช่วยให้มั่นใจว่าอินเทอร์เฟซทั้ง 2 ด้านจะยอมรับคำจำกัดความที่แน่นอนของอินเทอร์เฟซเวอร์ชันนั้น ซึ่งจำเป็นต่อการดำเนินการขั้นพื้นฐาน
  • HAL ทั้งหมดที่ประกาศในไฟล์ Manifest ของ VINTF จะพร้อมใช้งานในอุปกรณ์นั้น ไคลเอ็นต์ที่มีสิทธิ์เพียงพอในการใช้บริการ HAL ที่ประกาศไว้ต้องสามารถรับและใช้บริการเหล่านั้นได้ทุกเมื่อ
  • HAL ทั้งหมดที่ประกาศในไฟล์ Manifest ของ VINTF จะแสดงอินเทอร์เฟซเวอร์ชันที่ประกาศไว้ในไฟล์ Manifest
  • ไม่มี HAL ที่เลิกใช้งานแสดงในอุปกรณ์ Android จะหยุดรองรับอินเทอร์เฟซ HAL เวอร์ชันที่ต่ำกว่าตามที่อธิบายไว้ในวงจรชีวิตของ FCM
  • มี HAL ที่จำเป็นในอุปกรณ์ HAL บางรายการจําเป็นต่อการทํางานของ Android

2. ยืนยันลักษณะการทำงานที่คาดไว้ของ HAL แต่ละรายการ

อินเทอร์เฟซ HAL แต่ละรายการมีการทดสอบ VTS เป็นของตัวเองเพื่อยืนยันลักษณะการทำงานที่คาดหวังจากไคลเอ็นต์ เทสเคสจะทํางานกับอินสแตนซ์ HAL ทั้งหมดที่ประกาศไว้และบังคับใช้ลักษณะการทํางานเฉพาะตามเวอร์ชันของอินเทอร์เฟซที่ติดตั้งใช้งาน

การทดสอบเหล่านี้พยายามครอบคลุมทุกแง่มุมของการใช้งาน HAL ที่เฟรมเวิร์ก Android ต้องใช้หรืออาจต้องใช้ในอนาคต

การทดสอบเหล่านี้รวมถึงการยืนยันการรองรับฟีเจอร์ การจัดการข้อผิดพลาด และลักษณะการทำงานอื่นๆ ที่ไคลเอ็นต์อาจคาดหวังจากบริการ

เหตุการณ์สำคัญ VTS สำหรับการพัฒนา HAL

คุณควรอัปเดตการทดสอบ VTS เมื่อสร้างหรือแก้ไขอินเทอร์เฟซ HAL ของ Android

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

VTS ใน Cuttlefish

เมื่อไม่มีฮาร์ดแวร์ Android จะใช้ Cuttlefish เป็นแพลตฟอร์มการพัฒนาสำหรับอินเทอร์เฟซ HAL ซึ่งช่วยให้ VTS และทดสอบการผสานรวมของ Android ปรับขนาดได้

hal_implementation_test ทดสอบว่า Cuttlefish มีการใช้งานอินเทอร์เฟซ HAL เวอร์ชันล่าสุดเพื่อให้แน่ใจว่า Android พร้อมจัดการอินเทอร์เฟซใหม่ และการทดสอบ VTS พร้อมทดสอบการใช้งานของผู้ให้บริการรายใหม่ทันทีที่มีฮาร์ดแวร์และอุปกรณ์ใหม่