Аннотации в 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
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 std::optional<T> в Android 12 или более поздней версии.

В бэкэнде 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>>> в случае серверной части CPP для Android 11 или ниже).

Существует исключение из этого сопоставления. Когда T является IBinder или AIDL, @nullable не работает. Другими словами, как @nullable IBinder , так и IBinder в равной степени сопоставляются с android::sp<IBinder> , который уже допускает значение NULL, поскольку является сильным указателем (чтение CPP по-прежнему обеспечивает обнуляемость, но тип по-прежнему остается android::sp<IBinder> ).

Начиная с Android T (экспериментальный AOSP), @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-битный)

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
}

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}

JavaDefault

JavaDefault , добавленный в Android T (экспериментальный AOSP), управляет созданием поддержки версий реализации по умолчанию (для setDefaultImpl ). Эта поддержка больше не создается по умолчанию в целях экономии места.

JavaPassthrough

JavaPassthrough позволяет аннотировать созданный Java API произвольной аннотацией 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 для захвата металавой. Этот комментарий гарантирует, что система сборки Android знает, что API-интерфейсы AIDL не являются API-интерфейсами SDK.

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

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

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

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