Linguaggio AIDL

Il linguaggio AIDL è vagamente basato sul linguaggio Java. I file specificano un contratto di interfaccia e vari tipi di dati e costanti utilizzati in questo contratto.

Pacco

Ogni file AIDL inizia con un pacchetto facoltativo che corrisponde ai nomi dei pacchetti nei vari backend. Una dichiarazione del pacchetto ha il seguente aspetto:

    package my.package;

Come in Java, i file AIDL devono trovarsi in una struttura di cartelle corrispondente al loro pacchetto. I file con il pacchetto my.package devono trovarsi nella cartella my/package/.

Tipi

Nei file AIDL esistono molti punti in cui è possibile specificare i tipi. Per un elenco esatto dei tipi supportati nel linguaggio AIDL, consulta Tipi di backend AIDL.

Annotazioni

Diverse parti del linguaggio AIDL supportano le annotazioni. Per un elenco delle annotazioni e dei relativi punti di applicazione, consulta Annotazioni AIDL.

Importazioni

Per utilizzare i tipi definiti in altre interfacce, devi prima aggiungere le dipendenze nel sistema di build. Nei moduli Soong cc_* e java_*, in cui i file .aidl vengono utilizzati direttamente in srcs nelle build della piattaforma Android, puoi aggiungere directory utilizzando il campo aidl: { include_dirs: ... }. Per le importazioni utilizzando aidl_interface, visita questa pagina.

Un'importazione ha il seguente aspetto:

    import some.package.Foo;  // explicit import

Quando si importa un tipo nello stesso pacchetto, il pacchetto può essere omesso. Tuttavia, l'omissione del pacchetto può causare errori di importazione ambigui quando i tipi vengono specificati senza un pacchetto e inseriti nello spazio dei nomi globale (in genere, tutti i tipi devono avere uno spazio dei nomi):

    import Foo;  // same as my.package.Foo

Definisci i tipi

I file AIDL definiscono in genere i tipi utilizzati come interfaccia.

Interfacce

Ecco un esempio di interfaccia 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();
    }

Un'interfaccia definisce un oggetto con una serie di metodi. I metodi possono essere oneway (oneway void doFoo()) o sincroni. Se un'interfaccia è definita come oneway (oneway interface ITeleport {...}), tutti i metodi al suo interno sono implicitamente oneway. I metodi unidirezionali vengono inviati in modo asincrono e non possono restituire un risultato. Anche i metodi unidirezionali dallo stesso thread allo stesso binder vengono eseguiti in sequenza (anche se potenzialmente su thread diversi). Per una discussione su come configurare i thread, consulta Gestione dei thread dei backend AIDL.

Binder consente di condividere molte interfacce e oggetti binder tramite le interfacce binder. Le interfacce AIDL utilizzano spesso callback come parte delle chiamate al metodo, come con ITeleportCallback nell'esempio precedente. Puoi riutilizzare gli oggetti callback tra chiamate allo stesso metodo o a metodi diversi. Un altro uso comune dei tipi di interfaccia è la restituzione di sottointerfacce o oggetti di sessione da metodi come ITeleportSession nell'esempio precedente. Questo nidificazione consente di incapsulare API diverse all'interno dell'API o in base allo stato di runtime. Ad esempio, una sessione potrebbe rappresentare la proprietà di una determinata risorsa. Quando le interfacce vengono passate più volte o restituite al client o al server da cui provengono, mantengono sempre l'uguaglianza del puntatore dell'oggetto binder sottostante.

I metodi possono avere zero o più argomenti. Gli argomenti dei metodi possono essere in, out o inout. Per una discussione su come questo influisce sui tipi di argomenti, consulta la sezione sulla direzionalità dei backend AIDL.

Parcellable

Per una descrizione di come creare partizioni speciali specifiche per il backend, parcelabili personalizzati dei backend AIDL.

Android 10 e versioni successive supportano le definizioni di parcelable direttamente in AIDL. Questo tipo di parcelable è chiamato parcelable strutturato. Per ulteriori informazioni sulla relazione tra AIDL strutturato e stabile nel compilatore AIDL e nel nostro sistema di compilazione, consulta AIDL strutturato e stabile.

Ad esempio:

    package my.package;

    import my.package.Boo;

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

Sindacati

Android 12 e versioni successive supportano le dichiarazioni di unione con tag. Ad esempio:

    package my.package;

    import my.package.FooSettings;
    import my.package.BarSettings;

    union Settings {
        FooSettings fooSettings;
        BarSettings barSettings;
        @utf8InCpp String str;
        int number;
    }

Per dettagli specifici per il backend, consulta Unione di backend AIDL.

Enumerazionis

Android 11 e versioni successive supportano le dichiarazioni enum. Ad esempio:

    package my.package;

    enum Boo {
        A = 1 * 4,
        B = 3,
    }

Dichiarazioni di tipo nidificate

Android 13 e versioni successive supportano le dichiarazioni dei tipi nidificate. Ad esempio:

    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
    }

Costanti

Le interfacce, i parcelable e le unioni AIDL personalizzate possono contenere anche costanti di interi e stringhe, ad esempio:

    const @utf8InCpp String HAPPY = ":)";
    const String SAD = ":(";
    const byte BYTE_ME = 1;
    const int ANSWER = 6 * 7;

Espressioni costanti

Le costanti AIDL, le dimensioni degli array e gli enumeratori possono essere specificati utilizzando espressioni costanti. Le espressioni possono utilizzare le parentesi per nidificare le operazioni. I valori di espressione costante possono essere utilizzati con valori integrali o in virgola mobile.

I valori letterali true e false rappresentano valori booleani. I valori con . ma senza suffisso, come 3.8, sono considerati valori doppi. I valori in virgola mobile hanno il suffisso f, ad esempio 2.4f. Un valore integrale con il suffisso l o L indica un valore lungo a 64 bit. In caso contrario, i valori degli integrali ottengono il tipo firmato più piccolo che mantiene il valore tra 8 bit (byte), 32 bit (int) e 64 bit (long). Pertanto, 256 è considerato un int, ma 255 + 1 viene visualizzato come byte 0. I valori esadecimali, come 0x3, vengono inizialmente interpretati come il tipo senza segno più piccolo che conserva il valore tra 32 e 64 bit e poi reinterpretati come valori senza segno. Pertanto, 0xffffffff ha il valore int -1. A partire da Android 13, il suffisso u8 può essere aggiunto alle costanti, ad esempio 3u8, per rappresentare un valore byte. Questo suffisso è importante, pertanto un calcolo, ad esempio 0xffu8 * 3, viene interpretato come -3 con il tipo byte, mentre 0xff * 3 è 765 con il tipo int.

Gli operatori supportati hanno la semantica di C++ e Java. A partire dalla precedenza più bassa fino a quella più alta, gli operatori binari sono || && | ^ & == != < > <= >= << >> + - * / %. Gli operatori unari sono + - ! ~.