AIDL ที่เสถียร

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

Android 10 เพิ่มการรองรับ Android Interface Definition Language (AIDL) ที่เสถียร ซึ่งเป็นวิธีใหม่ในการติดตาม application program interface (API)/application binary interface (ABI) ที่จัดเตรียมโดย AIDL interfaces AIDL ที่เสถียรมีความแตกต่างที่สำคัญต่อไปนี้จาก AIDL:

  • อินเตอร์เฟสถูกกำหนดไว้ในระบบบิลด์ด้วย aidl_interfaces
  • อินเทอร์เฟซสามารถมีได้เฉพาะข้อมูลที่มีโครงสร้าง Parcelables ที่แสดงประเภทที่ต้องการจะถูกสร้างขึ้นโดยอัตโนมัติตามคำจำกัดความของ AIDL และจะถูกจัดเรียงและยกเลิกการจัดเรียงโดยอัตโนมัติ
  • อินเตอร์เฟสสามารถประกาศได้ว่าเสถียร (เข้ากันได้กับรุ่นหลัง) เมื่อสิ่งนี้เกิดขึ้น API ของพวกเขาจะถูกติดตามและกำหนดเวอร์ชันในไฟล์ถัดจากอินเทอร์เฟซ AIDL

การกำหนดอินเตอร์เฟส AIDL

คำจำกัดความของ aidl_interface มีลักษณะดังนี้:

