Implementierung von eSIM

Mit der integrierten SIM-Technologie (eSIM oder eUICC) können mobile Benutzer ein Trägerprofil herunterladen und den Dienst eines Mobilfunkanbieters aktivieren, ohne über eine physische SIM-Karte zu verfügen. Dabei handelt es sich um eine globale Spezifikation der GSMA, die die Remote-SIM-Bereitstellung (RSP) jedes Mobilgeräts ermöglicht. Ab Android 9 stellt das Android-Framework Standard-APIs für den Zugriff auf eSIM und die Verwaltung von Abonnementprofilen auf dem eSIM bereit. Diese eUICC-APIs ermöglichen es Dritten, ihre eigenen Carrier-Apps und lokalen Profilassistenten (LPAs) auf eSIM-fähigen Android-Geräten zu entwickeln.

Die LPA ist eine eigenständige System-App, die im Android-Build-Image enthalten sein sollte. Die Verwaltung der Profile auf der eSIM erfolgt im Allgemeinen durch die LPA, da sie als Brücke zwischen dem SM-DP+ (Remote-Dienst, der Profilpakete vorbereitet, speichert und an Geräte liefert) und dem eUICC-Chip dient. Das LPA APK kann optional eine UI-Komponente namens LPA UI oder LUI enthalten, um dem Endbenutzer einen zentralen Ort zur Verwaltung aller eingebetteten Abonnementprofile bereitzustellen. Das Android-Framework erkennt automatisch das beste verfügbare LPA, stellt eine Verbindung zu diesem her und leitet alle eUICC-Vorgänge über eine LPA-Instanz weiter.

Vereinfachte RSP-Architektur (Remote SIM Provisioning).

Abbildung 1. Vereinfachte RSP-Architektur

Mobilfunknetzbetreiber, die an der Erstellung einer Carrier-App interessiert sind, sollten sich die APIs in EuiccManager ansehen, die Profilverwaltungsvorgänge auf hoher Ebene wie downloadSubscription() , switchToSubscription() und deleteSubscription() bereitstellen.

Wenn Sie ein Geräte-OEM sind und daran interessiert sind, Ihre eigene LPA-System-App zu erstellen, müssen Sie EuiccService für das Android-Framework erweitern, um eine Verbindung zu Ihren LPA-Diensten herzustellen. Darüber hinaus sollten Sie die APIs in EuiccCardManager verwenden, die ES10x-Funktionen basierend auf GSMA RSP v2.0 bereitstellen. Diese Funktionen werden verwendet, um Befehle an den eUICC-Chip auszugeben, z. B. prepareDownload() , loadBoundProfilePackage() , retrieveNotificationList() und resetMemory() .

Die APIs in EuiccManager erfordern eine ordnungsgemäß implementierte LPA-App, um zu funktionieren, und der Aufrufer der EuiccCardManager APIs muss ein LPA sein. Dies wird durch das Android-Framework erzwungen.

Geräte mit Android 10 oder höher können Geräte mit mehreren eSIMs unterstützen. Weitere Informationen finden Sie unter Unterstützung mehrerer eSIMs .

Eine Carrier-App erstellen

Die eUICC-APIs in Android 9 ermöglichen es Mobilfunknetzbetreibern, Apps unter der Marke des Mobilfunkanbieters zu erstellen, um ihre Profile direkt zu verwalten. Dazu gehört das Herunterladen und Löschen von Abonnementprofilen, die dem Netzbetreiber gehören, sowie der Wechsel zu einem Profil, das einem Netzbetreiber gehört.

EuiccManager

EuiccManager ist der Haupteinstiegspunkt für Apps zur Interaktion mit der LPA. Dazu gehören Netzbetreiber-Apps, die Abonnements des Netzbetreibers herunterladen, löschen und zu diesen wechseln. Dazu gehört auch die LUI-System-App, die einen zentralen Ort/eine zentrale Benutzeroberfläche für die Verwaltung aller eingebetteten Abonnements bietet und eine separate App von der App sein kann, die den EuiccService bereitstellt.

Um die öffentlichen APIs verwenden zu können, muss eine Träger-App zunächst die Instanz von EuiccManager über Context#getSystemService abrufen:

EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);

Sie sollten prüfen, ob eSIM auf dem Gerät unterstützt wird, bevor Sie eSIM-Vorgänge durchführen. EuiccManager#isEnabled() gibt im Allgemeinen true zurück, wenn die Funktion android.hardware.telephony.euicc definiert ist und ein LPA-Paket vorhanden ist.

