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

วิธีใช้พาร์เซลนี้

  • คุณต้องระบุ 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}

ค่าเริ่มต้น Java

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 จะทําเครื่องหมายพาร์เซลที่มีโครงสร้างเป็นขนาดคงที่ เมื่อทำเครื่องหมายแล้ว จะไม่สามารถเพิ่มฟิลด์ที่แปลงข้อมูลได้ ทุกช่องของพื้นที่เก็บข้อมูลต้องเป็นประเภทขนาดคงที่ เช่น ประเภทพื้นฐาน, enum, อาร์เรย์ขนาดคงที่ และพาร์เซลอื่นๆ ที่ทำเครื่องหมายด้วย FixedSize

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

ข้อบ่งชี้

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

package android.foo;

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

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

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

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

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

@เลิกใช้งานแล้วในความคิดเห็น

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

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

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