คําอธิบายประกอบใน AIDL

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

ไวยากรณ์จะคล้ายกับของ Java ดังนี้

@AnnotationName(argument1=value, argument2=value) AidlEntity

โดย AnnotationName คือชื่อของคำอธิบายประกอบ และ AidlEntity คือ เอนทิตี AIDL เช่น interface Foo, void method() หรือ int arg โดย คำอธิบายประกอบจะแนบไปกับเอนทิตีที่อยู่หลังคำอธิบายประกอบ

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

@AnnotationName AidlEntity

หมายเหตุเหล่านี้ไม่เหมือนกับหมายเหตุ Java แม้ว่าจะมีลักษณะคล้ายกันก็ตาม คำอธิบายประกอบทั้งหมดได้รับการกำหนดไว้ล่วงหน้า และมีข้อจำกัดเกี่ยวกับตำแหน่งที่คุณจะแนบคำอธิบายประกอบได้ คำอธิบายประกอบบางรายการจะมีผลกับแบ็กเอนด์บางอย่างเท่านั้น และจะไม่มีผลในแบ็กเอนด์อื่นๆ

รายการคำอธิบายประกอบ AIDL ที่กำหนดไว้ล่วงหน้ามีดังนี้

คำอธิบายประกอบเพิ่มในเวอร์ชัน Android
nullable7
utf8InCpp7
VintfStability11
UnsupportedAppUsage10
Hide11
Backing11
NdkOnlyStableParcelable14
JavaOnlyStableParcelable11
JavaDerive12
JavaPassthrough12
FixedSize12
Descriptor12

เว้นว่างได้

nullable ประกาศว่าค่าของเอนทิตีที่อธิบายประกอบอาจเป็นค่า Null ได้

คุณแนบคำอธิบายประกอบนี้ได้เฉพาะกับประเภทการคืนค่าของเมธอด พารามิเตอร์ของเมธอด และฟิลด์ที่ส่งผ่านได้:

interface IFoo {
    // method return types
    @nullable Data method();

    // method parameters
    void method2(in @nullable Data d);
}

parcelable Data {
    // parcelable fields
    @nullable Data d;
}

แนบคำอธิบายประกอบกับประเภทดั้งเดิมไม่ได้ ข้อผิดพลาดต่อไปนี้

void method(in @nullable int a); // int is a primitive type

คำอธิบายประกอบนี้ไม่มีผลกับแบ็กเอนด์ Java ใน Java ระบบจะส่งประเภทข้อมูลที่ไม่ใช่ประเภทข้อมูลพื้นฐานทั้งหมดโดยการอ้างอิง ซึ่งอาจเป็น null

ในแบ็กเอนด์ CPP @nullable T จะแมปกับ std::unique_ptr<T> ใน Android 11 หรือต่ำกว่า และกับ std::optional<T> ใน Android 12 ขึ้นไป

ในแบ็กเอนด์ NDK @nullable T จะแมปกับ std::optional<T>

ในแบ็กเอนด์ Rust @nullable T จะแมปกับ Option<T>

สำหรับประเภทที่คล้ายรายการ L เช่น T[] หรือ List<T> @nullable L จะแมปกับ std::optional<std::vector<std::optional<T>>> (หรือ std::unique_ptr<std::vector<std::unique_ptr<T>>> ในกรณีของแบ็กเอนด์ CPP สำหรับ Android 11 หรือต่ำกว่า)

การแมปนี้มีข้อยกเว้น เมื่อ T เป็น IBinder หรืออินเทอร์เฟซ AIDL @nullable จะไม่มีการดำเนินการใดๆ สำหรับแบ็กเอนด์ Java, CPP และ NDK ตัวอย่างเช่น ในแบ็กเอนด์ CPP ทั้ง @nullable IBinder และ IBinder จะแมปกับ android::sp<IBinder> เท่ากัน ซึ่งเป็นค่าที่อนุญาตให้เป็น Null ได้อยู่แล้วเนื่องจากเป็นพอยน์เตอร์ที่แข็งแกร่ง (การอ่าน CPP และ NDK ยังคงบังคับให้เป็น Null ได้ แต่ประเภทจะยังคงเป็น android::sp<IBinder> หรือ ndk::SpAIBinder)

