Język AIDL jest luźno oparty na języku Java. Pliki określają umowę interfejsu oraz różne typy danych i stałe używane w tej umowie.
Przesyłka
Każdy plik AIDL zaczyna się od opcjonalnego pakietu, który odpowiada nazwom pakietów w różnych backendach. Deklaracja pakietu wygląda tak:
package my.package;
Podobnie jak w przypadku plików Java, pliki AIDL muszą znajdować się w strukturze folderów odpowiadającej ich pakietowi. Pliki z pakietem my.package
muszą znajdować się w folderze my/package/
.
Typy
W plikach AIDL typy można określać w wielu miejscach. Dokładną listę typów backendów obsługiwanych w języku AIDL znajdziesz w artykule Typy backendów AIDL.
Adnotacje
kilka części adnotacji dotyczących obsługi języka w AIDL; Listę adnotacji i miejsca, w których można je stosować, znajdziesz w sekcji Adnotacje AIDL.
Importy
Aby używać typów zdefiniowanych w innych interfejsach, musisz najpierw dodać zależności w systemie kompilacji. W modułach Soong cc_*
i java_*
, w których pliki .aidl
są używane bezpośrednio w srcs
w kompilacji platformy Android, możesz dodawać katalogi za pomocą pola aidl: { include_dirs: ... }
. Więcej informacji o importowaniu za pomocą właściwości aidl_interface
znajdziesz tutaj.
Import wygląda tak:
import some.package.Foo; // explicit import
Podczas importowania typu w tym samym pakiecie można pominąć ten pakiet. Pominięcie pakietu może jednak spowodować niejednoznaczne błędy importowania, gdy typy są określone bez pakietu i znajdują się w przestrzeni nazw globalnej (zazwyczaj wszystkie typy powinny mieć przestrzeń nazw):
import Foo; // same as my.package.Foo
Definiowanie typów
Pliki AIDL zwykle definiują typy używane jako interfejs.
Interfejsy
Oto przykład interfejsu AIDL:
interface ITeleport {
// Location defined elsewhere
void teleport(Location baz, float speed);
String getName();
// ITeleportCallback defined elsewhere
void methodWithCallback(ITeleportCallback callback);
// ITeleportSession defined elsewhere
ITeleportSession getASubInterface();
}
Interfejs definiuje obiekt za pomocą serii metod. Metody mogą być asynchroniczne (oneway
) lub synchroniczne.oneway void doFoo()
Jeśli interfejs jest zdefiniowany jako oneway
(oneway interface ITeleport {...}
), wszystkie zawarte w nim metody domyślnie mają ustawioną wartość oneway
. Metody jednokierunkowe są wysyłane asynchronicznie i nie mogą zwrócić wyniku. Jednokierunkowe metody z tego samego wątku do tego samego powiązania również są wykonywane po kolei (choć potencjalnie w różnych wątkach). Informacje o konfigurowaniu wątków znajdziesz w artykule Zarządzanie wątkami w systemie AIDL backend.
Binder umożliwia udostępnianie wielu interfejsów i obiektów bindera za pomocą interfejsów bindera. Interfejsy AIDL często używają wywołań zwrotnych w ramach wywołań metod, na przykład ITeleportCallback
w poprzednim przykładzie. Możesz używać wywołań zwrotnych pomiędzy wywołaniami tej samej metody lub różnych metod. Innym
częstym zastosowaniem typów interfejsów jest zwracanie obiektów podrzędnych lub sesji przez metody takie jak ITeleportSession
w poprzednim przykładzie. Dzięki temu różne interfejsy API mogą być opakowane na poziomie interfejsu API lub na podstawie stanu w czasie wykonywania. Sesja może na przykład reprezentować własność określonego zasobu. Gdy interfejsy są przekazywane wielokrotnie lub zwracane do klienta lub serwera, z którego pochodzą, zawsze zachowują równość wskaźnika do podstawowego obiektu bindera.
Metody mogą mieć zero lub więcej argumentów. Argumenty metod mogą być typu in
, out
lub inout
. Informacje o tym, jak ta zmiana wpływa na typy argumentów, znajdziesz w artykule AIDL: kierunkowość backendów.
Parcelables
Aby dowiedzieć się, jak tworzyć obiekty parcelable dla konkretnego backendu, zapoznaj się z artykułem Parcelable dla backendu AIDL.
Android 10 i nowsze wersje obsługują definicje parcelable bezpośrednio w pliku AIDL. Ten typ obiektu do zapakowania nazywamy obiektem zapakowanym strukturalnie. Więcej informacji o tym, jak uporządkowane i stabilne AIDL są ze sobą powiązane w kompilatorze AIDL i naszym systemie kompilacji, znajdziesz w sekcji Uporządkowane i stabilne AIDL.
Na przykład:
package my.package;
import my.package.Boo;
parcelable Baz {
@utf8InCpp String name = "baz";
Boo boo;
}
Związki
Android 12 i nowsze wersje obsługują deklaracje z otagowanymi typami z unii. Na przykład:
package my.package;
import my.package.FooSettings;
import my.package.BarSettings;
union Settings {
FooSettings fooSettings;
BarSettings barSettings;
@utf8InCpp String str;
int number;
}
Szczegółowe informacje o backendach znajdziesz w artykule Związki backendu AIDL.
Wykazy
Android 11 i nowsze obsługują deklaracje typów wyliczeniowych. Na przykład:
package my.package;
enum Boo {
A = 1 * 4,
B = 3,
}
Deklaracje typu zagnieżdżonego
Android 13 i nowsze wersje obsługują deklaracje typu zagnieżdżone. Na przykład:
package my.package;
import my.package.Baz;
interface IFoo {
void doFoo(Baz.Nested nested); // defined in my/package/Baz.aidl
void doBar(Bar bar); // defined below
parcelable Bar { ... } // nested type definition
}
Stałe
Niestandardowe interfejsy AIDL, obiekty Parcelable i typy zjednoczone mogą też zawierać stałe liczbowe i ciągowe, takie jak:
const @utf8InCpp String HAPPY = ":)";
const String SAD = ":(";
const byte BYTE_ME = 1;
const int ANSWER = 6 * 7;
wyrażenia statyczne,
Stałej AIDL, rozmiarów tablic i enumeracji można używać za pomocą wyrażeń stałych. W wyrażeniach możesz używać nawiasów do zagnieżdżania operacji. Wartości wyrażeń stałych mogą być używane z wartościami całkowitymi lub zmiennoprzecinkowymi.
Literaly true
i false
reprezentują wartości logiczne. Wartości z .
, ale bez przyrostka, np. 3.8
, są uznawane za wartości podwójne. Wartości zmiennoprzecinkowe mają sufiks f
, np. 2.4f
. Wartość całkowita z sufiksem l
lub L
oznacza 64-bitową wartość. W przeciwnym razie wartości całkowite otrzymują najmniejszy typ ze znakiem, który zachowuje wartość, spośród 8-bitowego (byte), 32-bitowego (int) i 64-bitowego (long). 256
jest uznawany za int
, ale 255 + 1
wykracza poza byte
0
. Wartości szesnastkowe, takie jak 0x3
, są najpierw interpretowane jako najmniejszy typ bez znaku, który zachowuje wartość, między 32- i 64-bitową, a następnie interpretowane jako wartości bez znaku. W związku z tym 0xffffffff
ma wartość int
-1
. Począwszy od Androida 13, do stałych wartości, takich jak 3u8
, można dodawać sufiks u8
, aby reprezentowały one wartość byte
. Ten przyrostek jest ważny, ponieważ dzięki niemu obliczenie takie jak 0xffu8 * 3
jest interpretowane jako -3
typu byte
, podczas gdy 0xff * 3
jest 765
typu int
.
Obsługiwane operatory mają semantykę C++ i Java. Operatory binarne w kolejności od najniższego do najwyższego są: || && | ^ & == != < > <= >= << >> + - * / %
. Operatory jednoargumentowe to + - ! ~
.