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 และ Talk ในวันที่ /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 ที่ 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
}

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