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
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 會對應至 Android 11 以下版本的 std::unique_ptr<T>,以及 Android 12 以上版本的 std::optional<T>。
在 NDK 後端中,@nullable T 一律會對應至 std::optional<T>。
在 Rust 後端中,@nullable T 一律會對應至 Option<T>。
對於列表類型 L (例如 T[] 或 List<T>),@nullable L 會對應至 std::optional<std::vector<std::optional<T>>> (如果是 Android 11 以下版本的 CPP 後端,則會對應至 std::unique_ptr<std::vector<std::unique_ptr<T>>>)。
不過,這項對應方式有例外狀況。如果 T 是 IBinder 或 AIDL 介面,@nullable 對所有後端都為無操作,但 Rust 除外。換句話說,@nullable IBinder 和 IBinder 都會對應至 android::sp<IBinder>,而 android::sp<IBinder> 是強力 指標,因此已可判斷為空值 (CPP 讀取仍會強制判斷為空值,但類型仍為 android::sp<IBinder>)。在 Rust 中,只有在加上 @nullable 註解時,這些類型才會是 nullable。如果已標註,則會對應至 Option<T>。
從 Android 13 開始,@nullable(heap=true) 可用於可分割的欄位,以模擬遞迴類型。@nullable(heap=true) 無法與方法參數或傳回類型搭配使用。加上註解後,這個欄位會對應至 CPP/NDK 後端中的堆積分配參照 std::unique_ptr<T>。@nullable(heap=true) 在 Java 後端中為無操作。
utf8InCpp
utf8InCpp 宣告 String 以 UTF8 格式表示 CPP 後端。顧名思義,註解對其他後端而言是無操作。具體來說,在 Java 後端中,String 一律為 UTF16,在 NDK 後端中則為 UTF8。
這個註解可附加至可使用 String 類型的任何位置,包括回傳值、參數、常數宣告和可分割的欄位。
針對 CPP 後端,AIDL 中的 @utf8InCpp String 會對應至 std::string,而沒有註解的 String 會對應至使用 UTF16 的 android::String16。
請注意,utf8InCpp 註解的存在並不會改變字串透過電線傳輸的方式。字串一律會以 UTF16 格式透過網路傳輸。utf8InCpp 註解字串會在傳送前轉換為 UTF16。收到字串時,如果標記為 utf8InCpp,系統會將其從 UTF16 轉換為 UTF8。
VintfStability
VintfStability 宣告使用者定義的類型 (介面、可分割包裝和列舉) 可在系統和供應商網域中使用。如要進一步瞭解系統供應商的互通性,請參閱「HAL 專用 AIDL」。
註解不會變更類型的簽章,但在設定時,類型執行個體會標示為穩定,以便在供應商和系統程序之間傳遞。
註解只能附加至使用者定義的類型宣告,如下所示:
@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 {...}
此外,定義以 VintfStability 加註的類型的 AIDL 檔案,只能使用 aidl_interface Soong 模組類型建構,且 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
Backing 註解會指定 AIDL 列舉型別的儲存類型。
@Backing(type="int")
enum Color { RED, BLUE, }
在 CPP 後端中,這會產生類型為 int32_t 的 C++ 列舉類別。
enum class Color : int32_t {
RED = 0,
BLUE = 1,
}
如果未使用註解,系統會假設 type 為 byte,並將其對應至 CPP 後端的 int8_t。
type 引數只能設為下列整數類型:
byte(寬度為 8 位元)int(32 位元寬度)long(64 位元寬度)
NdkOnlyStableParcelable
NdkOnlyStableParcelable 會將可分割宣告 (非定義) 標示為穩定,以便從其他穩定的 AIDL 類型參照。這與 JavaOnlyStableParcelable 類似,但 NdkOnlyStableParcelable 會將 parcelable 宣告標示為 NDK 後端的穩定版本,而非 Java 的穩定版本。
如何使用這個可分割的項目:
- 您必須指定
ndk_header。 - 您必須擁有指定可分割的 NDK 程式庫,且該程式庫必須編譯至程式庫。舉例來說,在
cc_*模組的核心建構系統中,請使用static_libs或shared_libs。如果是aidl_interface,請在Android.bp的additional_shared_libraries下方新增程式庫。
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
}
當您參照的 parcelable 已安全地提供為 Android SDK 的一部分時,JavaOnlyStableParcelable 可讓您覆寫檢查作業。
@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=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=true
如需這些特徵的說明,請前往 https://doc.rust-lang.org。
FixedSize
FixedSize 會將結構化 parcelable 標示為固定大小。標記後,Parcelable 就無法新增欄位。可分割的所有欄位也必須是固定大小的型別,包括基本型別、列舉、固定大小的陣列,以及標示為 FixedSize 的其他可分割項目。
這不會為不同位元數提供任何保證,也不應用於混合位元數的通訊。
描述元
Descriptor 會強制指定介面的介面描述元。
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
這個介面的描述元是 android.bar.IWorld。如果缺少 Descriptor 註解,描述元會是 android.foo.IHello。
這項功能可用於重新命名已發布的介面。讓重新命名的介面描述符與重新命名前的介面描述符相同,即可讓兩個介面互相通訊。
@hide in comments
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 程式碼。