La technologie SIM intégrée (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 avoir de carte SIM physique. Il s'agit d'une spécification mondiale pilotée par la GSMA qui permet le provisionnement à distance de cartes SIM (RSP) sur 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 les eSIM.
L'application LPA est une application système autonome qui doit être incluse dans l'image de compilation Android. La gestion des profils sur l'eSIM est généralement effectuée par le LPA, car il sert de pont entre le SM-DP+ (service à distance qui prépare, stocke et fournit des packages de profils aux appareils) et la puce eUICC. L'APK LPA peut éventuellement inclure un composant d'UI, appelé LPA UI ou LUI, pour fournir à l'utilisateur final un emplacement centralisé pour gérer tous les profils d'abonnement intégrés. Le framework Android détecte automatiquement le meilleur LPA disponible et s'y connecte, puis achemine toutes les opérations eUICC via une instance LPA.
Figure 1 : Architecture RSP simplifiée
Les opérateurs de réseau mobile qui souhaitent créer une application d'opérateur doivent consulter les API dans 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'appareils et que vous souhaitez créer votre propre application système LPA, vous devez étendre EuiccService
pour que le framework Android se connecte à vos services LPA. De plus, vous devez utiliser les API dans 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()
.
Les API de EuiccManager
nécessitent une application LPA correctement implémentée pour fonctionner, et l'appelant des API EuiccCardManager
doit être un LPA. Cette limite est appliquée par le framework Android.
Les appareils équipés d'Android 10 ou version ultérieure peuvent être compatibles avec les appareils dotés de plusieurs eSIM. Pour en savoir plus, consultez Compatibilité avec plusieurs eSIM.
Créer une application d'opérateur
Les API eUICC d'Android 9 permettent aux opérateurs de réseau mobile de créer des applications à leur marque pour gérer directement leurs profils. Cela inclut le téléchargement et la suppression des 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 le LPA. Cela inclut les applications d'opérateur qui téléchargent, suppriment et passent aux abonnements appartenant à l'opérateur. Cela inclut également l'application système LUI, qui fournit un emplacement/une UI centralisés pour gérer tous les abonnements intégrés et peut être une application distincte de celle qui fournit le 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);
Avant d'effectuer des opérations sur l'eSIM, vous devez vérifier si elle est compatible avec l'appareil. 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 de l'eSIM :
EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();
De nombreuses API, telles que downloadSubscription()
et switchToSubscription()
, utilisent des rappels PendingIntent
, car elles peuvent prendre plusieurs secondes, voire plusieurs 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 LPA en tant que EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE
, permettant à l'application de l'opérateur 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é à partir 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 API eUICC.
Erreurs résolvables
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. Ou switchToSubscription
peut échouer si l'application de l'opérateur dispose de droits d'accès à la fiche de destination (c'est-à-dire que l'opérateur est propriétaire de la fiche), mais pas à la fiche actuellement activée, 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 locale. En reprenant l'exemple du code de confirmation, EuiccManager#startResolutionActivity
déclenche un écran d'interface utilisateur vocale qui permet à l'utilisateur de saisir un code de confirmation. Une fois le code saisi, l'opération de téléchargement reprend. Cette approche permet à l'application de l'opérateur de contrôler entièrement le moment où l'UI est affichée, mais offre au LPA/LUI une méthode extensible pour ajouter de nouvelles gestions des problèmes récupérables par l'utilisateur à l'avenir sans avoir à modifier les applications clientes.
Android 9 définit ces erreurs résolvables dans EuiccService
, que l'interface utilisateur vocale 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 d'opérateur qui appelle EuiccManager
pour télécharger des profils sur un appareil, votre profil doit inclure des règles de privilèges d'opérateur correspondant à votre application d'opérateur 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 d'opérateur ne doit être autorisée à accéder qu'aux profils appartenant à cet opérateur. Par exemple, le fournisseur A ne doit pas pouvoir télécharger, activer ni désactiver un profil appartenant au fournisseur B.
Pour s'assurer qu'un profil n'est accessible qu'à son propriétaire, Android utilise un mécanisme pour accorder des privilèges 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 autorise les applications signées par ces certificats à 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 joint le certificat de clé publique à l'APK.
L'opérateur/SM-DP+ prépare un profil et ses métadonnées, qui incluent un fichier ARF contenant :
- Signature (SHA-1 ou SHA-256) du certificat de clé publique de l'application de l'opérateur (obligatoire)
- Nom du package de l'application du transporteur (fortement 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 de package de l'application de l'opérateur est inclus dans l'ARF, il doit également correspondre au nom de package de l'application appelante.
Une fois la signature et le nom du package (le cas échéant) validés, le privilège de l'opérateur 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 l'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 droits d'accès à l'opérateur que dans le profil.
L'OS eUICC et SM-DP+ doivent être compatibles avec un tag propriétaire BF76
dans les métadonnées du profil. Le contenu du tag doit correspondre aux règles de droits d'accès de l'opérateur renvoyées par l'applet de règles d'accès (ARA) définie dans Droits d'accès 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 Signer votre application. Pour en savoir plus sur les droits de l'opérateur, consultez Droits de l'opérateur UICC.
Créer une application d'assistance pour un profil local
Les fabricants d'appareils peuvent implémenter leur propre assistant de profil local (LPA), qui doit être connecté aux API Android Euicc. Les sections suivantes présentent brièvement la création d'une application LPA et son intégration au système Android.
Configuration matérielle/du modem requise
L'agent de profil de l'opérateur (LPA) et l'OS de l'eSIM sur la carte eUICC doivent être compatibles au moins avec GSMA RSP (Remote SIM Provisioning) v2.0 ou v2.2. Vous devez également prévoir d'utiliser des serveurs SM-DP+ et SM-DS dont la version RSP correspond. 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 dans Android 9, le modem de l'appareil doit envoyer des capacités de terminal avec la prise en charge des capacités eUICC encodées (gestion des profils locaux et téléchargement des profils). 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
L'APL Google doit connaître l'état du verrouillage de l'opérateur pour pouvoir autoriser le téléchargement ou le transfert d'eSIM uniquement pour l'opérateur autorisé. Sinon, les utilisateurs peuvent télécharger et transférer une carte SIM, puis se rendre compte que l'appareil est verrouillé par un autre opérateur.
Les fournisseurs ou les OEM doivent implémenter l'API HAL IRadioSim.getAllowedCarriers().
Le fournisseur RIL / Modem doit renseigner l'état de verrouillage et l'ID de l'opérateur auquel l'appareil est verrouillé dans l'API HAL IRadioSimResponse.getAllowedCarriersResponse().
Le modem doit reconnaître l'eSIM avec le profil de démarrage par défaut activé comme carte SIM valide et maintenir l'alimentation de la carte SIM.
Pour les appareils équipés d'Android 10, un tableau d'ID d'emplacement eUICC non amovible doit être défini. Pour obtenir un 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 liées au modem, consultez Exigences liées au modem pour la compatibilité avec les eSIM.
EuiccService
Une LPA se compose de deux composants distincts (qui peuvent être implémentés dans le même APK) : le backend LPA et l'UI LPA ou LUI.
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 si plusieurs implémentations sont 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 l'autorité de certification de la plate-forme active et interagit avec elle si nécessaire pour prendre en charge les API eUICC Android. PackageManager
est interrogé pour toutes les applications disposant de 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 prise en charge de LPA est désactivée.
Pour implémenter l'interface utilisateur de l'application, 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.
Une logique similaire est utilisée pour choisir les implémentations de ces activités, comme pour choisir 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'avoir un seul ou plusieurs APK (par exemple, un qui implémente EuiccService
et un qui fournit des activités LUI) est une décision 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 et ne peut être appelée que par des applications disposant de privilèges système.
Figure 2. L'application de l'opérateur et l'agent LPA utilisent tous deux les API Euicc.
Les API d'opération de profil via EuiccCardManager
exigent que l'appelant soit un représentant légal. Cette limite 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);
Ensuite, pour obtenir tous les profils sur 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
par lequel le rappel est invoqué. 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
suivent 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 à partir 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 d'opérateur
Sur les appareils équipés d'Android 9 ou version ultérieure, vous pouvez utiliser une application d'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 downloadSubscription
directement ou en fournissant un code d'activation au LPA.
Lorsqu'une application d'opérateur télécharge un profil en appelant downloadSubscription
, l'appel garantit que l'application peut gérer le profil via une balise de métadonnées BF76
qui encode les règles de privilèges 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 comment activer une eSIM via une application d'opérateur à l'aide d'un code d'activation.
Activer une 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 depuis l'application de l'opérateur et télécharge le profil. Ce flux peut être initié par le LPA, qui peut contrôler l'ensemble du flux d'UI. Cela signifie qu'aucune UI d'application de l'opérateur n'est affichée. Cette approche contourne la vérification de la balise BF76
. Les opérateurs réseau n'ont pas besoin d'implémenter l'intégralité du flux d'interface utilisateur 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.
Le LPA doit se lier à ICarrierEuiccProvisioningService
et implémenter IGetActivationCodeCallback
. Pour savoir comment implémenter et exposer une interface AIDL, consultez Définir une interface AIDL.
Pour définir les interfaces AIDL, créez les fichiers AIDL suivants pour les applications LPA et 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 de LPA
Pour établir une liaison avec l'implémentation ICarrierEuiccProvisioningService
de l'application de l'opérateur, le LPA doit copier ICarrierEuiccProvisioningService.aidl
et IGetActivationCodeCallback.aidl
dans votre projet et implémenter ServiceConnection
.
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mCarrierProvisioningService = ICarrierEuiccProvisioningService.Stub.asInterface(iBinder);
}
Après l'association à l'implémentation ICarrierEuiccProvisioningService
de l'application de l'opérateur, le LPA appelle getActivationCode
ou getActivationCodeForEid
pour obtenir le code d'activation de l'application de l'opérateur en transmettant l'implémentation de la classe stub IGetActivationCodeCallback
.
La différence entre getActivationCode
et getActivationCodeForEid
est que getActivationCodeForEid
permet à un opérateur de préassocier un profil à l'EID de l'appareil avant le début du processus de téléchargement.
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'APL se lie à 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 garantir que seule l'application LPA, qui dispose de privilèges 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 opérateur AIDL, créez un service, étendez la classe Stub
et implémentez les méthodes getActivationCode
et getActivationCodeForEid
. Le 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 celui-ci a été récupéré avec succès depuis le serveur de l'opérateur. En cas d'échec, l'application de l'opérateur doit répondre avec 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 LPA
Sur les appareils équipés d'Android 11 ou version ultérieure, le LPA peut démarrer l'UI d'une application d'opérateur. Cela peut être utile, car une application d'opérateur peut avoir besoin d'informations supplémentaires de l'utilisateur avant de fournir un code d'activation au LPA. Par exemple, les opérateurs peuvent exiger des utilisateurs qu'ils se connectent pour activer leurs numéros de téléphone ou effectuer d'autres services de transfert.
Voici comment démarrer l'UI d'une application d'opérateur dans le LPA :
L'autorité de certification 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 de l'opérateur doit être protégé dans la déclaration du fichier manifeste avecandroid:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
pour éviter de recevoir des intents provenant d'applications non 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 fonctionne avec sa propre UI. Par exemple, la connexion de l'utilisateur ou l'envoi de requêtes HTTP au backend de l'opérateur.
L'application de l'opérateur répond au LPA en appelant
setResult(int, Intent)
etfinish()
.- Si l'application de l'opérateur répond avec
RESULT_OK
, le LPA poursuit le processus d'activation. Si l'application de l'opérateur détermine que l'utilisateur doit scanner un code QR au lieu de laisser l'autorité de gestion des profils locaux associer le service de l'application de l'opérateur, l'application de l'opérateur répond à l'autorité de gestion des profils locaux à l'aide desetResult(int, Intent)
avecRESULT_OK
et une instanceIntent
contenant l'extra booléenandroid.telephony.euicc.extra.USE_QR_SCANNER
défini surtrue
. Le LPA vérifie ensuite l'extra et lance le lecteur de code QR au lieu de lier l'implémentationICarrierEuiccProvisioningService
de l'application de l'opérateur. - Si l'application de l'opérateur plante ou répond avec
RESULT_CANCELED
(code de réponse par défaut), le LPA annule le flux d'activation de l'eSIM. - Si l'application de l'opérateur répond avec autre chose que
RESULT_OK
ouRESULT_CANCELED
, l'autorité de certification locale considère qu'il s'agit d'une erreur.
Pour des raisons de sécurité, le LPA ne doit pas accepter directement un code d'activation fourni dans l'intent de résultat afin de s'assurer que les appelants non LPA ne peuvent pas obtenir de code d'activation à partir de l'application de l'opérateur.
- Si l'application de l'opérateur répond avec
Lancer le flux d'activation LPA dans une application d'opérateur
À partir d'Android 11, les applications des opérateurs peuvent utiliser les API eUICC pour démarrer une interface utilisateur locale pour l'activation de l'eSIM. Cette méthode affiche l'UI du flux d'activation de l'eSIM du LPA pour activer le profil eSIM. L'autorité de certification LPA envoie ensuite une diffusion lorsque l'activation du profil eSIM est terminée.
L'application LPA doit déclarer une activité incluant 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 si 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 fonctionne avec sa propre UI. Par exemple, la connexion de l'utilisateur ou l'envoi de requêtes HTTP au backend de l'opérateur.
À 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 le LPA en appelantstartActivityForResult(Intent, int)
avec l'actionandroid.telephony.euicc.action.START_EUICC_ACTIVATION
. L'autorité de certification LPA vérifie également l'extra booléenandroid.telephony.euicc.extra.USE_QR_SCANNER
. Si la valeur esttrue
, le LPA lance le lecteur de code QR pour permettre à l'utilisateur de scanner le code QR du profil.Du côté de l'LPA, l'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, comme un écran de chargement.Une fois le flux d'activation LPA terminé, le LPA répond à l'application de l'opérateur avec un code de résultat, que l'application de l'opérateur gère dans
onActivityResult(int, int, Intent)
.- Si le LPA parvient à 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 autre chose que
RESULT_OK
ouRESULT_CANCELED
, l'application de l'opérateur 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 afin de s'assurer que les appelants non-LPA ne peuvent pas obtenir le code d'activation depuis l'application de l'opérateur.
- Si le LPA parvient à télécharger le nouveau profil eSIM, il répond avec
Prendre en charge 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 dotés d'une seule eSIM qui passent à Android 10 ne nécessitent aucune modification de l'implémentation LPA, car la plate-forme associe automatiquement l'instance EuiccManager
à l'eUICC par défaut. L'eUICC par défaut est déterminé par la plate-forme pour les appareils dont la version HAL radio est égale ou supérieure à 1.2, et par l'LPA pour les appareils dont la version HAL radio est inférieure à 1.2.
Conditions requises
Pour prendre en charge plusieurs eSIM, l'appareil doit disposer de plusieurs eUICC, qui peuvent être intégrées ou insérées dans un emplacement SIM physique.
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), le LPA doit implémenter EuiccService
, qui reçoit l'ID d'emplacement correspondant à l'ID de 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 d'emplacement des eUICCs intégrés 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 d'opérateur pour un appareil avec plusieurs eSIM, utilisez la méthode createForCardId
dans EuiccManager
pour créer un objet EuiccManager
associé à un ID de carte donné. L'ID de carte est une valeur entière qui identifie de manière unique une UICC ou une eUICC sur l'appareil.
Pour obtenir l'ID de carte de 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 HAL radio est inférieure à 1.2 et renvoie UNINITIALIZED_CARD_ID
si l'appareil n'a pas lu l'eUICC.
Vous pouvez également obtenir des ID de cartes à partir de getUiccCardsInfo
et getUiccSlotsInfo
(API système) dans TelephonyManager
, et 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 de transporteur.
Exemple 1 : Obtenir l'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 : Parcourir les UICC et instancier EuiccManager
pour un 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
L'AOSP n'est pas fourni avec une implémentation LPA et vous n'êtes pas censé avoir de LPA disponible sur toutes les versions d'Android (tous les téléphones ne sont pas compatibles avec les eSIM). Pour cette raison, il n'existe aucun scénario de test CTS de bout en bout. Toutefois, des cas de test de base sont disponibles dans AOSP pour s'assurer que les API eUICC exposées sont valides dans les versions Android.
Vous devez vous assurer que les builds réussissent les cas 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 d'opérateur 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 être en mesure de lister tous les profils d'abonnement appartenant au même opérateur, de télécharger et d'installer un profil, d'activer un service sur le profil, de passer d'un profil à l'autre et de 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, de puce eUICC ou d'OS eSIM, de fournisseurs SM-DP+ et d'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.