eSIM implementieren

Mit der Embedded SIM-Technologie (eSIM oder eUICC) können Nutzer ein Mobilfunkanbieterprofil herunterladen und den Dienst eines Mobilfunkanbieters aktivieren, ohne eine physische SIM-Karte zu haben. Es ist eine globale Spezifikation der GSMA, die die Remote-SIM-Bereitstellung (Remote SIM Provisioning, RSP) auf beliebigen Mobilgeräten ermöglicht. Ab Android 9 bietet das Android-Framework Standard-APIs für den Zugriff auf die eSIM und die Verwaltung von Aboprofilen auf der eSIM. Mit diesen eUICC-APIs können Drittanbieter eigene Mobilfunkanbieter-Apps und lokale Profilassistenten (Local Profile Assistants, LAs) auf eSIM-fähigen Android-Geräten entwickeln.

Die LPA ist eine eigenständige System-App, die im Android-Build-Image enthalten sein sollte. Die Profile auf der eSIM werden in der Regel vom LPA verwaltet, 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 enthalten, die LPA-UI oder LUI genannt wird. Sie bietet dem Endnutzer einen zentralen Ort, an dem er alle eingebetteten Aboprofile verwalten kann. Das Android-Framework erkennt automatisch die beste verfügbare LPA, stellt eine Verbindung her und leitet alle eUICC-Vorgänge über eine LPA-Instanz weiter.

Vereinfachte Architektur für Remote-SIM-Bereitstellung (RSP)

Abbildung 1. Vereinfachte RSP-Architektur

Mobilfunkanbieter, die eine Mobilfunkanbieter-App erstellen möchten, sollten sich die APIs in EuiccManager ansehen. Dort finden sie Profileverwaltungsfunktionen auf hoher Ebene wie downloadSubscription(), switchToSubscription() und deleteSubscription().

Wenn Sie ein OEM sind und eine eigene LPA-System-App erstellen möchten, müssen Sie EuiccService erweitern, damit das Android-Framework eine Verbindung zu Ihren LPA-Diensten herstellen kann. Außerdem solltest du die APIs in EuiccCardManager verwenden, die ES10x-Funktionen basierend auf GSMA RSP v2.0 bereitstellen. Mit diesen Funktionen werden Befehle an den eUICC-Chip gesendet, z. B. prepareDownload(), loadBoundProfilePackage(), retrieveNotificationList() und resetMemory().

Für die APIs in EuiccManager ist eine ordnungsgemäß implementierte LPA-App erforderlich. Außerdem muss der Aufrufer der EuiccCardManager-APIs eine LPA sein. Dies wird vom 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.

Mobilfunkanbieter-App erstellen

Mit den eUICC APIs in Android 9 können Mobilfunkanbieter Apps mit eigenem Branding erstellen, um ihre Profile direkt zu verwalten. Dazu gehört das Herunterladen und Löschen von Aboprofilen, die dem Mobilfunkanbieter gehören, sowie den Wechsel zu einem Profil eines Anbieters.

EuiccManager

EuiccManager ist der Haupteinstiegspunkt für Apps, um mit der LPA zu interagieren. Dazu gehören auch Mobilfunkanbieter-Apps, die Abos des Anbieters herunterladen, löschen und auf diese umstellen. Dazu gehört auch die LUI-System-App, die einen zentralen Ort bzw. eine zentrale Benutzeroberfläche für die Verwaltung aller eingebetteten Abos bietet und eine von der App abweichen kann, die EuiccService bereitstellt.

Um die öffentlichen APIs zu verwenden, muss eine Mobilfunkanbieter-App zuerst die Instanz von EuiccManager über Context#getSystemService abrufen:

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

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

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

So rufen Sie Informationen zur eUICC-Hardware und zur eSIM-Betriebssystemversion ab:

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

Viele APIs wie downloadSubscription() und switchToSubscription() verwenden PendingIntent-Callbacks, da sie Sekunden oder sogar Minuten in Anspruch nehmen können. PendingIntent wird mit einem Ergebniscode im Bereich EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_ gesendet, der frameworkdefinierte Fehlercodes sowie einen beliebigen detaillierten Ergebniscode enthält, der von der LPA als EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE weitergegeben wird. So kann die Mobilfunkanbieter-App zu Logging- und Debugging-Zwecken nachverfolgt werden. Der PendingIntent-Callback muss BroadcastReceiver sein.