aidl_interface {
    name: "my-aidl",
    srcs: ["srcs/aidl/**/*.aidl"],
    local_include_dir: "srcs/aidl",
    imports: ["other-aidl"],
    versions_with_info: [
        {
            version: "1",
            imports: ["ohter-aidl-V1"],
        },
        {
            version: "2",
            imports: ["other-aidl-V3"],
        }
    ],
    stability: "vintf",
    backend: {
        java: {
            enabled: true,
            platform_apis: true,
        },
        cpp: {
            enabled: true,
        },
        ndk: {
            enabled: true,
        },
        rust: {
            enabled: true,
        },
    },

}
  • name : ชื่อของโมดูลอินเทอร์เฟซ AIDL ที่ระบุอินเทอร์เฟซ AIDL โดยไม่ซ้ำกัน
  • srcs : รายการไฟล์ต้นฉบับ AIDL ที่ประกอบอินเทอร์เฟซ เส้นทางสำหรับ AIDL ประเภท Foo ที่กำหนดไว้ในแพ็คเกจ com.acme ควรอยู่ที่ <base_path>/com/acme/Foo.aidl โดยที่ <base_path> อาจเป็นไดเร็กทอรีใดๆ ที่เกี่ยวข้องกับไดเร็กทอรีที่ Android.bp อยู่ ในตัวอย่างข้างต้น <base_path> คือ srcs/aidl
  • local_include_dir : เส้นทางที่เริ่มต้นชื่อแพ็คเกจ ซึ่งสอดคล้องกับ <base_path> อธิบายไว้ข้างต้น
  • imports : รายการของโมดูล aidl_interface ที่ใช้ หากหนึ่งในอินเทอร์เฟซ AIDL ของคุณใช้อินเทอร์เฟซหรือพัสดุจาก aidl_interface อื่น ให้ใส่ชื่อที่นี่ ซึ่งอาจเป็นชื่อโดยตัวมันเอง เพื่ออ้างถึงเวอร์ชันล่าสุด หรือชื่อที่มีคำต่อท้ายเวอร์ชัน (เช่น -V1 ) เพื่ออ้างถึงเวอร์ชันเฉพาะ การระบุเวอร์ชันได้รับการสนับสนุนตั้งแต่ Android 12
  • versions : เวอร์ชันก่อนหน้าของอินเทอร์เฟซที่ถูกระงับภายใต้ api_dir เริ่มตั้งแต่ Android 11 versions จะถูกตรึงไว้ภายใต้ aidl_api/ name หากไม่มีอินเทอร์เฟซเวอร์ชันค้าง ก็ไม่ควรระบุสิ่งนี้ และจะไม่มีการตรวจสอบความเข้ากันได้ ฟิลด์นี้ถูกแทนที่ด้วย versions_with_info สำหรับ 13 และสูงกว่า
  • versions_with_info : รายการของทูเพิล ซึ่งแต่ละอันมีชื่อของเวอร์ชันที่ตรึงไว้ และรายการที่มีเวอร์ชันอิมพอร์ตของโมดูล คำจำกัดความของเวอร์ชัน V ของอินเทอร์เฟซ AIDL IFACE อยู่ที่ aidl_api/ IFACE / V ฟิลด์นี้ได้รับการแนะนำใน Android 13 และไม่ควรแก้ไขใน Android.bp โดยตรง ฟิลด์นี้ถูกเพิ่มหรืออัปเดตโดยการเรียกใช้ *-update-api หรือ *-freeze-api นอกจากนี้ ฟิลด์ versions จะถูกย้ายไปยัง versions_with_info โดยอัตโนมัติเมื่อผู้ใช้เรียกใช้ *-update-api หรือ *-freeze-api
  • stability : แฟล็กทางเลือกสำหรับสัญญาความเสถียรของอินเทอร์เฟซนี้ ขณะนี้รองรับเฉพาะ "vintf" หากไม่ได้ตั้งค่า สิ่งนี้จะสอดคล้องกับอินเทอร์เฟซที่มีความเสถียรภายในบริบทการคอมไพล์นี้ (ดังนั้นอินเทอร์เฟซที่โหลดที่นี่จึงใช้ได้กับสิ่งที่คอมไพล์ไว้ด้วยกันเท่านั้น เช่น บน system.img) หากตั้งค่าเป็น "vintf" สิ่งนี้จะสอดคล้องกับคำมั่นสัญญาด้านความเสถียร: อินเทอร์เฟซจะต้องคงความเสถียรตราบเท่าที่มีการใช้งาน
  • gen_trace : แฟล็กเผื่อเลือกเพื่อเปิดหรือปิดการติดตาม ค่าเริ่มต้นเป็น false
  • host_supported : แฟล็กทางเลือกที่เมื่อตั้งค่า true จะทำให้ไลบรารีที่สร้างขึ้นพร้อมใช้งานสำหรับสภาพแวดล้อมโฮสต์
  • unstable : แฟล็กตัวเลือกที่ใช้เพื่อทำเครื่องหมายว่าอินเทอร์เฟซนี้ไม่จำเป็นต้องเสถียร เมื่อตั้งค่า true ระบบบิลด์จะไม่สร้างดัมพ์ API สำหรับอินเทอร์เฟซหรือกำหนดให้อัปเดต
  • backend.<type>.enabled : แฟล็กเหล่านี้สลับแบ็คเอนด์แต่ละอันที่คอมไพเลอร์ AIDL สร้างโค้ดให้ ปัจจุบัน รองรับแบ็กเอนด์ 4 รายการ ได้แก่ Java, C++, NDK และ Rust แบ็กเอนด์ Java, C++ และ NDK เปิดใช้งานโดยค่าเริ่มต้น หากไม่ต้องการแบ็กเอนด์ใดในสามนี้ จำเป็นต้องปิดการใช้งานอย่างชัดเจน สนิมถูกปิดใช้งานตามค่าเริ่มต้น
  • backend.<type>.apex_available : รายการชื่อ APEX ที่ห้องสมุด stub สร้างขึ้นพร้อมใช้งาน
  • backend.[cpp|java].gen_log : แฟล็กทางเลือกที่ควบคุมว่าจะสร้างโค้ดเพิ่มเติมสำหรับการรวบรวมข้อมูลเกี่ยวกับธุรกรรมหรือไม่
  • backend.[cpp|java].vndk.enabled : แฟล็กทางเลือกเพื่อทำให้อินเทอร์เฟซนี้เป็นส่วนหนึ่งของ VNDK ค่าเริ่มต้นเป็น false
  • backend.java.platform_apis : แฟล็กเผื่อเลือกที่ควบคุมว่าไลบรารี Java stub สร้างขึ้นเทียบกับ API ส่วนตัวจากแพลตฟอร์มหรือไม่ สิ่งนี้ควรตั้งค่าเป็น "true" เมื่อตั้งค่า stability เป็น "vintf"
  • backend.java.sdk_version : แฟล็กเผื่อเลือกสำหรับการระบุเวอร์ชันของ SDK ที่ไลบรารี Java stub สร้างขึ้น ค่าเริ่มต้นคือ "system_current" ไม่ควรตั้งค่านี้เมื่อ backend.java.platform_apis เป็นจริง
  • backend.java.platform_apis : แฟล็กทางเลือกที่ควรตั้งค่า true เมื่อไลบรารีที่สร้างขึ้นจำเป็นต้องสร้างจากแพลตฟอร์ม API แทนที่จะเป็น SDK

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

