Implémenter une eSIM

La technologie SIM intégrée (eSIM, ou eUICC) permet aux utilisateurs mobiles de de télécharger un profil d'opérateur et d'activer le service d'un opérateur carte SIM physique. Il s'agit d'une spécification globale pilotée par la GSMA qui permet le provisionnement à distance de la carte SIM (RSP) de n'importe quel appareil mobile. À partir d'Android 9, le framework Android fournit des API standards l'accès à l'eSIM et la gestion des profils d'abonnement sur l'eSIM. Ces eUICC les API permettent aux tiers de développer leurs propres applications d'opérateur et leur profil local. sur les appareils Android compatibles eSIM.

Le LPA est une application système autonome qui doit être incluse dans Image de build Android La gestion des profils sur l'eSIM est généralement assurée par le LPA, car il sert de pont entre le SM-DP+ (service à distance qui prépare, stocke et livre les packages de profil aux appareils) et la puce eUICC. L'APK LPA peut éventuellement inclure un composant d'UI, appelé UI LPA, ou LUI, pour fournir à l'utilisateur final un emplacement centralisé pour gérer tous les abonnements intégrés profils. Le framework Android détecte et s'y connecte automatiquement disponible et achemine toutes les opérations eUICC via une instance LPA.

Architecture simplifiée de provisionnement de SIM à distance (RSP)

Figure 1 : Architecture RSP simplifiée

Les opérateurs de réseau mobile qui souhaitent créer une application d'opérateur doivent se tourner vers les API EuiccManager qui permet d'effectuer des opérations générales de gestion des profils, 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 EuiccCardManager qui fournissent des fonctions ES10x basées sur GSMA RSP v2.0. Ces fonctions sont utilisées pour envoyer des commandes à la puce eUICC, telles que prepareDownload(), loadBoundProfilePackage(), retrieveNotificationList() et resetMemory().

Les API de EuiccManager ont besoin d'une application LPA correctement implémentée pour fonctionner et que l'appelant de EuiccCardManager Les API doivent être des LPA. Cette règle est appliquée par le framework Android.

Compatibilité avec les appareils équipés d'Android 10 ou version ultérieure appareils avec plusieurs eSIM. Pour en savoir plus, consultez Compatibilité avec plusieurs eSIM.

Créer une appli d'opérateur

Les API eUICC d'Android 9 permettent les opérateurs de réseau mobile peuvent créer des applications aux couleurs de l'opérateur afin de gérer des profils. Cela inclut le téléchargement et la suppression de profils d'abonnement appartenant à l'opérateur, et passer à un profil appartenant à un opérateur.

EuiccManager

EuiccManager est le principal point d'entrée des applications pour interagir avec LPA. Cela inclut les applis d'opérateurs qui téléchargent, suppriment abonnements appartenant à l'opérateur. Cela inclut également l'application système LUI, qui fournit un emplacement/une interface utilisateur centralisé pour gérer tous les abonnements intégrés ; Il peut s'agir d'une application distincte de celle qui fournit EuiccService.

Pour utiliser les API publiques, l'application d'opérateur doit d'abord obtenir l'instance de EuiccManager à 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 une Opérations eSIM. EuiccManager#isEnabled() renvoie généralement true si le android.hardware.telephony.euicc est définie et un package LPA est à l'heure actuelle.

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 PendingIntent, car leur exécution peut prendre quelques secondes, voire quelques minutes. PendingIntent est envoyé avec un code de résultat dans 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 du LPA sous la forme EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, permettant l'application de l'opérateur pour effectuer le suivi à des fins de journalisation/débogage. PendingIntent Le rappel doit être BroadcastReceiver.

