AIDL สำหรับ HALs

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

การเขียนอินเตอร์เฟส AIDL HAL

สำหรับอินเทอร์เฟซ AIDL ที่จะใช้ระหว่างระบบและผู้จำหน่าย อินเทอร์เฟซจำเป็นต้องเปลี่ยนแปลงสองอย่าง:

  • คำจำกัดความทุกประเภทต้องใส่คำอธิบายประกอบด้วย @VintfStability
  • การประกาศ aidl_interface จำเป็นต้องมี stability: "vintf", .

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

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

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

โปรดทราบว่าการใช้ backends ในตัวอย่างโค้ดด้านล่างนั้นถูกต้อง เนื่องจากมีแบ็กเอนด์สามส่วน (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 จะทำงานต่อไปได้

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

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

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

Parcelables ส่วนขยาย: ParcelableHolder

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

ก่อนหน้านี้หากไม่มี 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

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

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

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

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

ต้องประกาศเซิร์ฟเวอร์ @VintfStability AIDL ในรายการ 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
  • สร้างกฎการสร้างสำหรับไลบรารีแปลที่มีการขึ้นต่อกันที่จำเป็น
  • สร้างการยืนยันแบบคงที่เพื่อให้แน่ใจว่าตัวแจงนับ HIDL และ AIDL มีค่าเดียวกันในแบ็กเอนด์ CPP และ NDK

ทำตามขั้นตอนเหล่านี้เพื่อแปลงแพ็คเกจของไฟล์ .hal เป็นไฟล์ .aidl:

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

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

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

    hidl2aidl -o <output directory> <package>
    

    ตัวอย่างเช่น:

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

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

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

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

Sepolicy สำหรับ AIDL HALs

ประเภทบริการ AIDL ซึ่งรหัสผู้ขายสามารถมองเห็นได้ต้องมีแอตทริบิวต์ vendor_service มิฉะนั้น คอนฟิกูเรชัน sepolicy จะเหมือนกับบริการ AIDL อื่นๆ (แม้ว่าจะมีแอตทริบิวต์พิเศษสำหรับ HAL) นี่คือตัวอย่างคำจำกัดความของบริบทบริการ HAL:

    type hal_foo_service, service_manager_type, vendor_service;

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

อย่างไรก็ตาม จนถึงตอนนี้ เรายังไม่ได้เชื่อมโยง 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, vendor_service, 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_call(hal_foo_server, servicemanager)

    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
    binder_use(some_hal_server_domain)
    hal_server_domain(some_hal_server_domain, hal_foo)

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

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

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

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

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

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

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

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

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

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

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