การเขียนไฟล์ AIDL

ส่วนต่อประสานใน AIDL ที่เสถียรนั้นคล้ายกับส่วนต่อประสานแบบดั้งเดิม โดยมีข้อยกเว้นว่าจะไม่ได้รับอนุญาตให้ใช้พัสดุที่ไม่มีโครงสร้าง (เพราะสิ่งเหล่านี้ไม่เสถียร!) ความแตกต่างหลักใน AIDL ที่เสถียรคือวิธีการกำหนดพัสดุ ก่อนหน้านี้ มีการ ประกาศส่งต่อ พัสดุภัณฑ์ ; ใน AIDL ที่เสถียร ฟิลด์และตัวแปรที่แยกได้ของพัสดุจะถูกกำหนดไว้อย่างชัดเจน

// in a file like 'some/package/Thing.aidl'
package some.package;

parcelable SubThing {
    String a = "foo";
    int b;
}

ขณะนี้ค่าดีฟอลต์ได้รับการสนับสนุน (แต่ไม่จำเป็น) สำหรับ boolean , char , float , double , byte , int , long และ String ใน Android 12 รองรับค่าเริ่มต้นสำหรับการแจงนับที่ผู้ใช้กำหนด เมื่อไม่ได้ระบุค่าเริ่มต้น จะใช้ค่าเหมือน 0 หรือค่าว่าง การแจงนับที่ไม่มีค่าเริ่มต้นจะเริ่มต้นเป็น 0 แม้ว่าจะไม่มีตัวแจงนับเป็นศูนย์ก็ตาม

การใช้ห้องสมุดต้นขั้ว

หลังจากเพิ่ม stub libraries เป็นการอ้างอิงไปยังโมดูลของคุณแล้ว คุณสามารถรวมไว้ในไฟล์ของคุณได้ ต่อไปนี้เป็นตัวอย่างของ stub libraries ในระบบบิลด์ ( Android.mk สามารถใช้สำหรับคำจำกัดความของโมดูลเดิมได้เช่นกัน):

cc_... {
    name: ...,
    shared_libs: ["my-module-name-cpp"],
    ...
}
# or
java_... {
    name: ...,
    // can also be shared_libs if desire is to load a library and share
    // it among multiple users or if you only need access to constants
    static_libs: ["my-module-name-java"],
    ...
}
# or
rust_... {
    name: ...,
    rust_libs: ["my-module-name-rust"],
    ...
}

ตัวอย่างใน C ++:

#include "some/package/IFoo.h"
#include "some/package/Thing.h"
...
    // use just like traditional AIDL

ตัวอย่างในภาษาจาวา:

import some.package.IFoo;
import some.package.Thing;
...
    // use just like traditional AIDL

ตัวอย่างในสนิม:

use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
    // use just like traditional AIDL

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

การประกาศโมดูลด้วยชื่อ foo ยังสร้างเป้าหมายในระบบบิลด์ที่คุณสามารถใช้เพื่อจัดการ API ของโมดูล เมื่อสร้างแล้ว foo-freeze-api จะเพิ่มข้อกำหนด API ใหม่ภายใต้ api_dir หรือ aidl_api/ name ทั้งนี้ขึ้นอยู่กับเวอร์ชัน Android และเพิ่มไฟล์ .hash ซึ่งทั้งคู่แสดงถึงอินเทอร์เฟซเวอร์ชันที่แช่แข็งใหม่ foo-freeze-api ยังอัปเดตคุณสมบัติversion_with_infoเพื่อแสดง versions_with_info เพิ่มเติมและ imports สำหรับเวอร์ชันนั้น โดยพื้นฐานแล้ว imports ใน versions_with_info จะถูกคัดลอกจากฟิลด์ imports แต่มีการระบุเวอร์ชันเสถียรล่าสุดใน imports ใน versions_with_info สำหรับการนำเข้าที่ไม่มีเวอร์ชันที่ชัดเจน เมื่อระบุคุณสมบัติversion_with_infoแล้ว ระบบ build จะรันการตรวจสอบความเข้ากันได้ระหว่าง versions_with_info ที่แช่แข็งและระหว่าง Top of Tree (ToT) และเวอร์ชันที่แช่แข็งล่าสุด

