Język AIDL

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 można określić wiele typów. Dokładną listę typó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żyć typów zdefiniowanych w innych interfejsach, musisz najpierw dodać zależności w systemu kompilacji. w modułach cc_* i java_*, w których używane są pliki .aidl. bezpośrednio w obszarze srcs w kompilacjach platformy Androida, możesz dodawać katalogi za pomocą pola aidl: { include_dirs: ... }. W przypadku importu przy użyciu aidl_interface, zobacz 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 zasadniczo definiują typy używane jako interfejsy.

Interfejsy

Oto przykładowy interfejs 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ć oneway (oneway void doFoo()) lub synchroniczne. Jeśli interfejs jest zdefiniowany jako oneway (oneway interface ITeleport {...}), wszystkie metody w nim są domyślnie oneway. Metody jednokierunkowe są wysyłane asynchronicznie i nie mogą zwracać wyniku. Jednokierunkowe metody z tego samego wątku do tego samego łącznika są również wykonywane sekwencyjnie (chociaż 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 w ramach wywołań metod wykorzystują wywołania zwrotne, jak w ITeleportCallback w poprzednim przykładzie. Możesz używać wywołań zwrotnych w ramach wywołań tej samej metody lub różnych metod. Inny typowym zastosowaniem interfejsów jest interfejs podrzędny lub obiekty sesji, które są zwracane za pomocą metod takich jak ITeleportSession w z poprzedniego przykładu. 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 przedstawiać prawa własności do określonego zasobu. Gdy interfejsy są przekazywane między wieloma lub wróciły do klienta bądź serwera, z których przyszły, zawsze zachowują równość wskaźnika bazowego obiektu wiązania.

Metody mogą mieć zero lub więcej argumentów. Argumenty metod mogą być 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ć pakiety dodatkowe specyficzne dla backendu, Niestandardowe backendy AIDL Parcelables.

Android 10 i nowsze wersje obsługują definicje parcelable bezpośrednio w pliku AIDL. Ten typ przesyłki nazywanej paczkomatem strukturalnym. Więcej informacji o tym, jak uporządkowane i stabilne AIDL są ze sobą powiązane, znajdziesz w Kompilator AIDL i nasz system kompilacji: Uporządkowane a stabilne AIDL.

Na przykład:

    package my.package;

    import my.package.Boo;

    parcelable Baz {
        @utf8InCpp String name = "baz";
        Boo boo;
    }

Związki

deklaracje dotyczące wsparcia dla Androida 12 i nowszych wersji. 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;
    }

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 stałe

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. Stała wartości wyrażeń można używać z wartościami całkowitymi lub zmiennoprzecinkowymi.

Literale true i false reprezentują wartości logiczne. Wartości z parametrem . oprócz bez sufiksu, np. 3.8, są uznawane za wartości podwójne. Pływające wartości mają sufiks f, np. 2.4f. Wartość całkowita z parametrem l lub Sufiks L oznacza wartość o długości 64 bitów. 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). Dlatego 256 uznaje się za int, ale 255 + 1 przepełnia się na byte 0. Wartości szesnastkowe, np. 0x3, są interpretowane w pierwszej kolejności. jako najmniejszy, zachowujący wartość typ bez znaku, między 32-bitowym a 64-bitowym. a potem zinterpretowany 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 sufiks to jest ważne, aby obliczenia, takie jak 0xffu8 * 3, były interpretowane jako -3 z typem byte, a 0xff * 3 to 765 z typem int.

Obsługiwane operatory mają semantykę w językach C++ i Java. W kolejności od najniższego do najwyższego priorytetu operatory binarne to: || && | ^ & == != < > <= >= << >> + - * / %. Operatory jednoargumentowe to + - ! ~.