AIDL 中的註解

AIDL 支持為 AIDL 編譯器提供有關帶註釋元素的額外信息的註釋,這也會影響生成的存根代碼。

語法類似於Java:

@AnnotationName(argument1=value, argument2=value) AidlEntity

這裡, AnnotationName是註解的名稱, AidlEntity是一個 AIDL 實體,例如interface Foo 、 void method()或int arg 。註釋附加到它後面的實體。

一些註釋可以在括號內設置參數,如上所示。沒有參數的註釋不需要括號。例如:

@AnnotationName AidlEntity

這些註釋與 Java 註釋不同,儘管它們看起來非常相似。用戶不能定義自定義 AIDL 註解;註釋都是預定義的。一些註釋只影響某個後端並且在其他後端是無操作的。它們在可以附加的地方有不同的限制。

下面是預定義的 AIDL 註釋列表:

註釋安卓版新增
nullable 7
utf8InCpp 7
VintfStability 11
UnsupportedAppUsage 10
Hide 11
Backing 11
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> 。

對於類似列表的類型L ,例如T[]或List<T> , @nullable L映射到std::optional<std::vector<std::optional<T>>> (或std::unique_ptr<std::vector<std::unique_ptr<T>>>如果是 Android 11 或更低版本的 CPP 後端)。

此映射有一個例外。當T是IBinder或 AIDL 接口時, @nullable是無操作的。換句話說, @nullable IBinder和IBinder同樣映射到android::sp<IBinder> ,它已經可以為空,因為它是一個強指針(CPP 讀取仍然強制可空性,但類型仍然是android::sp<IBinder> )。

從 Android T(AOSP 實驗性)開始, @nullable(heap=true)可用於 parcelable 字段以對遞歸類型進行建模。 @nullable(heap=true)不能與方法參數或返回類型一起使用。當使用它進行註釋時,該字段將映射到 CPP/NDK 後端中的堆分配引用std::unique_ptr<T> 。 @nullable(heap=true)在 Java 後端是無操作的。

utf8InCpp

utf8InCpp聲明一個String以 UTF8 格式表示 CPP 後端。顧名思義,註解對於其他後端是無操作的。具體來說, String在 Java 後端始終為 UTF16,在 NDK 後端始終為 UTF8。

這個註解可以附加到任何可以使用String類型的地方,包括返回值、參數、常量聲明和 parcelable 字段。

對於 CPP 後端,AIDL 中的@utf8InCpp String映射到std::string ,而沒有註釋的String映射到使用 UTF16 的android::String16 。

請注意, utf8InCpp註釋的存在不會改變字符串通過網絡傳輸的方式。字符串始終以 UTF16 格式通過網絡傳輸。一個utf8InCpp註釋的字符串在傳輸之前被轉換為 UTF16。當接收到一個字符串時,如果它被註釋為utf8InCpp ,它會從 UTF16 轉換為 UTF8。

Vintf穩定性

VintfStability聲明用戶定義的類型(接口、parcelable 和枚舉)可以跨系統和供應商域使用。有關係統供應商互操作性的更多信息,請參閱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註釋表示帶註釋的 AIDL 類型是舊版應用程序可訪問的非 SDK 接口的一部分。有關隱藏 API 的更多信息,請參閱對非 SDK 接口的限制。

UnsupportedAppUsage註釋不會影響生成代碼的行為。註解只用同名的Java註解對生成的Java類進行註解。

// in AIDL
@UnsupportedAppUsage
interface IFoo {...}

// in Java
@android.compat.annotation.UnsupportedAppUsage
public interface IFoo {...}

這對於非 Java 後端是無操作的。

後盾

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 位寬)

JavaOnlyStableParcelable

JavaOnlyStableParcelable將 parcelable 聲明(而非定義)標記為穩定,以便可以從其他穩定的 AIDL 類型引用它。

穩定的 AIDL 要求所有用戶定義的類型都是穩定的。對於 parcelables,穩定要求其字段在 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
}

Java派生

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}

Java默認

JavaDefault在 Android T(AOSP 實驗性)中添加,控制是否生成默認實現版本控制支持(用於setDefaultImpl )。為了節省空間,默認情況下不再生成此支持。

JavaPassthrough

JavaPassthrough允許使用任意 Java 註釋對生成的 Java API 進行註釋。

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 後端是無操作的。

固定尺寸

FixedSize將結構化 Parcelable 標記為固定大小。一旦標記,parcelable 將不允許添加新字段。 parcelable 的所有字段也必須是固定大小的類型,包括原始類型、枚舉、固定大小的數組和其他標有 FixedSize 的FixedSize 。

這不提供跨不同位的任何保證,並且不應依賴於混合位通信。

描述符

Descriptor強制指定接口的接口描述符。

package android.foo;

@Descriptor(value="android.bar.IWorld")
interface IHello {...}

上述接口的描述符是android.bar.IWorld 。如果缺少Descriptor註釋,則描述符將為android.foo.IHello 。

這對於重命名已發布的接口很有用。使重命名接口的描述符與重命名前接口的描述符相同,允許兩個接口相互通信。

@隱藏在評論中

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 生成的代碼。