if (mgr == null || !mgr.isEnabled()) {
    return;
}

So erhalten Sie Informationen zur eUICC-Hardware und der eSIM-Betriebssystemversion:

EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();

Viele APIs wie downloadSubscription() und switchToSubscription() verwenden PendingIntent Rückrufe, da deren Abschluss Sekunden oder sogar Minuten dauern kann. PendingIntent wird mit einem Ergebniscode im EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_ -Bereich gesendet, der vom Framework definierte Fehlercodes sowie einen beliebigen detaillierten Ergebniscode bereitstellt, der von der LPA als EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE weitergegeben wird und es der Carrier-App ermöglicht, zu Protokollierungs-/Debugzwecken nachzuverfolgen. Der PendingIntent Rückruf muss BroadcastReceiver sein.

So laden Sie ein bestimmtes herunterladbares Abonnement herunter (erstellt aus einem Aktivierungscode oder einem QR-Code):

// 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);

Definieren und verwenden Sie die Berechtigung in AndroidManifest.xml :

    <permission android:protectionLevel="signature" android:name="com.your.company.lpa.permission.BROADCAST" />
    <uses-permission android:name="com.your.company.lpa.permission.BROADCAST"/>

So wechseln Sie zu einem Abonnement mit der Abonnement-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);

Eine vollständige Liste der EuiccManager APIs und Codebeispiele finden Sie unter eUICC-APIs .

Behebbare Fehler

Es gibt einige Fälle, in denen das System den eSIM-Vorgang nicht abschließen kann, der Fehler jedoch vom Benutzer behoben werden kann. Beispielsweise kann downloadSubscription fehlschlagen, wenn die Profilmetadaten darauf hinweisen, dass ein Anbieterbestätigungscode erforderlich ist. Oder switchToSubscription schlägt möglicherweise fehl, wenn die Netzbetreiber-App über Netzbetreiberprivilegien für das Zielprofil verfügt (d. h., der Netzbetreiber besitzt das Profil), aber keine Netzbetreiberprivilegien für das aktuell aktivierte Profil hat und daher die Zustimmung des Benutzers erforderlich ist.

In diesen Fällen wird der Rückruf des Anrufers mit EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR aufgerufen. Der Callback- Intent enthält interne Extras, sodass eine Auflösung über die LUI angefordert werden kann, wenn der Aufrufer ihn an EuiccManager#startResolutionActivity übergibt. Unter erneuter Verwendung des Bestätigungscodes löst EuiccManager#startResolutionActivity beispielsweise einen LUI-Bildschirm aus, der es dem Benutzer ermöglicht, einen Bestätigungscode einzugeben. Nach Eingabe des Codes wird der Downloadvorgang fortgesetzt. Dieser Ansatz gibt der Netzbetreiber-App die volle Kontrolle darüber, wann die Benutzeroberfläche angezeigt wird, bietet der LPA/LUI jedoch eine erweiterbare Methode, um in Zukunft eine neue Behandlung von vom Benutzer behebbaren Problemen hinzuzufügen, ohne dass Client-Apps geändert werden müssen.

Android 9 definiert diese lösbaren Fehler in EuiccService , die von der LUI behandelt werden sollen:

/**
 * 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";

Carrier-Privilegien

Wenn Sie als Netzbetreiber eine eigene Netzbetreiber-App entwickeln, die EuiccManager aufruft, um Profile auf ein Gerät herunterzuladen, sollte Ihr Profil in den Metadaten Netzbetreiber-Berechtigungsregeln enthalten, die Ihrer Netzbetreiber-App entsprechen. Dies liegt daran, dass Abonnementprofile verschiedener Netzbetreiber im eUICC eines Geräts nebeneinander existieren können und jede Netzbetreiber-App nur auf die Profile zugreifen darf, die diesem Netzbetreiber gehören. Beispielsweise sollte Netzbetreiber A nicht in der Lage sein, ein Profil von Netzbetreiber B herunterzuladen, zu aktivieren oder zu deaktivieren.

Um sicherzustellen, dass ein Profil nur für seinen Besitzer zugänglich ist, verwendet Android einen Mechanismus, um der App des Profilbesitzers (d. h. der Betreiber-App) besondere Privilegien zu gewähren. Die Android-Plattform lädt Zertifikate, die in der Zugriffsregeldatei (ARF) des Profils gespeichert sind, und erteilt Apps, die mit diesen Zertifikaten signiert sind, die Berechtigung, Aufrufe an EuiccManager APIs durchzuführen. Der allgemeine Prozess wird im Folgenden beschrieben:

  1. Betreiber signiert die Carrier-App APK; Das Apksigner- Tool hängt das Public-Key-Zertifikat an die APK an.
  2. Operator/SM-DP+ bereitet ein Profil und seine Metadaten vor, einschließlich eines ARF, das Folgendes enthält:

    1. Signatur (SHA-1 oder SHA-256) des Public-Key-Zertifikats der Träger-App (erforderlich)
    2. Paketname der Carrier-App (dringend empfohlen)
  3. Die Carrier-App versucht, einen eUICC-Vorgang über EuiccManager API auszuführen.

  4. Die Android-Plattform überprüft, ob der SHA-1- oder SHA-256-Hash des Zertifikats der Anrufer-App mit der Signatur des vom ARF des Zielprofils erhaltenen Zertifikats übereinstimmt. Wenn der Paketname der Carrier-App im ARF enthalten ist, muss dieser auch mit dem Paketnamen der Anrufer-App übereinstimmen.

  5. Nachdem die Signatur und der Paketname (falls enthalten) überprüft wurden, wird der Anrufer-App das Trägerrecht für das Zielprofil gewährt.

Da Profilmetadaten außerhalb des Profils selbst verfügbar sein können (damit LPA die Profilmetadaten von SM-DP+ abrufen kann, bevor das Profil heruntergeladen wird, oder von ISD-R, wenn das Profil deaktiviert ist), sollte es dieselben Betreiberprivilegierungsregeln enthalten wie im Profil.

Das eUICC-Betriebssystem und SM-DP+ müssen ein proprietäres Tag BF76 in den Profilmetadaten unterstützen. Der Tag-Inhalt sollte denselben Carrier-Berechtigungsregeln entsprechen, die vom Access Rule Applet (ARA) zurückgegeben werden, das in UICC Carrier Privileges definiert ist:

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
    }
}

Weitere Informationen zum Signieren von Apps finden Sie unter Signieren Sie Ihre App . Einzelheiten zu Trägerprivilegien finden Sie unter UICC-Trägerprivilegien .

Erstellen einer lokalen Profilassistenten-App

Gerätehersteller können ihren eigenen lokalen Profilassistenten (LPA) implementieren, der mit Android Euicc-APIs verbunden werden muss. Die folgenden Abschnitte geben einen kurzen Überblick über die Erstellung einer LPA-App und deren Integration in das Android-System.

Hardware-/Modemanforderungen

Das LPA und das eSIM-Betriebssystem auf dem eUICC-Chip müssen mindestens GSMA RSP (Remote SIM Provisioning) v2.0 oder v2.2 unterstützen. Sie sollten auch die Verwendung von SM-DP+- und SM-DS-Servern einplanen, die über eine passende RSP-Version verfügen. Eine detaillierte RSP-Architektur finden Sie in der GSMA SGP.21 RSP-Architekturspezifikation .

Darüber hinaus sollte das Gerätemodem zur Integration mit den eUICC-APIs in Android 9 Terminalfunktionen mit der Unterstützung für eUICC-Funktionen codiert senden (lokale Profilverwaltung und Profildownload). Außerdem müssen die folgenden Methoden implementiert werden:

  • IRadio HAL v1.1: setSimPower
  • IRadio HAL v1.2: getIccCardStatus

  • IRadioConfig HAL v1.0: getSimSlotsStatus

  • IRadioConfig AIDL v1.0: getAllowedCarriers

    Der Google LPA muss den Status der Netzbetreibersperre kennen, damit er das Herunterladen oder Übertragen von eSIMs nur für den zulässigen Netzbetreiber zulassen kann. Andernfalls könnte es passieren, dass Benutzer eine SIM-Karte herunterladen und übertragen und später feststellen, dass das Gerät an einen anderen Anbieter gebunden ist.

    • Anbieter oder OEMs müssen die IRadioSim.getAllowedCarriers()HAL-API implementieren.

    • Der RIL/das Modem des Anbieters muss den Sperrstatus und die Carrier-ID des Netzbetreibers angeben, an den das Gerät als Teil der IRadioSimResponse.getAllowedCarriersResponse()-HAL-API gebunden ist.

Das Modem sollte die eSIM mit aktiviertem Standard-Startprofil als gültige SIM-Karte erkennen und die SIM-Karte eingeschaltet lassen.

Für Geräte mit Android 10 muss ein nicht entfernbares eUICC-Steckplatz-ID-Array definiert werden. Siehe beispielsweise 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>

Eine vollständige Liste der Modemanforderungen finden Sie unter Modemanforderungen für die eSIM-Unterstützung .

EuiccService

Eine LPA besteht aus zwei separaten Komponenten (können beide in derselben APK implementiert werden): dem LPA-Backend und der LPA-Benutzeroberfläche oder LUI.

Um das LPA-Backend zu implementieren, müssen Sie EuiccService erweitern und diesen Dienst in Ihrer Manifestdatei deklarieren. Der Dienst muss die Systemberechtigung android.permission.BIND_EUICC_SERVICE erfordern, um sicherzustellen, dass nur das System eine Bindung an ihn herstellen kann. Der Dienst muss außerdem einen Absichtsfilter mit der Aktion android.service.euicc.EuiccService enthalten. Die Priorität des Intent-Filters sollte auf einen Wert ungleich Null gesetzt werden, falls mehrere Implementierungen auf dem Gerät vorhanden sind. Zum Beispiel:

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

Intern bestimmt das Android-Framework die aktive LPA und interagiert bei Bedarf mit ihr, um die Android eUICC-APIs zu unterstützen. PackageManager wird für alle Apps mit der Berechtigung android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS abgefragt, die einen Dienst für die Aktion android.service.euicc.EuiccService angibt. Der Dienst mit der höchsten Priorität wird ausgewählt. Wenn kein Dienst gefunden wird, ist die LPA-Unterstützung deaktiviert.

Um die LUI zu implementieren, müssen Sie eine Aktivität für die folgenden Aktionen bereitstellen:

  • android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS
  • android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION

Wie beim Dienst muss für jede Aktivität die Systemberechtigung android.permission.BIND_EUICC_SERVICE erforderlich sein. Jeder sollte über einen Absichtsfilter mit der entsprechenden Aktion, der Kategorie android.service.euicc.category.EUICC_UI “ und einer Priorität ungleich Null verfügen. Zur Auswahl der Implementierungen für diese Aktivitäten wird eine ähnliche Logik wie bei der Auswahl der Implementierung von EuiccService verwendet. Zum Beispiel:

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

Dies bedeutet, dass die Benutzeroberfläche, die diese Bildschirme implementiert, von einem anderen APK stammen kann als dem, das EuiccService implementiert. Ob ein einzelnes APK oder mehrere APKs vorhanden sein sollen (z. B. eines, das EuiccService implementiert, und eines, das LUI-Aktivitäten bereitstellt), ist eine Entwurfsentscheidung.

EuiccCardManager

EuiccCardManager ist die Schnittstelle zur Kommunikation mit dem eSIM-Chip. Es bietet ES10-Funktionen (wie in der GSMA-RSP-Spezifikation beschrieben) und verarbeitet die Low-Level-APDU-Anfrage-/Antwortbefehle sowie die ASN.1-Analyse. EuiccCardManager ist eine System-API und kann nur von systemprivilegierten Apps aufgerufen werden.

Carrier-Apps, LPA und Euicc-APIs

Abbildung 2. Sowohl die Carrier-App als auch die LPA verwenden Euicc-APIs

Für die Profiloperations-APIs über EuiccCardManager muss der Aufrufer ein LPA sein. Dies wird durch das Android-Framework erzwungen. Das bedeutet, dass der Aufrufer EuiccService erweitern und in Ihrer Manifestdatei deklariert werden muss, wie in den vorherigen Abschnitten beschrieben.

Ähnlich wie bei EuiccManager muss Ihr LPA zur Verwendung der EuiccCardManager APIs zunächst die Instanz von EuiccCardManager über Context#getSystemService abrufen:

EuiccCardManager cardMgr = (EuiccCardManager) context.getSystemService(Context.EUICC_CARD_SERVICE);

So erhalten Sie dann alle Profile im 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);

Intern bindet EuiccCardManager über eine AIDL-Schnittstelle an EuiccCardController (der im Telefonprozess ausgeführt wird) und jede EuiccCardManager Methode erhält ihren Rückruf vom Telefonprozess über eine andere, dedizierte AIDL-Schnittstelle. Bei Verwendung von EuiccCardManager APIs muss der Aufrufer (LPA) ein Executor Objekt bereitstellen, über das der Rückruf aufgerufen wird. Dieses Executor Objekt kann in einem einzelnen Thread oder in einem Thread-Pool Ihrer Wahl ausgeführt werden.

Die meisten EuiccCardManager APIs haben das gleiche Verwendungsmuster. Um beispielsweise ein gebundenes Profilpaket auf die eUICC zu laden:

...
cardMgr.loadBoundProfilePackage(eid, boundProfilePackage,
        AsyncTask.THREAD_POOL_EXECUTOR, callback);

So wechseln Sie zu einem anderen Profil mit einer bestimmten ICCID:

...
cardMgr.switchToProfile(eid, iccid, true /* refresh */,
        AsyncTask.THREAD_POOL_EXECUTOR, callback);