นอกจากนี้ คุณต้องจัดการข้อกำหนด API ของเวอร์ชัน ToT เมื่อใดก็ตามที่อัปเดต API ให้เรียกใช้ foo-update-api เพื่ออัปเดต aidl_api/ name /current ซึ่งมีข้อกำหนด API ของเวอร์ชัน ToT

เพื่อรักษาความเสถียรของอินเทอร์เฟซ เจ้าของสามารถเพิ่ม:

  • เมธอดไปยังส่วนท้ายของอินเทอร์เฟซ (หรือเมธอดที่มีซีเรียลใหม่ที่กำหนดไว้อย่างชัดเจน)
  • องค์ประกอบที่ส่วนท้ายของพัสดุ (ต้องเพิ่มค่าเริ่มต้นสำหรับแต่ละองค์ประกอบ)
  • ค่าคงที่
  • ใน Android 11 ตัวแจงนับ
  • ใน Android 12 ช่องต่อท้ายสหภาพ

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

หากต้องการทดสอบว่าอินเทอร์เฟซทั้งหมดหยุดทำงานเพื่อเผยแพร่ คุณสามารถสร้างด้วยชุดตัวแปรสภาพแวดล้อมต่อไปนี้:

  • AIDL_FROZEN_REL=true m ... - บิลด์ต้องการอินเตอร์เฟส AIDL ที่เสถียรทั้งหมดที่จะหยุดทำงานซึ่งไม่มี owner: ระบุฟิลด์
  • AIDL_FROZEN_OWNERS="aosp test" - build ต้องการให้อินเตอร์เฟส AIDL ที่เสถียรทั้งหมดถูกตรึงไว้กับ owner: ฟิลด์ที่ระบุเป็น "aosp" หรือ "test"

เสถียรภาพของการนำเข้า

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

ในรหัสแพลตฟอร์ม Android android.hardware.graphics.common เป็นตัวอย่างที่ใหญ่ที่สุดของการอัปเกรดเวอร์ชันประเภทนี้

การใช้อินเทอร์เฟซเวอร์ชัน

วิธีการเชื่อมต่อ

ที่รันไทม์ เมื่อพยายามเรียกเมธอดใหม่บนเซิร์ฟเวอร์เก่า ไคลเอนต์ใหม่จะได้รับข้อผิดพลาดหรือข้อยกเว้น ขึ้นอยู่กับแบ็กเอนด์

  • แบ็กเอนด์ cpp ได้รับ ::android::UNKNOWN_TRANSACTION
  • แบ็กเอนด์ STATUS_UNKNOWN_TRANSACTION ได้รับ ndk
  • แบ็กเอนด์ของ java ได้รับ android.os.RemoteException พร้อมข้อความแจ้งว่าไม่ได้ใช้งาน API

สำหรับกลยุทธ์ในการจัดการสิ่งนี้ โปรดดู การสืบค้นเวอร์ชัน และ การใช้ค่าดีฟอลต์

พัสดุ

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

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

Enums และค่าคงที่

ในทำนองเดียวกัน ไคลเอนต์และเซิร์ฟเวอร์ควรปฏิเสธหรือเพิกเฉยต่อค่าคงที่และตัวแจงนับที่ไม่รู้จักตามความเหมาะสม เนื่องจากอาจมีการเพิ่มเติมในอนาคต ตัวอย่างเช่น เซิร์ฟเวอร์ไม่ควรยกเลิกเมื่อได้รับตัวแจงนับที่ไม่รู้จัก ควรเพิกเฉยหรือส่งคืนบางอย่างเพื่อให้ไคลเอนต์รู้ว่าไม่รองรับการใช้งานนี้

สหภาพแรงงาน

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

กฎการตั้งชื่อโมดูล

