Android 10 est désormais compatible avec l'interface Android stable Le langage de définition (AIDL), une nouvelle façon de suivre le programme d'une application interface (API) et interface binaire d'application (ABI) fournies par AIDL de commande. La version stable d'AIDL fonctionne exactement comme AIDL, mais le système de compilation suit la compatibilité de l'interface utilisateur. De plus, des restrictions s'appliquent à ce que vous pouvez faire:
- Les interfaces sont définies dans le système de compilation avec
aidl_interfaces
. - Les interfaces ne peuvent contenir que des données structurées. Éléments Parcelable représentant types préférés sont automatiquement créés en fonction de leur définition AIDL et sont automatiquement marqués et non marqués.
- Les interfaces peuvent être déclarées comme stables (rétrocompatibles). Lorsque cette le suivi de leur API et la gestion des versions sont effectués dans un fichier placé à côté du fichier AIDL de commande.
AIDL structuré ou stable
L'AIDL structuré fait référence aux types définis uniquement dans AIDL. Par exemple, un une déclaration parcelable (parcelable) n'est pas une déclaration AIDL structurée. Éléments Parcelables dont les champs sont définis dans AIDL sont appelés parcelables structurés.
AIDL stable nécessite un AIDL structuré de sorte que le système de compilation et le compilateur
peut comprendre si les modifications apportées aux
parcelables sont rétrocompatibles.
Cependant, toutes les interfaces structurées ne sont pas stables. Pour être stable,
une interface ne doit utiliser que des types structurés, ainsi que les éléments suivants :
de gestion des versions. À l'inverse, une interface n'est pas stable si la version de base
est utilisé pour la compiler, ou si unstable:true
est défini.
Définir une interface AIDL
Voici à quoi ressemble la définition de aidl_interface
:
aidl_interface {
name: "my-aidl",
srcs: ["srcs/aidl/**/*.aidl"],
local_include_dir: "srcs/aidl",
imports: ["other-aidl"],
versions_with_info: [
{
version: "1",
imports: ["other-aidl-V1"],
},
{
version: "2",
imports: ["other-aidl-V3"],
}
],
stability: "vintf",
backend: {
java: {
enabled: true,
platform_apis: true,
},
cpp: {
enabled: true,
},
ndk: {
enabled: true,
},
rust: {
enabled: true,
},
},
}
name
: nom du module d'interface AIDL qui identifie de manière unique un via l'interface AIDL.srcs
: liste des fichiers sources AIDL qui composent l'interface. Le chemin d'accès pour un type AIDLFoo
défini dans un packagecom.acme
doit être<base_path>/com/acme/Foo.aidl
, où<base_path>
peut correspondre à n'importe quel répertoire liés au répertoire où se trouveAndroid.bp
. Dans l'exemple précédent,<base_path>
correspond àsrcs/aidl
.local_include_dir
: chemin d'accès à partir duquel commence le nom du package. Il correspond à<base_path>
expliqué ci-dessus.imports
: liste des modulesaidl_interface
utilisés par ce service. Si l'un de vos Les interfaces AIDL utilisent une interface ou un fragmentable d'une autreaidl_interface
, saisissez son nom ici. Il peut s'agir du nom seul, pour se référer aux derniers ou le nom avec le suffixe de version (tel que-V1
) auquel faire référence une version spécifique. La spécification d'une version est prise en charge depuis Android 12versions
: versions précédentes de l'interface figée sousapi_dir
, à partir d'Android 11, lesversions
sont figées sousaidl_api/name
. S'il n'y a pas de versions figées d'une interface, ceci ne devrait pas être spécifié, et il n'y aura pas de vérification de compatibilité. Ce champ a été remplacé parversions_with_info
pour Android 13 et ultérieure.versions_with_info
: liste des tuples, chacun contenant le nom d'un version figée et une liste avec les importations de versions d'autres aidl_interface modules importés par cette version de "aidl_interface". La définition de la version V de l'IFACE de l'interface AIDL se trouve à l'adresseaidl_api/IFACE/V
Ce champ a été introduit dans Android 13, Elle ne doit pas être modifiée directement dansAndroid.bp
. Le champ est ajouté ou mis à jour en appelant*-update-api
ou*-freeze-api
. De plus, les champsversions
sont automatiquement migrés versversions_with_info
. Lorsqu'un utilisateur appelle*-update-api
ou*-freeze-api
.stability
: option facultative de la promesse de stabilité de cette interface. Cette option n'est compatible qu'avec"vintf"
. Sistability
n'est pas défini, la compilation le système vérifie que l'interface est rétrocompatible, saufunstable
est spécifié. N'est pas défini correspond à une interface avec la stabilité dans ce contexte de compilation (soit toutes les choses du système, exemple, les éléments danssystem.img
et les partitions associées, ou tous les fournisseurs éléments (par exemple, les éléments dansvendor.img
et les partitions associées). Sistability
est défini sur"vintf"
, ce qui correspond à une promesse de stabilité: l'interface doit rester stable tant qu’elle est utilisée.gen_trace
: option facultative permettant d'activer ou de désactiver le traçage. Début dans Android 14 est la valeur par défauttrue
pourcpp
.java
backends.host_supported
: l'indicateur facultatif qui, lorsqu'il est défini surtrue
, rend la les bibliothèques générées disponibles pour l'environnement hôte.unstable
: l'indicateur facultatif utilisé pour marquer que cette interface n'est pas doivent être stables. Lorsque ce paramètre est défini surtrue
, le système de compilation ne peut ni crée le vidage de l'API pour l'interface et ne nécessite aucune mise à jour.frozen
: l'indicateur facultatif qui, lorsqu'il est défini surtrue
, signifie que l'interface n'a pas été modifiée par rapport à la version précédente de l'interface. Cela permet de tests de compilation supplémentaires. Si défini surfalse
, cela signifie que l'interface est dans et comporte de nouvelles modifications. L'exécution defoo-freeze-api
génère donc nouvelle version et remplacer automatiquement la valeur partrue
. Première apparition Android 14.backend.<type>.enabled
: ces options activent/désactive chacun des backends pour lequel le compilateur AIDL génère du code. Quatre backends sont compatibles: Java, C++, NDK et Rust. Les backends Java, C++ et NDK sont activés par défaut. Si l'un de ces trois backends n'est pas nécessaire, il doit être explicitement désactivées. Rust est désactivé par défaut jusqu'à ce qu'Android 15.backend.<type>.apex_available
: liste des noms d'APEX générés pour laquelle la bibliothèque de bouchons est disponible.backend.[cpp|java].gen_log
: option facultative qui contrôle s'il faut générer un code supplémentaire pour recueillir des informations sur la transactionbackend.[cpp|java].vndk.enabled
: l'option facultative permettant de rendre cette interface une partie du VNDK. La valeur par défaut estfalse
.backend.[cpp|ndk].additional_shared_libraries
: ajout en tant que Android 14, cet indicateur ajoute des dépendances au bibliothèques natives. Cette option est utile avecndk_header
etcpp_header
.backend.java.sdk_version
: option facultative permettant de spécifier la version du SDK avec lequel la bibliothèque de bouchon Java est compilée. La valeur par défaut est"system_current"
Ne doit pas être défini lorsquebackend.java.platform_apis
esttrue
.backend.java.platform_apis
: l'indicateur facultatif qui doit être défini surtrue
lorsque les bibliothèques générées doivent compiler avec l'API de la plate-forme plutôt que le SDK.
Pour chaque combinaison de versions et de backends activés, un bouchon bibliothèque est créée. Pour savoir comment faire référence à la version spécifique de la bibliothèque bouchon pour un backend spécifique, consultez la section Règles de dénomination des modules.
Écrire des fichiers AIDL
Dans la version stable d'AIDL, les interfaces sont semblables aux interfaces traditionnelles : exception au fait qu'ils ne sont pas autorisés à utiliser des parcelles non structurées (car elles ne sont pas stables ! Voir la section Structuré / stable AIDL, La principale différence avec une version stable d'AIDL est parcelables sont définies. Auparavant, les parcelles étaient déclarées vers l'avant. dans stable (et donc structuré) AIDL, les champs et variables parcelables sont définies explicitement.
// in a file like 'some/package/Thing.aidl'
package some.package;
parcelable SubThing {
String a = "foo";
int b;
}
Une valeur par défaut est acceptée (mais pas obligatoire) pour boolean
, char
,
float
, double
, byte
, int
, long
et String
. Sur Android
12, les valeurs par défaut pour les énumérations définies par l'utilisateur sont également
compatibles. Lorsqu'aucune valeur par défaut n'est spécifiée, une valeur vide ou de type 0 est utilisée.
Les énumérations sans valeur par défaut sont initialisées sur 0 même s'il existe
aucun énumérateur.
Utiliser des bibliothèques de bouchons
Après avoir ajouté des bibliothèques de bouchon en tant que dépendance à votre module, vous
vous pouvez les inclure dans vos fichiers. Voici des exemples de bibliothèques de bouchons
système de compilation (Android.mk
peut également être utilisé pour les définitions d'anciens modules):
cc_... {
name: ...,
shared_libs: ["my-module-name-cpp"],
...
}
# or
java_... {
name: ...,
// can also be shared_libs if your preference is to load a library and share
// it among multiple users or if you only need access to constants
static_libs: ["my-module-name-java"],
...
}
# or
rust_... {
name: ...,
rustlibs: ["my-module-name-rust"],
...
}
Exemple en C++:
#include "some/package/IFoo.h"
#include "some/package/Thing.h"
...
// use just like traditional AIDL
Exemple en Java:
import some.package.IFoo;
import some.package.Thing;
...
// use just like traditional AIDL
Exemple en Rust:
use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
// use just like traditional AIDL
Interfaces de gestion des versions
La déclaration d'un module portant le nom foo crée également une cible dans le système de compilation.
que vous pouvez utiliser pour gérer l'API du module. Lors de sa compilation, foo-Free-api
ajoute une nouvelle définition d'API sous api_dir
ou
aidl_api/name
, selon la version d'Android
ajoute un fichier .hash
, qui représente tous deux la version nouvellement figée du
de commande. foo-gel-api met également à jour la propriété versions_with_info
.
pour refléter la version supplémentaire et imports
pour la version. En gros,
imports
dans versions_with_info
est copié à partir du champ imports
. Toutefois,
la dernière version stable est spécifiée dans imports
dans versions_with_info
pour
, qui ne possède pas de version explicite.
Une fois la propriété versions_with_info
spécifiée, le système de compilation s'exécute
des vérifications de compatibilité entre les versions figées et entre les versions Top of Tree (ToT)
et la dernière version gelée.
En outre, vous devez gérer la définition de la version de l'API ToT. Chaque fois qu'une API est
à jour, exécutez foo-update-api pour mettre à jour
aidl_api/name/current
qui contient la définition d'API de la version ToT.
Pour maintenir la stabilité d'une interface, les propriétaires peuvent ajouter les éléments suivants:
- Les méthodes à la fin d'une interface (ou les méthodes avec les nouvelles séries)
- Éléments à la fin d'un élément parcelable (un élément par défaut doit être ajouté pour chaque élément )
- Valeurs constantes
- Dans Android 11, les énumérateurs
- Sous Android 12, les champs situés à la fin d'une union
Aucune autre action n'est autorisée et personne d'autre ne peut modifier une interface (dans le cas contraire, ils risquent d'entrer en conflit avec les modifications apportées par le propriétaire).
Pour vérifier que toutes les interfaces sont figées en vue de leur publication, vous pouvez compiler avec le de variables d'environnement suivantes:
AIDL_FROZEN_REL=true m ...
: la compilation nécessite toutes les interfaces AIDL stables pour être figées si aucun champowner:
n'est spécifié.AIDL_FROZEN_OWNERS="aosp test"
: la compilation nécessite toutes les interfaces AIDL stables être figée avec le champowner:
spécifié en tant que "aosp" ou "test".
Stabilité des importations
La mise à jour des versions des importations pour les versions figées d'une interface est rétrocompatible au niveau de la couche AIDL stable. Cependant, leur mise à jour nécessite mettre à jour tous les serveurs et clients qui utilisent une version précédente de l'interface, et certaines applications peuvent être confuses si elles mélangent différentes versions de types. En règle générale, pour les packages courants ou ne contenant que des types, c'est sûr, car le code doit déjà écrit pour gérer les types inconnus des transactions IPC.
Sur la plate-forme Android, le code android.hardware.graphics.common
est le plus grand
exemple de ce type de mise à niveau de version.
Utiliser des interfaces avec gestion des versions
Méthodes d'interface
Lors de l'exécution, lorsque vous essayez d'appeler de nouvelles méthodes sur un ancien serveur, les nouveaux clients reçoivent une erreur ou une exception, selon le backend.
- Le backend
cpp
obtient::android::UNKNOWN_TRANSACTION
. - Le backend
ndk
obtientSTATUS_UNKNOWN_TRANSACTION
. - Le backend
java
reçoitandroid.os.RemoteException
avec un message indiquant que le L'API n'est pas implémentée.
Pour connaître les stratégies à suivre, consultez interroger les versions et avec les valeurs par défaut.
Éléments Parcelables
Lorsque de nouveaux champs sont ajoutés aux parcelables, les anciens clients et serveurs les suppriment. Lorsque de nouveaux clients et serveurs reçoivent d'anciens parcelables, valeurs par défaut pour les nouveaux les champs sont automatiquement remplis. Cela signifie que les valeurs par défaut doivent être spécifié pour tous les nouveaux champs d'une parcelle.
Les clients ne doivent pas s'attendre à ce que les serveurs utilisent les nouveaux champs, sauf s'ils connaissent le met en œuvre la version dans laquelle le champ est défini (voir d'interrogation de versions).
Énumérations et constantes
De même, les clients et les serveurs doivent rejeter ou ignorer les informations des valeurs constantes et des énumérateurs, le cas échéant, car davantage peuvent être ajoutés à l'avenir. Par exemple, un serveur ne doit pas abandonner lorsqu'il reçoit une énumérateur dont il n'a pas connaissance. Le serveur doit ignorer les un énumérateur, ou renvoyer quelque chose pour que le client sache qu'il n'est pas pris en charge dans cette implémentation.
Union
Toute tentative d'envoi d'une union avec un nouveau champ échoue si le récepteur est ancien et
ne connaissent pas le domaine. L'implémentation ne verra jamais l'union avec
le nouveau champ. L'échec est ignoré s'il s'agit d'une
pour les transactions à sens unique ; Sinon, l'erreur est BAD_VALUE
(pour les langages C++ ou NDK,
backend) ou IllegalArgumentException
(pour le backend Java). L'erreur est
reçu si le client envoie un ensemble d'union sur le nouveau champ vers un ancien champ
serveur, ou lorsqu'il s'agit d'un ancien client recevant
l'union d'un nouveau serveur.
Gérer plusieurs versions
Un espace de noms éditeur de liens dans Android ne peut avoir qu'une seule version d'un aidl
spécifique.
pour éviter les situations où les types aidl
générés ont plusieurs
et définitions. C++ a la règle de définition unique qui ne nécessite qu’une seule définition
de chaque symbole.
Le build Android génère une erreur lorsqu'un module dépend de différentes
de la même bibliothèque aidl_interface
. Le module peut dépendre
ces bibliothèques directement ou indirectement via des dépendances
les dépendances. Ces erreurs montrent le graphique
des dépendances du module défaillant
les versions en conflit de la bibliothèque aidl_interface
. Toutes les
les dépendances doivent être mises à jour pour inclure la même version (généralement la plus récente)
de ces bibliothèques.
Si la bibliothèque d'interfaces est utilisée par de nombreux modules différents, elle peut être utile
pour créer cc_defaults
, java_defaults
et rust_defaults
pour tout groupe de
bibliothèques et processus qui doivent
utiliser la même version. Lorsque vous introduisez un
nouvelle version de l'interface, ces paramètres par défaut peuvent être mis à jour et tous les modules
font l'objet d'une mise à jour simultanée, ce qui garantit qu'ils n'utilisent pas de versions différentes
de l'interface.
cc_defaults {
name: "my.aidl.my-process-group-ndk-shared",
shared_libs: ["my.aidl-V3-ndk"],
...
}
cc_library {
name: "foo",
defaults: ["my.aidl.my-process-group-ndk-shared"],
...
}
cc_binary {
name: "bar",
defaults: ["my.aidl.my-process-group-ndk-shared"],
...
}
Lorsque les modules aidl_interface
importent d'autres modules aidl_interface
, cela crée
des dépendances supplémentaires qui nécessitent
des versions spécifiques à utiliser ensemble. Ce
la situation peut devenir difficile à gérer lorsqu'il existe des aidl_interface
courants
modules importés dans plusieurs modules aidl_interface
utilisés
dans les mêmes processus.
aidl_interfaces_defaults
peut être utilisé pour conserver une définition du
dernières versions des dépendances d'un aidl_interface
pouvant être mises à jour
au même endroit et sont utilisés par tous les modules aidl_interface
qui souhaitent importer
cette interface commune.
aidl_interface_defaults {
name: "android.popular.common-latest-defaults",
imports: ["android.popular.common-V3"],
...
}
aidl_interface {
name: "android.foo",
defaults: ["my.aidl.latest-ndk-shared"],
...
}
aidl_interface {
name: "android.bar",
defaults: ["my.aidl.latest-ndk-shared"],
...
}
Développement basé sur des indicateurs
Les interfaces en développement (non figées) ne peuvent pas être utilisées sur les versions, car leur rétrocompatibilité n'est pas garantie.
AIDL prend en charge l'exécution de remplacement pour ces bibliothèques d'interfaces non figées afin que pour que le code soit écrit par rapport à la dernière version non figée et continue d'être utilisé sur les appareils de publication. Le comportement rétrocompatible des clients est semblable à le comportement existant. Avec la création de remplacement, les implémentations doivent également ces comportements. Voir Utilisez des interfaces avec gestion des versions.
Indicateur de build AIDL
L'indicateur qui contrôle ce comportement est RELEASE_AIDL_USE_UNFROZEN
défini dans build/release/build_flags.bzl
. true
correspond à la version non figée de
l'interface est utilisée au moment de l'exécution et false
signifie que les bibliothèques du
versions non figées se comportent toutes
comme leur dernière version figée.
Vous pouvez remplacer l'indicateur par true
pour
développement local, mais vous devez rétablir la version false
avant la publication. Habituellement
se fait avec une configuration dont l'option est définie sur true
.
Matrice de compatibilité et fichiers manifestes
Les objets d'interface fournisseur (objets VINTF) définissent les versions attendues et les versions fournies de chaque côté l'interface du fournisseur.
La plupart des appareils autres que Cuttlefish ciblent la dernière matrice de compatibilité
qu'une fois les interfaces figées, il n'y a donc aucune différence au niveau de l'AIDL
basées sur RELEASE_AIDL_USE_UNFROZEN
.
Matrices
Les interfaces appartenant au partenaire sont ajoutées aux interfaces spécifiques à un appareil ou à un produit
les matrices de compatibilité ciblées par
l'appareil pendant le développement. Ainsi, lorsqu'un
la nouvelle version non figée d'une interface
est ajoutée à une matrice de compatibilité,
les précédentes versions figées
doivent rester pendant
RELEASE_AIDL_USE_UNFROZEN=false
Vous pouvez gérer cela en utilisant différentes
fichiers de matrice de compatibilité pour différents RELEASE_AIDL_USE_UNFROZEN
configurations ou autoriser les deux versions dans un seul fichier de matrice de compatibilité
utilisé dans toutes les configurations.
Par exemple, lorsque vous ajoutez une version 4 non figée, utilisez <version>3-4</version>
.
Lorsque la version 4 est bloquée, vous pouvez supprimer la version 3 de la matrice de compatibilité
car la version figée 4 est utilisée lorsque RELEASE_AIDL_USE_UNFROZEN
est
false
Fichiers manifestes
Dans Android 15, une modification de libvintf
est introduite dans
modifier les fichiers manifestes au moment de la compilation en fonction de la valeur
RELEASE_AIDL_USE_UNFROZEN
Les fichiers manifestes et leurs fragments déclarent la version d'une interface
implémente un service. Lorsque vous utilisez la dernière
version non figée d'une interface,
le fichier manifeste doit être mis à jour pour refléter cette nouvelle version. Quand ?
RELEASE_AIDL_USE_UNFROZEN=false
: les entrées du fichier manifeste sont ajustées par
libvintf
pour refléter les modifications apportées à la bibliothèque AIDL générée. La version
de la version non figée, N
, a été remplacé par
la dernière version figée N - 1
. Ainsi, les utilisateurs n'ont pas besoin de gérer plusieurs
des fichiers manifestes ou fragments de manifestes pour chacun de leurs services.
Modifications du client HAL
Le code client HAL doit être rétrocompatible avec chaque ancien blocage pris en charge
version. Lorsque RELEASE_AIDL_USE_UNFROZEN
est défini sur false
, les services recherchent toujours
comme la dernière version figée ou antérieure (par exemple, appeler de nouvelles fonctions
renvoie UNKNOWN_TRANSACTION
, ou les nouveaux champs parcelable
ont leurs valeurs
valeurs par défaut). Les clients du framework Android doivent être rétrogradés
compatible avec d'autres versions précédentes, mais il s'agit d'un nouveau détail pour
les clients des fournisseurs et ceux
des interfaces détenues par les partenaires.
Modifications apportées à l'implémentation HAL
La principale différence entre le développement HAL et le développement basé sur des indicateurs est
pour que les implémentations HAL soient rétrocompatibles avec le dernier
version figée pour fonctionner lorsque RELEASE_AIDL_USE_UNFROZEN
est false
.
La prise en compte de la rétrocompatibilité dans les implémentations et le code des appareils
de l'exercice physique. Voir la section Utiliser la gestion des versions
interfaces Google Cloud.
Les considérations de rétrocompatibilité sont généralement les mêmes pour les clients et les serveurs, ainsi que le code du framework et le code du fournisseur, mais il existe de légères différences que vous devez connaître, car vous savez maintenant implémentant deux versions qui utilisent le même code source (la version actuelle, non figée version).
Exemple: une interface comporte trois versions figées. L'interface est mise à jour avec
nouvelle méthode. Le client et le service sont tous deux mis à jour pour utiliser la nouvelle version 4
bibliothèque. La bibliothèque V4 étant basée sur une version non figée du
se comporte comme la dernière version figée, la version 3,
RELEASE_AIDL_USE_UNFROZEN
a la valeur false
et empêche l'utilisation de la nouvelle méthode.
Lorsque l'interface est figée, toutes les valeurs de RELEASE_AIDL_USE_UNFROZEN
utilisent cette
la version gelée, et le code qui gère
la rétrocompatibilité peut être supprimé.
Lorsque vous appelez des méthodes sur des rappels, vous devez gérer correctement le cas :
UNKNOWN_TRANSACTION
est renvoyé. Les clients peuvent mettre en œuvre deux
d'un rappel basé sur la configuration. Vous ne pouvez donc pas
suppose que le client envoie la version la plus récente, et que les nouvelles méthodes peuvent renvoyer
cette étape. Cela ressemble à la façon dont la stabilité des clients AIDL est maintenue
la compatibilité avec les serveurs décrit dans la section Utiliser la gestion
interfaces Google Cloud.
// Get the callback along with the version of the callback
ScopedAStatus RegisterMyCallback(const std::shared_ptr<IMyCallback>& cb) override {
mMyCallback = cb;
// Get the version of the callback for later when we call methods on it
auto status = mMyCallback->getInterfaceVersion(&mMyCallbackVersion);
return status;
}
// Example of using the callback later
void NotifyCallbackLater() {
// From the latest frozen version (V2)
mMyCallback->foo();
// Call this method from the unfrozen V3 only if the callback is at least V3
if (mMyCallbackVersion >= 3) {
mMyCallback->bar();
}
}
Il est possible que de nouveaux champs dans les types existants (parcelable
, enum
, union
)
n'existent pas ou ne contiennent pas leurs valeurs par défaut lorsque RELEASE_AIDL_USE_UNFROZEN
est
false
et les valeurs des nouveaux champs sur lesquels un service tente d'envoyer sont supprimées
la sortie du processus.
Impossible d'envoyer les nouveaux types ajoutés dans cette version non figée ou reçues via l'interface.
L'implémentation n'obtient jamais d'appel de nouvelles méthodes de la part des clients
RELEASE_AIDL_USE_UNFROZEN
est false
.
Veillez à n'utiliser les nouveaux énumérateurs qu'avec la version dans laquelle ils sont introduits, et non à la version précédente.
Normalement, vous utilisez foo->getInterfaceVersion()
pour connaître la version de l'instance distante
l'interface utilisée. Cependant, grâce à la prise en charge
de la gestion des versions basée sur des indicateurs,
implémentant deux versions différentes, vous voudrez donc peut-être obtenir la version
l'interface actuelle. Pour ce faire, vous devez obtenir la version de l'interface
l'objet actuel, par exemple this->getInterfaceVersion()
ou l'autre
pour my_ver
. Consultez la section Interroger la version de l'interface de la télécommande
objet
pour en savoir plus.
Nouvelles interfaces VINTF stables
Lorsqu'un nouveau package d'interface AIDL est ajouté, il n'y a pas de dernière version figée, donc
il n'y a aucun comportement à utiliser lorsque RELEASE_AIDL_USE_UNFROZEN
est
false
N'utilisez pas ces interfaces. Lorsque RELEASE_AIDL_USE_UNFROZEN
est
false
, le gestionnaire de services n'autorise pas le service à enregistrer l'interface
et les clients
ne le trouveront pas.
Vous pouvez ajouter les services de manière conditionnelle en fonction de la valeur du champ
RELEASE_AIDL_USE_UNFROZEN
dans le fichier makefile de l'appareil:
ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
android.hardware.health.storage-service
endif
Si le service fait partie d'un processus plus vaste et que vous ne pouvez donc pas l'ajouter à l'appareil
vous pouvez vérifier si le service est déclaré
IServiceManager::isDeclared()
Si elle est déclarée et que son enregistrement échoue, alors
annuler le processus. Si elle n'est pas déclarée, il ne devrait pas s'enregistrer.
Seiche comme outil de développement
Chaque année, après l'arrêt du VINTF, nous ajustons la compatibilité du framework
matrice (FCM) target-level
et PRODUCT_SHIPPING_API_LEVEL
de seiche
afin qu'elles reflètent les appareils
lancés avec la version de l'année prochaine. Nous ajustons
target-level
et PRODUCT_SHIPPING_API_LEVEL
pour vous assurer qu'il y a
un appareil qui est testé et qui répond aux nouvelles exigences pour l'année prochaine
de sortie.
Lorsque RELEASE_AIDL_USE_UNFROZEN
est défini sur true
, seiche est
utilisée pour le développement des futures versions d'Android. Il cible la version Android de l'année prochaine
niveau FCM de la version et PRODUCT_SHIPPING_API_LEVEL
, ce qui nécessite que la version soit conforme
les exigences logicielles du
fournisseur de la prochaine version.
Lorsque RELEASE_AIDL_USE_UNFROZEN
est défini sur false
, Settlefish a la valeur précédente
target-level
et PRODUCT_SHIPPING_API_LEVEL
pour refléter une version d'appareil.
Dans Android 14 et versions antérieures, cette différenciation serait
avec différentes branches Git qui ne récupèrent pas le changement vers FCM
target-level
, le niveau d'API de livraison ou tout autre code ciblant le prochain
de sortie.
Règles de dénomination des modules
Dans Android 11, pour chaque combinaison de versions et
les backends activés, un module de bibliothèque bouchon est automatiquement créé. Pour parrainer
à un module de bibliothèque bouchon spécifique pour la liaison, n'utilisez pas le nom du
aidl_interface
, mais le nom du module de bibliothèque bouchon, qui est
ifacename-version-backend, où
ifacename
: nom du moduleaidl_interface
version
correspond à l'une des valeurs suivantes : <ph type="x-smartling-placeholder">- </ph>
Vversion-number
pour les versions figéesVlatest-frozen-version-number + 1
pour le version pointe de l'arbre (encore à geler)
backend
correspond à l'une des valeurs suivantes : <ph type="x-smartling-placeholder">- </ph>
java
pour le backend Javacpp
pour le backend C++ndk
oundk_platform
pour le backend du NDK. Le premier s'applique aux applications, le second est destiné à l'utilisation de la plate-forme jusqu'à Android 13. Dans Android 13 et versions ultérieures n'utilisez quendk
.rust
pour le backend Rust.
Supposons qu'il existe un module nommé foo et que sa dernière version est 2. et est compatible avec le NDK et C++. Dans ce cas, AIDL génère les modules suivants:
- Basé sur la version 1
<ph type="x-smartling-placeholder">
- </ph>
foo-V1-(java|cpp|ndk|ndk_platform|rust)
- Basé sur la version 2 (la dernière version stable)
<ph type="x-smartling-placeholder">
- </ph>
foo-V2-(java|cpp|ndk|ndk_platform|rust)
- Basé sur la version de la ToT
<ph type="x-smartling-placeholder">
- </ph>
foo-V3-(java|cpp|ndk|ndk_platform|rust)
Par rapport à Android 11:
foo-backend
, qui faisait référence à la dernière version stable La version devientfoo-V2-backend
.foo-unstable-backend
, qui faisait référence aux conditions d'utilisation La version devientfoo-V3-backend
.
Les noms des fichiers de sortie sont toujours les mêmes que les noms des modules.
- Basé sur la version 1:
foo-V1-(cpp|ndk|ndk_platform|rust).so
- Basé sur la version 2:
foo-V2-(cpp|ndk|ndk_platform|rust).so
- Basé sur la version de la ToT:
foo-V3-(cpp|ndk|ndk_platform|rust).so
Notez que le compilateur AIDL ne crée pas de module de version unstable
,
ou un module sans gestion des versions pour une interface AIDL stable.
Depuis Android 12, le nom de module généré à partir d'un
l'interface AIDL stable inclut toujours sa version.
Nouvelles méthodes de méta-interface
Android 10 ajoute plusieurs méthodes de méta-interface pour la la version stable d'AIDL.
Interroger la version d'interface de l'objet distant
Les clients peuvent interroger la version et le hachage de l'interface que l'objet distant implémente et compare les valeurs renvoyées avec les valeurs de l'interface que le client utilise.
Exemple avec le backend cpp
:
sp<IFoo> foo = ... // the remote object
int32_t my_ver = IFoo::VERSION;
int32_t remote_ver = foo->getInterfaceVersion();
if (remote_ver < my_ver) {
// the remote side is using an older interface
}
std::string my_hash = IFoo::HASH;
std::string remote_hash = foo->getInterfaceHash();
Exemple avec le backend ndk
(et ndk_platform
) :
IFoo* foo = ... // the remote object
int32_t my_ver = IFoo::version;
int32_t remote_ver = 0;
if (foo->getInterfaceVersion(&remote_ver).isOk() && remote_ver < my_ver) {
// the remote side is using an older interface
}
std::string my_hash = IFoo::hash;
std::string remote_hash;
foo->getInterfaceHash(&remote_hash);
Exemple avec le backend java
:
IFoo foo = ... // the remote object
int myVer = IFoo.VERSION;
int remoteVer = foo.getInterfaceVersion();
if (remoteVer < myVer) {
// the remote side is using an older interface
}
String myHash = IFoo.HASH;
String remoteHash = foo.getInterfaceHash();
Pour le langage Java, le côté distant DOIT implémenter getInterfaceVersion()
et
getInterfaceHash()
comme suit (super
est utilisé à la place de IFoo
pour éviter
les erreurs de copier-coller. L'annotation @SuppressWarnings("static")
peut
nécessaire pour désactiver les avertissements, selon la configuration javac
):
class MyFoo extends IFoo.Stub {
@Override
public final int getInterfaceVersion() { return super.VERSION; }
@Override
public final String getInterfaceHash() { return super.HASH; }
}
En effet, les classes générées (IFoo
, IFoo.Stub
, etc.) sont partagées
entre le client et le serveur (par exemple, les classes peuvent se trouver dans
classpath). En cas de partage de classes, le serveur est également associé
la dernière version des classes, même s'il est possible qu'elle ait été créée à partir d'une
version de l'interface. Si cette méta-interface est implémentée dans la balise
elle renvoie toujours la version la plus récente. Cependant, en implémentant la méthode
comme ci-dessus, le numéro de version de l'interface est intégré dans le code du serveur
(car IFoo.VERSION
est un static final int
intégré lorsqu'il est référencé)
et la méthode peut donc renvoyer la version exacte
avec laquelle le serveur a été compilé.
Gérer les anciennes interfaces
Il est possible qu'un client soit mis à jour avec la version la plus récente d'AIDL
mais le serveur utilise l'ancienne interface AIDL. Dans ce cas,
L'appel d'une méthode sur une ancienne interface renvoie UNKNOWN_TRANSACTION
.
Grâce à la version stable d'AIDL, les clients ont plus de contrôle. Côté client, vous pouvez définir une implémentation par défaut dans une interface AIDL. Une méthode utilisée par défaut n'est appelée que lorsque la méthode n'est pas implémentée dans le (car il a été créé avec une ancienne version de l'interface). Depuis sont définies de manière globale, elles ne doivent pas être utilisées différents contextes.
Exemple en C++ sous Android 13 et versions ultérieures:
class MyDefault : public IFooDefault {
Status anAddedMethod(...) {
// do something default
}
};
// once per an interface in a process
IFoo::setDefaultImpl(::android::sp<MyDefault>::make());
foo->anAddedMethod(...); // MyDefault::anAddedMethod() will be called if the
// remote side is not implementing it
Exemple en Java:
IFoo.Stub.setDefaultImpl(new IFoo.Default() {
@Override
public xxx anAddedMethod(...) throws RemoteException {
// do something default
}
}); // once per an interface in a process
foo.anAddedMethod(...);
Il n'est pas nécessaire de fournir l'implémentation par défaut de toutes les méthodes dans un AIDL
de commande. Méthodes dont l'implémentation à distance est garantie
(car vous êtes certain que la télécommande est créée lorsque les méthodes étaient dans le
description de l'interface AIDL) n'ont pas besoin d'être remplacés dans le impl
par défaut.
.
Convertir un AIDL existant en AIDL structuré ou stable
Si vous disposez déjà d'une interface AIDL et que du code l'utilise, utilisez le code suivant : les étapes à suivre pour convertir l'interface en une interface AIDL stable.
Identifiez toutes les dépendances de votre interface. Pour chaque package, dépend de l'interface, déterminez si le package est défini dans AIDL stable. Si n'est pas définie, le package doit être converti.
Convertissez tous les éléments parcelables de votre interface en fichiers stables (les peuvent rester inchangés. Pour ce faire, procédez comme suit : en exprimant leur structure directement dans des fichiers AIDL. Les classes de gestion doivent être réécrit pour utiliser ces nouveaux types. Vous pouvez le faire avant de créer Package
aidl_interface
(ci-dessous).Créez un package
aidl_interface
(comme décrit ci-dessus) contenant le le nom de votre module, ses dépendances et toute autre information dont vous avez besoin. Pour la rendre stabilisée (et pas seulement structurée), vous devez également gérer les versions. Pour en savoir plus, consultez la section Interfaces de gestion des versions.