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 + - ! ~
.