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และhashCodetoString=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=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=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 สร้างขึ้น