AIDL เวอร์ชันเสถียร

Android 10 เพิ่มการรองรับภาษาคำจำกัดความอินเทอร์เฟซ Android (AIDL) ที่เสถียร ซึ่งเป็นวิธีใหม่ในการตรวจสอบ Application Programming Interface (API) และ Application Binary Interface (ABI) ที่อินเทอร์เฟซ AIDL ระบุ AIDL เวอร์ชันเสถียรทํางานเหมือนกับ AIDL ทุกประการ แต่ระบบบิลด์จะติดตามความเข้ากันได้ของอินเทอร์เฟซ และมีข้อจํากัดในสิ่งที่คุณทําได้ ดังนี้

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

AIDL แบบมีโครงสร้างกับแบบเสถียร

AIDL ที่มีโครงสร้างหมายถึงประเภทที่กำหนดไว้ใน AIDL เพียงอย่างเดียว เช่น การประกาศที่แยกย่อยได้ (การแยกย่อยที่กําหนดเอง) ไม่ใช่ AIDL ที่มีโครงสร้าง Parcelable ที่มีการกำหนดช่องใน AIDL จะเรียกว่า Structured Parcelable

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

กำหนดอินเทอร์เฟซ 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: ["other-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 รายการใดรายการหนึ่งใช้อินเทอร์เฟซหรือ Parcelable จาก aidl_interface รายการอื่น ให้ใส่ชื่อของอินเทอร์เฟซนั้นที่นี่ ซึ่งอาจเป็นชื่อเพียงอย่างเดียวเพื่ออ้างอิงถึงเวอร์ชันล่าสุด หรือชื่อที่มีส่วนต่อท้ายเวอร์ชัน (เช่น -V1) เพื่ออ้างอิงถึงเวอร์ชันที่เฉพาะเจาะจง ระบบรองรับการระบุเวอร์ชันตั้งแต่ Android 12
  • versions: อินเทอร์เฟซเวอร์ชันก่อนหน้าที่ตรึงไว้ภายใต้ api_dir ตั้งแต่ Android 11 เป็นต้นไป versions จะตรึงชั่วคราวอยู่ภายใต้ aidl_api/name หากไม่มีเวอร์ชันใดที่หยุดนิ่งของอินเทอร์เฟซ ก็ไม่ควรระบุไว้ และจะไม่มีการตรวจสอบความเข้ากันได้ ช่องนี้มีการแทนที่ด้วย versions_with_info สำหรับ Android 13 ขึ้นไป
  • versions_with_info: รายการทูเพลตแต่ละรายการมีชื่อของเวอร์ชันที่หยุดทำงานและรายการที่มีการนําเข้าเวอร์ชันของโมดูล aidl_interface อื่นๆ ที่ aidl_interface เวอร์ชันนี้นําเข้า คําจํากัดความของเวอร์ชัน V ของอินเทอร์เฟซ AIDL IFACE อยู่ที่ aidl_api/IFACE/V ช่องนี้เปิดตัวใน Android 13 และไม่ควรแก้ไขใน Android.bp โดยตรง ระบบจะเพิ่มหรืออัปเดตช่องโดยการเรียกใช้ *-update-api หรือ *-freeze-api นอกจากนี้ ระบบจะย้ายข้อมูลช่อง versions ไปยัง versions_with_info โดยอัตโนมัติเมื่อผู้ใช้เรียกใช้ *-update-api หรือ *-freeze-api
  • stability: Flag ไม่บังคับสำหรับสัญญาความเสถียรของอินเทอร์เฟซนี้ การดำเนินการนี้รองรับเฉพาะ "vintf" หากไม่ได้ตั้งค่า stability ไว้ ระบบบิลด์จะตรวจสอบว่าอินเทอร์เฟซสามารถใช้งานร่วมกันได้แบบย้อนหลัง เว้นแต่จะมีการระบุ unstable ไว้ การตั้งค่าเป็น "ไม่ตั้งค่า" สอดคล้องกับอินเทอร์เฟซที่มีความเสถียรภายในบริบทการคอมไพล์นี้ (ดังนั้น สิ่งต่างๆ ทั้งหมดของระบบ เช่น สิ่งต่างๆ ใน system.img และพาร์ติชันที่เกี่ยวข้อง หรือสิ่งต่างๆ ทั้งหมดของผู้ให้บริการ เช่น สิ่งต่างๆ ใน vendor.img และพาร์ติชันที่เกี่ยวข้อง) หากตั้งค่า stability เป็น "vintf" แสดงว่าสอดคล้องกับสัญญาความเสถียร ซึ่งหมายความว่าอินเทอร์เฟซต้องมีความเสถียรตราบใดที่มีการใช้งาน
  • gen_trace: แฟล็กที่ไม่บังคับสำหรับเปิดหรือปิดการติดตาม โดยตั้งแต่ Android 14 เป็นต้นไป ค่าเริ่มต้นคือ true สำหรับแบ็กเอนด์ cpp และ java
  • host_supported: Flag ไม่บังคับซึ่งเมื่อตั้งค่าเป็น true จะทำให้ไลบรารีที่สร้างขึ้นพร้อมใช้งานสำหรับสภาพแวดล้อมโฮสต์
  • unstable: Flag ที่ไม่บังคับซึ่งใช้ทำเครื่องหมายว่าอินเทอร์เฟซนี้ไม่จำเป็นต้องเสถียร เมื่อตั้งค่าเป็น true ระบบบิลด์จะไม่สร้างการดัมพ์ API สําหรับอินเทอร์เฟซหรือกําหนดให้อัปเดต
  • frozen: แฟล็กที่ไม่บังคับซึ่งเมื่อตั้งค่าเป็น true หมายความว่าอินเทอร์เฟซไม่มีการเปลี่ยนแปลงนับตั้งแต่อินเทอร์เฟซเวอร์ชันก่อนหน้า ซึ่งจะทำให้มีการตรวจสอบเวลาบิลด์มากยิ่งขึ้น เมื่อตั้งค่าเป็น false หมายความว่าอินเทอร์เฟซอยู่ระหว่างการพัฒนาและมีการเปลี่ยนแปลงใหม่ ดังนั้นการเรียกใช้ foo-freeze-api จะสร้างเวอร์ชันใหม่และเปลี่ยนค่าเป็น true โดยอัตโนมัติ เปิดตัวใน Android 14
  • backend.<type>.enabled: Flag เหล่านี้จะเปิด/ปิดแบ็กเอนด์แต่ละรายการที่คอมไพเลอร์ AIDL สร้างขึ้น ระบบรองรับแบ็กเอนด์ 4 รายการ ได้แก่ Java, C++, NDK และ Rust แบ็กเอนด์ Java, C++ และ NDK จะเปิดใช้โดยค่าเริ่มต้น หากไม่จำเป็นต้องใช้แบ็กเอนด์ใดเลย จะต้องปิดใช้แบ็กเอนด์นั้นอย่างชัดเจน ระบบจะปิดใช้ Rust โดยค่าเริ่มต้นจนกว่า Android 15 จะพร้อมให้บริการ
  • backend.<type>.apex_available: รายการชื่อ APEX ที่ไลบรารีสแต็บที่สร้างขึ้นใช้ได้
  • backend.[cpp|java].gen_log: Flag ไม่บังคับที่ใช้ควบคุมว่าจะสร้างโค้ดเพิ่มเติมเพื่อรวบรวมข้อมูลเกี่ยวกับธุรกรรมหรือไม่
  • backend.[cpp|java].vndk.enabled: Flag ที่ไม่บังคับเพื่อทำให้อินเทอร์เฟซนี้เป็นส่วนหนึ่งของ VNDK ค่าเริ่มต้นคือ false
  • backend.[cpp|ndk].additional_shared_libraries: เปิดตัวใน Android 14 โดย Flag นี้จะเพิ่มการพึ่งพาไปยังไลบรารีแบบเนทีฟ ธงนี้มีประโยชน์กับ ndk_header และ cpp_header
  • backend.java.sdk_version: แฟล็กที่ไม่บังคับสำหรับระบุเวอร์ชันของ SDK ที่ใช้ไลบรารี Java Stub สร้างขึ้น โดยมีค่าเริ่มต้นเป็น "system_current" ไม่ควรตั้งค่านี้เมื่อ backend.java.platform_apis เป็น true
  • backend.java.platform_apis: Flag ที่ไม่บังคับซึ่งควรตั้งค่าเป็น true เมื่อต้องสร้างไลบรารีที่สร้างขึ้นจาก API ของแพลตฟอร์มแทน SDK

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

เขียนไฟล์ AIDL

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

// 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 แม้ว่าจะไม่มีตัวนับ 0 ก็ตาม

ใช้ไลบรารีสแต็บ

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

cc_... {
    name: ...,
    shared_libs: ["my-module-name-cpp"],
    ...
}
# or
java_... {
    name: ...,
    // can also be shared_libs if your preference 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: ...,
    rustlibs: ["my-module-name-rust"],
    ...
}

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

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

ตัวอย่างใน Java

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

ตัวอย่างใน Rust

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 ซึ่งทั้ง 2 ไฟล์จะแสดงอินเทอร์เฟซเวอร์ชันแช่แข็งใหม่ foo-freeze-api จะอัปเดตพร็อพเพอร์ตี้ versions_with_info เพื่อแสดงเวอร์ชันเพิ่มเติมและ imports สำหรับเวอร์ชันนั้นด้วย โดยทั่วไปแล้ว imports ใน versions_with_info จะคัดลอกมาจากช่อง imports แต่มีการระบุเวอร์ชันเสถียรล่าสุดใน imports ใน versions_with_info สำหรับการนําเข้า ซึ่งไม่มีเวอร์ชันที่ชัดเจน หลังจากระบุพร็อพเพอร์ตี้ versions_with_info แล้ว ระบบบิลด์จะทำการตรวจสอบความเข้ากันได้ระหว่างเวอร์ชันที่ตรึงไว้และระหว่าง Top of Tree (ToT) กับเวอร์ชันล่าสุดที่ตรึงไว้

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

เจ้าของสามารถเพิ่มรายการต่อไปนี้ได้เพื่อรักษาเสถียรภาพของอินเทอร์เฟซ

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

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

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

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

ความเสถียรของการนําเข้า

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

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

ใช้อินเทอร์เฟซที่มีเวอร์ชัน

วิธีการของอินเทอร์เฟซ

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

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

ดูกลยุทธ์ในการจัดการปัญหานี้ได้ที่หัวข้อการค้นหาเวอร์ชันและการใช้ค่าเริ่มต้น

พาร์เซล

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

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

ค่าแจกแจงและค่าคงที่

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

สหภาพแรงงาน

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

จัดการหลายเวอร์ชัน

เนมสเปซ Linker ใน Android มีอินเทอร์เฟซ aidl ที่เฉพาะเจาะจงได้เพียง 1 เวอร์ชันเท่านั้น เพื่อหลีกเลี่ยงสถานการณ์ที่ประเภท aidl ที่สร้างขึ้นมีคำจำกัดความหลายรายการ C++ มีกฎคำจำกัดความเดียวที่กำหนดให้มีคำจำกัดความของสัญลักษณ์แต่ละรายการเพียงรายการเดียว

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

หากมีการใช้ไลบรารีอินเทอร์เฟซโดยโมดูลต่างๆ หลายรายการ คุณอาจต้องสร้าง cc_defaults, java_defaults และ rust_defaults สำหรับกลุ่มไลบรารีและกระบวนการที่ต้องใช้เวอร์ชันเดียวกัน เมื่อเริ่มใช้อินเทอร์เฟซเวอร์ชันใหม่ คุณจะอัปเดตค่าเริ่มต้นเหล่านั้นได้และโมดูลทั้งหมดที่ใช้อินเทอร์เฟซเหล่านั้นได้รับการอัปเดตพร้อมกันเพื่อให้มั่นใจว่าไม่ได้ใช้อินเทอร์เฟซเวอร์ชันอื่น

cc_defaults {
  name: "my.aidl.my-process-group-ndk-shared",
  shared_libs: ["my.aidl-V3-ndk"],
  ...
}

cc_library {
  name: "foo",
  defaults: ["my.aidl.my-process-group-ndk-shared"],
  ...
}

cc_binary {
  name: "bar",
  defaults: ["my.aidl.my-process-group-ndk-shared"],
  ...
}

เมื่อโมดูล aidl_interface นําเข้าโมดูล aidl_interface อื่นๆ การดำเนินการนี้จะสร้างข้อกําหนดเพิ่มเติมที่ต้องใช้เวอร์ชันที่เฉพาะเจาะจงร่วมกัน สถานการณ์นี้อาจจัดการได้ยากเมื่อมีaidl_interfaceโมดูลทั่วไปที่นําเข้าในaidl_interfaceโมดูลหลายรายการที่ใช้ร่วมกันในกระบวนการเดียวกัน

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

aidl_interface_defaults {
  name: "android.popular.common-latest-defaults",
  imports: ["android.popular.common-V3"],
  ...
}

aidl_interface {
  name: "android.foo",
  defaults: ["my.aidl.latest-ndk-shared"],
  ...
}

aidl_interface {
  name: "android.bar",
  defaults: ["my.aidl.latest-ndk-shared"],
  ...
}

การพัฒนาตามธง

อินเทอร์เฟซเวอร์ชันที่พัฒนาอยู่ (ไม่ได้หยุดทำงานชั่วคราว) จะใช้กับอุปกรณ์รุ่นต่างๆ ไม่ได้เนื่องจากไม่มีการรับประกันว่าจะใช้งานร่วมกันได้ย้อนหลัง

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

Flag การสร้าง AIDL

Flag ที่ควบคุมลักษณะการทำงานนี้มีRELEASE_AIDL_USE_UNFROZEN การกําหนดไว้ใน build/release/build_flags.bzl true หมายความว่าจะมีการใช้อินเทอร์เฟซเวอร์ชันที่ไม่ได้ตรึงไว้ในขณะรันไทม์ และ false หมายความว่าไลบรารีของเวอร์ชันที่ไม่ได้ตรึงไว้ทำงานเหมือนกับเวอร์ชันที่ตรึงไว้ล่าสุด คุณสามารถลบล้าง Flag เป็น true สำหรับการพัฒนาการในเครื่องได้ แต่ต้องเปลี่ยนกลับไปเป็น false ก่อนเผยแพร่ โดยปกติแล้วการพัฒนาจะทําด้วยการกำหนดค่าที่ตั้งค่า Flag เป็น true

เมทริกซ์และไฟล์ Manifest ของความเข้ากันได้

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

อุปกรณ์ที่ไม่ใช่ Cuttlefish ส่วนใหญ่จะกําหนดเป้าหมายเมทริกซ์ความเข้ากันได้ล่าสุดหลังจากที่อินเทอร์เฟซค้างเท่านั้น ไลบรารี AIDL ที่ใช้ RELEASE_AIDL_USE_UNFROZEN จึงไม่มีความแตกต่าง

เมทริกซ์

ระบบจะเพิ่มอินเทอร์เฟซที่พาร์ทเนอร์เป็นเจ้าของลงในเมทริกซ์ความเข้ากันได้เฉพาะอุปกรณ์หรือเมทริกซ์ความเข้ากันได้เฉพาะผลิตภัณฑ์ที่อุปกรณ์กำหนดเป้าหมายระหว่างการพัฒนา ดังนั้นเมื่อมีการเพิ่มอินเทอร์เฟซเวอร์ชันใหม่ที่ไม่ได้ตรึงไว้ลงในเมทริกซ์ความเข้ากันได้ เวอร์ชันที่ตรึงไว้ก่อนหน้านี้จะยังคงต้องใช้เวอร์ชัน RELEASE_AIDL_USE_UNFROZEN=false ต่อไป คุณจัดการสิ่งนี้ได้โดยใช้ไฟล์เมทริกซ์ความเข้ากันได้ที่ต่างกันสำหรับการกำหนดค่า RELEASE_AIDL_USE_UNFROZEN ที่แตกต่างกัน หรืออนุญาตให้ใช้ทั้ง 2 เวอร์ชันในไฟล์เมทริกซ์ความเข้ากันได้ไฟล์เดียวซึ่งใช้ในการกำหนดค่าทั้งหมด

เช่น เมื่อเพิ่มเวอร์ชัน 4 ที่เลิกระงับแล้ว ให้ใช้ <version>3-4</version>

เมื่อเวอร์ชัน 4 หยุดทำงานแล้ว คุณจะนําเวอร์ชัน 3 ออกจากตารางความเข้ากันได้ได้เนื่องจากระบบจะใช้เวอร์ชัน 4 ที่หยุดทำงานเมื่อ RELEASE_AIDL_USE_UNFROZEN มีค่าเป็น false

Manifest

ใน Android 15 จะมีการเปลี่ยนแปลง libvintf เพื่อแก้ไขไฟล์ Manifest ในเวลาที่สร้างตามค่าของ RELEASE_AIDL_USE_UNFROZEN

ไฟล์ Manifest และเศษส่วนของไฟล์ Manifest จะประกาศเวอร์ชันของอินเทอร์เฟซที่บริการนำมาใช้ เมื่อใช้อินเทอร์เฟซเวอร์ชันล่าสุดที่เลิกแช่แข็งแล้ว คุณต้องอัปเดตไฟล์ Manifest ให้สอดคล้องกับเวอร์ชันใหม่นี้ เมื่อ RELEASE_AIDL_USE_UNFROZEN=false ระบบจะปรับรายการไฟล์ Manifest โดย libvintf เพื่อให้สอดคล้องกับการเปลี่ยนแปลงในไลบรารี AIDL ที่สร้างขึ้น เวอร์ชันดังกล่าวได้รับการแก้ไขจากเวอร์ชันที่เลิกแช่แข็งแล้ว N เป็นเวอร์ชันที่แช่แข็งล่าสุด N - 1 ดังนั้นผู้ใช้จึงไม่ต้องจัดการไฟล์ Manifest หรือเศษส่วนของไฟล์ Manifest หลายรายการสำหรับบริการแต่ละรายการ

การเปลี่ยนแปลงไคลเอ็นต์ HAL

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

การเปลี่ยนแปลงการติดตั้งใช้งาน HAL

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

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

ตัวอย่าง: อินเทอร์เฟซมีเวอร์ชันที่หยุดทำงาน 3 เวอร์ชัน อินเทอร์เฟซได้รับการอัปเดตด้วยวิธีการใหม่ ทั้งไคลเอ็นต์และบริการได้รับการอัปเดตให้ใช้ไลบรารีเวอร์ชัน 4 ใหม่ เนื่องจากไลบรารี V4 อิงตามอินเทอร์เฟซเวอร์ชันที่ไม่มีการแช่แข็ง ไลบรารีจึงทํางานเหมือนเวอร์ชันที่แช่แข็งล่าสุด ซึ่งเป็นเวอร์ชัน 3 เมื่อ RELEASE_AIDL_USE_UNFROZEN เป็น false และป้องกันไม่ให้ใช้เมธอดใหม่

เมื่ออินเทอร์เฟซหยุดทำงาน ค่าทั้งหมดของ RELEASE_AIDL_USE_UNFROZEN จะใช้เวอร์ชันที่หยุดทำงานนั้น และสามารถนําโค้ดที่จัดการความเข้ากันได้แบบย้อนหลังออกได้

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

// Get the callback along with the version of the callback
ScopedAStatus RegisterMyCallback(const std::shared_ptr<IMyCallback>& cb) override {
    mMyCallback = cb;
    // Get the version of the callback for later when we call methods on it
    auto status = mMyCallback->getInterfaceVersion(&mMyCallbackVersion);
    return status;
}

// Example of using the callback later
void NotifyCallbackLater() {
  // From the latest frozen version (V2)
  mMyCallback->foo();
  // Call this method from the unfrozen V3 only if the callback is at least V3
  if (mMyCallbackVersion >= 3) {
    mMyCallback->bar();
  }
}

ช่องใหม่ในประเภทที่มีอยู่ (parcelable, enum, union) อาจไม่อยู่หรือมีค่าเริ่มต้นเมื่อ RELEASE_AIDL_USE_UNFROZEN เป็น false และระบบจะทิ้งค่าของช่องใหม่ที่บริการพยายามส่งออก

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

การใช้งานไม่เคยได้รับการเรียกใช้เมธอดใหม่จากลูกค้ารายใดเมื่อ RELEASE_AIDL_USE_UNFROZEN เป็น false

โปรดใช้ตัวนับใหม่กับเวอร์ชันที่เปิดตัวเท่านั้น และอย่าใช้กับเวอร์ชันก่อนหน้า

โดยปกติแล้ว คุณจะใช้ foo->getInterfaceVersion() เพื่อดูว่าอินเทอร์เฟซระยะไกลใช้เวอร์ชันใด อย่างไรก็ตาม เมื่อใช้การรองรับการแยกเวอร์ชันตาม Flag คุณจะใช้งาน 2 เวอร์ชันที่แตกต่างกัน คุณจึงอาจต้องการใช้เวอร์ชันของอินเทอร์เฟซปัจจุบัน ซึ่งทำได้โดยการรับเวอร์ชันอินเทอร์เฟซของออบเจ็กต์ปัจจุบัน เช่น this->getInterfaceVersion() หรือเมธอดอื่นๆ สำหรับ my_ver ดูการค้นหาเวอร์ชันอินเทอร์เฟซของออบเจ็กต์ระยะไกล สำหรับข้อมูลเพิ่มเติม

อินเทอร์เฟซ VINTF เวอร์ชันเสถียรใหม่

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

คุณเพิ่มบริการแบบมีเงื่อนไขได้โดยอิงตามค่าของ Flag RELEASE_AIDL_USE_UNFROZEN ในไฟล์บิลด์ของอุปกรณ์

ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
    android.hardware.health.storage-service
endif

หากบริการเป็นส่วนหนึ่งของกระบวนการที่ใหญ่กว่า คุณจึงเพิ่มบริการลงในอุปกรณ์อย่างมีเงื่อนไขไม่ได้ ให้ตรวจสอบเพื่อดูว่ามีการประกาศบริการด้วย IServiceManager::isDeclared() หรือไม่ หากมีการประกาศและลงทะเบียนไม่สำเร็จ ให้ยกเลิกกระบวนการ หากไม่ได้ประกาศ คาดว่าการลงทะเบียนจะไม่สำเร็จ

หมึกกระดองเป็นเครื่องมือพัฒนา

ทุกปีหลังจากที่ VINTF หยุดทำงาน เราจะปรับตารางความเข้ากันได้ของเฟรมเวิร์ก (FCM) target-level และ PRODUCT_SHIPPING_API_LEVEL ของ Cuttlefish เพื่อให้สอดคล้องกับอุปกรณ์ที่เปิดตัวพร้อมกับรุ่นของปีถัดไป เราปรับ target-level และ PRODUCT_SHIPPING_API_LEVEL เพื่อให้แน่ใจว่าอุปกรณ์ที่จะเปิดตัวบางรุ่นได้รับการทดสอบและเป็นไปตามข้อกำหนดใหม่สำหรับการเปิดตัวในปีหน้า

เมื่อ RELEASE_AIDL_USE_UNFROZEN คือ true ระบบจะใช้ Cuttlefish เพื่อพัฒนา Android รุ่นต่อๆ ไป แอปกำหนดเป้าหมายเป็น FCM ระดับ PRODUCT_SHIPPING_API_LEVEL ของ Android รุ่นปีหน้า โดยต้องเป็นไปตามข้อกำหนดซอฟต์แวร์ของผู้ให้บริการ (VSR) ของรุ่นถัดไป

เมื่อ RELEASE_AIDL_USE_UNFROZEN เป็น false หมายความว่า Cuttlefish มี target-level และ PRODUCT_SHIPPING_API_LEVEL ก่อนหน้าเพื่อแสดงอุปกรณ์รุ่น ใน Android 14 และต่ำกว่า การแยกความแตกต่างนี้จะทำได้โดยใช้สาขา Git ที่แตกต่างกันซึ่งไม่รับการเปลี่ยนแปลง FCMtarget-level, ระดับ API ที่ใช้งานจริง หรือโค้ดอื่นๆ ที่กําหนดเป้าหมายเป็นรุ่นถัดไป

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

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

  • ifacename: ชื่อของโมดูล aidl_interface
  • version เป็นค่าใดค่าหนึ่งต่อไปนี้
    • Vversion-number สำหรับเวอร์ชันที่อัปเดตไม่ได้
    • Vlatest-frozen-version-number + 1 สำหรับเวอร์ชันต้นๆ (ยังแข็ง)
  • backend เป็นค่าใดค่าหนึ่งต่อไปนี้
    • java สำหรับแบ็กเอนด์ Java
    • cpp สำหรับแบ็กเอนด์ C++
    • ndk หรือ ndk_platform สำหรับแบ็กเอนด์ NDK ตัวเลือกแรกมีไว้สำหรับแอป ส่วนหลังจะใช้สำหรับการใช้งานแพลตฟอร์มจนถึง Android 13 ใน Android 13 ขึ้นไป ให้ใช้เฉพาะ ndk
    • rust สำหรับแบ็กเอนด์ 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 (และ ndk_platform)

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() ดังนี้ (ใช้ super แทน IFoo เพื่อหลีกเลี่ยงการคัดลอกและวางที่ผิดพลาด คุณอาจต้องใช้คำอธิบายประกอบ @SuppressWarnings("static") เพื่อปิดใช้คำเตือน ทั้งนี้ขึ้นอยู่กับการกำหนดค่า javac

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

    @Override
    public final String getInterfaceHash() { return super.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

ตัวอย่างใน Java

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

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

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