So erhalten Sie die Standard-SM-DP+-Adresse vom eUICC-Chip:

...
cardMgr.requestDefaultSmdpAddress(eid, AsyncTask.THREAD_POOL_EXECUTOR,
        callback);

So rufen Sie eine Liste der Benachrichtigungen der angegebenen Benachrichtigungsereignisse ab:

...
cardMgr.listNotifications(eid,
        EuiccNotification.Event.INSTALL
              | EuiccNotification.Event.DELETE /* events */,
        AsyncTask.THREAD_POOL_EXECUTOR, callback);

Aktivieren eines eSIM-Profils über eine Mobilfunkanbieter-App

Auf Geräten mit Android 9 oder höher können Sie die eSIM über eine Mobilfunkanbieter-App aktivieren und Profile herunterladen. Die Carrier-App kann Profile herunterladen, indem sie downloadSubscription direkt aufruft oder der LPA einen Aktivierungscode zur Verfügung stellt.

Wenn eine Netzbetreiber-App ein Profil herunterlädt, indem sie downloadSubscription aufruft, erzwingt der Aufruf, dass die App das Profil über ein BF76 Metadaten-Tag verwalten kann, das Netzbetreiber-Berechtigungsregeln für das Profil kodiert. Wenn ein Profil kein BF76 Tag hat oder sein BF76 Tag nicht mit der Signatur der anrufenden Anbieter-App übereinstimmt, wird der Download abgelehnt.

