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
nullable указывает, что значение аннотированного объекта может быть нулевым.
Эту аннотацию можно прикрепить только к типам возвращаемых значений методов, параметрам методов и полям Parcelable:
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 не выполняет никаких действий для серверных частей Java, CPP и NDK. Например, в бэкенде CPP оба типа @nullable IBinder и IBinder одинаково сопоставляются с типом android::sp<IBinder>, который уже может иметь допустимость значения NULL, поскольку является указателем (при чтении в CPP и NDK по-прежнему требуется допустимость значения NULL, но тип остается android::sp<IBinder> или ndk::SpAIBinder).
В бэкенде Rust типы, которые не реализуют Default (IBinder, интерфейсы AIDL, ParcelFileDescriptor и неструктурированные объекты Parcelable), сопоставляются с Option<T> в зависимости от контекста:
- Типы возвращаемых значений методов, параметры
inи параметрыinout. Эти типы допускают значение NULL, только если они аннотированы с помощью@nullable, сопоставляемого сOption<T>(илиOption<&T>для параметровinи&mut Option<T>для параметровinout). Без@nullableони напрямую сопоставляются сT(или&Tи&mut T). - Поля Parcelable и параметры
out. Поскольку сгенерированные объекты Parcelable в Rust наследуют параметрыDefaultиout, которые инициализируются по умолчанию, эти типы всегда сопоставляются сOption<T>(а массивы фиксированного размера в этих контекстах сопоставляются с[Option<T>; N], тогда как динамические массивы в параметрахoutсопоставляются сVec<Option<T>>), даже без@nullable. Если аннотация@nullableотсутствует, проверка на возможность иметь значение null выполняется во время выполнения при передаче данных (если значение равноNone, возвращаетсяStatusCode::UNEXPECTED_NULL).
Начиная с Android 13, @nullable(heap=true) можно использовать для полей parcelable, чтобы моделировать рекурсивные типы. @nullable(heap=true) нельзя использовать с параметрами методов или типами возвращаемых значений. Если поле аннотировано с помощью этого тега, оно сопоставляется со ссылкой std::unique_ptr<T>, выделенной в куче, в серверных частях CPP и NDK. В серверном коде Java функция @nullable(heap=true) не выполняет никаких действий.
utf8InCpp
utf8InCpp указывает, что String представлен в формате UTF8 для внутреннего кода CPP. Как следует из названия, аннотация не работает для других бэкендов.
В частности, String всегда имеет кодировку UTF16 в серверной части Java и UTF8 в серверной части NDK.
Эту аннотацию можно прикрепить в любом месте, где можно использовать тип String, включая возвращаемые значения, параметры, объявления констант и поля Parcelable.
Для бэкенда CPP @utf8InCpp String в AIDL сопоставляется с std::string, а String без аннотации – с android::String16, где используется UTF16.
VintfStability
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, можно создавать только с помощью модуля Soong типа aidl_interface, для которого свойство stability имеет значение vintf:
aidl_interface {
name: "my_interface",
srcs: [...],
stability: "vintf",
}
UnsupportedAppUsage
Аннотация UnsupportedAppUsage указывает, что аннотированный тип AIDL является частью интерфейса, не относящегося к SDK, который был доступен для устаревших приложений.
Подробнее об ограничениях на интерфейсы, не относящиеся к 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.
Чтобы использовать этот объект Parcelable:
- Вы должны указать свойство
ndk_header. - У вас должна быть библиотека NDK, в которой указан объект Parcelable, и эта библиотека должна быть скомпилирована в библиотеку. Например, в основной системе сборки в модуле
cc_*используйтеstatic_libsилиshared_libs. Дляaidl_interfaceдобавьте библиотеку в разделadditional_shared_librariesфайлаAndroid.bp.
JavaOnlyStableParcelable
JavaOnlyStableParcelable помечает объявление (не определение) parcelable как стабильное, чтобы на него можно было ссылаться из других стабильных типов AIDL.
Стабильный AIDL требует, чтобы все пользовательские типы были стабильными. Для объектов Parcelable стабильность означает, что их поля явно описаны в исходном файле 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 автоматически создает методы для типов Parcelable в серверной части 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=trueClone=trueOrd=truePartialOrd=trueEq=truePartialEq=trueHash=true
Описание этих черт можно найти в документации по языку Rust.
FixedSize
FixedSize помечает структурированный объект Parcelable как имеющий фиксированный размер. После этого вы не сможете добавлять новые поля в Parcelable. Все поля parcelable должны быть типами фиксированного размера, включая примитивные типы, перечисления, массивы фиксированного размера и другие parcelable, помеченные как FixedSize.
Объекты FixedSize имеют стабильные размеры и выравнивание в серверной части ndk.
| Тип | Размер (байты) | Выравнивание (байты) |
|---|---|---|
boolean |
1 |
1 |
byte |
1 |
1 |
char |
2 |
2 |
int |
4 |
4 |
long |
8 |
8 |
float |
4 |
4 |
double |
8 |
8 |
parcelable |
Общий размер всех полей | Самое большое выравнивание всех полей |
union |
Самый большой размер всех полей | Выравнивание по самому большому полю |
enum |
Размер типа поддержки | Соответствие типа резервного копирования |
T[N] (массив фиксированного размера) |
Размер: T * N |
Соответствие: T |
String, IBinder, FileDescriptor, ParcelFileDescriptor |
N/A |
N/A |
Дескриптор
Descriptor принудительно задает дескриптор интерфейса:
package android.foo;
@Descriptor(value="android.bar.IWorld")
interface IHello {...}
Дескриптор этого интерфейса – android.bar.IWorld. Если аннотация Descriptor отсутствует, дескриптор будет иметь значение android.foo.IHello.
Это полезно, если вы хотите переименовать уже опубликованный интерфейс. Если дескриптор переименованного интерфейса будет таким же, как дескриптор интерфейса до переименования, то два интерфейса смогут взаимодействовать друг с другом.
@hide в комментариях
Компилятор 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.