ในแบ็กเอนด์ของ Rust ประเภทที่ไม่ได้ใช้ Default (IBinder, อินเทอร์เฟซ AIDL , ParcelFileDescriptor และ Parcelable ที่ไม่มีโครงสร้าง) จะแมปกับ Option<T> โดยขึ้นอยู่กับบริบทของประเภทนั้นๆ

  • ประเภทการคืนค่าของเมธอด พารามิเตอร์ in และพารามิเตอร์ inout: ประเภทเหล่านี้ จะเป็นค่า Null ได้ก็ต่อเมื่อมีการใส่คำอธิบายประกอบด้วย @nullable ซึ่งแมปกับ Option<T> (หรือ Option<&T> สำหรับพารามิเตอร์ in และ &mut Option<T> สำหรับ พารามิเตอร์ inout) หากไม่มี @nullable ระบบจะแมปกับ T โดยตรง (หรือ &T และ &mut T)
  • ฟิลด์ที่ส่งผ่านได้และพารามิเตอร์ out: เนื่องจาก Rust parcelable ที่สร้างขึ้นจะได้รับพารามิเตอร์ Default และ out ที่เริ่มต้นเป็นค่าเริ่มต้น ประเภทเหล่านี้จึงแมปกับ Option<T> เสมอ (และอาร์เรย์ขนาดคงที่ในบริบทเหล่านี้จะแมปกับ [Option<T>; N] ในขณะที่อาร์เรย์แบบไดนามิกในพารามิเตอร์ out จะแมปกับ Vec<Option<T>>) แม้ว่าจะไม่มี @nullable ก็ตาม เมื่อไม่ได้ใส่คำอธิบายประกอบด้วย @nullable ระบบจะยังคงบังคับใช้การไม่เป็นค่าว่างในรันไทม์ระหว่างการแยกวิเคราะห์ (แสดงผล StatusCode::UNEXPECTED_NULL หากค่าเป็น None)

ตั้งแต่ Android 13 เป็นต้นไป คุณจะใช้ @nullable(heap=true) กับ ฟิลด์ที่ส่งผ่านได้เพื่อสร้างโมเดลประเภทแบบเรียกซ้ำ @nullable(heap=true) ใช้กับพารามิเตอร์ของเมธอดหรือประเภทการคืนค่าไม่ได้ เมื่อมีการใส่คำอธิบายประกอบด้วยฟิลด์นี้ ฟิลด์จะ แมปกับข้อมูลอ้างอิงที่จัดสรรฮีป std::unique_ptr<T> ในแบ็กเอนด์ CPP และ NDK @nullable(heap=true) ไม่มีการดำเนินการใดๆ ในแบ็กเอนด์ Java

utf8InCpp

utf8InCpp ประกาศว่า String แสดงในรูปแบบ UTF8 สำหรับแบ็กเอนด์ CPP คำอธิบายประกอบนี้จะไม่มีผลกับแบ็กเอนด์อื่นๆ ตามชื่อที่ระบุ โดยเฉพาะอย่างยิ่ง String จะเป็น UTF16 เสมอในแบ็กเอนด์ Java และเป็น UTF8 ในแบ็กเอนด์ NDK

คำอธิบายประกอบนี้สามารถแนบได้ทุกที่ที่ใช้ประเภท String ได้ รวมถึงค่าที่ส่งคืน พารามิเตอร์ การประกาศค่าคงที่ และฟิลด์ที่ส่งผ่านได้

สำหรับแบ็กเอนด์ CPP @utf8InCpp String ใน AIDL จะแมปกับ std::string โดยที่ String ที่ไม่มีคำอธิบายประกอบจะแมปกับ android::String16 เมื่อใช้ UTF16

VintfStability

VintfStability ประกาศว่าสามารถใช้ประเภทที่ผู้ใช้กำหนด (อินเทอร์เฟซ, Parcelable และ Enum) ในโดเมนของระบบและผู้ให้บริการได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับ ความสามารถในการทำงานร่วมกันระหว่างระบบกับผู้ให้บริการได้ที่ AIDL สำหรับ HAL

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

คำอธิบายประกอบจะแนบได้เฉพาะกับการประกาศประเภทที่ผู้ใช้กำหนดเท่านั้น ดังที่แสดง ที่นี่

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

เมื่อมีการอธิบายประเภทด้วย VintfStability ประเภทอื่นๆ ที่ อ้างอิงในประเภทนั้นควรมีการอธิบายเช่นกัน ในตัวอย่างต่อไปนี้ Data และ IBar ควรมีคำอธิบายประกอบเป็น VintfStability ทั้งคู่

@VintfStability
interface IFoo {
    void doSomething(in IBar b); // references IBar
    void doAnother(in Data d); // references Data
}

@VintfStability // required
interface IBar {...}

@VintfStability // required
parcelable Data {...}

นอกจากนี้ ไฟล์ AIDL ที่กำหนดประเภทซึ่งมีคำอธิบายประกอบ VintfStability จะสร้างได้โดยใช้ประเภทโมดูล aidl_interface Soong เท่านั้น โดยตั้งค่าพร็อพเพอร์ตี้ stability เป็น vintf

aidl_interface {
    name: "my_interface",
    srcs: [...],
    stability: "vintf",
}

