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

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

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

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

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

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

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

กำลังเขียนไฟล์ AIDL

อินเทอร์เฟซใน 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 แม้ว่าจะไม่มีตัวระบุที่เป็น 0 ก็ตาม

การใช้ไลบรารีต้นขั้ว

หลังจากเพิ่มไลบรารี Stub เป็นทรัพยากร Dependency ของโมดูลแล้ว คุณจะรวมไลบรารีดังกล่าวลงในไฟล์ได้ ต่อไปนี้คือตัวอย่างไลบรารีสตับในระบบบิลด์ (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: ...,
    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

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

  • เมธอดต่อท้ายอินเทอร์เฟซ (หรือเมธอดที่มีหมายเลขซีเรียลใหม่กำหนดไว้อย่างชัดเจน)
  • องค์ประกอบที่อยู่ท้ายไฟล์พาร์เซล (ต้องมีค่าเริ่มต้นเพื่อเพิ่มสำหรับแต่ละองค์ประกอบ)
  • ค่าคงที่
  • ใน 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 ได้รับ STATUS_UNKNOWN_TRANSACTION
  • แบ็กเอนด์ java ได้รับ android.os.RemoteException พร้อมข้อความแจ้งว่ายังไม่ได้ใช้ API

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

พาร์เซล

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

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

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

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

สหภาพ

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

การพัฒนาที่อิงตาม Flag

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

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

Flag บิลด์ AIDL

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

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

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

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

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

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

ใน Android 11 ระบบจะสร้างโมดูลไลบรารี 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 ตัวเลือกแรกมีไว้สำหรับแอป ส่วนหลังมีไว้สำหรับการใช้งานแพลตฟอร์ม
    • 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)
  • ตามเวอร์ชันของข้อกำหนดในการให้บริการ
    • foo-V3-(java|cpp|ndk|ndk_platform|rust)

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

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

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

  • จากเวอร์ชัน 1: foo-V1-(cpp|ndk|ndk_platform|rust).so
  • จากเวอร์ชัน 2: foo-V2-(cpp|ndk|ndk_platform|rust).so
  • ตามเวอร์ชันข้อกำหนดในการให้บริการ: 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 ฯลฯ) ระหว่างไคลเอ็นต์และเซิร์ฟเวอร์ (เช่น คลาสอาจอยู่ใน Bootclasspath) เมื่อมีการแชร์ชั้นเรียน เซิร์ฟเวอร์จะลิงก์กับชั้นเรียนเวอร์ชันล่าสุดด้วย แม้ว่าระบบอาจสร้างด้วยอินเทอร์เฟซเวอร์ชันเก่าก็ตาม หากใช้อินเทอร์เฟซเมตานี้ในชั้นเรียนที่แชร์ อินเทอร์เฟซเมตาก็จะเป็นเวอร์ชันล่าสุดเสมอ แต่ด้วยการใช้วิธีการดังกล่าวข้างต้น หมายเลขเวอร์ชันของอินเทอร์เฟซจะฝังอยู่ในโค้ดของเซิร์ฟเวอร์ (เนื่องจาก 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 และข้อมูลอื่นๆ ที่คุณต้องการ นอกจากนี้ ยังต้องมีเวอร์ชันเพื่อให้มีความเสถียร (ไม่ใช่แค่มีโครงสร้าง) ด้วย ดูข้อมูลเพิ่มเติมได้ที่การกำหนดเวอร์ชันอินเทอร์เฟซ