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 .
В бэкэнде 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. В бэкенде Java аннотация @nullable(heap=true) не является оператором.
utf8InCpp
utf8InCpp объявляет, что String представлена в формате UTF8 для бэкенда CPP. Как следует из названия, эта аннотация не является операцией для других бэкендов. В частности, String всегда представлена в формате UTF16 в бэкенде Java и в формате UTF8 в бэкенде NDK.
Эту аннотацию можно прикрепить в любом месте, где может использоваться тип String , включая возвращаемые значения, параметры, объявления констант и пакетируемые поля.
Для бэкэнда CPP @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 означает, что аннотированный тип 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 помечает объявление (не определение) 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
}
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, помеченные как 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.