UnsupportedAppUsage

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

คำอธิบายประกอบ UnsupportedAppUsage จะไม่มีผลต่อลักษณะการทำงานของโค้ดที่สร้างขึ้น โดยคำอธิบายประกอบจะใส่คำอธิบายประกอบเฉพาะคลาส Java ที่สร้างขึ้นด้วย คำอธิบายประกอบ Java ที่มีชื่อเดียวกัน

// in AIDL
@UnsupportedAppUsage
interface IFoo {...}

// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}

ซึ่งจะไม่มีผลกับแบ็กเอนด์ที่ไม่ใช่ Java

คำอธิบายประกอบการสนับสนุน

คำอธิบายประกอบ Backing จะระบุประเภทพื้นที่เก็บข้อมูลของประเภท enum ของ AIDL ดังนี้

@Backing(type="int")
enum Color { RED, BLUE, }

ในแบ็กเอนด์ CPP จะมีการปล่อยคลาส enum C++ ประเภท int32_t ดังนี้

enum class Color : int32_t {
    RED = 0,
    BLUE = 1,
}

หากไม่มีคำอธิบายประกอบ ระบบจะถือว่า type เป็น byte ซึ่งแมปกับ int8_t สำหรับแบ็กเอนด์ CPP

อาร์กิวเมนต์ type สามารถตั้งค่าได้เฉพาะประเภทจำนวนเต็มต่อไปนี้

  • byte (กว้าง 8 บิต)
  • int (32 บิต)
  • long (64 บิต)

NdkOnlyStableParcelable

NdkOnlyStableParcelable จะทำเครื่องหมายการประกาศ (ไม่ใช่คำจำกัดความ) ที่ส่งผ่านได้ ว่าเสถียรเพื่อให้สามารถอ้างอิงจากประเภท AIDL อื่นๆ ที่เสถียรได้ ซึ่งคล้ายกับ JavaOnlyStableParcelable แต่ NdkOnlyStableParcelable จะทำเครื่องหมายการประกาศที่ส่งผ่านได้เป็นแบบเสถียรสำหรับแบ็กเอนด์ NDK แทนที่จะเป็น Java

วิธีใช้ Parcelable นี้

  • คุณต้องระบุ ndk_header
  • คุณต้องมีไลบรารี NDK ที่ระบุ Parcelable และต้องคอมไพล์ไลบรารี ลงในไลบรารี เช่น ในระบบบิลด์หลักในโมดูล cc_* ให้ใช้ static_libs หรือ shared_libs สำหรับ aidl_interface ให้เพิ่ม ไลบรารีในส่วน additional_shared_libraries ใน Android.bp

JavaOnlyStableParcelable

JavaOnlyStableParcelable จะทำเครื่องหมายการประกาศ (ไม่ใช่คำจำกัดความ) ที่ส่งผ่านได้ ว่าเสถียรเพื่อให้สามารถอ้างอิงจากประเภท AIDL อื่นๆ ที่เสถียรได้

AIDL ที่เสถียรกำหนดให้ประเภทที่ผู้ใช้กำหนดทั้งหมดต้องเสถียร สำหรับ Parcelable การมีเสถียรภาพกำหนดให้ต้องอธิบายฟิลด์อย่างชัดเจนใน ไฟล์ต้นฉบับ AIDL

parcelable Data { // Data is a structured parcelable.
    int x;
    int y;
}

parcelable AnotherData { // AnotherData is also a structured parcelable
    Data d; // OK, because Data is a structured parcelable
}

หาก Parcelable ไม่มีโครงสร้าง (หรือเพียงประกาศ) ก็จะอ้างอิงไม่ได้

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable ช่วยให้คุณลบล้างการตรวจสอบได้เมื่อ Parcelable ที่คุณอ้างอิงพร้อมใช้งานอย่างปลอดภัยใน Android SDK

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive จะสร้างเมธอดสำหรับประเภทที่ส่งผ่านได้ในแบ็กเอนด์ Java โดยอัตโนมัติ ดังนี้

@JavaDerive(equals = true, toString = true)
parcelable Data {
  int number;
  String str;
}

คำอธิบายประกอบต้องมีพารามิเตอร์เพิ่มเติมเพื่อควบคุมสิ่งที่ต้อง สร้าง พารามิเตอร์ที่รองรับมีดังนี้

  • equals=trueสร้างequalsและhashCode
  • toString=true จะสร้างเมธอด toString ที่พิมพ์ชื่อของประเภท และฟิลด์ เช่น Data{number: 42, str: foo}

JavaDefault (เลิกใช้งาน)