Im folgenden Abschnitt wird die Aktivierung einer eSIM über eine Mobilfunkanbieter-App mithilfe eines Aktivierungscodes beschrieben.

eSIM mit einem Aktivierungscode aktivieren

Wenn Sie einen Aktivierungscode zum Aktivieren eines eSIM-Profils verwenden, ruft die LPA einen Aktivierungscode von der Mobilfunkanbieter-App ab und lädt das Profil herunter. Dieser Fluss kann von der LPA initiiert werden und die LPA kann den gesamten UI-Fluss steuern, was bedeutet, dass keine Carrier-App-Benutzeroberfläche angezeigt wird. Dieser Ansatz umgeht die BF76 Tag-Prüfung und Netzwerkbetreiber müssen nicht den gesamten eSIM-Aktivierungs-UI-Ablauf implementieren, einschließlich des Herunterladens eines eSIM-Profils und der Fehlerbehandlung.

Definieren des eUICC-Bereitstellungsdienstes des Netzbetreibers

Die LPA- und Carrier-App kommunizieren über zwei AIDL- Schnittstellen: ICarrierEuiccProvisioningService und IGetActivationCodeCallback . Die Carrier-App muss eine ICarrierEuiccProvisioningService Schnittstelle implementieren und diese in ihrer Manifestdeklaration verfügbar machen. Die LPA muss an ICarrierEuiccProvisioningService binden und IGetActivationCodeCallback implementieren. Weitere Informationen zum Implementieren und Bereitstellen einer AIDL-Schnittstelle finden Sie unter Definieren einer AIDL-Schnittstelle .

Um die AIDL-Schnittstellen zu definieren, erstellen Sie die folgenden AIDL-Dateien sowohl für die LPA- als auch für die Carrier-Apps.

  • 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();
    }
    

Beispiel einer LPA-Implementierung

Um eine Bindung an die ICarrierEuiccProvisioningService Implementierung der Carrier-App herzustellen, muss die LPA sowohl ICarrierEuiccProvisioningService.aidl als auch IGetActivationCodeCallback.aidl in Ihr Projekt kopieren und ServiceConnection implementieren.

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