So lädst du ein bestimmtes herunterladbares Abo herunter, das über einen Aktivierungscode oder einen QR-Code erstellt wurde:

// 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 wechselst du zu einem Abo anhand der Abo-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

In einigen Fällen kann das System den eSIM-Vorgang nicht abschließen, der Fehler kann jedoch vom Nutzer behoben werden. downloadSubscription kann beispielsweise fehlschlagen, wenn in den Profilmetadaten angegeben ist, dass ein Bestätigungscode des Mobilfunkanbieters erforderlich ist. switchToSubscription kann auch fehlschlagen, wenn die Mobilfunkanbieter-App Berechtigungen des Mobilfunkanbieters für das Zielprofil hat (d. h. der Mobilfunkanbieter ist der Inhaber des Profils), aber keine Berechtigungen des Mobilfunkanbieters für das aktuell aktivierte Profil hat und daher die Einwilligung des Nutzers erforderlich ist.

In diesen Fällen wird der Callback des Aufrufers mit EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR aufgerufen. Der Rückruf Intent enthält interne Extras, sodass die Lösung über die LUI angefordert werden kann, wenn der Aufrufer ihn an EuiccManager#startResolutionActivity weitergibt. Wenn wir zum Beispiel den Bestätigungscode verwenden, wird durch EuiccManager#startResolutionActivity ein LUI-Bildschirm ausgelöst, auf dem der Nutzer einen Bestätigungscode eingeben kann. Nachdem der Code eingegeben wurde, wird der Download fortgesetzt. Bei diesem Ansatz hat die Mobilfunkanbieter-App die volle Kontrolle darüber, wann die Benutzeroberfläche angezeigt wird. Die LPA/LUI bietet jedoch eine erweiterbare Methode, um in Zukunft neue Abläufe für vom Nutzer behebbare Probleme hinzuzufügen, ohne dass Client-Apps geändert werden müssen.

Unter Android 9 werden diese behebbaren Fehler in EuiccService definiert, die vom LUI verarbeitet 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";

Berechtigungen für Mobilfunkanbieter

Wenn du ein Mobilfunkanbieter bist, der eine eigene Mobilfunkanbieter-App entwickelt, die EuiccManager aufruft, um Profile auf ein Gerät herunterzuladen, sollte dein Profil in den Metadaten Regeln für Mobilfunkanbieter-Berechtigungen enthalten, die der App deines Mobilfunkanbieters entsprechen. Das liegt daran, dass Aboprofile verschiedener Mobilfunkanbieter im eUICC eines Geräts gleichzeitig vorhanden sein können und jede Mobilfunkanbieter-App nur auf die Profile zugreifen darf, die diesem Mobilfunkanbieter gehören. Anbieter A sollte beispielsweise kein Profil von Anbieter B herunterladen, aktivieren oder deaktivieren können.

Damit nur der Inhaber auf ein Profil zugreifen kann, verwendet Android einen Mechanismus, mit dem der App des Profilinhabers (d. h. der Mobilfunkanbieter-App) spezielle Berechtigungen gewährt werden. Die Android-Plattform lädt Zertifikate aus der Zugriffsregeldatei (ARF) des Profils und gewährt Apps, die mit diesen Zertifikaten signiert sind, die Berechtigung, EuiccManager APIs aufzurufen. Der Prozess wird unten allgemein beschrieben:

  1. Der Operator signiert das APK der Mobilfunkanbieter-App. Das Tool apksigner hängt das Zertifikat mit öffentlichem Schlüssel an das APK an.
  2. Der Betreiber/SM-DP+ erstellt ein Profil und die zugehörigen Metadaten, einschließlich einer ARF mit folgenden Inhalten:

    1. Signatur (SHA-1 oder SHA-256) des Public-Key-Zertifikats der Mobilfunkanbieter-App (erforderlich)
    2. Paketname der Mobilfunkanbieter-App (streng empfohlen)
  3. Die App des Mobilfunkanbieters versucht, einen eUICC-Vorgang mit der EuiccManager API auszuführen.

  4. Die Android-Plattform prüft, ob der SHA-1- oder SHA-256-Hash des Zertifikats der anrufenden App mit der Signatur des Zertifikats übereinstimmt, das aus dem ARF des Zielprofils abgerufen wurde. Wenn der Paketname der Mobilfunkanbieter-App im ARF enthalten ist, muss er auch mit dem Paketnamen der anrufenden App übereinstimmen.

  5. Nachdem die Signatur und der Paketname (falls enthalten) verifiziert wurden, wird der Aufrufer-App die Berechtigung des Mobilfunkanbieters für das Zielprofil gewährt.

