AIDL stable

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 AIDL Foo défini dans un package com.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 trouve Android.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 modules aidl_interface utilisés par ce service. Si l'un de vos Les interfaces AIDL utilisent une interface ou un fragmentable d'une autre aidl_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 12
  • versions: versions précédentes de l'interface figée sous api_dir, à partir d'Android 11, les versions sont figées sous aidl_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é par versions_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'adresse aidl_api/IFACE/V Ce champ a été introduit dans Android 13, Elle ne doit pas être modifiée directement dans Android.bp. Le champ est ajouté ou mis à jour en appelant *-update-api ou *-freeze-api. De plus, les champs versions sont automatiquement migrés vers versions_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". Si stability n'est pas défini, la compilation le système vérifie que l'interface est rétrocompatible, sauf unstable 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 dans system.img et les partitions associées, ou tous les fournisseurs éléments (par exemple, les éléments dans vendor.img et les partitions associées). Si stability 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éfaut true pour cpp. java backends.
  • host_supported: l'indicateur facultatif qui, lorsqu'il est défini sur true, 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 sur true, 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 sur true, 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 sur false, cela signifie que l'interface est dans et comporte de nouvelles modifications. L'exécution de foo-freeze-api génère donc nouvelle version et remplacer automatiquement la valeur par true. 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 transaction
  • backend.[cpp|java].vndk.enabled: l'option facultative permettant de rendre cette interface une partie du VNDK. La valeur par défaut est false.
  • 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 avec ndk_header et cpp_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 lorsque backend.java.platform_apis est true.
  • backend.java.platform_apis: l'indicateur facultatif qui doit être défini sur true 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 champ owner: n'est spécifié.
  • AIDL_FROZEN_OWNERS="aosp test" : la compilation nécessite toutes les interfaces AIDL stables être figée avec le champ owner: 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 obtient STATUS_UNKNOWN_TRANSACTION.
  • Le backend java reçoit android.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 module aidl_interface
  • version correspond à l'une des valeurs suivantes : <ph type="x-smartling-placeholder">
      </ph>
    • Vversion-number pour les versions figées
    • Vlatest-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 Java
    • cpp pour le backend C++
    • ndk ou ndk_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 que ndk.
    • 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 devient foo-V2-backend.
  • foo-unstable-backend, qui faisait référence aux conditions d'utilisation La version devient foo-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.

  1. 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.

  2. 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).

  3. 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.