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

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

ไวยากรณ์จะคล้ายกับ Java:

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

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

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

@AnnotationName AidlEntity

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

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

คำอธิบายประกอบ เพิ่มในเวอร์ชัน Android แล้ว
nullable 7
utf8InCpp 7
VintfStability 11
UnsupportedAppUsage 10
Hide 11
Backing 11
NdkOnlyStableParcelable 14
JavaOnlyStableParcelable 11
JavaDerive 12
JavaPassthrough 12
FixedSize 12
Descriptor 12

เว้นว่างได้

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

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

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 จะไม่มีผลกับแบ็กเอนด์ทั้งหมดยกเว้น Rust กล่าวคือ ทั้ง @nullable IBinder และ IBinder จะแมปกับ android::sp<IBinder> เท่าๆ กัน ซึ่งจะเป็น Nullable อยู่แล้วเนื่องจากเป็น pointer แบบ Strong (การอ่าน CPP จะยังคงบังคับใช้ Nullable แต่ประเภทจะยังคงเป็น android::sp<IBinder>) ใน Rust ประเภทเหล่านี้จะเป็น nullable ก็ต่อเมื่อมีการทำเครื่องหมายกำกับด้วย @nullable เท่านั้น โดยจะแมปกับ Option<T> หากมีคำอธิบายประกอบ

ตั้งแต่ 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

โปรดทราบว่าการใส่คำอธิบายประกอบ utf8InCpp จะไม่เปลี่ยนวิธีส่งสตริงผ่านเครือข่าย ระบบจะส่งสตริงเป็น UTF16 เสมอผ่านเครือข่าย ระบบจะแปลงสตริงที่มีคำอธิบายประกอบ utf8InCpp เป็น UTF16 ก่อนส่ง เมื่อได้รับสตริง ระบบจะแปลงจาก UTF16 เป็น UTF8 หากมีคำอธิบายประกอบเป็น utf8InCpp

VintfStability

VintfStability ประกาศว่าระบบและโดเมนของผู้ให้บริการสามารถใช้ประเภทที่ผู้ใช้กำหนด (อินเทอร์เฟซ พาร์เซลได้ และ 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 จะสร้างได้โดยใช้ประเภทโมดูล Soong aidl_interface เท่านั้น โดยตั้งค่าพร็อพเพอร์ตี้ 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 จะระบุประเภทพื้นที่เก็บข้อมูลของประเภท AIDL enum

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

ในแบ็กเอนด์ CPP การดำเนินการนี้จะสร้างคลาส C++ enum ประเภท 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 ที่เสถียรกำหนดให้ประเภทที่ผู้ใช้กำหนดทั้งหมดต้องเสถียร สำหรับพาร์เซล ความเสถียรกำหนดให้ต้องมีการอธิบายฟิลด์ในไฟล์ต้นทาง 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 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)")

กลายเป็น

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

ในโค้ด Java ที่สร้างขึ้น

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

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

FixedSize

FixedSize ทำเครื่องหมาย Structured Parcelable เป็นขนาดคงที่ เมื่อทำเครื่องหมายแล้ว ระบบจะไม่อนุญาตให้เพิ่มช่องใหม่ในแปลงที่ดิน ทุกช่องของพื้นที่เก็บข้อมูลต้องเป็นประเภทขนาดคงที่ด้วย เช่น ประเภทพื้นฐาน, enum, อาร์เรย์ขนาดคงที่ และพาร์เซลอื่นๆ ที่ทำเครื่องหมายด้วย FixedSize

การดำเนินการนี้ไม่ได้รับประกันอะไรเลยสำหรับบิตที่แตกต่างกัน และไม่ควรใช้เพื่อการสื่อสารแบบผสมบิต

ข้อบ่งชี้

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

package android.foo;

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

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

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

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

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

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

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

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

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