Da Profilmetadaten auch außerhalb des Profils verfügbar sein können (damit LPA die Profilmetadaten aus SM-DP+ abrufen kann, bevor das Profil heruntergeladen wird, oder aus ISD-R, wenn das Profil deaktiviert ist), sollten sie dieselben Berechtigungsregeln für Mobilfunkanbieter wie im Profil enthalten.

Das eUICC-Betriebssystem und SM-DP+ müssen ein proprietäres Tag BF76 in den Profilmetadaten unterstützen. Der Tag-Inhalt sollte den gleichen Mobilfunkanbieter-Berechtigungsregeln entsprechen, die vom Applet für die Zugriffsregel (Access Rule Access Rule, ARA) zurückgegeben werden und unter UICC-Mobilfunkanbieterberechtigungen definiert sind:

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 zur App-Signatur finden Sie unter App signieren. Informationen zu Mobilfunkanbieterberechtigungen finden Sie unter UICC-Mobilfunkanbieterberechtigungen.

App für lokalen Profilassistenten erstellen

Gerätehersteller können ihren eigenen lokalen Profilassistenten (LPA) implementieren, der mit den Android Euicc APIs verbunden sein muss. In den folgenden Abschnitten erhalten Sie einen kurzen Überblick darüber, wie Sie eine LPA-App erstellen und in das Android-System einbinden.

Hardware-/Modemanforderungen

Der LPA und das eSIM-Betriebssystem auf dem eUICC-Chip müssen mindestens GSMA RSP (Remote SIM Provisioning) 2.0 oder 2.2 unterstützen. Sie sollten auch SM-DP+ und SM-DS-Server mit einer übereinstimmenden RSP-Version verwenden. Eine detaillierte RSP-Architektur finden Sie in der GSMA SGP.21 RSP Architecture Specification.

Darüber hinaus sollte das Gerätemodem Terminalfunktionen mit codierten Unterstützung für eUICC-Funktionen (lokale Profilverwaltung und Profildownload) senden, um die eUICC-APIs in Android 9 einzubinden. 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

    Die Google LPA muss den Status der Sperrung durch den Mobilfunkanbieter kennen, damit der Download oder die Übertragung der eSIM nur für den zulässigen Mobilfunkanbieter zugelassen werden kann. Andernfalls kann es passieren, dass Nutzer eine SIM herunterladen und übertragen und später feststellen, dass das Gerät an einen anderen Mobilfunkanbieter gebunden ist.

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

    • Der Anbieter-RIL / das Anbieter-Modem muss den Sperrstatus und die Carrier-ID des Mobilfunkanbieters, bei dem das Gerät gesperrt ist, im Rahmen der HAL-API „IRadioSimResponse.getAllowedCarriersResponse()“ angeben.

Das Modem sollte die eSIM mit dem aktivierten Standard-Bootprofil als gültige SIM erkennen und die SIM-Stromversorgung eingeschaltet lassen.

Für Geräte mit Android 10 muss ein nicht entfernbares eUICC-Steckplatz-ID-Array definiert sein. Beispiele finden Sie unter 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 den eSIM-Support.

Euicc-Service

Ein LPA besteht aus zwei separaten Komponenten, die beide in derselben APK implementiert werden können: dem LPA-Backend und der LPA-UI oder LUI.

