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

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

ไวยากรณ์คล้ายกับของ 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> เสมอ

สำหรับประเภทรายการเหมือน 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 จะเป็น no-op กล่าวอีกนัยหนึ่ง ทั้ง @nullable IBinder และ IBinder แมปกับ android::sp<IBinder> อย่างเท่าเทียมกัน ซึ่งเป็นโมฆะอยู่แล้วเพราะมันเป็น ตัวชี้ ที่แข็งแกร่ง (CPP การอ่านยังคงบังคับใช้ความเป็นโมฆะ แต่ประเภทยังคงเป็น android::sp<IBinder> ).

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

Vintfความเสถียร

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

คำอธิบายประกอบ 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 รายการด้านบนจะส่งคลาส 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

หากต้องการใช้พัสดุนี้: * คุณต้องระบุ ndk_header * คุณต้องมีไลบรารี NDK ที่ระบุพัสดุ และต้องรวบรวมไลบรารีลงในไลบรารี ตัวอย่างเช่น ในระบบคอร์บิลด์บนโมดูล 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 ช่วยให้คุณสามารถแทนที่การตรวจสอบเมื่อพัสดุที่คุณกำลังอ้างอิงนั้นพร้อมใช้งานอย่างปลอดภัยแล้วโดยเป็นส่วนหนึ่งของ 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

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

คำอธิบาย

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

package android.foo;

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

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

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

@ซ่อนในความคิดเห็น

คอมไพลเลอร์ 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