Pour télécharger un abonnement téléchargeable donné (créé à partir d'un code d'activation ou 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 en fonction de l'ID d'abonnement:

// 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 pouvant être résolues

Dans certains cas, le système ne parvient pas à effectuer l'opération de l'eSIM. mais l'erreur peut être résolue par l'utilisateur. Exemple : downloadSubscription peut échouer si les métadonnées du profil indiquent qu'un code de confirmation de l'opérateur est obligatoire. Sinon, l'switchToSubscription peut échouer si l'appli de l'opérateur est associée des privilèges sur le profil de destination (c'est-à-dire que l'opérateur est propriétaire du profil), mais ne dispose d'aucun privilège d'opérateur sur le profil actuellement activé et, par conséquent, le consentement de l'utilisateur est requis.

Dans ce cas, le rappel de l'appelant est appelé avec EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR Rappel Intent contient des extras internes de telle sorte que lorsque l'appelant le transmet à EuiccManager#startResolutionActivity, de résolution peut être demandée via l'interface utilisateur. Utiliser le code de confirmation pour à nouveau, EuiccManager#startResolutionActivity déclenche un écran LUI qui permet à l'utilisateur de saisir un code de confirmation ; Une fois le code saisi, le téléchargement reprend. Cette approche permet à l'application de l'opérateur de contrôler totalement le moment où l'interface utilisateur s'affiche, mais donne LPA/LUI, une méthode extensible permettant d'ajouter une nouvelle gestion des récupérations par l'utilisateur de problèmes à l'avenir sans avoir besoin de modifier les applications clientes.

Android 9 définit ces erreurs pouvant être résolues dans EuiccService que l'interface utilisateur 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 d'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 l'opérateur des règles de privilèges correspondant à l'application de votre opérateur dans les métadonnées. C'est car les profils d'abonnement de différents opérateurs peuvent coexister l'eUICC d'un appareil, et chaque appli d'opérateur ne doit être autorisée à accéder qu'à les profils appartenant à cet opérateur. Par exemple, l'opérateur A ne doit pas pouvoir télécharger, activer ou 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 accorder des privilèges spéciaux à l'application du propriétaire du profil (c'est-à-dire à l'application de l'opérateur) La La plate-forme Android charge les certificats stockés dans le fichier de règles d'accès du profil. (ARF) et autorise les applis signées à l'aide de ces certificats à passer des appels vers les API EuiccManager. Le processus général est décrit ci-dessous:

  1. L'opérateur signe l'APK de l'application de l'opérateur. la apksigner associe le certificat de clé publique à l'APK.
  2. L'opérateur/SM-DP+ prépare un profil et ses métadonnées, qui incluent un ARF contenant:

    1. Signature (SHA-1 ou SHA-256) du certificat de clé publique de l'application de l'opérateur (obligatoire)
    2. Nom de package de l'application de l'opérateur (vivement recommandé)
  3. L'application de l'opérateur tente d'effectuer une opération eUICC avec l'API EuiccManager.

  4. La plate-forme Android vérifie le hachage SHA-1 ou SHA-256 de l'appel d'API certificat correspond à la signature du certificat obtenu à partir du ARF du profil cible. Si le nom de package de l'application de l'opérateur figure dans le fichier de récupération de compte, il doit également correspondre au nom du package de l'application appelante.

  5. Une fois que la signature et le nom du package (le cas échéant) ont été vérifiés, le un droit d'opérateur est accordé à l'application appelante via le profil cible.

Étant donné que les métadonnées de profil peuvent être disponibles en dehors du profil lui-même, LPA peut récupérer les métadonnées de profil à partir de SM-DP+ avant que le profil ne soit téléchargée ou à partir d'ISD-R lorsque le profil est désactivé), il doit contenir les mêmes règles en matière de droits d'opérateur que dans le profil.

L'OS eUICC et SM-DP+ doivent être compatibles avec un tag propriétaire BF76 dans le profil de métadonnées. Le contenu du tag doit respecter les mêmes règles en matière de droits d'opérateur que celles renvoyées par l'applet de règle d'accès (ARA) défini dans Droits d'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 Signez votre application. Pour en savoir plus sur les droits d'opérateur, consultez Droits d'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 accrochée grâce aux API Android Euicc. Les sections suivantes présentent brièvement créer une application LPA et l’intégrer au système Android.

Configuration matérielle/configuration requise pour le modem

Le LPA et l'OS eSIM sur la puce eUICC doivent être compatibles au minimum avec les réseaux GSMA RSP provisionnement de la carte SIM) v2.0 ou v2.2. Vous devez également prévoir d'utiliser SM-DP+ et SM-DS avec une version RSP correspondante. Pour en savoir plus sur l'architecture RSP, consultez Spécification d'architecture RSP GSMA SGP.21

De plus, pour intégrer les API eUICC dans Android 9, le modem de l'appareil doit envoyer les capacités du terminal et prend en charge les fonctionnalités eUICC encodées (gestion des profils en local téléchargement du profil). 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'application Google LPA doit connaître l'état du verrouillage de l'opérateur afin de pouvoir autoriser le téléchargement ou le transfert d'eSIM uniquement pour l'opérateur autorisé. Dans le cas contraire, les utilisateurs risquent de télécharger et de transférer leur carte SIM, puis de réaliser plus tard que l'opérateur de leur appareil est bloqué par un autre opérateur.

    • Les fournisseurs ou les OEM doivent implémenter l'API IRadioSim.getAllowedCarriers()HAL.

    • Dans le cadre de l'API IRadioSimResponse.getAllowedCarriersResponse()HAL, le fournisseur RIL / Modem doit renseigner l'état du 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é en tant que une carte SIM valide et laissez la carte sous tension.

Pour les appareils équipés d'Android 10, Vous devez définir un tableau d'ID d'emplacement. 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 de modem, consultez Exigences de modem pour la prise en charge des eSIM.

EuiccService

Un LPA se compose de deux composants distincts (ils peuvent tous deux ê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éclarez ce service dans votre fichier manifeste. Le service doit exiger android.permission.BIND_EUICC_SERVICE l'autorisation système pour s'assurer que uniquement 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é de l'intent le filtre doit être défini sur une valeur non nulle dans le 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 le LPA actif et interagit avec afin de prendre en charge les API Android eUICC. La requête PackageManager est interrogée 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é, LPA la prise en charge est désactivée.

Pour implémenter l'interface utilisateur, 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 Autorisation système android.permission.BIND_EUICC_SERVICE. Chacun d'eux doit comporter le filtre d'intent correspondant à 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 pour ces activités le choix de l'implémentation 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 qui implémente ces écrans peut provenir APK issu de celui qui met en œuvre EuiccService Indique s'il faut un seul ou plusieurs APK (par exemple, un qui implémente EuiccService et un autre qui fournit des activités LUI) est un choix de conception.

EuiccCardManager

EuiccCardManager est l'interface permettant de communiquer avec la puce eSIM. Il fournit les fonctions ES10 (telles que décrites dans la spécification RSP GSMA) et gère les 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 privilèges système applications.

Applications d&#39;opérateur, LPA et API Euicc

Figure 2. L'application de l'opérateur et l'application LPA utilisent des API Euicc

Les API d'opération de profil via EuiccCardManager exigent 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 obtenez d'abord 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 un processus téléphonique) via une interface AIDL et chaque méthode EuiccCardManager reçoit son rappel du processus téléphonique via un autre service AIDL dédié de commande. Lorsque vous utilisez les API EuiccCardManager, l'appelant (LPA) doit fournir une Executor via lequel le rappel est invoqué. Cet objet Executor peut s'exécuter sur 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 de profil lié à 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 l'application de l'opérateur pour activer l'eSIM et télécharger les profils. L'application de l'opérateur peut télécharger des profils en Appel en cours downloadSubscription directement ou en fournissant un code d'activation à la 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 un BF76 balise de métadonnées qui encode les règles de privilège de l'opérateur pour le profil. Si un profil ne comporte pas de balise BF76 ou si sa balise BF76 n'en comporte pas ne correspond pas à la signature de l'application de l'opérateur téléphonique, 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 l'application de l'opérateur et télécharge le profil. Ce flux peut être lancé par le LPA et le LPA peut contrôler l'ensemble du flux d'UI, ce qui signifie qu'aucune UI d'application d'opérateur n'est affichés. Cette approche permet de contourner la vérification du tag BF76, et les opérateurs réseau besoin d'implémenter l'intégralité du flux d'interface utilisateur d'activation eSIM, y compris le téléchargement d'un le 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 AIDL interfaces: ICarrierEuiccProvisioningService et IGetActivationCodeCallback. L'opérateur l'application doit implémenter une interface ICarrierEuiccProvisioningService et l'exposer dans son déclaration du fichier manifeste. Le LPA doit être lié à ICarrierEuiccProvisioningService et implémenter IGetActivationCodeCallback Pour en savoir plus sur l'implémentation et exposer une interface AIDL : consultez la section Définition et interface AIDL.

Pour définir les interfaces AIDL, créez les fichiers AIDL suivants pour l'application LPA et celle 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 l'application LPA

Pour vous lier à l'implémentation ICarrierEuiccProvisioningService de l'application de l'opérateur, le LPA doit copier à la fois ICarrierEuiccProvisioningService.aidl et IGetActivationCodeCallback.aidl à votre projet et implémenter ServiceConnection

@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    mCarrierProvisioningService = ICarrierEuiccProvisioningService.Stub.asInterface(iBinder);
}

Après la liaison au ICarrierEuiccProvisioningService de l'appli de l'opérateur l'implémentation, le LPA appelle getActivationCode ou getActivationCodeForEid pour obtenir le code d'activation de l'application de l'opérateur d'ici le en transmettant l'implémentation de la classe bouchon IGetActivationCodeCallback.

La différence entre getActivationCode et getActivationCodeForEid est que getActivationCodeForEid permet à un opérateur de pré-lier un profil à l'appareil EID 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 la LPA s'associe à l'application de l'opérateur, celle-ci doit copier les deux ICarrierEuiccProvisioningService.aidl et IGetActivationCodeCallback.aidl à votre projet et déclarez le service ICarrierEuiccProvisioningService dans AndroidManifest.xml. Le service doit exiger android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS autorisation système pour garantir que seul le LPA, une application privilégiée du système, peut s’y lier. Le service doit incluent également un filtre d'intent 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 Stub et implémenter getActivationCode et getActivationCodeForEid. méthodes. Le LPA peut ensuite appeler l'une ou l'autre des méthodes pour récupérer l'activation du profil. du code source. L'application de l'opérateur doit répondre en appelant IGetActivationCodeCallback#onSuccess par le code d'activation, si le code était récupérées sur le serveur de l'opérateur. En cas d'échec, 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'interface utilisateur de l'application de l'opérateur dans le flux d'activation de l'application 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. Ceci est utile, car l'appli d'un opérateur peut avoir besoin d'informations supplémentaires avant de fournir un code d'activation au LPA. Par exemple, les opérateurs peuvent exiger des utilisateurs qu'ils se connectent pour activer leur numéro de téléphone ou effectuer d'autres transferts services.

Voici le processus permettant de démarrer l'interface utilisateur d'une application d'opérateur dans le LPA:

  1. La LPA lance le flux d'activation de l'application de l'opérateur en envoyant le l'intent android.service.euicc.action.START_CARRIER_ACTIVATION à la classe package d'application de l'opérateur contenant l'action. (Le récepteur de l'application de l'opérateur doit être protégées dans la déclaration du fichier manifeste android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" jusqu'à éviter de recevoir des intents 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);
    
  2. L'application de l'opérateur effectue son travail à l'aide de sa propre interface utilisateur. Par exemple, Logging ou l'envoi de requêtes HTTP au backend de l'opérateur.

  3. L'application de l'opérateur répond au LPA en appelant setResult(int, Intent) et finish().

    1. Si l'application de l'opérateur répond avec RESULT_OK, le 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 l'application LPA lier l'opérateur l'application de l'opérateur répond à la LPA en utilisant setResult(int, Intent) avec RESULT_OK et une instance Intent contenant l'extra booléen android.telephony.euicc.extra.USE_QR_SCANNER défini sur true. LPA puis vérifie l'extra et lance le lecteur de code QR au lieu de lier l'implémentation ICarrierEuiccProvisioningService de l'application de l'opérateur ;
    2. Si l'application de l'opérateur plante ou répond avec RESULT_CANCELED (il s'agit du code de réponse par défaut), le LPA annule l'eSIM processus d'activation.
    3. Si l'application de l'opérateur renvoie un résultat autre que RESULT_OK ou RESULT_CANCELED, le LPA le traite comme 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 pour garantir que les tests non-LPA les appelants ne peuvent pas obtenir de code d'activation via l'application de l'opérateur.

Lancer le flux d'activation LPA dans une application d'opérateur

À partir d'Android 11, les applis d'opérateur peuvent utiliser les API eUICC pour démarrer une LUI pour l'eSIM l'activation. Cette méthode présente l'UI du flux d'activation eSIM de la LPA à activer le profil eSIM. La LPA envoie ensuite une annonce lorsque le profil eSIM l'activation est terminée.

  1. Le LPA doit déclarer une activité comprenant un filtre d'intent avec Action android.service.euicc.action.START_EUICC_ACTIVATION. La priorité du filtre d'intent doit être défini sur une valeur non nulle si plusieurs implémentations 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>
    
  2. L'application de l'opérateur effectue son travail à l'aide de sa propre interface utilisateur. Par exemple, Logging ou l'envoi de requêtes HTTP au backend de l'opérateur.

  3. À ce stade, l'application de l'opérateur doit être prête à fournir une activation. via son implémentation ICarrierEuiccProvisioningService. La l'application de l'opérateur lance l'application du LPA en appelant startActivityForResult(Intent, int) avec le android.telephony.euicc.action.START_EUICC_ACTIVATION action. Le LPA vérifie également l'extra booléen android.telephony.euicc.extra.USE_QR_SCANNER Si la valeur est true, le LPA lance le lecteur de code QR pour permettre à l'utilisateur de scanner le code QR du profil.

  4. Du côté de la LPA, celle-ci se lie au LPA Implémentation de ICarrierEuiccProvisioningService pour récupérer l'activation code et téléchargez le profil correspondant. Le LPA affiche toutes les données Des éléments d'interface utilisateur pendant le téléchargement, comme un écran de chargement

  5. Une fois le flux d'activation de LPA terminé, le LPA répond au l'application de l'opérateur avec un code de résultat, que l'appli de l'opérateur gère dans onActivityResult(int, int, Intent)

    1. Si le LPA réussit à télécharger le nouveau profil eSIM, il répond avec RESULT_OK.
    2. Si l'utilisateur annule l'activation du profil eSIM dans le LPA, il répond avec RESULT_CANCELED.
    3. Si l'application LPA renvoie une réponse autre que RESULT_OK ou RESULT_CANCELED, l'appli de l'opérateur considère cela comme une erreur.

    Pour des raisons de sécurité, l'API LPA n'accepte pas les codes d'activation. directement dans l'intent fourni pour garantir que les appelants non-LPA ne peuvent pas le code d'activation à partir de l'application de l'opérateur.

Assurer la compatibilité avec plusieurs cartes eSIM

Pour les appareils équipés d'Android 10 ou version ultérieure, La classe EuiccManager est compatible avec les appareils avec plusieurs eSIM. Appareils avec une seule eSIM qui passent à Android 10 n'exigent aucune modification de l'implémentation de LPA en tant que plate-forme associe automatiquement l'instance EuiccManager à l'eUICC par défaut. La L'eUICC par défaut est déterminé par la plate-forme pour les appareils dotés de la version HAL radio 1.2 ou version ultérieure et par LPA pour les appareils dotés de versions HAL radio antérieures à 1.2.

Conditions requises

Pour prendre en charge plusieurs eSIM, l'appareil doit disposer de plusieurs eUICC, ce qui peut être soit un eUICC intégré, soit un emplacement SIM physique où des eUICC amovibles peuvent être inséré.

La version 1.2 ou ultérieure de Radio HAL est requise pour prendre en charge plusieurs eSIM. Radio HAL Les versions 1.4 et 1.2 de RadioConfig HAL sont recommandées.

Implémentation

Pour prendre en charge plusieurs eSIM (y compris les cartes EUICC amovibles ou les cartes SIM programmables), la doivent implémenter EuiccService qui reçoit l'ID d'emplacement correspondant à l'ID de la carte fournie par l'appelant.

La non_removable_euicc_slots ressource spécifiée dans arrays.xml est un tableau d'entiers représentant les ID d'emplacement de l'instance eUICC Vous devez spécifier cette ressource pour permettre à la plate-forme de déterminer si un eUICC inséré est amovible ou non.

Application de l'opérateur pour l'appareil avec plusieurs eSIM

Lorsque vous créez une application d'opérateur pour un appareil avec plusieurs eSIM, utilisez le createForCardId dans EuiccManager pour créer un objet EuiccManager épinglé à un l'ID de la carte fournie. L'ID de carte est un nombre entier qui identifie un UICC de manière unique. ou eUICC sur l'appareil.

Pour obtenir l'ID de carte correspondant à l'eUICC par défaut de l'appareil, utilisez le getCardIdForDefaultEuicc dans TelephonyManager. Cette méthode renvoie UNSUPPORTED_CARD_ID si la version radio HAL est antérieure à 1.2 et renvoie UNINITIALIZED_CARD_ID si l'appareil n'a pas lu l'eUICC.

Vous pouvez également obtenir les ID de carte 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, tous des opérations sont dirigées vers l’eUICC avec cet ID de carte. Si l'eUICC devient inaccessible (par exemple, lorsqu'elle est désactivée ou supprimée) EuiccManager non fonctionne plus longtemps.

Vous pouvez utiliser les exemples de code suivants pour créer une application d'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: Effectuer une itération via 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

AOSP n’est pas fourni avec une implémentation LPA et vous n’êtes pas censé ont un LPA disponible sur tous les builds Android (tous les téléphones ne sont pas compatibles avec eSIM). Pour il n'existe aucun scénario de test CTS de bout en bout. Toutefois, les 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): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts.

Les opérateurs qui mettent en place une application d'opérateur doivent appliquer leurs processus habituels en interne assurance qualité cycles pour s'assurer que toutes les fonctionnalités implémentées fonctionnent comme prévu. Au l'application de l'opérateur doit pouvoir répertorier 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 APA, vous devez vous soumettre à des examens tests. Vous devez contacter le fournisseur de votre modem, de votre puce électronique eUICC ou de votre système d'exploitation eSIM, les opérateurs et fournisseurs SM-DP+ pour résoudre les problèmes et garantir l'interopérabilité des votre LPA dans l'architecture RSP. Une bonne partie des tests manuels est inévitable. Pour optimiser la couverture de test, suivez les instructions Plan de test RSP GSMA SGP.23