Nach der Bindung an die ICarrierEuiccProvisioningService Implementierung der Träger-App ruft die LPA entweder getActivationCode oder getActivationCodeForEid auf, um den Aktivierungscode von der Träger-App abzurufen, indem sie die Implementierung der Stub-Klasse IGetActivationCodeCallback übergibt.

Der Unterschied zwischen getActivationCode und getActivationCodeForEid besteht darin, dass getActivationCodeForEid es einem Netzbetreiber ermöglicht, ein Profil vorab an die EID des Geräts zu binden, bevor der Downloadvorgang beginnt.

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
    }
}

Beispielimplementierung für Carrier-App

Damit die LPA an die Netzbetreiber-App gebunden werden kann, muss die Netzbetreiber-App sowohl ICarrierEuiccProvisioningService.aidl als auch IGetActivationCodeCallback.aidl in Ihr Projekt kopieren und den ICarrierEuiccProvisioningService -Dienst in der Datei AndroidManifest.xml deklarieren. Der Dienst muss die Systemberechtigung android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS erfordern, um sicherzustellen, dass nur die LPA, eine systemprivilegierte App, eine Bindung an ihn herstellen kann. Der Dienst muss außerdem einen Absichtsfilter mit der Aktion android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE enthalten.

  • 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>
    

Um den AIDL-Carrier-App-Dienst zu implementieren, erstellen Sie einen Dienst, erweitern Sie die Stub Klasse und implementieren Sie die Methoden getActivationCode und getActivationCodeForEid . Die LPA kann dann eine der beiden Methoden aufrufen, um den Profilaktivierungscode abzurufen. Die Netzbetreiber-App sollte mit dem Aufruf von IGetActivationCodeCallback#onSuccess mit dem Aktivierungscode antworten, wenn der Code erfolgreich vom Server des Netzbetreibers abgerufen wurde. Wenn dies nicht erfolgreich ist, sollte die Netzbetreiber-App mit IGetActivationCodeCallback#onFailure antworten.

  • 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);
              }
          }
    }
    

Starten der Benutzeroberfläche der Carrier-App im LPA-Aktivierungsablauf

Auf Geräten mit Android 11 und höher kann die LPA die Benutzeroberfläche einer Mobilfunkanbieter-App starten. Dies ist nützlich, da eine Mobilfunkanbieter-App möglicherweise zusätzliche Informationen vom Benutzer benötigt, bevor sie einen Aktivierungscode an die LPA übermittelt. Beispielsweise könnten Netzbetreiber verlangen, dass sich Benutzer anmelden, um ihre Telefonnummern zu aktivieren oder andere Portierungsdienste durchzuführen.