Zum Implementieren des LPA-Back-Ends müssen Sie EuiccService erweitern und diesen Dienst in der Manifestdatei deklarieren. Der Dienst muss die Systemberechtigung android.permission.BIND_EUICC_SERVICE erfordern, damit nur das System eine Bindung daran vornehmen kann. Der Dienst muss außerdem einen Intent-Filter mit der Aktion android.service.euicc.EuiccService enthalten. Die Priorität des Intent-Filters sollte auf einen Wert ungleich 0 festgelegt werden, falls sich auf dem Gerät mehrere Implementierungen befinden. 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>

Das Android-Framework bestimmt intern die aktive LPA und interagiert nach Bedarf mit ihm, um die Android eUICC APIs zu unterstützen. PackageManager wird für alle Anwendungen 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, wird der LPA-Support deaktiviert.

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

  • 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 einen Intent-Filter mit der entsprechenden Aktion, der Kategorie android.service.euicc.category.EUICC_UI und einer Priorität ungleich null haben. Die Implementierungen für diese Aktivitäten werden nach derselben Logik ausgewählt wie die Implementierung von EuiccService. 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 impliziert, dass die UI, die diese Bildschirme implementiert, von einem anderen APK stammen kann als dem, das EuiccService implementiert. Ob Sie ein einzelnes APK oder mehrere APKs verwenden (z. B. eines, das EuiccService implementiert, und eines, das LUI-Aktivitäten bereitstellt), ist eine Designentscheidung.

EuiccCardManager

EuiccCardManager ist die Schnittstelle für die 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 das ASN.1-Parsen. EuiccCardManager ist eine System-API und kann nur von Apps mit Systemberechtigungen aufgerufen werden.

Mobilfunkanbieter-Apps, LPA und Euicc-APIs

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

Für die Profilvorgangs-APIs über EuiccCardManager muss der Aufrufer ein LPA sein. Dies wird vom 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 dein LPA zuerst die Instanz von EuiccCardManager über Context#getSystemService abrufen, um die EuiccCardManager APIs zu verwenden:

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

Gehen Sie dann so vor, um alle Profile auf der eUICC abzurufen:

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 wird EuiccCardManager über eine AIDL-Schnittstelle an EuiccCardController (das im Smartphone-Prozess ausgeführt wird) gebunden. Jede EuiccCardManager-Methode erhält ihren Rückruf vom Smartphone-Prozess über eine andere, spezielle AIDL-Schnittstelle. Bei der Verwendung von EuiccCardManager APIs muss der Aufrufer (LPA) ein Executor-Objekt angeben, über das der Callback aufgerufen wird. Dieses Executor-Objekt kann in einem einzelnen Thread oder in einem Threadpool Ihrer Wahl ausgeführt werden.

Die meisten EuiccCardManager APIs haben das gleiche Nutzungsmuster. So laden Sie beispielsweise ein gebundenes Profilpaket auf die eUICC:

...
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 rufen Sie die SM-DP+ Standardadresse über den eUICC-Chip ab:

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

So rufen Sie eine Liste der Benachrichtigungen zu den angegebenen Benachrichtigungsereignissen ab:

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

eSIM-Profil über eine Mobilfunkanbieter-App aktivieren

Auf Geräten mit Android 9 oder höher können Sie die eSIM mit einer App des Mobilfunkanbieters aktivieren und Profile herunterladen. Die Mobilfunkanbieter-App kann Profile herunterladen, indem sie downloadSubscription direkt anruft oder dem LPA einen Aktivierungscode zur Verfügung stellt.

Wenn eine Mobilfunkanbieter-App ein Profil durch Aufrufen von downloadSubscription herunterlädt, wird durch den Aufruf erzwungen, dass die App das Profil über ein BF76-Metadaten-Tag verwalten kann, das Berechtigungsregeln für Mobilfunkanbieter für das Profil codiert. Wenn ein Profil kein BF76-Tag hat oder das BF76-Tag nicht mit der Signatur der Anruf-App des Mobilfunkanbieters übereinstimmt, wird der Download abgelehnt.

Im folgenden Abschnitt wird beschrieben, wie Sie eine eSIM über eine Mobilfunkanbieter-App mit einem Aktivierungscode aktivieren.

eSIM mit einem Aktivierungscode aktivieren

