Chú thích trong AIDL

AIDL hỗ trợ các chú giải cung cấp thêm thông tin cho trình biên dịch AIDL về phần tử được chú thích. Điều này cũng ảnh hưởng đến mã mã giả lập được tạo.

Cú pháp tương tự như cú pháp của Java:

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

Ở đây, AnnotationName là tên của chú thích và AidlEntity là một thực thể AIDL như interface Foo, void method() hoặc int arg. Một chú giải sẽ được đính kèm vào thực thể theo sau chú giải đó.

Một số chú giải có thể có đối số được đặt bên trong dấu ngoặc đơn, như được hiển thị ở trên. Chú thích không có đối số không cần dấu ngoặc đơn. Ví dụ:

@AnnotationName AidlEntity

Các chú giải này không giống với các chú giải Java, mặc dù chúng trông rất giống nhau. Người dùng không thể xác định các chú giải AIDL tuỳ chỉnh; các chú giải đó đều được xác định trước. Một số chú giải chỉ ảnh hưởng đến một phần phụ trợ nhất định và không hoạt động trong các phần phụ trợ khác. Có nhiều quy định hạn chế kèm theo.

Dưới đây là danh sách các chú thích AIDL được xác định trước:

Chú thích Đã thêm vào phiên bản 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

rỗng

nullable khai báo rằng có thể không cung cấp giá trị của thực thể được chú giải.

Bạn chỉ có thể đính kèm chú giải này vào các loại dữ liệu trả về của phương thức, tham số phương thức và các trường theo gói.

interface IFoo {
    // method return types
    @nullable Data method();

    // method parameters
    void method2(in @nullable Data d);
}

parcelable Data {
    // parcelable fields
    @nullable Data d;
}

Không thể đính kèm chú thích vào các loại dữ liệu nguyên gốc. Sau đây là một lỗi.

void method(in @nullable int a); // int is a primitive type

Chú thích này không hoạt động đối với phần phụ trợ Java. Nguyên nhân là do trong Java, tất cả kiểu không phải là nguyên gốc đều được truyền qua tham chiếu, có thể là null.

Trong phần phụ trợ CPP, @nullable T ánh xạ tới std::unique_ptr<T> trong Android 11 trở xuống và tới std::optional<T> trong Android 12 trở lên.

Trong phần phụ trợ của NDK, @nullable T luôn ánh xạ với std::optional<T>.

Đối với loại L giống danh sách, chẳng hạn như T[] hoặc List<T>, @nullable L sẽ ánh xạ tới std::optional<std::vector<std::optional<T>>> (hoặc std::unique_ptr<std::vector<std::unique_ptr<T>>> trong trường hợp phần phụ trợ CPP cho Android 11 trở xuống).

Có một ngoại lệ đối với việc liên kết này. Khi TIBinder hoặc giao diện AIDL, thì @nullable không hoạt động. Nói cách khác, cả @nullable IBinderIBinder đều ánh xạ như nhau đến android::sp<IBinder>, vốn có thể có giá trị rỗng vì đây là một con trỏ mạnh (CPP vẫn thực thi tính chất rỗng, nhưng loại này vẫn là android::sp<IBinder>).

Kể từ Android 13, bạn có thể sử dụng @nullable(heap=true) cho các trường theo gói để lập mô hình các kiểu đệ quy. Bạn không thể sử dụng @nullable(heap=true) với tham số phương thức hoặc kiểu dữ liệu trả về. Khi được chú thích, trường này sẽ được liên kết với một tệp tham chiếu phân bổ vùng nhớ khối xếp std::unique_ptr<T> trong phần phụ trợ CPP/NDK. @nullable(heap=true) không hoạt động trong phần phụ trợ Java.

utf8InCpp

utf8InCpp khai báo rằng String được biểu thị dưới định dạng UTF8 cho phần phụ trợ CPP. Đúng như tên gọi, chú thích này không hoạt động đối với các phần phụ trợ khác. Cụ thể, String luôn là UTF16 trong phần phụ trợ Java và UTF8 trong phần phụ trợ NDK.

Bạn có thể đính kèm chú giải này vào bất kỳ nơi nào loại String có thể được sử dụng, bao gồm cả giá trị trả về, tham số, nội dung khai báo hằng số và trường có thể đóng gói.

Đối với phần phụ trợ CPP, @utf8InCpp String trong AIDL liên kết với std::string, trong khi String không có chú thích liên kết với android::String16 nơi sử dụng UTF16.