Dies ist der Prozess zum Starten der Benutzeroberfläche einer Mobilfunkanbieter-App im LPA:

  1. Die LPA startet den Aktivierungsablauf der Träger-App, indem sie die Absicht android.service.euicc.action.START_CARRIER_ACTIVATION “ an das Träger-App-Paket sendet, das die Aktion enthält. (Der Träger-App-Empfänger muss in der Manifestdeklaration mit android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" geschützt werden, um den Empfang von Absichten von Nicht-LPA-Apps zu vermeiden.)

    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. Die Carrier-App erledigt ihre Arbeit über ihre eigene Benutzeroberfläche. Zum Beispiel das Anmelden des Benutzers oder das Senden von HTTP-Anfragen an das Backend des Netzbetreibers.

  3. Die Carrier-App antwortet auf die LPA mit dem Aufruf von setResult(int, Intent) und finish() .

    1. Wenn die Carrier-App mit RESULT_OK antwortet, setzt die LPA den Aktivierungsfluss fort. Wenn die Netzbetreiber-App feststellt, dass der Benutzer einen QR-Code scannen soll, anstatt die LPA den Dienst der Netzbetreiber-App binden zu lassen, antwortet die Netzbetreiber-App auf die LPA mit setResult(int, Intent) mit RESULT_OK und einer Intent -Instanz, die den booleschen Zusatz android.telephony.euicc.extra.USE_QR_SCANNER auf true gesetzt. Die LPA prüft dann das Extra und startet den QR-Scanner, anstatt die ICarrierEuiccProvisioningService Implementierung der Carrier-App zu binden.
    2. Wenn die Mobilfunkanbieter-App abstürzt oder mit RESULT_CANCELED antwortet (dies ist der Standardantwortcode), bricht die LPA den eSIM-Aktivierungsablauf ab.
    3. Wenn die Carrier-App mit etwas anderem als RESULT_OK oder RESULT_CANCELED antwortet, behandelt die LPA dies als Fehler.

    Aus Sicherheitsgründen sollte die LPA einen im Ergebnisabsicht bereitgestellten Aktivierungscode nicht direkt akzeptieren, um sicherzustellen, dass Nicht-LPA-Anrufer keinen Aktivierungscode von der Mobilfunkanbieter-App erhalten können.

Starten des LPA-Aktivierungsablaufs in einer Mobilfunkanbieter-App

Ab Android 11 können Betreiber-Apps eUICC-APIs verwenden, um eine LUI für die eSIM-Aktivierung zu starten. Diese Methode zeigt die Benutzeroberfläche des eSIM-Aktivierungsablaufs des LPA an, um das eSIM-Profil zu aktivieren. Die LPA sendet dann eine Nachricht, wenn die Aktivierung des eSIM-Profils abgeschlossen ist.

  1. Die LPA muss eine Aktivität einschließlich eines Absichtsfilters mit der Aktion android.service.euicc.action.START_EUICC_ACTIVATION deklarieren. Die Priorität des Intent-Filters sollte auf einen Wert ungleich Null gesetzt werden, falls mehrere Implementierungen auf dem Gerät vorhanden sind. Zum Beispiel:

    <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. Die Carrier-App erledigt ihre Arbeit über ihre eigene Benutzeroberfläche. Zum Beispiel das Anmelden des Benutzers oder das Senden von HTTP-Anfragen an das Backend des Netzbetreibers.

  3. Zu diesem Zeitpunkt muss die Netzbetreiber-App bereit sein, über ihre ICarrierEuiccProvisioningService Implementierung einen Aktivierungscode bereitzustellen. Die Mobilfunkanbieter-App startet die LPA, indem sie startActivityForResult(Intent, int) mit der Aktion android.telephony.euicc.action.START_EUICC_ACTIVATION aufruft. Der LPA überprüft auch das boolesche Extra android.telephony.euicc.extra.USE_QR_SCANNER . Wenn der Wert true ist, startet die LPA den QR-Scanner, damit der Benutzer den Profil-QR-Code scannen kann.

  4. Auf der LPA-Seite bindet die LPA an die ICarrierEuiccProvisioningService Implementierung der Netzbetreiber-App, um den Aktivierungscode abzurufen und das entsprechende Profil herunterzuladen. Der LPA zeigt während des Downloads alle notwendigen UI-Elemente an, wie zum Beispiel einen Ladebildschirm.

  5. Wenn der LPA-Aktivierungsablauf abgeschlossen ist, antwortet die LPA der Träger-App mit einem Ergebniscode, den die Träger-App in onActivityResult(int, int, Intent) verarbeitet.

    1. Wenn es dem LPA gelingt, das neue eSIM-Profil herunterzuladen, antwortet er mit RESULT_OK .
    2. Wenn der Benutzer die Aktivierung des eSIM-Profils im LPA abbricht, antwortet dieser mit RESULT_CANCELED .
    3. Wenn die LPA mit etwas anderem als RESULT_OK oder RESULT_CANCELED antwortet, behandelt die Carrier-App dies als Fehler.

    Aus Sicherheitsgründen akzeptiert die LPA keinen Aktivierungscode direkt im bereitgestellten Intent, um sicherzustellen, dass Nicht-LPA-Anrufer den Aktivierungscode nicht von der Mobilfunkanbieter-App erhalten können.

Unterstützt mehrere eSIMs

Für Geräte mit Android 10 oder höher unterstützt die EuiccManager Klasse Geräte mit mehreren eSIMs. Geräte mit einer einzelnen eSIM, die auf Android 10 aktualisiert werden, erfordern keine Änderungen an der LPA-Implementierung, da die Plattform die EuiccManager Instanz automatisch dem Standard-eUICC zuordnet. Der Standard-eUICC wird von der Plattform für Geräte mit Funk-HAL-Version 1.2 oder höher und von der LPA für Geräte mit Funk-HAL-Versionen niedriger als 1.2 bestimmt.

Anforderungen

Um mehrere eSIMs zu unterstützen, muss das Gerät über mehr als einen eUICC verfügen. Dies kann entweder ein integrierter eUICC oder ein physischer SIM-Steckplatz sein, in den entfernbare eUICCs eingesetzt werden können.

Zur Unterstützung mehrerer eSIMs ist Radio HAL Version 1.2 oder höher erforderlich. Empfohlen werden Radio HAL Version 1.4 und RadioConfig HAL Version 1.2.

Implementierung

Um mehrere eSIMs (einschließlich entfernbarer eUICCs oder programmierbarer SIMs) zu unterstützen, muss die LPA EuiccService implementieren, das die Steckplatz-ID empfängt, die der vom Anrufer bereitgestellten Karten-ID entspricht.

Die in arrays.xml angegebene Ressource non_removable_euicc_slots ist ein Array von Ganzzahlen, die die Steckplatz-IDs der integrierten eUICCs eines Geräts darstellen. Sie müssen diese Ressource angeben, damit die Plattform bestimmen kann, ob ein eingefügter eUICC entfernbar ist oder nicht.

Mobilfunkanbieter-App für Geräte mit mehreren eSIMs

Wenn Sie eine Mobilfunkanbieter-App für ein Gerät mit mehreren eSIMs erstellen, verwenden Sie die Methode createForCardId in EuiccManager , um ein EuiccManager Objekt zu erstellen, das an eine bestimmte Karten-ID angeheftet ist. Die Karten-ID ist ein ganzzahliger Wert, der eine UICC oder eine eUICC auf dem Gerät eindeutig identifiziert.

Um die Karten-ID für die Standard-eUICC des Geräts abzurufen, verwenden Sie die Methode getCardIdForDefaultEuicc in TelephonyManager . Diese Methode gibt UNSUPPORTED_CARD_ID zurück, wenn die Radio-HAL-Version niedriger als 1.2 ist, und gibt UNINITIALIZED_CARD_ID zurück, wenn das Gerät die eUICC nicht gelesen hat.

Sie können Karten-IDs auch von getUiccCardsInfo und getUiccSlotsInfo (System-API) in TelephonyManager und von getCardId in SubscriptionInfo abrufen.

Wenn ein EuiccManager Objekt mit einer bestimmten Karten-ID instanziiert wurde, werden alle Vorgänge mit dieser Karten-ID an den eUICC weitergeleitet. Wenn der eUICC nicht mehr erreichbar ist (z. B. wenn er ausgeschaltet oder entfernt wird), funktioniert EuiccManager nicht mehr.

Sie können die folgenden Codebeispiele verwenden, um eine Carrier-App zu erstellen.

Beispiel 1: Erhalten Sie ein aktives Abonnement und instanziieren Sie 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);