Wenn ein eSIM-Profil mit einem Aktivierungscode aktiviert wird, ruft die LPA einen Aktivierungscode aus der Mobilfunkanbieter-App ab und lädt das Profil herunter. Dieser Ablauf kann vom LPA eingeleitet werden und kann den gesamten UI-Ablauf steuern. Es wird also keine UI der Netzbetreiber-App angezeigt. Bei diesem Ansatz wird die BF76-Tag-Prüfung umgangen und Mobilfunkanbieter müssen nicht den gesamten UI-Vorgang für die eSIM-Aktivierung implementieren, einschließlich des Herunterladens eines eSIM-Profils und der Fehlerbehandlung.

Dienst zur Bereitstellung von eUICCs des Mobilfunkanbieters definieren

Die LPA und die Mobilfunkanbieter-App kommunizieren über zwei AIDL-Schnittstellen: ICarrierEuiccProvisioningService und IGetActivationCodeCallback. Die Mobilfunkanbieter-App muss eine ICarrierEuiccProvisioningService-Schnittstelle implementieren und in der Manifest-Erklärung offenlegen. Die LPA muss an ICarrierEuiccProvisioningService gebunden und IGetActivationCodeCallback implementieren. Weitere Informationen zum Implementieren und Bereitstellen einer AIDL-Schnittstelle finden Sie unter Definieren und Bereitstellen einer AIDL-Schnittstelle.

Erstellen Sie zum Definieren der AIDL-Schnittstellen die folgenden AIDL-Dateien sowohl für die LPA- als auch für die Mobilfunkanbieter-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 für die Implementierung von LPA

Um eine Bindung an die ICarrierEuiccProvisioningService-Implementierung der Mobilfunkanbieter-App herzustellen, muss der 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 Mobilfunkanbieter-App ruft der LPA entweder getActivationCode oder getActivationCodeForEid auf, um den Aktivierungscode aus der Mobilfunkanbieter-App abzurufen. Dazu wird die Implementierung der Stub-Klasse IGetActivationCodeCallback übergeben.

Der Unterschied zwischen getActivationCode und getActivationCodeForEid besteht darin, dass mit getActivationCodeForEid ein Mobilfunkanbieter ein Profil vorab an die EID des Geräts binden kann, 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 eine Mobilfunkanbieter-App

Damit die LPA an die Mobilfunkanbieter-App gebunden werden kann, muss die Mobilfunkanbieter-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, damit nur die LPA, eine App mit Systemberechtigungen, eine Bindung daran vornehmen kann. Der Dienst muss außerdem einen Intent-Filter 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>
    

Erstellen Sie zum Implementieren des AIDL-Carrier-App-Dienstes 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 Aktivierungscode für das Profil abzurufen. Die Mobilfunkanbieter-App sollte mit einer Antwort auf IGetActivationCodeCallback#onSuccess mit dem Aktivierungscode antworten, wenn der Code erfolgreich vom Server des Mobilfunkanbieters abgerufen wurde. Andernfalls sollte die Mobilfunkanbieter-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 Sie die Benutzeroberfläche der Mobilfunkanbieter-App im LPA-Aktivierungsvorgang.

Auf Geräten mit Android 11 und höher kann die LPA die Benutzeroberfläche einer Mobilfunkanbieter-App starten. Das ist nützlich, da eine Mobilfunkanbieter-App möglicherweise zusätzliche Informationen vom Nutzer benötigt, bevor ein Aktivierungscode an die LPA gesendet wird. So kann es beispielsweise sein, dass Mobilfunkanbieter Nutzer auffordern, sich anzumelden, um ihre Telefonnummern zu aktivieren oder andere Rufnummernmitnahmen durchzuführen.

