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

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

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

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

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

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

@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 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 ประกาศว่า CPP แสดง String ในรูปแบบ UTF8 แบ็กเอนด์ คำอธิบายประกอบเป็นสิ่งที่ไม่มีการดำเนินการสำหรับแบ็กเอนด์อื่นๆ ตามที่ชื่อระบุไว้ กล่าวอย่างเจาะจงคือ 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 สามารถสร้างได้โดยใช้ประเภทโมดูล aidl_interface ของ Soong เท่านั้นด้วย ตั้งค่าพร็อพเพอร์ตี้ stability เป็น "vintf" แล้ว

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

การใช้งานแอปที่ไม่รองรับ

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

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

ขนาดคงที่

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

ซึ่งไม่ได้ให้การรับประกันใดๆ ในทุกกรณี และไม่ควร อาศัยการสื่อสารที่มีความหลากหลาย

ข้อบ่งชี้

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

package android.foo;

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

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

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

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

คอมไพเลอร์ 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 สร้างขึ้น