Beispiel 2: Durchlaufen Sie UICCs und instanziieren Sie EuiccManager für einen entfernbaren eUICC

// 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);
}

Validierung

AOSP verfügt nicht über eine LPA-Implementierung und es wird nicht erwartet, dass auf allen Android-Builds eine LPA verfügbar ist (nicht jedes Telefon unterstützt eSIM). Aus diesem Grund gibt es keine durchgängigen CTS-Testfälle. In AOSP stehen jedoch grundlegende Testfälle zur Verfügung, um sicherzustellen, dass die offengelegten eUICC-APIs in Android-Builds gültig sind.

Sie sollten sicherstellen, dass die Builds die folgenden CTS-Testfälle bestehen (für öffentliche APIs): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts .

Netzbetreiber, die eine Netzbetreiber-App implementieren, sollten ihre normalen internen Qualitätssicherungszyklen durchlaufen, um sicherzustellen, dass alle implementierten Funktionen wie erwartet funktionieren. Die Mobilfunkanbieter-App sollte mindestens in der Lage sein, alle Abonnementprofile desselben Betreibers aufzulisten, ein Profil herunterzuladen und zu installieren, einen Dienst für das Profil zu aktivieren, zwischen Profilen zu wechseln und Profile zu löschen.

Wenn Sie Ihr eigenes LPA erstellen, sollten Sie viel strengere Tests durchlaufen. Sie sollten mit Ihrem Modemanbieter, eUICC-Chip- oder eSIM-Betriebssystemanbieter, SM-DP+-Anbietern und Netzbetreibern zusammenarbeiten, um Probleme zu lösen und die Interoperabilität Ihres LPA innerhalb der RSP-Architektur sicherzustellen. Ein umfangreicher manueller Test ist unvermeidlich. Für eine optimale Testabdeckung sollten Sie den GSMA SGP.23 RSP-Testplan befolgen.