คําอธิบายประกอบใน 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> เสมอ

ในแบ็กเอนด์ 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>อย่างเท่าเทียมกัน ซึ่ง เป็นค่าที่กำหนดให้เป็น Null ได้อยู่แล้วเนื่องจากเป็นพอยน์เตอร์ที่เข้มงวด (CPP ยังคง บังคับให้กำหนดค่าเป็น Null ได้ แต่ประเภทก็ยังคงเป็น 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 ผ่านสายเสมอ ระบบจะแปลงสตริงที่มีคำอธิบายประกอบเป็น UTF16 ก่อนที่จะส่ง utf8InCpp เมื่อได้รับสตริง ระบบจะแปลงจาก UTF16 เป็น UTF8 หากมีการ ใส่คำอธิบายประกอบเป็น utf8InCpp

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: &quot;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)")

กลายเป็น

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

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

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

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

RustDerive

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

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

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

ดูคำอธิบายลักษณะเหล่านี้ได้ที่ https://doc.rust-lang.org

FixedSize

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

ซึ่งไม่ได้เป็นการรับประกันสำหรับบิตเนสต่างๆ และไม่ควรใช้ ในการสื่อสารแบบผสมบิตเนส

ข้อบ่งชี้

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 ทราบว่า AIDL API ไม่ใช่ SDK API

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

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

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

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