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)
можно использовать для полей parcelable для моделирования рекурсивных типов. @nullable(heap=true)
нельзя использовать с параметрами метода или возвращаемыми типами. При аннотации с ним поле сопоставляется с выделенной в куче ссылкой std::unique_ptr<T>
в бэкэндах CPP/NDK. @nullable(heap=true)
является no-op в бэкэнде 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
заявляет, что определяемый пользователем тип (интерфейс, parcelable и enum) может использоваться в доменах системы и поставщика. Подробнее о взаимодействии системы и поставщика см. в 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 является частью интерфейса non-SDK, который был доступен для устаревших приложений. Дополнительные сведения о скрытых API см. в разделе Ограничения на интерфейсы non-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
помечает 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)")
становиться
@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 также должны быть типами фиксированного размера, включая примитивные типы, перечисления, массивы фиксированного размера и другие parcelable, помеченные 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.
@deprecated в комментариях
Компилятор AIDL распознает @deprecated
в комментариях как тег, идентифицирующий сущность AIDL, которую больше не следует использовать.
interface IFoo {
/** @deprecated use bar() instead */
void foo();
void bar();
}
Каждый бэкенд помечает устаревшие сущности аннотацией или атрибутом, специфичным для бэкенда, чтобы клиентский код был предупрежден, если он ссылается на устаревшие сущности. Например, аннотация @Deprecated
и тег @deprecated
прикреплены к сгенерированному коду Java.