AIDL สำหรับ HAL

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

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

แรงจูงใจ

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

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

สร้างเทียบกับรันไทม์ของ AIDL

AIDL มีแบ็กเอนด์ 3 แบบ ได้แก่ Java, NDK และ CPP หากต้องการใช้ AIDL เวอร์ชันเสถียร คุณต้องใช้สำเนาของ libbinder ของระบบที่ system/lib*/libbinder.so และพูดกับ /dev/binder เสมอ สำหรับโค้ดในอิมเมจผู้ให้บริการ คุณจะใช้ 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 ก่อนที่จะส่งไปยังกระบวนการอื่น การดาวน์เกรดบริการเป็นความเสถียรของผู้ให้บริการไม่รองรับใน Java เนื่องจากแอปทั้งหมดทำงานในบริบทของระบบ

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

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

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

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

อินเทอร์เฟซ AOSP Stable AIDL สำหรับ HAL อยู่ในไดเรกทอรีพื้นฐานเดียวกันกับอินเทอร์เฟซ HIDL ในโฟลเดอร์ aidl

  • ฮาร์ดแวร์/อินเทอร์เฟซ
  • เฟรมเวิร์ก/ฮาร์ดแวร์/อินเทอร์เฟซ
  • ระบบ/ฮาร์ดแวร์/อินเทอร์เฟซ

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

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

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

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

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

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

ส่วนขยายพาร์เซล: ParcelableHolder

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

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

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 ควรมี AIDL HAL ที่ประกาศทั้งหมดพร้อมใช้งาน

เขียนไคลเอ็นต์ 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 ไฟล์ตามไฟล์ .hal สำหรับแพ็กเกจที่ระบุ
  • สร้างกฎสำหรับบิลด์สำหรับแพ็กเกจ AIDL ที่สร้างใหม่ที่เปิดใช้แบ็กเอนด์ทั้งหมด
  • สร้างวิธีการแปลในแบ็กเอนด์ Java, CPP และ NDK สำหรับการแปลจากประเภท HIDL เป็นประเภท AIDL
  • สร้างกฎการสร้างสำหรับไลบรารีการแปลที่มีทรัพยากร Dependency ที่จำเป็น
  • สร้างการยืนยันแบบคงที่เพื่อให้แน่ใจว่าเครื่องมือแจกแจง 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

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

    • ปิดใช้แบ็กเอนด์ที่จะไม่ใช้ หากต้องการใช้แบ็กเอนด์ NDK แทนแบ็กเอนด์ CPP โปรดดูการเลือกรันไทม์
    • นำไลบรารีการแปลภาษาหรือโค้ดที่สร้างขึ้นซึ่งไม่มีการใช้งานออก
  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 ที่ระบุ เราจะสร้างโดเมน เช่น hal_foo_default สำหรับการอ้างอิงหรือ 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 ในแบ็กเอนด์ที่เกี่ยวข้อง ดูตัวอย่างวิธีใช้ส่วนขยายได้ในฮาร์ดแวร์/อินเทอร์เฟซ/การทดสอบ/ส่วนขยาย/ไวเบรเตอร์

ความแตกต่างของ AIDL และ HIDL ที่สำคัญ

เมื่อใช้ AIDL HAL หรือใช้อินเทอร์เฟซ AIDL HAL คุณควรคำนึงถึงความแตกต่างเมื่อเทียบกับการเขียน HIDL HAL

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