Аннотации в AIDL

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

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

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 сопоставляется с 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) можно использовать для разделяемых полей для моделирования рекурсивных типов. @nullable(heap=true) нельзя использовать с параметрами метода или возвращаемыми типами. Если оно снабжено аннотацией, поле сопоставляется с выделенной в куче ссылкой std::unique_ptr<T> в серверных модулях CPP/NDK. @nullable(heap=true) не работает в серверной части Java.

utf8InCpp

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

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

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

Обратите внимание, что наличие аннотации utf8InCpp не меняет способ передачи строк по сети. Строки всегда передаются по сети в формате UTF16. Строка с аннотацией utf8InCpp преобразуется в UTF16 перед передачей. Когда строка получена, она преобразуется из UTF16 в UTF8, если она была помечена как utf8InCpp .

VintfСтабильность

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 означает, что аннотированный тип 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 это создает класс перечисления C++ типа int32_t .

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

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

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

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

NdkOnlyStableParcelable

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

Чтобы использовать эту посылку:

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

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 Data; // Data is NOT a structured parcelable

parcelable AnotherData {
    Data d; // Error
}

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

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

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 знает, что API AIDL не являются API SDK.

@устарело в комментариях

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

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

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