ใน Android 11 สำหรับการรวมแต่ละเวอร์ชันและแบ็กเอนด์ที่เปิดใช้งาน โมดูลไลบรารีสตับจะถูกสร้างขึ้นโดยอัตโนมัติ ในการอ้างถึงโมดูลไลบรารี stub เฉพาะสำหรับการลิงก์ อย่าใช้ชื่อของโมดูล aidl_interface แต่ให้ใช้ชื่อของโมดูลไลบรารี stub ซึ่งก็คือ ifacename - version - backend โดยที่

  • ifacename : ชื่อของโมดูล aidl_interface
  • version ใดรุ่นหนึ่งของ
    • V version-number สำหรับเวอร์ชันแช่แข็ง
    • V latest-frozen-version-number + 1 สำหรับเวอร์ชันปลายของต้นไม้ (ยังไม่ถูกแช่แข็ง)
  • backend เป็นอย่างใดอย่างหนึ่งของ
    • java สำหรับแบ็กเอนด์ Java
    • cpp สำหรับแบ็กเอนด์ C ++
    • ndk_platform ndk แบ็กเอนด์ NDK อันแรกใช้สำหรับแอพ ส่วนอันหลังใช้สำหรับแพลตฟอร์ม
    • rust สำหรับแบ็กเอนด์ของสนิม

สมมติว่ามีโมดูลชื่อ foo และเวอร์ชันล่าสุดคือ 2 และรองรับทั้ง NDK และ C++ ในกรณีนี้ AIDL จะสร้างโมดูลเหล่านี้:

  • ขึ้นอยู่กับรุ่น 1
    • foo-V1-(java|cpp|ndk|ndk_platform|rust)
  • ขึ้นอยู่กับเวอร์ชัน 2 (เวอร์ชันเสถียรล่าสุด)
    • foo-V2-(java|cpp|ndk|ndk_platform|rust)
  • ขึ้นอยู่กับเวอร์ชัน ToT
    • foo-V3-(java|cpp|ndk|ndk_platform|rust)

เมื่อเทียบกับ Android 11

  • foo- backend ซึ่งอ้างอิงเวอร์ชันเสถียรล่าสุดกลายเป็น foo- V2 - backend
  • foo-unstable- backend ซึ่งอ้างถึงเวอร์ชัน ToT กลายเป็น foo- V3 - backend

ชื่อไฟล์เอาต์พุตจะเหมือนกับชื่อโมดูลเสมอ

  • อ้างอิงจากเวอร์ชัน 1: foo-V1-(cpp|ndk|ndk_platform|rust).so
  • อ้างอิงจากเวอร์ชัน 2: foo-V2-(cpp|ndk|ndk_platform|rust).so
  • ตามเวอร์ชัน ToT: foo-V3-(cpp|ndk|ndk_platform|rust).so

โปรดทราบว่าคอมไพเลอร์ AIDL ไม่ได้สร้างทั้งโมดูลเวอร์ชันที่ unstable หรือโมดูลที่ไม่ใช่เวอร์ชันสำหรับอินเทอร์เฟซ AIDL ที่เสถียร ใน Android 12 ชื่อโมดูลที่สร้างจากอินเทอร์เฟซ AIDL ที่เสถียรจะรวมเวอร์ชันของมันไว้ด้วยเสมอ

วิธีการเชื่อมต่อเมตาใหม่

Android 10 เพิ่มเมตาอินเทอร์เฟซหลายวิธีสำหรับ AIDL ที่เสถียร

การสอบถามเวอร์ชันอินเตอร์เฟสของวัตถุระยะไกล

ไคลเอนต์สามารถค้นหาเวอร์ชันและแฮชของอินเทอร์เฟซที่วัตถุระยะไกลกำลังใช้งาน และเปรียบเทียบค่าที่ส่งคืนกับค่าของอินเทอร์เฟซที่ไคลเอ็นต์กำลังใช้

ตัวอย่างที่มีแบ็กเอนด์ cpp :

sp<IFoo> foo = ... // the remote object
int32_t my_ver = IFoo::VERSION;
int32_t remote_ver = foo->getInterfaceVersion();
if (remote_ver < my_ver) {
  // the remote side is using an older interface
}

std::string my_hash = IFoo::HASH;
std::string remote_hash = foo->getInterfaceHash();

ตัวอย่างที่มีแบ็กเอนด์ ndk_platform ndk :