So starten Sie die Benutzeroberfläche einer Mobilfunkanbieter-App in der LPA:

  1. Die LPA startet den Aktivierungsvorgang der Mobilfunkanbieter-App, indem sie den android.service.euicc.action.START_CARRIER_ACTIVATION-Intent an das Paket der Mobilfunkanbieter-App sendet, das die Aktion enthält. Der Empfänger der Mobilfunkanbieter-App muss in der Manifestdeklaration mit android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" geschützt werden, um zu verhindern, dass Intents von nicht LPA-Apps empfangen werden.

    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 Mobilfunkanbieter-App nutzt ihre eigene Benutzeroberfläche. Zum Beispiel die Anmeldung des Nutzers oder das Senden von HTTP-Anfragen an das Back-End des Mobilfunkanbieters.

  3. Die Mobilfunk-App antwortet auf die LPA, indem sie setResult(int, Intent) und finish() aufruft.

    1. Wenn die App des Mobilfunkanbieters mit RESULT_OK antwortet, fährt die LPA mit dem Aktivierungsvorgang fort. Wenn die Mobilfunkanbieter-App feststellt, dass der Nutzer einen QR-Code scannen soll, anstatt die LPA den Dienst der Mobilfunkanbieter-App binden zu lassen, antwortet die Mobilfunkanbieter-App der LPA über setResult(int, Intent) mit RESULT_OK und einer Intent-Instanz, die das boolesche Extra android.telephony.euicc.extra.USE_QR_SCANNER auf true festgelegt hat. Der LPA prüft dann die zusätzlichen Angaben und startet den QR-Scanner, anstatt die ICarrierEuiccProvisioningService-Implementierung der Mobilfunkanbieter-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 App des Mobilfunkanbieters mit etwas anderem als RESULT_OK oder RESULT_CANCELED antwortet, behandelt die LPA dies als Fehler.

    Aus Sicherheitsgründen darf die LPA keinen Aktivierungscode direkt akzeptieren, der in der Ergebnisabsicht angegeben ist, damit Anrufer, die keine LPA sind, keinen Aktivierungscode von der Mobilfunkanbieter-App erhalten können.

LPA-Aktivierungsablauf in einer Mobilfunkanbieter-App starten

Ab Android 11 können Mobilfunkanbieter-Apps eUICC APIs verwenden, um eine LUI für die Aktivierung von eSIMs zu starten. Bei dieser Methode wird die Benutzeroberfläche für die eSIM-Aktivierung des LPA angezeigt, um das eSIM-Profil zu aktivieren. Der LPA sendet dann eine Übertragung, wenn das eSIM-Profil aktiviert ist.

  1. Die LPA muss eine Aktivität deklarieren, die einen Intent-Filter mit der Aktion android.service.euicc.action.START_EUICC_ACTIVATION enthält. Die Priorität des Intent-Filters sollte auf einen Wert ungleich 0 festgelegt werden, falls sich auf dem Gerät mehrere Implementierungen befinden. 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 Mobilfunkanbieter-App nutzt ihre eigene Benutzeroberfläche. Zum Beispiel die Anmeldung des Nutzers oder das Senden von HTTP-Anfragen an das Back-End des Mobilfunkanbieters.

  3. Die Mobilfunkanbieter-App muss jetzt über ihre ICarrierEuiccProvisioningService-Implementierung einen Aktivierungscode bereitstellen können. Die Carrier-App startet die LPA, indem sie startActivityForResult(Intent, int) mit der Aktion android.telephony.euicc.action.START_EUICC_ACTIVATION aufruft. Der LPA prüft auch das boolesche Extraandroid.telephony.euicc.extra.USE_QR_SCANNER. Wenn der Wert true ist, startet die LPA den QR-Scanner, damit der Nutzer den QR-Code des Profils scannen kann.

  4. Auf der LPA-Seite bindet sich der LPA an die ICarrierEuiccProvisioningService-Implementierung der Mobilfunkanbieter-App, um den Aktivierungscode abzurufen und das entsprechende Profil herunterzuladen. Die LPA zeigt während des Downloads alle erforderlichen UI-Elemente an, z. B. einen Ladebildschirm.

  5. Wenn der LPA-Aktivierungsablauf abgeschlossen ist, antwortet die LPA mit einem Ergebniscode an die Mobilfunkanbieter-App, der in onActivityResult(int, int, Intent) verarbeitet wird.

    1. Wenn der LPA das neue eSIM-Profil herunterladen konnte, antwortet er mit RESULT_OK.
    2. Wenn der Nutzer die Aktivierung des eSIM-Profils in der LPA storniert, antwortet er mit RESULT_CANCELED.
    3. Wenn die LPA mit etwas anderem als RESULT_OK oder RESULT_CANCELED antwortet, behandelt die Mobilfunkanbieter-App dies als Fehler.

    Aus Sicherheitsgründen wird von der LPA kein Aktivierungscode direkt in der bereitgestellten Intent-Anfrage akzeptiert, damit nicht von der LPA stammende Anrufer den Aktivierungscode nicht von der Mobilfunkanbieter-App abrufen können.

