La technologie eSIM (ou eUICC) permet aux utilisateurs mobiles de télécharger un profil d'opérateur et d'activer le service d'un opérateur sans carte SIM physique. Il s'agit d'une spécification globale pilotée par la GSMA qui permet le provisionnement de SIM à distance (RSP) pour n'importe quel appareil mobile. À partir d'Android 9, le framework Android fournit des API standards pour accéder à l'eSIM et gérer les profils d'abonnement sur l'eSIM. Ces API eUICC permettent aux tiers de développer leurs propres applications d'opérateur et assistants de profil local (LPA) sur les appareils Android compatibles avec l'eSIM.
Le LPA est une application système autonome qui doit être incluse dans l'image de build Android. La gestion des profils sur l'eSIM est généralement effectuée par la LPA, car elle sert de pont entre le SM-DP+ (service à distance qui prépare, stocke et distribue des packages de profils aux appareils) et la puce eUICC. L'APK LPA peut éventuellement inclure un composant d'interface utilisateur, appelé UI LPA ou LUI, afin de fournir un emplacement central permettant à l'utilisateur final de gérer tous les profils d'abonnement intégrés. Le framework Android détecte et se connecte automatiquement au meilleur LPA disponible, et achemine toutes les opérations eUICC via une instance LPA.
Figure 1 : Architecture RSP simplifiée
Les opérateurs de réseaux mobiles qui souhaitent créer une application opérateur doivent consulter les API de EuiccManager
, qui fournissent des opérations de gestion de profil de haut niveau telles que downloadSubscription()
, switchToSubscription()
et deleteSubscription()
.
Si vous êtes un OEM d'appareil et que vous souhaitez créer votre propre application système LPA, vous devez étendre EuiccService
pour que le framework Android puisse se connecter à vos services LPA. En outre, vous devez utiliser les API de EuiccCardManager
, qui fournissent des fonctions ES10x basées sur GSMA RSP v2.0.
Ces fonctions permettent d'envoyer des commandes à la puce eUICC, telles que prepareDownload()
, loadBoundProfilePackage()
, retrieveNotificationList()
et resetMemory()
.
Pour fonctionner, les API de EuiccManager
nécessitent une application LPA correctement implémentée, et l'appelant des API EuiccCardManager
doit être une LPA. Cette règle est appliquée par le framework Android.
Les appareils équipés d'Android 10 ou version ultérieure peuvent prendre en charge les appareils avec plusieurs eSIM. Pour en savoir plus, consultez la section Compatibilité avec plusieurs eSIM.
Créer une application de l'opérateur
Les API eUICC d'Android 9 permettent aux opérateurs de réseaux mobiles de créer des applications de la marque de l'opérateur pour gérer directement leurs profils. Cela inclut le téléchargement et la suppression de profils d'abonnement appartenant à l'opérateur, ainsi que le passage à un profil appartenant à un opérateur.
EuiccManager
EuiccManager
est le point d'entrée principal permettant aux applications d'interagir avec la LPA. Cela inclut les applications d'opérateurs qui téléchargent, suppriment et passent à des abonnements appartenant à l'opérateur. Cela inclut également l'application système LUI, qui fournit un emplacement/UI central pour gérer tous les abonnements intégrés. Elle peut être une application distincte de celle qui fournit EuiccService
.
Pour utiliser les API publiques, une application de l'opérateur doit d'abord obtenir l'instance de EuiccManager
via Context#getSystemService
:
EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
Vous devez vérifier si l'eSIM est compatible avec l'appareil avant d'effectuer des opérations eSIM. EuiccManager#isEnabled()
renvoie généralement true
si la fonctionnalité android.hardware.telephony.euicc
est définie et qu'un package LPA est présent.
if (mgr == null || !mgr.isEnabled()) {
return;
}
Pour obtenir des informations sur le matériel eUICC et la version de l'OS eSIM:
EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();
De nombreuses API, telles que downloadSubscription()
et switchToSubscription()
, utilisent des rappels PendingIntent
, car leur exécution peut prendre quelques secondes, voire quelques minutes.
PendingIntent
est envoyé avec un code de résultat dans l'espace EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_
, qui fournit des codes d'erreur définis par le framework, ainsi qu'un code de résultat détaillé arbitraire propagé à partir de l'LPA en tant que EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE
, ce qui permet à l'application du transporteur de suivre à des fins de journalisation/débogage. Le rappel PendingIntent
doit être BroadcastReceiver
.
Pour télécharger un abonnement téléchargeable donné (créé à partir d'un code d'activation ou d'un code QR):
// Register receiver.
static final String ACTION_DOWNLOAD_SUBSCRIPTION = "download_subscription";
static final String LPA_DECLARED_PERMISSION
= "com.your.company.lpa.permission.BROADCAST";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
0 /* defaultValue*/);
// If the result code is a resolvable error, call startResolutionActivity
if (resultCode == EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR) {
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.startResolutionActivity(
activity,
0 /* requestCode */,
intent,
callbackIntent);
}
resultIntent = intent;
}
};
context.registerReceiver(receiver,
new IntentFilter(ACTION_DOWNLOAD_SUBSCRIPTION),
LPA_DECLARED_PERMISSION /* broadcastPermission*/,
null /* handler */);
// Download subscription asynchronously.
DownloadableSubscription sub = DownloadableSubscription
.forActivationCode(code /* encodedActivationCode*/);
Intent intent = new Intent(action).setPackage(context.getPackageName());
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.downloadSubscription(sub, true /* switchAfterDownload */,
callbackIntent);
Définissez et utilisez l'autorisation dans AndroidManifest.xml
:
<permission android:protectionLevel="signature" android:name="com.your.company.lpa.permission.BROADCAST" />
<uses-permission android:name="com.your.company.lpa.permission.BROADCAST"/>
Pour passer à un abonnement donné en fonction de son ID:
// Register receiver.
static final String ACTION_SWITCH_TO_SUBSCRIPTION = "switch_to_subscription";
static final String LPA_DECLARED_PERMISSION
= "com.your.company.lpa.permission.BROADCAST";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
0 /* defaultValue*/);
resultIntent = intent;
}
};
context.registerReceiver(receiver,
new IntentFilter(ACTION_SWITCH_TO_SUBSCRIPTION),
LPA_DECLARED_PERMISSION /* broadcastPermission*/,
null /* handler */);
// Switch to a subscription asynchronously.
Intent intent = new Intent(action).setPackage(context.getPackageName());
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.switchToSubscription(1 /* subscriptionId */, callbackIntent);
Pour obtenir la liste complète des API EuiccManager
et des exemples de code, consultez la page API eUICC.
Erreurs résolubles
Dans certains cas, le système ne parvient pas à effectuer l'opération eSIM, mais l'utilisateur peut résoudre l'erreur. Par exemple, downloadSubscription
peut échouer si les métadonnées du profil indiquent qu'un code de confirmation de l'opérateur est requis. Sinon, switchToSubscription
peut échouer si l'application de l'opérateur dispose de privilèges d'opérateur sur le profil de destination (c'est-à-dire que l'opérateur est propriétaire du profil), mais qu'elle ne dispose pas de privilèges d'opérateur sur le profil actuellement activé, et que le consentement de l'utilisateur est donc requis.
Dans ces cas, le rappel de l'appelant est appelé avec EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
. Le rappel Intent
contient des extras internes de sorte que lorsque l'appelant le transmet à EuiccManager#startResolutionActivity
, la résolution peut être demandée via l'interface utilisateur. Par exemple, si vous utilisez à nouveau le code de confirmation, EuiccManager#startResolutionActivity
déclenche un écran de LUI permettant à l'utilisateur de saisir un code de confirmation. Une fois le code saisi, l'opération de téléchargement reprend. Cette approche donne à l'application de l'opérateur un contrôle total sur le moment où l'UI s'affiche, mais fournit à la LPA/LUI une méthode extensible pour ajouter de nouvelles solutions aux problèmes récupérables par l'utilisateur à l'avenir, sans que les applications clientes aient besoin d'être modifiées.
Android 9 définit ces erreurs pouvant être résolues dans EuiccService
, que l'UI doit gérer:
/**
* Alert the user that this action will result in an active SIM being
* deactivated. To implement the LUI triggered by the system, you need to define
* this in AndroidManifest.xml.
*/
public static final String ACTION_RESOLVE_DEACTIVATE_SIM =
"android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
/**
* Alert the user about a download/switch being done for an app that doesn't
* currently have carrier privileges.
*/
public static final String ACTION_RESOLVE_NO_PRIVILEGES =
"android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
/** Ask the user to resolve all the resolvable errors. */
public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS =
"android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";
Droits de l'opérateur
Si vous êtes un opérateur et que vous développez votre propre application qui appelle EuiccManager
pour télécharger des profils sur un appareil, votre profil doit inclure des règles d'accès de l'opérateur correspondant à votre application dans les métadonnées. En effet, les profils d'abonnement appartenant à différents opérateurs peuvent coexister dans l'eUICC d'un appareil, et chaque application de l'opérateur ne doit être autorisée qu'à accéder aux profils appartenant à cet opérateur. Par exemple, l'opérateur A ne doit pas pouvoir télécharger, activer ni désactiver un profil appartenant à l'opérateur B.
Pour s'assurer qu'un profil n'est accessible qu'à son propriétaire, Android utilise un mécanisme permettant d'accorder des droits spéciaux à l'application du propriétaire du profil (c'est-à-dire à l'application de l'opérateur). La plate-forme Android charge les certificats stockés dans le fichier de règles d'accès (ARF) du profil et accorde aux applications signées par ces certificats l'autorisation d'effectuer des appels aux API EuiccManager
. Le processus général est décrit ci-dessous:
- L'opérateur signe l'APK de l'application de l'opérateur ; l'outil apksigner associe le certificat de clé publique à l'APK.
L'opérateur/SM-DP+ prépare un profil et ses métadonnées, qui incluent un ARF contenant:
- Signature (SHA-1 ou SHA-256) du certificat de clé publique de l'application du transporteur (obligatoire)
- Nom du package de l'application du transporteur (recommandé)
L'application de l'opérateur tente d'effectuer une opération eUICC avec l'API
EuiccManager
.La plate-forme Android vérifie que le hachage SHA-1 ou SHA-256 du certificat de l'application appelante correspond à la signature du certificat obtenu à partir de l'ARF du profil cible. Si le nom du package de l'application de l'opérateur est inclus dans le formulaire de récupération de compte, il doit également correspondre au nom du package de l'application appelante.
Une fois la signature et le nom du package (le cas échéant) validés, le privilège du transporteur est accordé à l'application appelante sur le profil cible.
Étant donné que les métadonnées de profil peuvent être disponibles en dehors du profil lui-même (afin que le LPA puisse récupérer les métadonnées de profil à partir de SM-DP+ avant le téléchargement du profil ou à partir d'ISD-R lorsque le profil est désactivé), elles doivent contenir les mêmes règles de privilèges de l'opérateur que dans le profil.
L'OS eUICC et SM-DP+ doivent prendre en charge une balise propriétaire BF76
dans les métadonnées du profil. Le contenu de la balise doit correspondre aux mêmes règles de privilèges de l'opérateur que celles renvoyées par l'applet de règles d'accès (ARA) définies dans les privilèges de l'opérateur UICC:
RefArDo ::= [PRIVATE 2] SEQUENCE { -- Tag E2
refDo [PRIVATE 1] SEQUENCE { -- Tag E1
deviceAppIdRefDo [PRIVATE 1] OCTET STRING (SIZE(20|32)), -- Tag C1
pkgRefDo [PRIVATE 10] OCTET STRING (SIZE(0..127)) OPTIONAL -- Tag CA
},
arDo [PRIVATE 3] SEQUENCE { -- Tag E3
permArDo [PRIVATE 27] OCTET STRING (SIZE(8)) -- Tag DB
}
}
Pour en savoir plus sur la signature d'application, consultez la section Signer votre application. Pour en savoir plus sur les droits de l'opérateur, consultez la section Droits de l'opérateur UICC.
Créer une application d'assistant de profil local
Les fabricants d'appareils peuvent implémenter leur propre assistant de profil local (LPA), qui doit être associé aux API Android Euicc. Les sections suivantes donnent un bref aperçu de la création d'une application LPA et de son intégration au système Android.
Configuration matérielle/configuration requise pour le modem
Le LPA et l'OS eSIM de la puce eUICC doivent être compatibles avec au moins la version 2.0 ou 2.2 du RSP (Remote SIM Provisioning) GSMA. Vous devez également planifier d'utiliser des serveurs SM-DP+ et SM-DS avec une version RSP correspondante. Pour en savoir plus sur l'architecture RSP, consultez la spécification de l'architecture RSP GSMA SGP.21.
De plus, pour s'intégrer aux API eUICC d'Android 9, le modem de l'appareil doit envoyer des fonctionnalités de terminal avec la prise en charge des fonctionnalités eUICC encodées (gestion et téléchargement de profils locaux). Il doit également implémenter les méthodes suivantes:
- IRadio HAL v1.1:
setSimPower
IRadio HAL v1.2:
getIccCardStatus
IRadioConfig HAL v1.0:
getSimSlotsStatus
IRadioConfig AIDL v1.0:
getAllowedCarriers
La LPA Google doit connaître l'état du verrouillage de l'opérateur afin de n'autoriser le téléchargement ou le transfert de l'eSIM que pour l'opérateur autorisé. Sinon, les utilisateurs peuvent télécharger et transférer une carte SIM, puis se rendre compte plus tard que l'appareil est verrouillé par un autre opérateur.
Les fournisseurs ou OEM doivent implémenter l'API HAL IRadioSim.getAllowedCarriers().
Dans le cadre de l'API IRadioSimResponse.getAllowedCarriersResponse()HAL, le fournisseur RIL / Modem doit renseigner l'état de verrouillage et l'ID du transporteur de l'opérateur sur lequel l'appareil est verrouillé.
Le modem doit reconnaître l'eSIM avec le profil de démarrage par défaut activé comme une SIM valide et maintenir la SIM sous tension.
Pour les appareils équipés d'Android 10, vous devez définir un tableau d'ID d'emplacements eUICC non amovibles. Par exemple, consultez arrays.xml
.
<resources>
<!-- Device-specific array of SIM slot indexes which are are embedded eUICCs.
e.g. If a device has two physical slots with indexes 0, 1, and slot 1 is an
eUICC, then the value of this array should be:
<integer-array name="non_removable_euicc_slots">
<item>1</item>
</integer-array>
If a device has three physical slots and slot 1 and 2 are eUICCs, then the value of
this array should be:
<integer-array name="non_removable_euicc_slots">
<item>1</item>
<item>2</item>
</integer-array>
This is used to differentiate between removable eUICCs and built in eUICCs, and should
be set by OEMs for devices which use eUICCs. -->
<integer-array name="non_removable_euicc_slots">
<item>1</item>
</integer-array>
</resources>
Pour obtenir la liste complète des exigences concernant les modems, consultez la section Exigences concernant les modems pour la prise en charge de l'eSIM.
EuiccService
Une LPA se compose de deux composants distincts (qui peuvent tous deux être implémentés dans le même APK): le backend de la LPA et l'UI ou LUI de la LPA.
Pour implémenter le backend LPA, vous devez étendre EuiccService
et déclarer ce service dans votre fichier manifeste. Le service doit exiger l'autorisation système android.permission.BIND_EUICC_SERVICE
pour garantir que seul le système peut s'y associer. Le service doit également inclure un filtre d'intent avec l'action android.service.euicc.EuiccService
. La priorité du filtre d'intent doit être définie sur une valeur non nulle au cas où plusieurs implémentations seraient présentes sur l'appareil. Exemple :
<service
android:name=".EuiccServiceImpl"
android:permission="android.permission.BIND_EUICC_SERVICE">
<intent-filter android:priority="100">
<action android:name="android.service.euicc.EuiccService" />
</intent-filter>
</service>
En interne, le framework Android détermine la LPA active et interagit avec elle si nécessaire pour prendre en charge les API eUICC Android. PackageManager
est interrogé pour toutes les applications avec l'autorisation android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
, qui spécifie un service pour l'action android.service.euicc.EuiccService
.
Le service ayant la priorité la plus élevée est sélectionné. Si aucun service n'est trouvé, la compatibilité
LPA est désactivée.
Pour implémenter la LUI, vous devez fournir une activité pour les actions suivantes:
android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS
android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION
Comme pour le service, chaque activité doit nécessiter l'autorisation système android.permission.BIND_EUICC_SERVICE
. Chacun doit comporter un filtre d'intent avec l'action appropriée, la catégorie android.service.euicc.category.EUICC_UI
et une priorité non nulle.
Pour choisir les implémentations de ces activités, la logique est la même que pour l'implémentation de EuiccService
.
Exemple :
<activity android:name=".MyLuiActivity"
android:exported="true"
android:permission="android.permission.BIND_EUICC_SERVICE">
<intent-filter android:priority="100">
<action android:name="android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS" />
<action android:name="android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.service.euicc.category.EUICC_UI" />
</intent-filter>
</activity>
Cela implique que l'UI implémentant ces écrans peut provenir d'un APK différent de celui qui implémente EuiccService
.
Le choix d'utiliser un seul APK ou plusieurs APK (par exemple, un qui implémente EuiccService
et un qui fournit des activités LUI) est un choix de conception.
EuiccCardManager
EuiccCardManager
est l'interface de communication avec la puce eSIM. Il fournit des fonctions ES10 (comme décrit dans la spécification GSMA RSP) et gère les commandes de requête/réponse APDU de bas niveau ainsi que l'analyse ASN.1.
EuiccCardManager
est une API système qui ne peut être appelée que par des applications privilégiées du système.
Figure 2. L'application de l'opérateur et la LPA utilisent les API Euicc
Les API d'opération de profil via EuiccCardManager
nécessitent que l'appelant soit un LPA. Cette règle est appliquée par le framework Android. Cela signifie que l'appelant doit étendre EuiccService
et être déclaré dans votre fichier manifeste, comme décrit dans les sections précédentes.
Comme pour EuiccManager
, pour utiliser les API EuiccCardManager
, votre LPA doit d'abord obtenir l'instance de EuiccCardManager
via Context#getSystemService
:
EuiccCardManager cardMgr = (EuiccCardManager) context.getSystemService(Context.EUICC_CARD_SERVICE);
Pour obtenir tous les profils de l'eUICC:
ResultCallback<EuiccProfileInfo[]> callback =
new ResultCallback<EuiccProfileInfo[]>() {
@Override
public void onComplete(int resultCode,
EuiccProfileInfo[] result) {
if (resultCode == EuiccCardManagerReflector.RESULT_OK) {
// handle result
} else {
// handle error
}
}
};
cardMgr.requestAllProfiles(eid, AsyncTask.THREAD_POOL_EXECUTOR, callback);
En interne, EuiccCardManager
se lie à EuiccCardController
(qui s'exécute dans le processus du téléphone) via une interface AIDL, et chaque méthode EuiccCardManager
reçoit son rappel du processus du téléphone via une interface AIDL différente et dédiée. Lorsque vous utilisez les API EuiccCardManager
, l'appelant (LPA) doit fournir un objet Executor
via lequel le rappel est appelé. Cet objet Executor
peut s'exécuter sur un seul thread ou sur un pool de threads de votre choix.
La plupart des API EuiccCardManager
ont le même schéma d'utilisation. Par exemple, pour charger un package de profil lié sur l'eUICC:
...
cardMgr.loadBoundProfilePackage(eid, boundProfilePackage,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Pour passer à un autre profil avec un ICCID donné:
...
cardMgr.switchToProfile(eid, iccid, true /* refresh */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Pour obtenir l'adresse SM-DP+ par défaut de la puce eUICC:
...
cardMgr.requestDefaultSmdpAddress(eid, AsyncTask.THREAD_POOL_EXECUTOR,
callback);
Pour récupérer la liste des notifications des événements de notification donnés:
...
cardMgr.listNotifications(eid,
EuiccNotification.Event.INSTALL
| EuiccNotification.Event.DELETE /* events */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Activer un profil eSIM via une application de l'opérateur
Sur les appareils équipés d'Android 9 ou d'une version ultérieure, vous pouvez utiliser une application de l'opérateur pour activer l'eSIM et télécharger des profils. L'application de l'opérateur peut télécharger des profils en appelant directement downloadSubscription
ou en fournissant un code d'activation à l'LPA.
Lorsqu'une application d'opérateur télécharge un profil en appelant downloadSubscription
, l'appel impose que l'application puisse gérer le profil via une balise de métadonnées BF76
qui encode les règles de droit de l'opérateur pour le profil. Si un profil ne comporte pas de balise BF76
ou si sa balise BF76
ne correspond pas à la signature de l'application de l'opérateur appelant, le téléchargement est refusé.
La section ci-dessous décrit l'activation d'une eSIM via l'application d'un opérateur à l'aide d'un code d'activation.
Activer l'eSIM à l'aide d'un code d'activation
Lorsque vous utilisez un code d'activation pour activer un profil eSIM, le LPA récupère un code d'activation à partir de l'application de l'opérateur et télécharge le profil. Ce flux peut être lancé par la LPA, qui peut contrôler l'ensemble du parcours de l'UI, ce qui signifie qu'aucune UI d'application de l'opérateur n'est affichée. Cette approche contourne la vérification du tag BF76
, et les opérateurs réseau n'ont pas besoin d'implémenter l'intégralité du parcours d'activation de l'eSIM, y compris le téléchargement d'un profil eSIM et la gestion des erreurs.
Définir le service de provisionnement eUICC de l'opérateur
L'application LPA et l'application de l'opérateur communiquent via deux interfaces AIDL : ICarrierEuiccProvisioningService
et IGetActivationCodeCallback
. L'application de l'opérateur doit implémenter une interface ICarrierEuiccProvisioningService
et l'exposer dans sa déclaration de fichier manifeste.
L'LPA doit se lier à ICarrierEuiccProvisioningService
et implémenter IGetActivationCodeCallback
. Pour en savoir plus sur l'implémentation et l'exposition d'une interface AIDL, consultez la section Définir une interface AIDL.
Pour définir les interfaces AIDL, créez les fichiers AIDL suivants à la fois pour l'application LPA et les applications de l'opérateur.
ICarrierEuiccProvisioningService.aidl
package android.service.euicc; import android.service.euicc.IGetActivationCodeCallback; oneway interface ICarrierEuiccProvisioningService { // The method to get the activation code from the carrier app. The caller needs to pass in // the implementation of IGetActivationCodeCallback as the parameter. void getActivationCode(in IGetActivationCodeCallback callback); // The method to get the activation code from the carrier app. The caller needs to pass in // the activation code string as the first parameter and the implementation of // IGetActivationCodeCallback as the second parameter. This method provides the carrier // app the device EID which allows a carrier to pre-bind a profile to the device's EID before // the download process begins. void getActivationCodeForEid(in String eid, in IGetActivationCodeCallback callback); }
IGetActivationCodeCallback.aidl
package android.service.euicc; oneway interface IGetActivationCodeCallback { // The call back method needs to be called when the carrier app gets the activation // code successfully. The caller needs to pass in the activation code string as the // parameter. void onSuccess(String activationCode); // The call back method needs to be called when the carrier app failed to get the // activation code. void onFailure(); }
Exemple d'implémentation d'une LPA
Pour se lier à l'implémentation ICarrierEuiccProvisioningService
de l'application de l'opérateur, la LPA doit copier à la fois ICarrierEuiccProvisioningService.aidl
et IGetActivationCodeCallback.aidl
dans votre projet, puis implémenter ServiceConnection
.
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mCarrierProvisioningService = ICarrierEuiccProvisioningService.Stub.asInterface(iBinder);
}
Après s'être lié à l'implémentation ICarrierEuiccProvisioningService
de l'application du transporteur, la LPA appelle getActivationCode
ou getActivationCodeForEid
pour obtenir le code d'activation de l'application du transporteur en transmettant l'implémentation de la classe de bouchon IGetActivationCodeCallback
.
La différence entre getActivationCode
et getActivationCodeForEid
est que getActivationCodeForEid
permet à un opérateur de pré-lier un profil à l'EID de l'appareil avant que le processus de téléchargement ne commence.
void getActivationCodeFromCarrierApp() {
IGetActivationCodeCallback.Stub callback =
new IGetActivationCodeCallback.Stub() {
@Override
public void onSuccess(String activationCode) throws RemoteException {
// Handle the case LPA success to get activation code from a carrier app.
}
@Override
public void onFailure() throws RemoteException {
// Handle the case LPA failed to get activation code from a carrier app.
}
};
try {
mCarrierProvisioningService.getActivationCode(callback);
} catch (RemoteException e) {
// Handle Remote Exception
}
}
Exemple d'implémentation pour une application d'opérateur
Pour que l'application LPA s'associe à l'application de l'opérateur, celle-ci doit copier ICarrierEuiccProvisioningService.aidl
et IGetActivationCodeCallback.aidl
dans votre projet et déclarer le service ICarrierEuiccProvisioningService
dans le fichier AndroidManifest.xml
. Le service doit exiger l'autorisation système android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
pour s'assurer que seule l'application LPA, une application privilégiée par le système, peut s'y associer. Le service doit également inclure un filtre d'intent avec l'action android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE
.
AndroidManifest.xml
<application> ... <service android:name=".CarrierEuiccProvisioningService" android:exported="true" android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"> <intent-filter> <action android:name="android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE"/> </intent-filter> </service> ... </application>
Pour implémenter le service d'application de l'opérateur AIDL, créez un service, étendez la classe Stub
, et implémentez les méthodes getActivationCode
et getActivationCodeForEid
. L'LPA peut ensuite appeler l'une ou l'autre méthode pour récupérer le code d'activation du profil. L'application de l'opérateur doit répondre en appelant IGetActivationCodeCallback#onSuccess
avec le code d'activation si le code a été extrait du serveur de l'opérateur. Si l'opération échoue, l'application de l'opérateur doit répondre par IGetActivationCodeCallback#onFailure
.
CarrierEuiccProvisioningService.java
import android.service.euicc.ICarrierEuiccProvisioningService; import android.service.euicc.ICarrierEuiccProvisioningService.Stub; import android.service.euicc.IGetActivationCodeCallback; public class CarrierEuiccProvisioningService extends Service { private final ICarrierEuiccProvisioningService.Stub binder = new Stub() { @Override public void getActivationCode(IGetActivationCodeCallback callback) throws RemoteException { String activationCode = // do whatever work necessary to get an activation code (HTTP requests to carrier server, fetch from storage, etc.) callback.onSuccess(activationCode); } @Override public void getActivationCodeForEid(String eid, IGetActivationCodeCallback callback) throws RemoteException { String activationCode = // do whatever work necessary (HTTP requests, fetch from storage, etc.) callback.onSuccess(activationCode); } } }
Démarrer l'UI de l'application de l'opérateur dans le flux d'activation de l'LPA
Sur les appareils équipés d'Android 11 ou version ultérieure, le LPA peut lancer l'interface utilisateur d'une application d'opérateur. Cela est utile, car une application de l'opérateur peut nécessiter des informations supplémentaires de la part de l'utilisateur avant de fournir un code d'activation à l'LPA. Par exemple, les opérateurs peuvent demander aux utilisateurs de se connecter pour activer leurs numéros de téléphone ou effectuer d'autres services de transfert.
Voici la procédure à suivre pour démarrer l'UI d'une application de l'opérateur dans la LPA:
La LPA lance le flux d'activation de l'application de l'opérateur en envoyant l'intent
android.service.euicc.action.START_CARRIER_ACTIVATION
au package de l'application de l'opérateur contenant l'action. (Le récepteur de l'application du transporteur doit être protégé dans la déclaration du fichier manifeste avecandroid:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
pour éviter de recevoir des intents d'applications autres que des LPA.)String packageName = // The carrier app's package name Intent carrierAppIntent = new Intent(“android.service.euicc.action.START_CARRIER_ACTIVATION”) .setPackage(packageName); ResolveInfo activity = context.getPackageManager().resolveActivity(carrierAppIntent, 0); carrierAppIntent .setClassName(activity.activityInfo.packageName, activity.activityInfo.name); startActivityForResult(carrierAppIntent, requestCode);
L'application de l'opérateur effectue son travail à l'aide de sa propre interface utilisateur. Par exemple, la connexion de l'utilisateur ou l'envoi de requêtes HTTP au backend du transporteur.
L'application de l'opérateur répond à l'LPA en appelant
setResult(int, Intent)
etfinish()
.- Si l'application de l'opérateur répond avec
RESULT_OK
, la LPA poursuit le flux d'activation. Si l'application de l'opérateur détermine que l'utilisateur doit scanner un code QR au lieu de laisser le LPA lier le service de l'application de l'opérateur, elle répond au LPA en utilisantsetResult(int, Intent)
avecRESULT_OK
et une instanceIntent
contenant l'android.telephony.euicc.extra.USE_QR_SCANNER
supplémentaire booléen défini surtrue
. La LPA vérifie ensuite l'extra et lance le lecteur de code QR au lieu de lier l'implémentationICarrierEuiccProvisioningService
de l'application du transporteur. - Si l'application de l'opérateur plante ou répond avec
RESULT_CANCELED
(code de réponse par défaut), la LPA annule le flux d'activation de l'eSIM. - Si l'application du transporteur répond avec un autre code que
RESULT_OK
ouRESULT_CANCELED
, la LPA le considère comme une erreur.
Pour des raisons de sécurité, l'LPA ne doit pas accepter directement un code d'activation fourni dans l'intent de résultat afin de s'assurer que les appelants autres que l'LPA ne peuvent pas obtenir de code d'activation auprès de l'application de l'opérateur.
- Si l'application de l'opérateur répond avec
Lancer le flux d'activation de l'application de l'opérateur
À partir d'Android 11, les applications de l'opérateur peuvent utiliser les API eUICC pour démarrer une UIL pour l'activation de l'eSIM. Cette méthode affiche l'interface utilisateur du flux d'activation eSIM de la LPA pour activer le profil eSIM. Le LPA envoie ensuite une diffusion lorsque l'activation du profil eSIM est terminée.
Le LPA doit déclarer une activité comprenant un filtre d'intent avec l'action
android.service.euicc.action.START_EUICC_ACTIVATION
. La priorité du filtre d'intent doit être définie sur une valeur non nulle dans le cas où plusieurs implémentations sont présentes sur l'appareil. Exemple :<application> ... <activity android:name=".CarrierAppInitActivity" android:exported="true"> <intent-filter android:priority="100"> <action android:name="android.service.euicc.action.START_EUICC_ACTIVATION" /> </intent-filter> </activity> ... </application>
L'application de l'opérateur effectue son travail à l'aide de sa propre interface utilisateur. Par exemple, la connexion de l'utilisateur ou l'envoi de requêtes HTTP au backend du transporteur.
À ce stade, l'application de l'opérateur doit être prête à fournir un code d'activation via son implémentation
ICarrierEuiccProvisioningService
. L'application de l'opérateur lance la LPA en appelantstartActivityForResult(Intent, int)
avec l'actionandroid.telephony.euicc.action.START_EUICC_ACTIVATION
. Le LPA vérifie également l'android.telephony.euicc.extra.USE_QR_SCANNER
supplémentaire booléen. Si la valeur esttrue
, la LPA lance le lecteur de code QR pour permettre à l'utilisateur de scanner le code QR du profil.Côté LPA, la LPA se lie à l'implémentation
ICarrierEuiccProvisioningService
de l'application de l'opérateur pour récupérer le code d'activation et télécharger le profil correspondant. L'application LPA affiche tous les éléments d'interface utilisateur nécessaires pendant le téléchargement, tels qu'un écran de chargement.Une fois le flux d'activation de l'LPA terminé, l'LPA répond à l'application du transporteur avec un code de résultat, que l'application du transporteur gère dans
onActivityResult(int, int, Intent)
.- Si le LPA réussit à télécharger le nouveau profil eSIM, il répond avec
RESULT_OK
. - Si l'utilisateur annule l'activation du profil eSIM dans le LPA, il répond avec
RESULT_CANCELED
. - Si la LPA répond avec un autre code que
RESULT_OK
ouRESULT_CANCELED
, l'application du transporteur considère cela comme une erreur.
Pour des raisons de sécurité, l'LPA n'accepte pas de code d'activation directement dans l'intent fourni pour s'assurer que les appelants autres que l'LPA ne peuvent pas obtenir le code d'activation de l'application de l'opérateur.
- Si le LPA réussit à télécharger le nouveau profil eSIM, il répond avec
Prise en charge de plusieurs eSIM
Pour les appareils équipés d'Android 10 ou version ultérieure, la classe EuiccManager
est compatible avec les appareils dotés de plusieurs eSIM. Les appareils équipés d'une seule eSIM qui passent à Android 10 ne nécessitent aucune modification de l'implémentation de la LPA, car la plate-forme associe automatiquement l'instance EuiccManager
à l'eUICC par défaut. L'eUICC par défaut est déterminée par la plate-forme pour les appareils équipés de la version 1.2 ou ultérieure du HAL radio et par la LPA pour les appareils équipés de versions antérieures à la version 1.2 du HAL radio.
Conditions requises
Pour prendre en charge plusieurs eSIM, l'appareil doit comporter plusieurs eUICC, qui peuvent être des eUICC intégrés ou un emplacement de carte SIM physique dans lequel des eUICC amovibles peuvent être insérés.
La version 1.2 ou ultérieure de Radio HAL est requise pour prendre en charge plusieurs eSIM. Les versions 1.4 de Radio HAL et 1.2 de RadioConfig HAL sont recommandées.
Implémentation
Pour prendre en charge plusieurs eSIM (y compris les eUICC amovibles ou les SIM programmables), la LPA doit implémenter EuiccService
, qui reçoit l'ID de l'emplacement correspondant à l'ID de la carte fourni par l'appelant.
La ressource non_removable_euicc_slots
spécifiée dans arrays.xml
est un tableau d'entiers représentant les ID de fente des eUICC intégrées d'un appareil. Vous devez spécifier cette ressource pour permettre à la plate-forme de déterminer si une eUICC insérée est amovible ou non.
Application de l'opérateur pour un appareil avec plusieurs eSIM
Lorsque vous créez une application de l'opérateur pour un appareil doté de plusieurs eSIM, utilisez la méthode createForCardId
dans EuiccManager
pour créer un objet EuiccManager
épinglé à un ID de carte donné. L'ID de carte est une valeur entière qui identifie de manière unique un UICC ou un eUICC sur l'appareil.
Pour obtenir l'ID de la carte pour l'eUICC par défaut de l'appareil, utilisez la méthode getCardIdForDefaultEuicc
dans TelephonyManager
. Cette méthode renvoie UNSUPPORTED_CARD_ID
si la version du HAL radio est inférieure à 1.2 et UNINITIALIZED_CARD_ID
si l'appareil n'a pas lu l'eUICC.
Vous pouvez également obtenir des ID de carte à partir de getUiccCardsInfo
et getUiccSlotsInfo
(API système) dans TelephonyManager
, et de getCardId
dans SubscriptionInfo
.
Lorsqu'un objet EuiccManager
a été instancié avec un ID de carte spécifique, toutes les opérations sont dirigées vers l'eUICC avec cet ID de carte. Si l'eUICC devient inaccessible (par exemple, lorsqu'il est désactivé ou supprimé), EuiccManager
ne fonctionne plus.
Vous pouvez utiliser les exemples de code suivants pour créer une application opérateur.
Exemple 1: Obtenir un abonnement actif et instancier EuiccManager
// Get the active subscription and instantiate an EuiccManager for the eUICC which holds
// that subscription
SubscriptionManager subMan = (SubscriptionManager)
mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int cardId = subMan.getActiveSubscriptionInfo().getCardId();
EuiccManager euiccMan = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE)
.createForCardId(cardId);
Exemple 2: Itérer sur les UICC et instancier EuiccManager
pour une eUICC amovible
// On a device with a built-in eUICC and a removable eUICC, iterate through the UICC cards
// to instantiate an EuiccManager associated with a removable eUICC
TelephonyManager telMan = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
List<UiccCardInfo> infos = telMan.getUiccCardsInfo();
int removableCardId = -1; // valid cardIds are 0 or greater
for (UiccCardInfo info : infos) {
if (info.isRemovable()) {
removableCardId = info.getCardId();
break;
}
}
if (removableCardId != -1) {
EuiccManager euiccMan = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE)
.createForCardId(removableCardId);
}
Validation
AOSP n'est pas fourni avec une implémentation LPA et vous ne devriez pas avoir de LPA disponible sur tous les builds Android (tous les téléphones ne sont pas compatibles avec eSIM). Pour cette raison, il n'existe pas de scénarios de test CTS de bout en bout. Toutefois, des scénarios de test de base sont disponibles dans AOSP pour garantir que les API eUICC exposées sont valides dans les builds Android.
Vous devez vous assurer que les builds réussissent les scénarios de test CTS suivants (pour les API publiques): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts.
Les opérateurs qui implémentent une application doivent suivre leurs cycles d'assurance qualité internes habituels pour s'assurer que toutes les fonctionnalités implémentées fonctionnent comme prévu. Au minimum, l'application de l'opérateur doit pouvoir lister tous les profils d'abonnement appartenant au même opérateur, télécharger et installer un profil, activer un service sur le profil, passer d'un profil à l'autre et supprimer des profils.
Si vous créez votre propre LPA, vous devez effectuer des tests beaucoup plus rigoureux. Vous devez collaborer avec votre fournisseur de modem, le fournisseur de la puce eUICC ou de l'OS eSIM, les fournisseurs SM-DP+ et les opérateurs pour résoudre les problèmes et assurer l'interopérabilité de votre LPA dans l'architecture RSP. Une bonne quantité de tests manuels est inévitable. Pour une couverture de test optimale, vous devez suivre le plan de test RSP SGP.23 de la GSMA.