IFoo* foo = ... // the remote object
int32_t my_ver = IFoo::version;
int32_t remote_ver = 0;
if (foo->getInterfaceVersion(&remote_ver).isOk() && remote_ver < my_ver) {
  // the remote side is using an older interface
}

std::string my_hash = IFoo::hash;
std::string remote_hash;
foo->getInterfaceHash(&remote_hash);

ตัวอย่างที่มีแบ็กเอนด์ของ java :

IFoo foo = ... // the remote object
int myVer = IFoo.VERSION;
int remoteVer = foo.getInterfaceVersion();
if (remoteVer < myVer) {
  // the remote side is using an older interface
}

String myHash = IFoo.HASH;
String remoteHash = foo.getInterfaceHash();

สำหรับภาษา Java ฝั่งรีโมตต้องใช้ getInterfaceVersion() และ getInterfaceHash() ดังนี้:

class MyFoo extends IFoo.Stub {
    @Override
    public final int getInterfaceVersion() { return IFoo.VERSION; }

    @Override
    public final String getInterfaceHash() { return IFoo.HASH; }
}

นี่เป็นเพราะคลาสที่สร้างขึ้น ( IFoo , IFoo.Stub และอื่น ๆ ) ถูกแชร์ระหว่างไคลเอนต์และเซิร์ฟเวอร์ (ตัวอย่างเช่น คลาสสามารถอยู่ในพาธคลาสสำหรับบูต) เมื่อมีการแชร์คลาส เซิร์ฟเวอร์จะเชื่อมโยงกับคลาสเวอร์ชันใหม่ล่าสุด แม้ว่าอาจสร้างด้วยอินเทอร์เฟซเวอร์ชันเก่ากว่าก็ตาม หากใช้อินเทอร์เฟซเมตานี้ในคลาสที่ใช้ร่วมกัน จะส่งคืนเวอร์ชันล่าสุดเสมอ อย่างไรก็ตาม โดยการใช้วิธีการข้างต้น หมายเลขเวอร์ชันของอินเทอร์เฟซจะถูกฝังอยู่ในโค้ดของเซิร์ฟเวอร์ (เนื่องจาก IFoo.VERSION เป็น static final int อินไลน์เมื่ออ้างอิง) และทำให้เมธอดสามารถส่งคืนเวอร์ชันที่แน่นอนที่เซิร์ฟเวอร์สร้างขึ้น กับ.

การจัดการกับอินเทอร์เฟซที่เก่ากว่า

เป็นไปได้ว่าไคลเอ็นต์ได้รับการอัปเดตด้วยอินเทอร์เฟซ AIDL เวอร์ชันใหม่กว่า แต่เซิร์ฟเวอร์กำลังใช้อินเทอร์เฟซ AIDL แบบเก่า ในกรณีดังกล่าว การเรียกใช้เมธอดบนอินเทอร์เฟซเก่าจะส่งคืน UNKNOWN_TRANSACTION

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

ตัวอย่างใน C++ ใน Android 13 และใหม่กว่า:

class MyDefault : public IFooDefault {
  Status anAddedMethod(...) {
   // do something default
  }
};

// once per an interface in a process
IFoo::setDefaultImpl(::android::sp<MyDefault>::make());

foo->anAddedMethod(...); // MyDefault::anAddedMethod() will be called if the
                         // remote side is not implementing it

ตัวอย่างในภาษาจาวา:

IFoo.Stub.setDefaultImpl(new IFoo.Default() {
    @Override
    public xxx anAddedMethod(...)  throws RemoteException {
        // do something default
    }
}); // once per an interface in a process


foo.anAddedMethod(...);

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

แปลง AIDL ที่มีอยู่เป็น AIDL ที่มีโครงสร้าง/เสถียร

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

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

  2. แปลงพัสดุทั้งหมดในอินเทอร์เฟซของคุณให้เป็นพัสดุที่เสถียร (ไฟล์อินเทอร์เฟซเองจะไม่เปลี่ยนแปลง) ทำได้โดยแสดงโครงสร้างโดยตรงในไฟล์ AIDL ต้องเขียนคลาสการจัดการใหม่เพื่อใช้ประเภทใหม่เหล่านี้ สามารถทำได้ก่อนที่คุณจะสร้างแพ็คเกจ aidl_interface (ด้านล่าง)

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