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
является no-op для всех бэкендов, кроме 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.
Обратите внимание, что наличие аннотации utf8InCpp
не влияет на способ передачи строк по сети. Строки всегда передаются по сети в кодировке UTF16. Строка с аннотацией utf8InCpp
преобразуется в UTF16 перед передачей. При получении строка преобразуется из UTF16 в UTF8, если она была аннотирована как utf8InCpp
.
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 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)")
становиться
@android.annotation.Alice
@com.android.Alice(arg=com.android.Alice.Value.A)
в сгенерированном коде Java.
Значение параметра annotation
выдаётся напрямую. Компилятор AIDL не анализирует значение параметра. Если есть какая-либо синтаксическая ошибка на уровне Java, она будет обнаружена не компилятором AIDL, а компилятором Java.
Эту аннотацию можно прикрепить к любой сущности AIDL. Для бэкендов, отличных от Java, эта аннотация не является операцией.
RustDerive
RustDerive
автоматически реализует черты для сгенерированных типов Rust.
Для управления генерируемыми данными аннотации требуются дополнительные параметры. Поддерживаются следующие параметры:
-
Copy=true
-
Clone=true
-
Ord=true
-
PartialOrd=true
-
Eq=true
-
PartialEq=true
-
Hash=true
Объяснения этих характеристик см. на сайте https://doc.rust-lang.org.
Фиксированный размер
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.