Аннотации в AIDL

AIDL поддерживает аннотации, которые предоставляют компилятору AIDL дополнительную информацию об аннотируемом элементе, что также влияет на сгенерированный код-заглушку.

Синтаксис похож на синтаксис Java:

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

Здесь AnnotationName — это имя аннотации, а AidlEntity — это сущность AIDL, например, interface Foo , void method() или int arg . К следующей за ней сущности прикрепляется аннотация.

Некоторые аннотации могут иметь аргументы, заданные внутри скобок, как показано в предыдущем примере. Аннотации, не имеющие аргументов, не нуждаются в скобках. Например:

@AnnotationName AidlEntity

Эти аннотации отличаются от аннотаций Java, хотя и выглядят похоже. Все аннотации предопределены и имеют ограничения по месту их применения. Некоторые аннотации влияют только на определенный бэкенд и не оказывают никакого воздействия на другие бэкенды.

Вот список предопределенных аннотаций 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 указывает, что значение аннотированного объекта может быть равно null.

Эту аннотацию можно добавлять только к типам возвращаемых значений методов, параметрам методов и полям, допускающим разделение по категориям:

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 .

В бэкенде C++ директива ` @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`, поскольку является сильным указателем (чтение в CPP по-прежнему обеспечивает допустимость значения `null`, но тип всё ещё android::sp<IBinder> `). В Rust эти типы допускают nullable только если они аннотированы @nullable . Они отображаются на Option<T> , если аннотированы.

Начиная с Android 13, аннотация @nullable(heap=true) может использоваться для полей, допускающих последовательность `parcelable`, для моделирования рекурсивных типов. @nullable(heap=true) нельзя использовать с параметрами методов или возвращаемыми типами. При использовании этой аннотации поле сопоставляется с выделенной в куче ссылкой std::unique_ptr<T> в бэкендах C++ и NDK. @nullable(heap=true) не выполняет никаких действий в бэкенде Java.

utf8InCpp

utf8InCpp указывает, что String представлена ​​в формате UTF8 для бэкенда C++. Как следует из названия, для других бэкендов эта аннотация ничего не делает. В частности, String всегда имеет кодировку UTF16 в бэкенде Java и UTF8 в бэкенде NDK.

Эту аннотацию можно добавить везде, где используется тип String , включая возвращаемые значения, параметры, объявления констант и поля, допускающие последовательность операций.

Для бэкенда на C++ @utf8InCpp String в AIDL соответствует std::string , тогда как String без аннотации соответствует android::String16 где используется кодировка UTF16.

VintfStability

VintfStability заявляет, что определяемый пользователем тип (интерфейс, параллелизуемый тип и перечисление) может использоваться в рамках системного и стороннего доменов. Дополнительную информацию о взаимодействии системы и поставщика см. в разделе 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 могут быть созданы только с использованием типа модуля aidl_interface Soong, у которого свойство stability установлено в значение vintf :

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

UnsupportedAppUsage

Аннотация UnsupportedAppUsage указывает на то, что аннотированный тип AIDL является частью интерфейса, не входящего в SDK, который был доступен для устаревших приложений. Дополнительную информацию о скрытых API см. в разделе «Ограничения на интерфейсы, не входящие в SDK» .

Аннотация UnsupportedAppUsage не влияет на поведение сгенерированного кода. Эта аннотация применяется только к сгенерированному 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, }

В бэкенде C++ это генерирует класс перечисления C++ типа int32_t :

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

Если аннотация опущена, предполагается, что typebyte , который соответствует int8_t для бэкенда CPP.

В качестве аргумента type можно установить только следующие целочисленные типы:

  • byte (8-битный)
  • int (32-битный)
  • long (64-битный по ширине)

NdkOnlyStableParcelable

NdkOnlyStableParcelable помечает объявление (а не определение) типа Parcelable как стабильное, чтобы на него можно было ссылаться из других стабильных типов AIDL. Это похоже на JavaOnlyStableParcelable , но NdkOnlyStableParcelable помечает объявление типа Parcelable как стабильное для бэкенда NDK, а не для Java.

Для использования этой посылки:

  • Необходимо указать ndk_header .
  • Необходимо наличие библиотеки NDK, указывающей на возможность использования Parcelable, и эта библиотека должна быть скомпилирована в основную библиотеку. Например, в основной системе сборки модуля cc_* используйте static_libs или shared_libs . Для aidl_interface добавьте библиотеку в additional_shared_libraries в Android.bp .

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 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 и 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)")

В сгенерированном Java-коде должно появиться следующее:

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

Значение параметра annotation передается напрямую. Компилятор AIDL не проверяет значение параметра. Если возникает синтаксическая ошибка на уровне Java, она будет обнаружена не компилятором AIDL, а компилятором Java.

Эта аннотация может быть прикреплена к любой сущности AIDL. Для бэкендов, не использующих Java, эта аннотация ничего не делает.

RustDerive

RustDerive автоматически реализует трейты для сгенерированных типов Rust.

Для аннотации требуются дополнительные параметры, определяющие процесс генерации. Поддерживаемые параметры:

  • Copy=true
  • Clone=true
  • Ord=true
  • PartialOrd=true
  • Eq=true
  • PartialEq=true
  • Hash=true

Для получения пояснений к этим свойствам см. документацию Rust .

Фиксированный размер

FixedSize помечает структурированный объект Parcelable как объект фиксированного размера. После присвоения такой маркировки добавлять новые поля в Parcelable нельзя. Все поля объекта Parcelable должны быть типами фиксированного размера, включая примитивные типы, перечисления, массивы фиксированного размера и другие объекты Parcelable, помеченные FixedSize .

Объекты FixedSize имеют стабильные размеры и выравнивание в бэкенде ndk .

Тип Размер (байты) Выравнивание (байты)
boolean 1 1
byte 1 1
char 2 2
int 4 4
long 8 8
float 4 4
double 8 8
parcelable Общий размер всех полей Наибольшее выравнивание всех полей
union Самое большое поле из всех. Наибольшее выравнивание всех полей
enum Размер типа подложки Выравнивание типа подложки
T[N] (массив фиксированного размера) Размер T * N Выравнивание T
String, IBinder, FileDescriptor, ParcelFileDescriptor N/A N/A

Дескриптор

Descriptor принудительно задает дескриптор интерфейса:

package android.foo;

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

Дескриптор этого интерфейса — android.bar.IWorld . Если аннотация Descriptor отсутствует, дескриптор будет android.foo.IHello .

Это полезно для переименования уже опубликованного интерфейса. Если сделать дескриптор переименованного интерфейса таким же, как и дескриптор интерфейса до переименования, это позволит двум интерфейсам взаимодействовать друг с другом.

@скрыть в комментариях

Компилятор AIDL распознает аннотацию @hide в комментариях и передает ее в вывод Java для обработки Metalava. Эта аннотация помогает гарантировать, что система сборки Android распознает, что API AIDL не являются API SDK.

@deprecated в комментариях

Компилятор AIDL распознает @deprecated в комментариях как тег, указывающий на сущность AIDL, которую больше не следует использовать:

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

Каждый бэкенд помечает устаревшие сущности аннотацией или атрибутом, специфичным для бэкенда, чтобы клиентский код получал предупреждение, если он ссылается на устаревшие сущности. Например, к сгенерированному Java-коду добавляются аннотация @Deprecated и тег @deprecated .