Lưu ý rằng sự tồn tại của chú giải utf8InCpp sẽ không làm thay đổi cách truyền các chuỗi qua dây. Các chuỗi luôn được truyền dưới dạng UTF16 qua truyền. Một chuỗi có chú thích utf8InCpp sẽ được chuyển đổi thành UTF16 trước khi được truyền. Khi nhận được một chuỗi, chuỗi đó sẽ được chuyển đổi từ UTF16 thành UTF8 nếu được chú thích là utf8InCpp.

Độ ổn định của Vintf

VintfStability khai báo rằng bạn có thể sử dụng một loại do người dùng xác định (giao diện, theo gói và enum) trên miền của hệ thống và nhà cung cấp. Xem phần AIDL cho HAL để biết thêm về khả năng tương tác của nhà cung cấp hệ thống.

Chú giải không thay đổi chữ ký của loại, nhưng khi được đặt, thực thể của loại này sẽ được đánh dấu là ổn định để có thể di chuyển giữa các quy trình của nhà cung cấp và hệ thống.

Bạn chỉ có thể đính kèm chú giải vào phần khai báo kiểu do người dùng xác định như minh hoạ dưới đây:

@VintfStability
interface IFoo {
    ....
}

@VintfStability
parcelable Data {
    ....
}

@VintfStability
enum Type {
    ....
}

Khi một kiểu được chú thích bằng VintfStability, mọi kiểu khác được tham chiếu trong kiểu đó cũng đều phải được chú giải theo cách tương tự. Trong ví dụ sau, cả DataIBar đều phải được chú thích bằng 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 {...}

Ngoài ra, các tệp AIDL xác định các loại được chú giải bằng VintfStability chỉ có thể được tạo bằng loại mô-đun aidl_interface Soong, trong đó thuộc tính stability được đặt thành "vintf".

aidl_interface {
    name: "my_interface",
    srcs: [...],
    stability: "vintf",
}

Sử dụng ứng dụng không được hỗ trợ

Chú thích UnsupportedAppUsage cho biết loại AIDL được chú giải là một phần của giao diện không phải SDK mà các ứng dụng cũ có thể truy cập được. Hãy xem Hạn chế đối với giao diện không phải SDK để biết thêm thông tin về các API ẩn.

Chú giải UnsupportedAppUsage không ảnh hưởng đến hành vi của mã được tạo. Chú thích chỉ chú giải lớp Java đã tạo bằng chú thích Java có cùng tên.

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

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

Tính năng này không hoạt động đối với các phần phụ trợ không phải là Java.

Dự phòng

Chú giải Backing chỉ định loại hình lưu trữ của một loại enum AIDL.

@Backing(type="int")
enum Color { RED, BLUE, }

Trong phần phụ trợ CPP, thao tác này sẽ tạo ra một lớp enum C++ thuộc loại int32_t.

enum class Color : int32_t {
    RED = 0,
    BLUE = 1,
}

Nếu chú thích bị bỏ qua, type được giả định là byte và ánh xạ với int8_t cho phần phụ trợ CPP.

Bạn chỉ có thể đặt đối số type thành các loại tích phân sau:

  • byte (rộng 8 bit)
  • int (rộng 32 bit)
  • long (rộng 64 bit)

NdkOnlyStableParcelable (Có thể đóng gói)

NdkOnlyStableParcelable đánh dấu một nội dung khai báo theo gói (không phải định nghĩa) là ổn định để có thể tham chiếu từ các kiểu AIDL ổn định khác. Hàm này giống như JavaOnlyStableParcelable, nhưng NdkOnlyStableParcelable đánh dấu một nội dung khai báo theo gói là ổn định cho phần phụ trợ NDK thay vì cho Java.

Cách sử dụng thuộc tính theo gói này:

  • Bạn phải chỉ định ndk_header.
  • Bạn phải có một thư viện NDK chỉ định gói có thể đóng gói và thư viện phải được biên dịch vào thư viện. Ví dụ: trong hệ thống xây dựng cốt lõi trên mô-đun cc_*, hãy sử dụng static_libs hoặc shared_libs. Đối với aidl_interface, hãy thêm thư viện trong additional_shared_libraries trong Android.bp.

Gói JavaOnlyStableParcelable

JavaOnlyStableParcelable đánh dấu một nội dung khai báo theo gói (không phải định nghĩa) là ổn định để có thể tham chiếu từ các kiểu AIDL ổn định khác.