Unterstützung mehrerer eSIMs

Bei Geräten mit Android 10 oder höher unterstützt die EuiccManager-Klasse Geräte mit mehreren eSIMs. Bei Geräten mit einer einzelnen eSIM, die auf Android 10 umgestellt werden, sind keine Änderungen an der LPA-Implementierung erforderlich, da die Plattform die EuiccManager-Instanz automatisch mit der Standard-eUICC verknüpft. 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 unter 1.2 bestimmt.

Voraussetzungen

Damit mehrere eSIMs unterstützt werden, muss das Gerät mehr als eine eUICC haben. Diese kann entweder eine integrierte eUICC sein oder ein physischer SIM-Steckplatz, in den entnehmbare eUICCs eingesetzt werden können.

Radio HAL Version 1.2 oder höher ist erforderlich, um mehrere eSIMs zu unterstützen. Empfohlen werden Radio HAL Version 1.4 und RadioConfig HAL Version 1.2.

Implementierung

Zur Unterstützung mehrerer eSIMs (einschließlich entfernbarer eUICCs oder programmierbarer SIMs) muss das LPA EuiccService implementieren, das die Slot-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 feststellen kann, ob eine eingelegte eUICC herausnehmbar ist oder nicht.

Anbieter-App für ein Gerät 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 angepinnt ist. Die Karten-ID ist ein ganzzahliger Wert, der eine UICC oder eUICC auf dem Gerät eindeutig identifiziert.

Verwenden Sie die Methode getCardIdForDefaultEuicc in TelephonyManager, um die Karten-ID für die standardmäßige eUICC des Geräts abzurufen. Diese Methode gibt UNSUPPORTED_CARD_ID zurück, wenn die HAL-Version der Funkschnittstelle niedriger als 1.2 ist, und UNINITIALIZED_CARD_ID, wenn das Gerät die eUICC nicht gelesen hat.

Karten-IDs können auch über getUiccCardsInfo und getUiccSlotsInfo (System-API) in TelephonyManager sowie über getCardId in SubscriptionInfo abgerufen werden.

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

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

Beispiel 1: Aktives Abo abrufen und EuiccManager instanziieren

// 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: Durch UICCs iterieren und EuiccManager für ein herausnehmbares eUICC instanziieren

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

Zertifizierungsstufe

AOSP enthält keine LPA-Implementierung und es ist nicht davon auszugehen, dass eine LPA für alle Android-Builds verfügbar ist (nicht jedes Smartphone unterstützt eSIM). Aus diesem Grund gibt es keine Ende-zu-Ende-CTS-Testfälle. In AOSP sind jedoch einfache Testläufe verfügbar, um sicherzustellen, dass die veröffentlichten eUICC-APIs in Android-Builds gültig sind.

Die Builds müssen die folgenden CTS-Tests bestehen (für öffentliche APIs): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts.

Mobilfunkanbieter, die eine Mobilfunkanbieter-App implementieren, sollten ihre normalen internen Qualitätssicherungszyklen durchlaufen, um sicherzustellen, dass alle implementierten Funktionen wie erwartet funktionieren. Die App des Mobilfunkanbieters sollte mindestens alle Aboprofile desselben Anbieters auflisten, ein Profil herunterladen und installieren, einen Dienst im Profil aktivieren, zwischen Profilen wechseln und Profile löschen können.

Wenn Sie Ihre eigene LPA erstellen, sollten Sie viel strengere Tests durchführen. Sie sollten mit Ihrem Modemanbieter, dem Anbieter des eUICC-Chips oder des eSIM-Betriebssystems, SM-DP+-Anbietern und Mobilfunkanbietern zusammenarbeiten, um Probleme zu beheben und die Interoperabilität Ihrer LPA innerhalb der RSP-Architektur zu gewährleisten. Ein großes Maß an manuellen Tests ist unvermeidlich. Für eine optimale Abdeckung sollten Sie dem GSMA SGP.23 RSP-Testplan folgen.