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>
เท่าๆ กัน ซึ่งก็อนุญาตให้เป็น Null ได้อยู่แล้วเนื่องจากเป็น pointer แบบ Strong (การอ่าน CPP จะยังคงบังคับใช้ Nullability แต่ประเภทจะยังคงเป็น 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 ไม่เป็นโครงสร้าง (หรือเพิ่งประกาศ) ระบบจะอ้างอิงไม่ได้
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 เป็นขนาดคงที่ เมื่อทำเครื่องหมายแล้ว ระบบจะไม่อนุญาตให้เพิ่มช่องใหม่ในแปลงที่ดิน ฟิลด์ทั้งหมดของรายการที่แยกส่วนได้ต้องเป็นแบบที่มีขนาดคงที่ด้วย ซึ่งรวมถึงประเภทพื้นฐาน อนุกรม อาร์เรย์ขนาดคงที่ และรายการที่แยกส่วนได้อื่นๆ ที่มีเครื่องหมาย 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 สร้างขึ้น