AIDL ổn định yêu cầu tất cả các kiểu do người dùng xác định đều phải ổn định. Đối với các Parcelable, để ổn định, các trường của nó phải được mô tả rõ ràng trong tệp nguồn 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
}

Nếu gói bưu kiện không có cấu trúc (hoặc vừa được khai báo), thì bạn không thể tham chiếu đến gói đó.

parcelable Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

JavaOnlyStableParcelable cho phép bạn ghi đè yêu cầu kiểm tra này khi gói thuê bao mà bạn đang tham chiếu đã có sẵn một cách an toàn trong SDK Android.

@JavaOnlyStableParcelable
parcelable Data;

parcelable AnotherData {
    Data d; // OK
}

JavaDerive

JavaDerive tự động tạo phương thức cho các loại có thể đóng gói trong phần phụ trợ Java.

@JavaDerive(equals = true, toString = true)
parcelable Data {
  int number;
  String str;
}

Chú giải yêu cầu các tham số bổ sung để kiểm soát nội dung sẽ tạo. Các tham số được hỗ trợ bao gồm:

  • equals=true tạo các phương thức equalshashCode.
  • toString=true tạo phương thức toString để in tên loại và trường. Ví dụ: Data{number: 42, str: foo}

Mặc định Java

JavaDefault, được thêm vào Android 13, kiểm soát việc có tạo tính năng hỗ trợ tạo phiên bản triển khai mặc định hay không (cho setDefaultImpl). Tính năng hỗ trợ này không còn được tạo theo mặc định để tiết kiệm dung lượng.

Thông qua Java

JavaPassthrough cho phép chú thích API Java đã tạo bằng một chú thích Java tuỳ ý.

Các chú thích sau trong AIDL

@JavaPassthrough(annotation="@android.annotation.Alice")
@JavaPassthrough(annotation="@com.android.Alice(arg=com.android.Alice.Value.A)")

trở thành

@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)

trong mã Java đã tạo.

Giá trị của tham số annotation được phát trực tiếp. Trình biên dịch AIDL không xem xét giá trị của tham số. Nếu có lỗi cú pháp ở cấp độ Java, thì trình biên dịch AIDL sẽ không phát hiện lỗi đó mà chỉ bị trình biên dịch Java phát hiện.

Bạn có thể đính kèm chú thích này vào bất kỳ thực thể AIDL nào. Chú thích này không hoạt động đối với các phần phụ trợ không phải là Java.

Kích thước cố định

FixedSize đánh dấu kích thước cố định cho gói có cấu trúc. Sau khi đánh dấu, gói sẽ không được phép thêm trường mới vào đó. Tất cả các trường của gói có thể cũng phải có loại kích thước cố định, bao gồm kiểu dữ liệu gốc, enum, mảng kích thước cố định và các gói khác được đánh dấu bằng FixedSize.

Điều này không đảm bảo trên nhiều bit và không nên dựa vào hoạt động giao tiếp bit hỗn hợp.

Nội dung mô tả

Descriptor buộc chỉ định mã mô tả giao diện của một giao diện.

package android.foo;

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

Phần mô tả của giao diện này là android.bar.IWorld. Nếu thiếu chú thích Descriptor, phần mô tả sẽ là android.foo.IHello.

Điều này rất hữu ích khi đổi tên giao diện đã được xuất bản. Việc làm cho phần mô tả của giao diện đã đổi tên giống với phần mô tả của giao diện trước khi đổi tên cho phép hai giao diện giao tiếp với nhau.

@ẩn trong nhận xét

Trình biên dịch AIDL nhận dạng @hide trong các nhận xét và truyền mã này qua đầu ra Java để Metalava đến lấy hàng. Nhận xét này đảm bảo rằng hệ thống xây dựng Android biết rằng các API AIDL không phải là API SDK.

@đã ngừng hoạt động trong nhận xét

Trình biên dịch AIDL nhận dạng @deprecated trong các nhận xét dưới dạng một thẻ để xác định một thực thể AIDL không nên dùng nữa.

interface IFoo {
  /** @deprecated use bar() instead */
  void foo();
  void bar();
}

Mỗi phần phụ trợ đánh dấu các thực thể không dùng nữa bằng một chú thích hoặc thuộc tính dành riêng cho phần phụ trợ để cảnh báo mã ứng dụng nếu đề cập đến các thực thể không dùng nữa. Ví dụ: chú giải @Deprecated và thẻ @deprecated được đính kèm vào mã do Java tạo.