JavaDefault ซึ่งเพิ่มใน Android 13 จะควบคุมว่าควรสร้างการรองรับการกำหนดเวอร์ชันการติดตั้งใช้งานเริ่มต้นหรือไม่ (สำหรับ setDefaultImpl) ระบบจะไม่สร้างการรองรับนี้โดยค่าเริ่มต้นอีกต่อไปเพื่อประหยัดพื้นที่

JavaPassthrough

JavaPassthrough ช่วยให้สามารถใส่คำอธิบายประกอบ Java API ที่สร้างขึ้นด้วยคำอธิบายประกอบ Java ที่กำหนดเองได้

คำอธิบายประกอบเหล่านี้ใน AIDL

@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")

จะกลายเป็นดังนี้ในโค้ด Java ที่สร้างขึ้น

@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)

ระบบจะส่งค่าของพารามิเตอร์ annotation โดยตรง คอมไพเลอร์ AIDL จะไม่ตรวจสอบค่าของพารามิเตอร์ หากมีข้อผิดพลาดทางไวยากรณ์ระดับ Java คอมไพเลอร์ AIDL จะไม่ตรวจพบ แต่คอมไพเลอร์ Java จะตรวจพบ

คำอธิบายประกอบนี้แนบกับเอนทิตี AIDL ใดก็ได้ คำอธิบายประกอบนี้ไม่มีผล สำหรับแบ็กเอนด์ที่ไม่ใช่ Java

RustDerive

RustDerive จะใช้ลักษณะสำหรับประเภท Rust ที่สร้างขึ้นโดยอัตโนมัติ

คำอธิบายประกอบต้องมีพารามิเตอร์เพิ่มเติมเพื่อควบคุมสิ่งที่ต้อง สร้าง พารามิเตอร์ที่รองรับมีดังนี้

  • Copy=true
  • Clone=true
  • Ord=true
  • PartialOrd=true
  • Eq=true
  • PartialEq=true
  • Hash=true

ดูคำอธิบายลักษณะเหล่านี้ได้ที่เอกสารประกอบของ Rust

FixedSize

FixedSize ทำเครื่องหมาย StructuredParcelable ว่าเป็นขนาดคงที่ หลังจากทำเครื่องหมายแล้ว คุณจะเพิ่มฟิลด์ใหม่ลงใน Parcelable ไม่ได้ ฟิลด์ทั้งหมดของ Parcelable ต้องเป็นประเภทขนาดคงที่ รวมถึงประเภทดั้งเดิม การแจงนับ อาร์เรย์ขนาดคงที่ และ Parcelable อื่นๆ ที่ทำเครื่องหมายด้วย FixedSize

ออบเจ็กต์ FixedSize มีขนาดและการจัดแนวที่เสถียรในแบ็กเอนด์ ndk

ประเภท ขนาด (ไบต์) การจัดแนว (ไบต์)
boolean 1 1
byte 1 1
char 2 2
int 4 4
long 8 8
float 4 4
double 8 8
parcelable ขนาดรวมของฟิลด์ทั้งหมด การจัดแนวที่ใหญ่ที่สุดของทุกฟิลด์
union ขนาดสูงสุดของทุกฟิลด์ การจัดแนวที่ใหญ่ที่สุดของฟิลด์ทั้งหมด
enum ขนาดของประเภทการสำรองข้อมูล การจัดแนวประเภทการสำรองข้อมูล
T[N] (อาร์เรย์ขนาดคงที่) ขนาดของ T * N การจัดแนวของ T
String, IBinder, FileDescriptor, ParcelFileDescriptor N/A N/A

ข้อบ่งชี้

Descriptor ระบุตัวอธิบายอินเทอร์เฟซของอินเทอร์เฟซอย่างบังคับ

package android.foo;

@Descriptor(value="android.bar.IWorld")
interface IHello {...}

ตัวอธิบายของอินเทอร์เฟซนี้คือ android.bar.IWorld หากไม่มี Descriptorคำอธิบายประกอบ ข้อบ่งชี้จะเป็น android.foo.IHello

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

@hide ในความคิดเห็น

คอมไพเลอร์ AIDL จะจดจำ @hide ในความคิดเห็นและส่งผ่านไปยังเอาต์พุต Java เพื่อให้ Metalava รับไป ความคิดเห็นนี้ช่วยให้มั่นใจได้ว่า ระบบบิลด์ของ Android จะรับรู้ว่า API ของ AIDL ไม่ใช่ API ของ SDK

@deprecated ในความคิดเห็น

คอมไพเลอร์ AIDL จะรับรู้ @deprecated ในความคิดเห็นเป็นแท็กเพื่อระบุเอนทิตี AIDL ที่ไม่ควรใช้อีกต่อไป ดังนี้

interface IFoo {
  /** @deprecated use bar() instead */
  void foo();
  void bar();
}

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