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
會對應至 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
是 或 AIDL 介面時,除了 Rust 以外,@nullable
對所有後端都是無運算。IBinder
換句話說,@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 後端。如名稱所示,註解是其他後端的無運算元。
具體來說,String
在 Java 後端一律為 UTF16,在 NDK 後端則為 UTF8。
只要可以使用 String
型別,就能附加這項註解,包括回傳值、參數、常數宣告和可封送欄位。
如果是 CPP 後端,AIDL 中的 @utf8InCpp String
會對應至 std::string
,而沒有註解的 String
則會對應至使用 UTF16 的 android::String16
。
請注意,utf8InCpp
註解的存在不會改變字串透過網路傳輸的方式。字串一律會透過網路以 UTF16 傳輸。utf8InCpp
註解字串會先轉換為 UTF16,再進行傳輸。收到字串時,如果已註解為 utf8InCpp
,系統會將字串從 UTF16 轉換為 UTF8。
VintfStability
VintfStability
宣告使用者定義型別 (介面、可封送和列舉) 可在系統和供應商網域中使用。如要進一步瞭解系統與供應商的互通性,請參閱「AIDL for HALs」。
註解不會變更型別的簽章,但設定後,型別的例項會標示為穩定,因此可以在供應商和系統程序之間傳輸。
註解只能附加至使用者定義的型別宣告,如下所示:
@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: &
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
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
會將可封送的宣告標示為 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
Android 13 新增的 JavaDefault
可控制是否產生預設實作版本控管支援 (適用於 setDefaultImpl
)。為節省空間,系統不再預設產生這項支援。
JavaPassthrough
JavaPassthrough
可讓產生的 Java API 加上任意 Java 註解。
AIDL 中的下列註解
@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Al
ice.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
會將結構化可打包物件標示為固定大小。標記後,系統就不允許在可封送物件中新增欄位。可封送物件的所有欄位也必須是固定大小的型別,包括原始型別、列舉、固定大小的陣列,以及標示為 FixedSize
的其他可封送物件。
這無法保證不同位元數之間的相容性,因此不應做為混合位元數通訊的依據。
描述元
Descriptor
會強制指定介面的介面描述元。
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHe
llo {...}
這個介面的描述元為 android.bar.IWorld
。如果缺少 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 程式碼。